MeasurementTesting / tameem3_2.py
Marthee's picture
Upload 5 files
154e666
# -*- 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