a b/inspection.py
1
import cv2 as cv
2
import numpy as np
3
from matplotlib import pyplot as plt
4
from statistics import stdev
5
from pathlib import Path
6
import datetime
7
8
class Rectangle:
9
    def __init__(self, x1, y1, w1, h1):
10
        self.x = x1
11
        self.y = y1
12
        self.w = w1
13
        self.h = h1
14
        self.is_surface_breaking=True
15
        self.is_acceptable=True
16
17
    def __repr__(self):
18
        return "("+str(self.x)+","+str(self.y)+"),"+str(self.w)+"x"+str(self.h)\
19
               + ", Surface: " + str(self.is_surface_breaking)+", Acceptance: "+str(self.is_acceptable)
20
21
22
def nothing(x):
23
    print("Nothing:"+str(x))
24
25
26
def is_inside_joint(inner: Rectangle, outer: Rectangle) -> bool:
27
    if(inner.x >= outer.x and inner.y >= outer.y and
28
            (inner.x+inner.w) <= (outer.x+outer.w) and (inner.y+inner.h) <= (outer.y+outer.h)):
29
        return True
30
    else:
31
        return False
32
33
34
def error_return():
35
    return 0, 0, 0, 0, 0, 0, 0
36
37
38
def find_smallest_rec(all_rec):
39
40
    smallest = all_rec[0]
41
    for rec in all_rec:
42
        if rec.w*rec.h < smallest.w*smallest.h:
43
            smallest = rec
44
    return smallest
45
46
47
def discard_irrelevant_results(all_recs):
48
    rec_fields = []
49
    rec_relevant = []
50
    sum_fields = 0
51
    for rec in all_recs:
52
        sum_fields += rec.w*rec.h
53
    average_field = sum_fields/len(all_recs)
54
    # for rec in all_recs:
55
    #     if rec.w * rec.h > average_field:
56
    #         rec_fields.append(rec.w*rec.h)
57
    #         rec_relevant.append(Rectangle(rec.x,rec.y,rec.w,rec.h))
58
    for rec in all_recs:
59
        rec_fields.append(rec.w * rec.h)
60
61
    all_recs.remove(find_smallest_rec(all_recs))
62
    deviation = stdev(rec_fields)
63
    while deviation/average_field >= 0.85 and len(all_recs) > 1:
64
        # print("dev/mean: "+str(deviation/average_field)+" dev: "+str(deviation)+" mean: "+str(average_field))
65
        all_recs.remove(find_smallest_rec(all_recs))
66
        for rec in all_recs:
67
            sum_fields += rec.w*rec.h
68
            rec_fields.append(rec.w*rec.h)
69
        average_field = sum_fields / len(all_recs)
70
        deviation = stdev(rec_fields)
71
    # print("dev/mean: " + str(deviation / average_field) + " dev: " + str(deviation) + " mean: " + str(average_field))
72
    # plt.hist(rec_fields, rwidth=5)
73
    # plt.title("Average field: "+str(average_field)+"\nIndications: "+str(len(rec_fields)))
74
    # plt.show()
75
    return all_recs
76
77
# def check_histograms(img, rec, roi):
78
#     k=45
79
#     #pobieram wymiary obrazu
80
#     ref_up = cv.imread("images\\ref_up.png")
81
#     ref_down = cv.imread("images\\ref_down.png")
82
#     #przycinam obrazy do mierzenia histogramów
83
#     indication_surface_down = img[roi.y+roi.h:roi.y+roi.h+k, rec.x:rec.x+rec.w]
84
#     indication_surface_up = img[roi.y-k:roi.y, rec.x:rec.x+rec.w] #górna część obrazu oobcięta SZTYWNO
85
#     #liczę histogramy
86
#     hist_indication_surface_down = cv.calcHist([indication_surface_down], [0], None, [256], [0,256])
87
#     hist_indication_surface_up = cv.calcHist([indication_surface_up], [0], None, [256], [0,256])
88
#     hist_surface_down = cv.calcHist([ref_down], [0], None, [256], [0,256])
89
#     hist_surface_up = cv.calcHist([ref_up], [0], None, [256], [0,256])
90
#     #porównuję histogramy
91
#     check_up = cv.compareHist(hist_surface_up, hist_indication_surface_up, cv.HISTCMP_CORREL)
92
#     check_down = cv.compareHist(hist_surface_down, hist_indication_surface_down, cv.HISTCMP_CORREL)
93
#     #zwracam poprawione prostokąty zależnie od histogramu
94
#     # if check_down<check_up and check_down<0.92:
95
#     #     corrected_rect = [(rec.x,rec.y),(rec.x+rec.w,roi.y+roi.h+k)]
96
#     # elif check_up<check_down and check_up<0.92:
97
#     #     corrected_rect = [(rec.x,roi.y-k),(rec.x+rec.w,rec.y+rec.h)]
98
#     # else:
99
#     #     corrected_rect = [(rec.x,rec.y),(rec.x+rec.w,rec.y+rec.h)]
100
#     if check_down<check_up and check_down<0.15:
101
#         corrected_rect = Rectangle(rec.x, rec.y, rec.w, roi.y+roi.h+k-rec.y)
102
#         corrected_rect.is_surface_breaking=True
103
#     elif check_up<check_down and check_up<=0.15:
104
#         corrected_rect = Rectangle(rec.x, roi.y-k, rec.w, rec.y-roi.y+rec.h+k)
105
#         corrected_rect.is_surface_breaking=True
106
#         # [(rec.x,roi.y-k),(rec.x+rec.w,rec.y+rec.h)]
107
#     else:
108
#         corrected_rect = Rectangle(rec.x,rec.y,rec.w,rec.h)
109
#     print("Input rec: "+str(rec))
110
#     print("Check down: " + str(check_down) + "\nCheck up: " + str(check_up))
111
#     print(corrected_rect)
112
#
113
#     return corrected_rect
114
115
116
def check_histograms(img, rec, roi):
117
    k = 20  # wysokość fali powierzchniowej
