# -*- coding: utf-8 -*- """3.2(Ready for new interface).ipynb Automatically generated by Colaboratory. Original file is located at https://colab.research.google.com/drive/16maX93rvCuU14RBPDK60YxXqxv7aB4Jz # Libraries """ # from google.colab.patches import cv2_imshow import cv2 import numpy as np import pandas as pd import statistics from statistics import mode from PIL import Image # !pip install easydev # !pip install colormap # !pip install extcolors import matplotlib.pyplot as plt import matplotlib.patches as patches import extcolors from colormap import rgb2hex # !pip install pypdfium2 import pypdfium2 as pdfium import math import fitz import db import pilecaps_adr """# Reading Pdf file and returning image ready to use """ def convert2img(path): pdf = pdfium.PdfDocument(path) page = pdf.get_page(0) pil_image = page.render().to_pil() pl1=np.array(pil_image) img = cv2.cvtColor(pl1, cv2.COLOR_RGB2BGR) return img def readImgggg(img): hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) return hsv #change Background to red, this step before changing the gray shapes #This function helps in improving colour extraction later in the code def changeBackground(img): imgCopy = img.copy() hsv = cv2.cvtColor(imgCopy, cv2.COLOR_BGR2HSV) white_range_low = np.array([0,0,250]) white_range_high = np.array([0,0,255]) mask2=cv2.inRange(hsv,white_range_low, white_range_high) imgCopy[mask2>0]=(0,0,255) return imgCopy #If there any gray shapes it will be changed to blue def changeGrayModify(img): noGray = changeBackground(img) hsv = cv2.cvtColor(noGray, cv2.COLOR_BGR2HSV) gray_range_low = np.array([0,0,170]) gray_range_high = np.array([150,30,255]) mask=cv2.inRange(hsv,gray_range_low,gray_range_high) noGray[mask>0]=(255,0,0) return noGray #We may use this function to return background to white after changing the gray shapes to blue def returnWhite(img): imgCopy = img.copy() hsv = cv2.cvtColor(imgCopy, cv2.COLOR_BGR2HSV) red_range_low = np.array([0,250,250]) red_range_high = np.array([0,255,255]) mask2=cv2.inRange(hsv,red_range_low, red_range_high) imgCopy[mask2>0]=(255,255,255) return imgCopy """# Extracting colours for the next phase (preprocessing)""" #This function will take the image with red background and extract all the colours in the plan def extractClrs(medianF): im = cv2.cvtColor(medianF, cv2.COLOR_BGR2RGB) im = Image.fromarray(im) colors_x = extcolors.extract_from_image(im,8,8) listofTuples = [] for i in range(len(colors_x[0])): listofTuples.append(colors_x[0][i][0]) rgb = [] for i in range(len(listofTuples)): rgb.append([]) for i in range(len(listofTuples)): for j in range(len(listofTuples[i])): rgb[i].append(listofTuples[i][j]) rgb = np.uint8([[rgb]]) clr_hsv = [] for i in range(len(rgb)): clr_hsv.append(cv2.cvtColor(rgb[i], cv2.COLOR_RGB2HSV)) return clr_hsv #Used to delete any gray or white colours detected def deleteZeroHue(clr_hsv): clr_hsv_short = [] for i in range(len(clr_hsv[0][0])): if clr_hsv[0][0][i][0] > 0: clr_hsv_short.append(clr_hsv[0][0][i]) return clr_hsv_short #Saving the region of the different colours in the plan def dividingInput(clr_hsv_short): hInput = [] sInput = [] vInput = [] for i in range(len(clr_hsv_short)): hInput.append(clr_hsv_short[i][0]) sInput.append(clr_hsv_short[i][1]) vInput.append(clr_hsv_short[i][2]) return hInput, sInput, vInput #Setting the range of upper and lower range of the Hue of different colours #Will be used to separate each shape inside the plan in a different img due to their different colours def setRange(n, hInput): lower = [] upper = [] for i in range(len(hInput)): if (hInput[i] - n > 0): lower.append(np.uint(hInput[i] - n)) else: lower.append(np.uint(hInput[i])) upper.append(np.uint(hInput[i] + n)) return lower, upper """# Reading the image's colours""" #Saving all the hues, saturations, values of the plan def getColoursImage(hsv, img): hue = hsv[:,:,0] saturation = hsv[:,:,1] value = hsv[:,:,2] h=[] s=[] v=[] for i in range(img.shape[1]): for j in range(img.shape[0]): if hue[j][i] > 0 : h.append(hue[j][i]) s.append(saturation[j][i]) v.append(value[j][i]) return h,s,v #Putting different hues in different categories (each colour is a category) def categorizeV4(hsv, lower, upper, img): h, s, v = getColoursImage(hsv, img) groups = [] for i in range(len(lower)): groups.append([]) for i in range(len(h)): for j in range(len(lower)): if h[i] in range(lower[j],upper[j]): groups[j].append([h[i], s[i], v[i]]) return groups #Putting the hue, saturation, values in the categories def getHuesV3(categorey): hues = [] for i in range(len(categorey)): hues.append([]) for i in range(len(categorey)): for j in range(len(categorey[i])): hues[i].append(categorey[i][j][0]) return hues def getSaturationsV3(categorey): saturations = [] for i in range(len(categorey)): saturations.append([]) for i in range(len(categorey)): for j in range(len(categorey[i])): saturations[i].append(categorey[i][j][1]) return saturations def getValuesV3(categorey): values = [] for i in range(len(categorey)): values.append([]) for i in range(len(categorey)): for j in range(len(categorey[i])): values[i].append(categorey[i][j][2]) return values #Getting the maximum and minimum of each h,s,v of each category def setBoundaries(hues, saturations, values): hueMin = [] hueMax = [] satMin = [] satMax = [] valMin = [] valMax = [] for i in range(len(hues)): hueMin.append(min(hues[i])) hueMax.append(max(hues[i])) for i in range(len(saturations)): satMin.append(min(saturations[i])) satMax.append(max(saturations[i])) for i in range(len(values)): valMin.append(min(values[i])) valMax.append(max(values[i])) return hueMin, hueMax, satMin, satMax, valMin, valMax """# Colour Segmentation""" #Producing List of images, each image contains a shape of different Colour (imgResult) def segment(hueMin, hueMax, satMin, satMax, valMin, valMax): lowerRange = [] upperRange = [] for i in range(len(hueMin)): #lowerRange.append([hueMin[i], satMin[i] , valMin[i]]) lowerRange.append([hueMin[i], np.uint8(satMin[i] +15) , valMin[i]]) upperRange.append([hueMax[i], satMax[i], valMax[i]]) lower_range = np.array(lowerRange) upper_range = np.array(upperRange) return lower_range, upper_range def masking(lower_range, upper_range, hsvMedian, img): mask = [] imgResult = [] for i in range(len(lower_range)): mask.append(cv2.inRange(hsvMedian, lower_range[i], upper_range[i])) for j in range(len(lower_range)): imgResult.append(cv2.bitwise_and(img, img, mask=mask[j])) return imgResult """# Preprocessing""" # Returning a Clean Image ready to be used in measurement def bluring(imgResult): imgGray = [] imgBlur = [] for i in range(len(imgResult)): imgGray.append(cv2.cvtColor(imgResult[i], cv2.COLOR_BGR2GRAY)) for i in range(len(imgGray)): imgBlur.append(cv2.GaussianBlur(imgGray[i], (5,5),3)) return imgBlur def preprocessing(imgBlur): imTT = [] th2 = [] for i in range(len(imgBlur)): imTT.append([]) for k in range(len(imgBlur)): for i in range(imgBlur[k].shape[1]): for j in range(imgBlur[k].shape[0]): if imgBlur[k][j][i] > 5: imTT[k].append(imgBlur[k][j][i]) modd = [] for i in range(len(imTT)): modd.append(mode(imTT[i])) for i in range(len(imgBlur)): th2.append(cv2.threshold(imgBlur[i],modd[i]-70,255,cv2.THRESH_BINARY)) return th2 def is_contour_bad(c): peri = cv2.arcLength(c, True) approx = cv2.approxPolyDP(c, 0.02 * peri, True) return cv2.contourArea(c) < 1200 def beforeCelaning(maskBad, th2): imgb4Cleaned = [] for i in range(len(th2)): imgb4Cleaned.append(th2[i][1].copy()) return imgb4Cleaned def badMask(imgResult, img): maskBad = [] for i in range(len(imgResult)): maskBad.append(np.ones(img.shape[:2], dtype="uint8") * 255) return maskBad def applyBadContours(imgb4Cleaned, th2, maskBad): imgCleaned = [] for j in range(len(th2)): contours, hierarchy = cv2.findContours(image=th2[j][1], mode=cv2.RETR_EXTERNAL, method=cv2.CHAIN_APPROX_SIMPLE) for k, cnt in enumerate(contours): if is_contour_bad(cnt): cv2.drawContours(maskBad[j], [cnt], -1, 0, -1) imgCleaned.append(cv2.bitwise_and(imgb4Cleaned[j], th2[j][1], mask=maskBad[j])) return imgCleaned def morph(imgCleaned): dilations = [] kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(5,5)) for i in range(len(imgCleaned)): dilations.append(cv2.dilate(imgCleaned[i], kernel, iterations=2)) return dilations """# (optional) If we want to get those rectangle colours in producing Legends""" def extractNewRgb(imgResult): im = cv2.cvtColor(imgResult, cv2.COLOR_BGR2RGB) im = Image.fromarray(im) colors_x = extcolors.extract_from_image(im,2,2) listofTuples = [] for i in range(len(colors_x[0])): listofTuples.append(colors_x[0][i][0]) rgb = [] for i in range(len(listofTuples)): rgb.append([]) for i in range(len(listofTuples)): for j in range(len(listofTuples[i])): rgb[i].append(listofTuples[i][j]) return rgb def intRgb(imgResult): list_keda = [] for i in range(len(imgResult)): list_keda.append(extractNewRgb(imgResult[i])) newRgb = [] for i in range(len(list_keda)): newRgb.append(list_keda[i][1]) list_int = [] for i in range(len(newRgb)): list_int.append([]) for i in range(len(newRgb)): for j in range(len(newRgb[i])): list_int[i].append(int(newRgb[i][j])) return list_int def rgb2hexa(list_int): x = [] for i in range(len(list_int)): x.append(rgb2hex(list_int[i][0],list_int[i][1],list_int[i][2])) return x # (optional) If we want to get those rectangle colours in producing Legends def extractNewRgb(imgResult): im = cv2.cvtColor(imgResult, cv2.COLOR_BGR2RGB) im = Image.fromarray(im) colors_x = extcolors.extract_from_image(im,2,2) listofTuples = [] for i in range(len(colors_x[0])): listofTuples.append(colors_x[0][i][0]) rgb = [] for i in range(len(listofTuples)): rgb.append([]) for i in range(len(listofTuples)): for j in range(len(listofTuples[i])): rgb[i].append(listofTuples[i][j]) return rgb def intRgb(imgResult): list_keda = [] for i in range(len(imgResult)): list_keda.append(extractNewRgb(imgResult[i])) newRgb = [] for i in range(len(list_keda)): newRgb.append(list_keda[i][1]) list_int = [] for i in range(len(newRgb)): list_int.append([]) for i in range(len(newRgb)): for j in range(len(newRgb[i])): list_int[i].append(int(newRgb[i][j])) return list_int def rgb2hexa(list_int): x = [] for i in range(len(list_int)): x.append(rgb2hex(list_int[i][0],list_int[i][1],list_int[i][2])) return x """# Measuring Area """ # Produce List of shape's area in PPIXELS def getArea(dilation): contourzz, hierarchy = cv2.findContours(image=dilation, mode=cv2.RETR_EXTERNAL, method=cv2.CHAIN_APPROX_NONE) areaa = 0 for i, cnt3 in enumerate(contourzz): M = cv2.moments(cnt3) if M['m00'] != 0.0: x2 = int(M['m10']/M['m00']) y2 = int(M['m01']/M['m00']) area3 = cv2.contourArea(cnt3) areaa = areaa+area3 return areaa def measure(dilations): areas = [] for i in range(len(dilations)): areas.append(getArea(dilations[i])) return areas #Producing Image with drawing Contours and putting the number of areas as text on the shape def getDrawing(page,ratio,dilation, img ,areaRatio,perimRatio): contourzz, hierarchy = cv2.findContours(image=dilation, mode=cv2.RETR_EXTERNAL, method=cv2.CHAIN_APPROX_NONE) areaa = 0 perimeter = 0 imgNew = img for i, cnt3 in enumerate(contourzz): shape=[] M = cv2.moments(cnt3) if M['m00'] != 0.0: x2 = int(M['m10']/M['m00']) y2 = int(M['m01']/M['m00']) area3 = cv2.contourArea(cnt3) areaRatio1= area3*areaRatio areaa = areaa+area3 perimeter3 = cv2.arcLength(cnt3, True) perimeterRatio1=perimeter3*perimRatio perimeterr = perimeter+perimeter3 approx = cv2.approxPolyDP(cnt3, 0.005 * perimeter3, True) for point in approx: x1, y1 = point[0] shape.append([int(x1*ratio),int(y1*ratio)]) #areaa = round(areaa * 15.25/13480.0, 3) cv2.putText(imgNew, f'Area :{areaa}', (x2, y2), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2) imgNew = cv2.drawContours(img, [cnt3], -1, (0,255,255), 3) annot = page.add_polygon_annot( points=shape ) # 'Polygon' annot.set_border(width=0.3, dashes=[2]) annot.set_colors( fill=( 0 , 1, 1 ) ) # annot.set_colors( fill=(1,0,1) ) annot.set_opacity(0.5) annot.set_info(content='Area='+str(areaRatio1)+' m2' +'\n \nPerimeter='+str(perimeterRatio1)+' m',subject='ADR Team')#,title='uuum') # annot.set_line_ends(fitz.PDF_ANNOT_LE_DIAMOND, fitz.PDF_ANNOT_LE_CIRCLE) annot.update() # doc.save('tameem.pdf', deflate=True) return imgNew def exDraw(plan, dilations, img, pdfpath,areaRatio,perimRatio): ## doc = fitz.open('dropbox_plans/3.2/'+plan) page = doc[0] page.set_rotation(0) pix=page.get_pixmap() ratio = pix.width/ img.shape[1] ### print(pdfpath) newImg = img for i in range(len(dilations)): newImg = (getDrawing(page,ratio, dilations[i], img ,areaRatio,perimRatio)) # doc.save('tameem.pdf', deflate=True) pdflink= db.dropbox_upload_file(doc=doc,pdfname=plan,pdfpath=pdfpath) print(pdflink) return newImg , pdflink # Perimeter def getPerimeter(dilation): contourzz, hierarchy = cv2.findContours(image=dilation, mode=cv2.RETR_EXTERNAL, method=cv2.CHAIN_APPROX_NONE) perimeter = 0 for i, cnt3 in enumerate(contourzz): #imgResult4 = img.copy() M = cv2.moments(cnt3) if M['m00'] != 0.0: x2 = int(M['m10']/M['m00']) y2 = int(M['m01']/M['m00']) perimeter3 = cv2.arcLength(cnt3, True) perimeter = perimeter+perimeter3 return perimeter def measureP(dilations): perimeters = [] for i in range(len(dilations)): perimeters.append(getPerimeter(dilations[i])) return perimeters # Number of Shapes def getNumber(dilation): contourzz, hierarchy = cv2.findContours(image=dilation, mode=cv2.RETR_EXTERNAL, method=cv2.CHAIN_APPROX_NONE) n_shapes = 0 for i, cnt3 in enumerate(contourzz): #imgResult4 = img.copy() M = cv2.moments(cnt3) if M['m00'] != 0.0: x2 = int(M['m10']/M['m00']) y2 = int(M['m01']/M['m00']) n_shapes = n_shapes + 1 return n_shapes def countShapes(dilations): n_shapes = [] for i in range(len(dilations)): n_shapes.append(getNumber(dilations[i])) return n_shapes # Length def getLength(dilation): contourzz, hierarchy = cv2.findContours(image=dilation, mode=cv2.RETR_EXTERNAL, method=cv2.CHAIN_APPROX_NONE) perimeter = 0 for i, cnt3 in enumerate(contourzz): #imgResult4 = img.copy() M = cv2.moments(cnt3) if M['m00'] != 0.0: x2 = int(M['m10']/M['m00']) y2 = int(M['m01']/M['m00']) x, y, w, h = cv2.boundingRect(cnt3) return w def measureL(dilations): Length = [] for i in range(len(dilations)): Length.append(getLength(dilations[i])) return Length """# Converting Pixels to M2 """ #Producing Reference Object and calculating it's vale in PIXELS def calcRef(img): blk = np.ones(img.shape, dtype="uint8") * [[[np.uint8(0), np.uint8(0), np.uint8(0)]]] start_point = (50, 100) end_point = (120, 200) color = (255, 255, 255) # white BGR thickness = -1 # Thickness of -1 will fill the entire shape blk = cv2.rectangle(blk, start_point, end_point, color, thickness) blk = cv2.cvtColor(blk, cv2.COLOR_BGR2GRAY) contourzz, hierarchy = cv2.findContours(image=blk, mode=cv2.RETR_EXTERNAL, method=cv2.CHAIN_APPROX_NONE) for i, cnt3 in enumerate(contourzz): M = cv2.moments(cnt3) if M['m00'] != 0.0: x2 = int(M['m10']/M['m00']) y2 = int(M['m01']/M['m00']) area = cv2.contourArea(cnt3) return area # Saving the Area of the Reference object in M2 that we get from the user def getRealRef(area): areaFromUser = area return areaFromUser # Calculating the M2 areas of each shape and saving them in a List # areaGotFromUser --> User will pass it after measuring the produced shape in BB # areaPixelRef --> will get it from calcRef() function # areas --> will get it from the measure() function in the "Measuring Area Cells" def m2R(PixelMetricRatio, areas): mreal = [] for i in range(len(areas)): mreal.append(areas[i] * PixelMetricRatio) return mreal """# Another approach (Getting the display screen dimensions from user)""" def ppi_calculate(width, height, inch): diagonal = math.sqrt((width**2 )+(height**2)) ppi = diagonal / inch ppi2 = ppi * ppi return ppi2 def convertToMeterSQ(ratio, areas): areaM2 = [] for i in range(len(areas)): areaM2.append(round(areas[i] * ratio, 3)) # true value of area of any shape/ area px value of same shape return areaM2 """# Main Function That calls all of the above functions""" def mainFunction(plan, areaRatio ,perimRatio, pdfpath): plan1='dropbox_plans/3.2/'+str(plan) img = convert2img(plan1) img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR) imgChange = changeGrayModify(img) hsv = readImgggg(imgChange) clr_hsv = extractClrs(imgChange) clr_hsv_short = deleteZeroHue(clr_hsv) hInput, sInput, vInput = dividingInput(clr_hsv_short) lower, upper = setRange(5, hInput) cat2 = categorizeV4(hsv, lower, upper, img) hues = getHuesV3(cat2) values = getValuesV3(cat2) saturations = getSaturationsV3(cat2) hueMin, hueMax, satMin, satMax, valMin, valMax = setBoundaries(hues, saturations, values) lower_range, upper_range = segment(hueMin, hueMax, satMin, satMax, valMin, valMax) imgResult = masking(lower_range, upper_range, hsv, img) ##For the Legend newRgb and hexClrs, make the main function returns one of the following two variables ## newRgb or hexClrs newRgb = intRgb(imgResult) hexClrs = rgb2hexa(newRgb) imgBlur = bluring(imgResult) th2 = preprocessing(imgBlur) maskBad = badMask(imgResult, img) imgb4Cleaned = beforeCelaning(maskBad,th2) imgCleaned = applyBadContours(imgb4Cleaned, th2, maskBad) dilations = morph(imgCleaned) # newImg , pdflink = exDraw(plan, dilations, img , pdfpath) areas = measure(imgCleaned) perimeters = measureP(imgCleaned) quantites = countShapes(imgCleaned) length = measureL(imgCleaned) # area_ref_pixel, perimeter_ref_pixel = calcRef(img) # area_ref_real = getRealRef(areaRef) # perimeter_ref_real = getRealRefL(perimeterRef) realArea = m2R(areaRatio, areas) realPerimeter = m2R(perimRatio, perimeters) newImg , pdflink= exDraw(plan,dilations, img, pdfpath,areaRatio, perimRatio ) data = { 'Color' : newRgb, 'Occurences': quantites, 'Area':realArea, 'Total Area': realArea, 'Perimeter':perimeters, 'Total Perimeter': perimeters, 'Length': length, 'Total Length': length} df = pd.DataFrame(data) print(df) gc,spreadsheet_service,spreadsheetId, spreadsheet_url , namepathArr= pilecaps_adr.legendGoogleSheets(df,plan ,pdfpath) dbx=db.dropbox_connect() md, res =dbx.files_download(path= pdfpath+plan) data = res.content doc=fitz.open("pdf", data) # list1=pd.DataFrame(columns=['content', 'creationDate', 'id', 'modDate', 'name', 'subject', 'title']) list1=pd.DataFrame(columns=['content', 'id', 'subject']) for page in doc: for annot in page.annots(): list1.loc[len(list1)] =annot.info print(list1) return newImg, df , pdflink , spreadsheetId, spreadsheet_url , list1