-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfunctions.py
431 lines (321 loc) · 12.3 KB
/
functions.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
#!/usr/bin/env python
# coding: utf-8
# In[1]:
import cv2 as cv
import numpy as np
import sys
import copy
import os
from matplotlib import pyplot as plt
from skimage.morphology import skeletonize
from mpl_toolkits.mplot3d import Axes3D
# In[2]:
PATH = 'G:/computer vision/alcon2019/dataset/test/imgs/'
WRITEPATH = 'C:/Users/AlcanderLiu/Desktop/outputs'
if not os.path.exists(WRITEPATH):
os.makedirs(WRITEPATH)
# In[3]:
def read_image(imgNum):
# path = PATH+str(imgNum)+'.jpg'
origImg = cv.imread(str(imgNum))
# plt.imshow(origImg)
# plt.title("origImg")
# plt.show()
return origImg
# In[4]:
# img = read_image(2231)
# In[5]:
'''
This function returns the ostu transform image of the input image with a Guassian blur with kernel of (11, 11)
'''
def otsu_img_blurred(img):
grayImg = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
blur = cv.GaussianBlur(grayImg, (11,11), 0)
ret, otsuImg = cv.threshold(blur, 0, 255, cv.THRESH_BINARY_INV + cv.THRESH_OTSU)
return otsuImg
'''
This function returns the opening image of the input with a kernel of (11, 11)
'''
def open_img(img):
kernel = np.ones((11,11), np.uint8)
temp = cv.morphologyEx(img, cv.MORPH_OPEN, kernel)
return temp
'''
This function returns the thinning image of the input
'''
def thin_img(img):
temp = cv.ximgproc.thinning(img)
return temp
'''
This fucntion returns all the stats for connencte components
Statistics output for each label, including the background label, see below for available statistics. Statistics are accessed via stats[label, COLUMN] where available columns are defined below.
cv2.CC_STAT_LEFT The leftmost (x) coordinate which is the inclusive start of the bounding box in the horizontal direction.
cv2.CC_STAT_TOP The topmost (y) coordinate which is the inclusive start of the bounding box in the vertical direction.
cv2.CC_STAT_WIDTH The horizontal size of the bounding box
cv2.CC_STAT_HEIGHT The vertical size of the bounding box
cv2.CC_STAT_AREA The total area (in pixels) of the connected component
'''
def find_cc(img):
ccOutput = cv.connectedComponentsWithStats(img)
return ccOutput
'''
This function returns the sum of every row in the input, divied by 255 to normalize
'''
def sum_row(img):
return np.array([np.sum(row) for row in img])/255
'''
This function will crop the images base on the crop location into 3 separate images
'''
def crop_img(imgNum, img, loc, method):
title = str(imgNum)+'_Seg'
loc = np.sort(loc)
seg1 = img[:loc[0], :]
seg2 = img[loc[0]:loc[1], :]
seg3 = img[loc[1]:, :]
segmentations = [seg1, seg2, seg3]
for i in range(3):
# plt.imshow(segmentations[i])
cv.imwrite(os.path.join(WRITEPATH, title+str(i+1)+'_'+str(method)+'.jpg'), segmentations[i])
return segmentations
# In[6]:
'''
First segmentation method
'''
def segmentation_1(imgNum, img):
otsu = otsu_img_blurred(img)
thinImg = thin_img(otsu)
thinRowSum = sum_row(thinImg)
charFlag = True
cropLoc = np.array([], dtype = 'int')
temp = 0
# Find first non-zero
for i in range(thinRowSum.shape[0]):
if thinRowSum[i] != 0:
temp = i
break
# print(temp)
# Find the lower bound of each charater in the picture
for row in range(temp, thinRowSum.shape[0]):
if thinRowSum[row] == 0 and charFlag == True:
cropLoc = np.append(cropLoc, row)
charFlag = False
elif thinRowSum[row] != 0 and charFlag == False:
charFlag = True
if cropLoc.size == 2:
break
# print(cropLoc)
if cropLoc.size != 2:
raise Exception('cropLox size should be 2. The value of size is: {}'.format(cropLoc.size))
else:
return crop_img(imgNum, img, cropLoc, 1)
# In[7]:
'''
Second sementation method
'''
def segmentation_2(imgNum, img):
cropLoc = np.array([])
otsu = otsu_img_blurred(img)
openImg = open_img(otsu)
thinImg = thin_img(otsu)
# ors := open row sum, trs := thin row sum
ors = sum_row(openImg)
trs = sum_row(thinImg)
# otm:= one third mark of the image
# ttm:= two third mark of the image
otm = int(img.shape[0]*(1/3))
ttm = int(img.shape[0]*(2/3))
#
break1NotDone = True
break2NotDone = True
conv = ors * trs
i = 0
while break1NotDone or break2NotDone:
# If the one third mark is zero, find the first non zero above and blow it in the rowSum
# If the one third mark isn't zero, find the first zero above and blow it in the rowSum
if break1NotDone:
if conv[otm] == 0:
if conv[otm-i] != 0 or conv[otm+i] !=0:
cropLoc = np.append(cropLoc, (otm-i) if conv[otm-i] != 0 else (otm+i))
break1NotDone = False
elif (otm+i) == ttm or (otm-i) == 0:
cropLoc = np.append(cropLoc, otm)
break1NotDone = False
else:
if conv[otm-i] == 0 or conv[otm+i] == 0:
cropLoc = np.append(cropLoc, (otm-i) if conv[otm-i] == 0 else (otm+i))
break1NotDone = False
elif (otm+i) == ttm or (otm-i) == 0:
cropLoc = np.append(cropLoc, otm)
break1NotDone = False
# Same thing as the previous loop but at two third mark
if break2NotDone:
if conv[ttm] == 0:
if conv[ttm-i] != 0 or conv[ttm+i] !=0:
cropLoc = np.append(cropLoc, (ttm-i) if conv[ttm-i] != 0 else (ttm+i))
break2NotDone = False
elif (ttm+i) == img.shape[0] or (ttm-i) == otm:
cropLoc = np.append(cropLoc, ttm)
break2NotDone = False
else:
if conv[ttm-i] == 0 or conv[ttm+i] == 0:
cropLoc = np.append(cropLoc, (ttm-i) if conv[ttm-i] == 0 else (ttm+i))
break2NotDone = False
elif (ttm+i) == img.shape[0] or (ttm-i) == otm:
cropLoc = np.append(cropLoc, ttm)
break2NotDone = False
i += 1
# print(cropLoc)
if cropLoc.size != 2:
raise Exception('cropLox size should be 2. The value of size is: {}'.format(cropLoc.size))
else:
return crop_img(imgNum, img, cropLoc.astype(int), 2)
# In[8]:
'''
Third segmentation method
'''
def segmentation_3(imgNum, img):
cropLoc = np.array([])
otsu = otsu_img_blurred(img)
openImg = open_img(otsu)
thinImg = thin_img(otsu)
cc = find_cc(thinImg)
# Get labels and totale number of labels
labelNum = cc[0]
labelImg = cc[1]
# Get area for the each label
lefts = cc[2][1:labelNum, 0]
tops = cc[2][1:labelNum, 1]
widths = cc[2][1:labelNum, 2]
heights = cc[2][1:labelNum, 3]
areas = cc[2][1:labelNum, 4]
# Element-wise multiplication of heights and areas
ha = heights * areas
haSum = np.sum(ha)
# print(ha)
# If the ha value of the label is smaller than 15% of the haSum, it is unsifnificant and can be labeled by its overlapping counterpart
sigLabel = np.array([], dtype = 'int')
for i in range(labelNum - 1):
if ha[i] >= 0.15*haSum:
# print(ha[i])
sigLabel = np.append(sigLabel, i+1)
# print(sigLabel.size)
# Find each label's range, labelRange = [label, top, bottom]
labelRange = np.array([], dtype = 'int')
labelArea = np.array([], dtype = 'int')
for i in range(labelNum - 1):
labelRange = np.append(labelRange, [i+1, tops[i], tops[i]+heights[i]])
labelArea = np.append(labelArea, [i+1, areas[i]])
# print(labelRange[3*i: 3*i+3])
# print("\n")
# Insignificant character overlapping
# Check the overlapping, if it is insignificant, repalce with overlapping counterpart
for i in range(labelNum - 1):
for j in range(labelNum - 1):
if i == j:
continue
if labelRange[3*i+1] >= labelRange[3*j+1] and labelRange[3*i+2] <= labelRange[3*j+2] and (labelRange[3*i] not in sigLabel):
labelRange[3*i] = labelRange[3*j]
labelArea[2*i] = labelRange[3*j]
break
# for i in range(labelNum-1):
# print(labelRange[3*i: 3*i+3])
# Replace the labels on the image for the insignificant ones
newLabelImg = copy.deepcopy(labelImg)
for i in range(labelNum - 1):
if (i+1) == labelRange[3*i]:
continue
else:
newLabelImg = np.where(newLabelImg == (i+1), labelRange[3*i], newLabelImg)
# If total labels are less than 2, the problem is out of the league of connected component
if labelNum <= 3:
return segmentation_10(imgNum, img)
# If significant labels are 0, means the pictures are highly scattered
elif sigLabel.size == 0 :
return segmentation_10(imgNum, img)
# If there is only one significant label
elif sigLabel.size == 1:
lab = sigLabel[0]
height = heights[lab - 1]
loc = labelRange[3*(lab-1)+1 :3*(lab-1)+3]
if height <= img.shape[0] * 0.4 and loc[1] < img.shape[0] * (1/3):
cropLoc = np.append(cropLoc, [loc[1], int(img.shape[0] * 2/3)])
# print(1, cropLoc)
return crop_img(imgNum, img, cropLoc.astype(int), 3)
elif height <= img.shape[0] * 0.4 and loc[0] > img.shape[0] * (2/3):
cropLoc = np.append(cropLoc, [int(img.shape[0] * 1/3), loc[0]])
# print(2, cropLoc)
return crop_img(imgNum,img, cropLoc.astype(int), 3)
else:
return segmentation_10(imgNum, img)
# If there are exactly two significant labels, crop base on the labels' location
elif sigLabel.size == 2 and labelNum > 3:
if sigLabel[0] != 1:
newLabelImg = np.where(newLabelImg == sigLabel[0], 1, newLabelImg)
if sigLabel[1] != 2:
newLabelImg = np.where(newLabelImg == sigLabel[1], 2, newLabelImg)
for i in range(3, labelNum):
newLabelImg = np.where(newLabelImg == int(i), int(3), newLabelImg)
twonotdone = False
threenotdone = False
# print(newLabelImg.shape)
for row in range(newLabelImg.shape[0]):
cropFlag = False
if 2 in newLabelImg[row] and cropFlag == False and twonotdone == False:
cropLoc = np.append(cropLoc, row)
cropFlag == True
twonotdone = True
if 3 in newLabelImg[row] and threenotdone == False:
cropLoc = np.append(cropLoc, row)
threenotdone = True
break
# print(3,cropLoc)
return crop_img(imgNum, img, cropLoc.astype(int), 3)
# In[9]:
'''
Fifth segmentation method
Pure brute force
'''
def segmentation_5(imgNum, img):
cropLoc = np.array([int(img.shape[0]*(1/3)), int(img.shape[0]*(2/3))])
return crop_img(imgNum, img, cropLoc, 5)
# In[10]:
'''
Backup segmentation method
Pure brute force
'''
def segmentation_10(imgNum, img):
cropLoc = np.array([int(img.shape[0]*(1/3)), int(img.shape[0]*(2/3))])
# print('!!!seg 10')
return crop_img(imgNum, img, cropLoc, 10)
# In[11]:
def main():
img = cv.imread('G:/computer vision/alcon2019/dataset/test/imgs/14.jpg')
print(img)
#grayImg = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
print(img)
imgNum = 14
'''
result = segmentation_1(imgNum, img)
if result is not None:
for img1 in result:
img1 = cv.cvtColor(img1, cv.COLOR_BGR2GRAY)
'''
result = segmentation_2(imgNum, img)
if result is not None:
for img1 in result:
img1 = cv.cvtColor(img1, cv.COLOR_BGR2GRAY)
'''
result = segmentation_3(imgNum, img)
if result is not None:
print(result)
for img1 in result:
img1 = cv.cvtColor(img1, cv.COLOR_BGR2GRAY)
'''
result = segmentation_5(imgNum, img)
if result is not None:
for img1 in result:
img1 = cv.cvtColor(img1, cv.COLOR_BGR2GRAY)
segMethods = [segmentation_1, segmentation_2, segmentation_3, None, segmentation_5]
# In[ ]:
if __name__ == "__main__":
main()