118
119
    # pobieram wymiary obrazu
120
    height, width, channels = img.shape
121
    # przycinam obrazy do mierzenia histogramów
122
    indication_surface_down = img[roi.y+roi.h:roi.y+roi.h+k, rec.x:rec.x+rec.w]
123
    indication_surface_up = img[roi.y-k:roi.y, rec.x:rec.x+rec.w]
124
    surface_down = img[roi.y+roi.h:roi.y+roi.h+k, roi.x:width]
125
    surface_up = img[roi.y-k:roi.y, roi.x:width]
126
    # liczę histogramy
127
    hist_indication_surface_down = cv.calcHist([indication_surface_down], [0], None, [256], [0,256])
128
    hist_indication_surface_up = cv.calcHist([indication_surface_up], [0], None, [256], [0,256])
129
    hist_surface_down = cv.calcHist([surface_down], [0], None, [256], [0,256])
130
    hist_surface_up = cv.calcHist([surface_up], [0], None, [256], [0,256])
131
    # porównuję histogramy
132
    check_up = cv.compareHist(hist_surface_up, hist_indication_surface_up, cv.HISTCMP_CORREL)
133
    check_down = cv.compareHist(hist_surface_down, hist_indication_surface_down, cv.HISTCMP_CORREL)
134
    # zwracam poprawione prostokąty zależnie od histogramu
135
    # if check_down<check_up and check_down<0.92:
136
    #     corrected_rect = [(rec.x,rec.y),(rec.x+rec.w,roi.y+roi.h+k)]
137
    # elif check_up<check_down and check_up<0.92:
138
    #     corrected_rect = [(rec.x,roi.y-k),(rec.x+rec.w,rec.y+rec.h)]
139
    # else:
140
    #     corrected_rect = [(rec.x,rec.y),(rec.x+rec.w,rec.y+rec.h)]
141
    if check_down<check_up and check_down < 0.9:
142
        corrected_rect = Rectangle(rec.x, rec.y, rec.w, roi.y+roi.h+k-rec.y)
143
        corrected_rect.is_surface_breaking=True
144
    elif check_up<check_down and check_up <= 0.9:
145
        corrected_rect = Rectangle(rec.x, roi.y-k, rec.w, rec.y-roi.y+rec.h+k)
146
        corrected_rect.is_surface_breaking = True
147
        # [(rec.x,roi.y-k),(rec.x+rec.w,rec.y+rec.h)]
148
    else:
149
        corrected_rect = Rectangle(rec.x,rec.y,rec.w,rec.h)
150
    print("Input rec: "+str(rec))
151
    print("Check down: " + str(check_down) + "\nCheck up: " + str(check_up))
152
    print(corrected_rect)
153
154
    return corrected_rect
155
156
157
def display_process(images):
158
    # titles = ['ORIGINAL', 'FILTER', 'CANNY', 'DILATE', 'CONTOURS']
159
    # for i in range(5):
160
    #     plt.subplot(3, 2, i+1)
161
    #     plt.imshow(images[i], 'gray')
162
    #     plt.title(titles[i])
163
    #     plt.xticks([])
164
    #     plt.yticks([])
165
    # plt.show()
166
    plt.subplot(1, 2, 1)
167
    plt.imshow(images[1], 'gray')
168
    plt.title('FILTER')
169
    plt.xticks([])
170
    plt.yticks([])
171
    plt.subplot(1,2,2)
172
    plt.imshow(images[2], 'gray')
173
    plt.title('EDGES')
174
    plt.xticks([])
175
    plt.yticks([])
176
    plt.show()
