+
+def getxy(file):
+ """
+ {
+ 'Image00001': [{
+ 'color': '#ff0000',
+ 'points': [
+ {'x': 94.377, 'y': 137.39},
+ {'x': 100.38, 'y': 139.55},
+ {'x': 103.26, 'y': 142.67},
+ {'x': 105.91, 'y': 147.95},
+ {'x': 105.42, 'y': 152.76},
+ {'x': 100.62, 'y': 156.84},
+ {'x': 95.338, 'y': 159.96},
+ {'x': 89.573, 'y': 158.52},
+ {'x': 84.53, 'y': 153},
+ {'x': 82.848, 'y': 149.15},
+ {'x': 82.368, 'y': 142.91},
+ {'x': 85.01, 'y': 138.11},
+ {'x': 89.813, 'y': 137.39},
+ {'x': 94.377, 'y': 137.39}
+ ]
+ }]
+ }
+ return [(94.377, 137.39), ...]
+ """
+ with open(file) as jsonfile:
+ data = json.load(jsonfile)
+ # pprint(data)
+
+ for imgXXX in data: pass # get the value of key ~= "Image00001", cause it's dynamic
+
+ for obj in data[imgXXX]: pass # get the object that contains the points, cause it's a list
+ points = obj['points']
+
+ # print("print, ", data)
+ # print("imgXXX, ", imgXXX)
+ # print("points, ", points)
+ # print("imgXXX, ", obj['points'])
+ tmp = [np.array( (round(pt['x']), round(pt['y'])) ).astype(np.int32) for pt in
+ points] # extract x,y. {'x': 94.377, 'y': 137.39} => (94.377, 137.39)
+ return np.array(tmp, dtype=np.int32)
+ # return tmp
+
+def minmax(file):
+ r = getxy(file)
+ if r is not None:
+ # print(r) # log
+ xmin, ymin = np.min(r, axis=0)
+ xmax, ymax = np.max(r, axis=0)
+
+ # print('xmax, ymax', xmax, ymax)
+ # print('xmin, ymin', xmin, ymin)
+
+ return roundall(xmin, ymin, xmax, ymax)
+
+def crop(Mat, maskfile, size=None):
+ """
+ size : if filled with a (45, 45), it will search the center of maskfile then crop by center Mat
+ """
+ xmin, ymin, xmax, ymax = minmax(maskfile)
+ if size:
+ xcenter = (xmin + xmax) / 2
+ ycenter = (ymin + ymax) / 2
+
+ # crop coords
+ ymin, xmin, ymax, xmax = roundall(xcenter - size[0], ycenter - size[0],
+ xcenter + size[1], ycenter + size[1])
+
+ return Mat[xmin:xmax, ymin:ymax]
+
+def contour(Mat, maskfiles, color, thickness=1):
+ # ---------- CONTOUR POLYGON ----------
+ # thickness = -1 => fill it
+ # = 1 => just draw the contour with color
+ #
+ # return new Mat
+ contours = [getxy(maskfile) for maskfile in maskfiles] # list of list of coords,
+ # [
+ # [ (3,43), (3,4) ],
+ # [ (33,43) ]
+ # ]
+ # print("log: contours", contours)
+ if contours is not None:
+ # print('type contours', type(contours))
+ # print('contours', contours)
+ msk = np.zeros(Mat.shape, dtype=np.int32) # init all the mask with True...
+ cv2.drawContours(msk, contours, -1, True, thickness) # affect Mat, fill the polygone with False
+ msk = msk.astype(np.bool)
+ # print('msk')
+ # print(msk)
+ # print("bool", timeit(lambda:msk, number=1000))
+ # print("normal", timeit(lambda:msk.astype(np.bool), number=1000))
+ # Mat = cv2.cvtColor(Mat, cv2.COLOR_RGB2GRAY) # apply gray
+
+ # Mat = drawcontours(Mat, contours)
+ # pass
+ Mat[msk] = color # each True in msk means 0 in Mat. msk is like a selector
+ return Mat
+
+def mask(Mat, maskfile, color=0, thickness=-1):
+ # ---------- MASK POLYGON ----------
+ # thickness = -1 => fill it
+ # = 1 => just draw the contour with color
+ #
+ # return new Mat
+ contours = getxy(maskfile)
+ # print("log: contours", contours)
+ if contours is not None:
+ # print('type contours', type(contours))
+ # print('contours', contours)
+ msk = np.ones(Mat.shape, dtype=np.int32) # init all the mask with True...
+ cv2.drawContours(msk, [contours], -1, False, thickness) # affect msk, fill the polygone with False, => further, don't touch where is False
+ msk = msk.astype(np.bool)
+ # print('msk')
+ # print(msk)
+ # print("bool", timeit(lambda:msk, number=1000))
+ # print("normal", timeit(lambda:msk.astype(np.bool), number=1000))
+ # Mat = cv2.cvtColor(Mat, cv2.COLOR_RGB2GRAY) # apply gray
+
+ # Mat = drawcontours(Mat, contours)
+ # pass
+ Mat[msk] = color # each True in msk means 0 in Mat. msk is like a selector
+ return Mat
+
+
+def hollowmask(Mat, epifile, endofile, color=0, thickness=-1):
+ # ---------- MASK POLYGON ----------
+ # thickness = -1 => fill it
+ # = 1 => just draw the contour with color
+ #
+ # return new Mat
+ epicontours = getxy(epifile)
+ endocontours = getxy(endofile)
+ if epicontours is not None and endocontours is not None:
+ msk = np.ones(Mat.shape, dtype=np.int32) # init all the mask with True...
+ cv2.drawContours(msk, [epicontours], -1, False, thickness) # affect msk, fill the polygone with False, => further, don't touch where is False
+ cv2.drawContours(msk, [endocontours], -1, True, thickness) # fill the intern polygone with True, (the holow in the larger polygon), => further, color where is True with black for example
+ msk = msk.astype(np.bool)
+
+ Mat[msk] = color # each True in msk means 0 in Mat. msk is like a selector
+ return Mat
+
+
+def sqrmask1(Mat, maskfile):
+ # ---------- SQUARE MASK 1st approach ----------
+ # print( timeit( lambda:sqrmask1(img, epimask), number=1000 ) ) # 0.48110522600000005
+ # return new Mat
+ xmin, ymin, xmax, ymax = minmax(maskfile)
+ # print("xmin, ymin, xmax, ymax", xmin, ymin, xmax, ymax)
+
+ i = 0
+ while i < ymin:# search by top
+ Mat[i].fill(0)# paint the row in black
+ i += 1
+
+ i = len(Mat) - 1
+ while i > ymax:# search by bottom
+ Mat[i].fill(0)# paint the row in black
+ i -= 1
+
+ i = 0
+ while i < xmin:# search by top
+ Mat.T[i, ymin:ymax+1].fill(0) # paint the column (row of the Transpose) in black, ymin and ymax to optimize, cause, I previously painted a part
+ i += 1
+
+ i = len(Mat.T) - 1
+ while i > xmax:# search by bottom
+ Mat.T[i, ymin:ymax+1].fill(0) # paint the column (row of the Transpose) in black, ymin and ymax to optimize, cause, I previously painted a part
+ i -= 1
+
+ return Mat
+
+def sqrmask2(Mat, maskfile):
+ # ---------- SQUARE MASK 2nd and best approach ----------
+ # print( timeit( lambda:sqrmask2(img, epimask), number=1000 ) ) # 0.3097705270000001
+ # return new Mat
+ xmin, ymin, xmax, ymax = minmax(maskfile)
+ # print("xmin, ymin, xmax, ymax", xmin, ymin, xmax, ymax)
+
+ msk = np.ones(Mat.shape, dtype=np.int32) # init all the mask with True...
+ msk = msk.astype(np.bool)
+
+ msk[ymin:ymax, xmin:xmax] = False # for after, don't touch between min and max region
+ Mat[msk] = 0
+
+ return Mat
+