177
178
179
def find_roi(filename):
180
181
    thresh1 = 100
182
    thresh2 = 255
183
    dil_kernel_size = 7
184
    dil_it = 3
185
    filter_kernel = 5
186
187
    roi_img = cv.imread(filename)
188
    roi_imgray = cv.cvtColor(roi_img, cv.COLOR_BGR2GRAY)
189
    roi_imgray=cv.GaussianBlur(roi_imgray,(filter_kernel,filter_kernel),0)
190
    _, roi_imthresh = cv.threshold(roi_imgray, thresh1, thresh2, cv.THRESH_BINARY_INV)
191
    roi_kernel = np.ones((dil_kernel_size, dil_kernel_size), np.uint8)
192
    roi_imdil = cv.dilate(roi_imthresh, roi_kernel, iterations=dil_it)
193
194
    h, w, c = roi_img.shape
195
    roi_mat_img = np.transpose(roi_imdil)
196
    first_column = roi_mat_img[0]
197
198
    for i in range(len(first_column)):
199
        if i == len(first_column)-1:
200
            y_min = 0
201
            y_max = len(first_column)-1
202
            break
203
        if first_column[i] == 255 and first_column[i + 1] == 0 and i > 10:
204
            y_min = i
205
            break
206
207
    for j in range(i, len(first_column) - 1):
208
        if first_column[j] == 0 and first_column[j + 1] == 255 and j - y_min > 50:
209
            y_max = j
210
            break
211
212
    roi = Rectangle(0, y_min, w, y_max-y_min)
213
    return roi
214
215
216
def convert_to_mm(roi, thickness, all_recs):
217
    px_to_mm = int(thickness)/(roi.h+60)
218
    all_recs_in_mm = []
219
    for rec in all_recs:
220
        rec_in_mm = Rectangle(round(rec.x*px_to_mm, 1), round(rec.y*px_to_mm, 1),
221
                              round(rec.w*px_to_mm, 1), round(rec.h*px_to_mm, 1))
222
        all_recs_in_mm.append(rec_in_mm)
223
224
    x_max = 0; y_max = 0; w_max = 0; h_max = 0
225
226
    for rec in all_recs_in_mm:
227
        if rec.w * rec.h > w_max * h_max:
228
            x_max = rec.x
229
            y_max = rec.y
230
            w_max = rec.w
231
            h_max = rec.h
232
233
    return x_max, y_max, w_max, h_max, all_recs_in_mm
234
235
236
def confirm_indications(all_indications, acceptance_level, thickness):
237
    joint_acceptance = True
238
    if acceptance_level == 1:
239
        l_max = 0.75*float(thickness)
240
        h3 = 1.5
241
        h2 = 2
242
        h1 = 1
243
    elif acceptance_level == 2:
244
        l_max = thickness
245
        h3 = 2
246
        h2 = 2
247
        h1 = 1
248
    elif acceptance_level == 3:
249
        l_max = min(1.5*thickness, 20)
250
        h3 = 2
251
        h2 = 2
252
        h1 = 1
253
254
    for ind in all_indications:
255
        if ind.w > l_max and ind.h > h1:
256
            ind.is_acceptable = False
257
            joint_acceptance = False
258
        elif ind.w <= l_max:
259
            if ind.is_surface_breaking and ind.h > h3:
260
                ind.is_acceptable = False
261
                joint_acceptance = False
262
            elif not ind.is_surface_breaking and ind.h > h2:
263
                ind.is_acceptable = False
264
                joint_acceptance = False
265
        elif ind.h < h2 or ind.h < h3:
266
            if ind.w > l_max:
267
                ind.is_acceptable = False
268
                joint_acceptance = False
269
270
    for ind in all_indications:
271
        print(ind)
272
273
    date = datetime.date.today()
274
    time = datetime.datetime.now().time()
275
276
    with open(str(date) + "_" + str(time).replace(':', '_')[:-8] + "_results.txt", "w") as f:
277
        i = 0
278
        for rec in all_indications:
279
            f.write("Pattern " + str(i) + ": x0 = " + str(rec.x) + "; y0 = " + str(rec.y) + "; w = "
280
                    + str(rec.w) + "; h = " + str(rec.h) + "; " + str(rec.is_acceptable) + "\n")
281
            i += 1
282
283
    return joint_acceptance
284
285
286
def inspect(filepath, list_of_parameters, acceptance_level, thickness):
287
    try:
288
        filter_size=list_of_parameters[0]
289
        canny_min=list_of_parameters[1]
290
        canny_max=list_of_parameters[2]
291
        dilation_kernel_size=list_of_parameters[3]
292
        dilation_it=list_of_parameters[4]
293
        roi_x_min=list_of_parameters[5]
294
        roi_x_max=list_of_parameters[6]
295
        roi_y_min=list_of_parameters[7]
296
        roi_y_max=list_of_parameters[8]
297
298
    except IndexError:
299
        filter_size = 9
300
        canny_min = 20
301
        canny_max = 77
302
        dilation_kernel_size = 3
303
        dilation_it = 3
304
        roi_x_min = -1
305
        roi_x_max = -1
306
        roi_y_min = -1
307
        roi_y_max = -1
308
309
    try_file = cv.imread(filepath)
310
    try:
311
        try_file.size == 0
312
    except AttributeError:
313
        return error_return()
314
315
    if roi_x_min == -1 and roi_x_max == -1 and roi_y_min == -1 and roi_y_max == -1:
316
        roi = find_roi(filepath)
317
    else:
318
        roi = Rectangle(roi_x_min, roi_y_min, roi_x_max-roi_x_min, roi_y_max-roi_y_min)
319
320
321
    img = cv.imread(filepath)
322
    height, width, channels = img.shape
323
    imgray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
324
325
    filter_img = cv.medianBlur(imgray,filter_size)
326
    # filter_img = cv.GaussianBlur(imgray,(filter_size,filter_size),0)
327
    # filter_img = cv.bilateralFilter(imgray, 10, 10, 10)
328
329
    edges = cv.Canny(filter_img, canny_min, canny_max)
330
    cv.imwrite("edges.png", edges)
331
332
    try:
333
        img_to_dilate = edges[roi.y:roi.y+roi.h, roi.x:roi.x+roi.w]
334
    except IndexError:
335
        return error_return()
336
337
    kernel = np.ones((dilation_kernel_size, dilation_kernel_size), np.uint8)
338
339
    img_to_dilate = cv.dilate(img_to_dilate, kernel, iterations=dilation_it)
340
    edges[roi.y:roi.y+roi.h,roi.x:roi.x+roi.w] = cv.morphologyEx(img_to_dilate, cv.MORPH_CLOSE, kernel)
341
    dilation = cv.morphologyEx(edges, cv.MORPH_ERODE, kernel)
342
343
    contours, hierarchy = cv.findContours(dilation, cv.RETR_TREE, cv.CHAIN_APPROX_NONE)
344
    number_of_recs=0
345
    all_recs = []
346
    for i in range(len(contours)):
347
        x, y, w, h = cv.boundingRect(contours[i])
348
        rec = Rectangle(x, y, w, h)
349
        if is_inside_joint(rec, roi):
350
            cv.drawContours(img, contours, i, (0, 0, 255), 1)
351
            all_recs.append(rec)
352
            number_of_recs += 1
353
354
    if len(all_recs) == 0:
355
        return error_return()
356
357
    cv.imwrite("contours.png",img)
358
    filtered_recs = discard_irrelevant_results(all_recs)
359
    corrected_recs = filtered_recs
360
    if len(corrected_recs) == 0:
361
        return error_return()
362
363
    # corrected_recs = []
364
    # for rec in filtered_recs:
365
    #     corrected_recs.append(check_histograms(img, rec, roi))
366
367
    x_max = 0; y_max = 0; w_max = 0; h_max = 0
368
    for rec in corrected_recs:
369
        cv.rectangle(img, (rec.x, rec.y), (rec.x + rec.w, rec.y + rec.h), (0, 255, 0), 1)
370
        if rec.w * rec.h > w_max * h_max:
371
            x_max = rec.x
372
            y_max = rec.y
373
            w_max = rec.w
374
            h_max = rec.h
375
376
    images = [imgray, filter_img, edges, dilation, img]
377
    filepath_inspected = filepath.replace(".png", "_inspected.png")
378
    cv.imwrite(filepath_inspected, img)
379
380
    x_max, y_max, w_max, h_max, all_recs_in_mm = convert_to_mm(roi, thickness, corrected_recs)
381
    acceptance = confirm_indications(all_recs_in_mm, acceptance_level, thickness)
382
383
    with open(Path(filepath).stem+"_results_in_pixels.txt", "w") as f:
384
        i = 0
385
        for rec in all_recs:
386
387
            f.write("Pattern " + str(i) + ": x0 = " + str(rec.x) + "; y0 = " + str(rec.y) + "; w = " +
388
                    str(rec.w) + "; h = " + str(rec.h) + "\n")
389
            i += 1
390
391
    return acceptance, x_max, y_max, w_max, h_max, filepath_inspected, images
392
393
394
#throwMe = [9, 20, 77, 3, 3, -1, -1, -1, -1]
395
#acc, x_max, y_max, w_max, h_max, filepath_inspected, images = inspect("images\\test1.png", throwMe, 3, 12)
396
#cv.imshow("result", images[0])
397
#cv.waitKey()
398
#cv.destroyAllWindows()
399
400
# pierwsza strona do podpisu, reszta mailem, prezka w grudniu mailem i przyjść przegadać
401
#