Development of the ocr part of AOI
Samo Penic
2018-11-16 5cb7c1dba78b025ff333a202b27f04a2230c9da9
commit | author | age
9efc18 1 import cv2
SP 2 import numpy as np
762a5e 3 from skimage import morphology, img_as_ubyte
02e0f7 4 from sklearn import svm
SP 5 from sklearn.externals import joblib
6
9efc18 7
SP 8 """
9   (1) The text is an array of chars (in row-major order) where
10  *          each char can be one of the following:
11  *             'x': hit
12  *             'o': miss
13  *             ' ': don't-care
14  *      (2) When the origin falls on a hit or miss, use an upper case
15  *          char (e.g., 'X' or 'O') to indicate it.  When the origin
16  *          falls on a don't-care, indicate this with a 'C'.
17  *          The string must have exactly one origin specified.
18  *      (3) The advantage of this method is that the text can be input
19  *          in a format that shows the 2D layout of the Sel; e.g.,
20
21
22     :::: AND ::::
23  
24  
25    (10) The sequence string is formatted as follows:
26  *            ~ An arbitrary number of operations,  each separated
27  *              by a '+' character.  White space is ignored.
28  *            ~ Each operation begins with a case-independent character
29  *              specifying the operation:
30  *                 d or D  (dilation)
31  *                 e or E  (erosion)
32  *                 o or O  (opening)
33  *                 c or C  (closing)
34  *                 r or R  (rank binary reduction)
35  *                 x or X  (replicative binary expansion)
36  *                 b or B  (add a border of 0 pixels of this size)
37  *            ~ The args to the morphological operations are bricks of hits,
38  *              and are formatted as a.b, where a and b are horizontal and
39  *              vertical dimensions, rsp.
40  *            ~ The args to the reduction are a sequence of up to 4 integers,
41  *              each from 1 to 4.
42  *            ~ The arg to the expansion is a power of two, in the set
43  *              {2, 4, 8, 16}.
44  *      (11) An example valid sequence is:
45  *               "b32 + o1.3 + C3.1 + r23 + e2.2 + D3.2 + X4"
46  *           In this example, the following operation sequence is carried out:
47  *             * b32: Add a 32 pixel border around the input image
48  *             * o1.3: Opening with vert sel of length 3 (e.g., 1 x 3)
49  *             * C3.1: Closing with horiz sel of length 3  (e.g., 3 x 1)
50  *             * r23: Two successive 2x2 reductions with rank 2 in the first
51  *                    and rank 3 in the second.  The result is a 4x reduced pix.
52  *             * e2.2: Erosion with a 2x2 sel (origin will be at x,y: 0,0)
53  *             * d3.2: Dilation with a 3x2 sel (origin will be at x,y: 1,0)
54  *             * X4: 4x replicative expansion, back to original resolution
55
56 """
57
58
59 def kernel(x, y):
60     return np.ones((x, y), np.uint8)
61
62
762a5e 63 def segment_by_contours(image, sorted_ctrs, classifier):
SP 64     sid_no = ""
65     for i, ctr in enumerate(sorted_ctrs):
66         # Get bounding box
67         x, y, w, h = cv2.boundingRect(ctr)
68         # Getting ROI
69         if w < h / 2:
70             sid_no = sid_no + "1"
71             continue
72         roi = image[y : y + h, x : x + w]
73         roi = img_as_ubyte(roi < 128)
74         roi = cv2.resize(roi, (32, 32))
75
76         # cv2.rectangle(image,(x,y),( x + w, y + h ),(0,255,0),2)
77         cv2.imwrite("sid_no_{}.png".format(i), roi)
78         sid_no = sid_no + str(classifier.predict(roi.reshape(1, -1) / 255.0)[0])
79     return sid_no
80
81
5cb7c1 82 def segment_by_sid_len(image, sid_mask, classifier):
SP 83     sid_no = ""
84     sid_len = len(sid_mask)
85     if sid_mask[0] == "1":
86         move_left = 45
87     elif sid_mask[0] == "x":
88         move_left = 55
89     else:
90         move_left = 0
91     # find biggest block of pixels
ac766e 92
5cb7c1 93     image1 = cv2.morphologyEx(image, cv2.MORPH_DILATE, kernel(5, 25), iterations=3)
SP 94     cv2.imwrite("sidblock1.png", image1)
ac766e 95     im2, ctrs, hier = cv2.findContours(
SP 96         image1.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE
97     )
5cb7c1 98     sorted_ctrs = sorted(
SP 99         ctrs, key=lambda ctr: cv2.contourArea(ctr)
100     )  # get bigges contour
ac766e 101     x, y, w, h = cv2.boundingRect(sorted_ctrs[-1])
5cb7c1 102     image = image[y : y + h, x + 25 - move_left : x + w - 25]
SP 103     cv2.imwrite("sidblock2.png", image)
ac766e 104     imgHeight, imgWidth = image.shape[0:2]
5cb7c1 105     numWidth = int(imgWidth / (sid_len))
SP 106     for i in range(0, sid_len):
107         num = image[:, i * numWidth : (i + 1) * numWidth]
ac766e 108         num = img_as_ubyte(num < 128)
SP 109         num = cv2.resize(num, (32, 32))
110
111         # cv2.rectangle(image,(x,y),( x + w, y + h ),(0,255,0),2)
112         cv2.imwrite("sid_no_{}.png".format(i), num)
113         sid_no = sid_no + str(classifier.predict(num.reshape(1, -1) / 255.0)[0])
114     return sid_no
115
116
762a5e 117 def getSID(image, classifier, sid_mask):
5cb7c1 118     sid_warn = []
762a5e 119     image = 255 - image
SP 120     image = img_as_ubyte(image > 100)
9efc18 121     cv2.imwrite("enSID0.png", image)
SP 122     # Remove noise
762a5e 123     image = cv2.morphologyEx(image, cv2.MORPH_OPEN, kernel(2, 2), iterations=1)
9efc18 124     # Closing. Connect non connected parts
02e0f7 125     image = cv2.morphologyEx(image, cv2.MORPH_CLOSE, kernel(5, 3), iterations=4)
9efc18 126     # Again noise removal after closing
02e0f7 127
5cb7c1 128     # image = cv2.morphologyEx(image, cv2.MORPH_OPEN, kernel(8, 8), iterations=1)
SP 129     # don't do too much noise removal.
ac766e 130     image = cv2.morphologyEx(image, cv2.MORPH_OPEN, kernel(3, 3), iterations=1)
SP 131
9efc18 132     # Skeletonization
762a5e 133     image = img_as_ubyte(morphology.thin(image > 128))
SP 134     cv2.imwrite("enSID1.png", image)
9efc18 135     # Stub removal (might not be necessary if thinning instead of skeletonize is used above
SP 136     # Making lines stronger
137     image = cv2.morphologyEx(image, cv2.MORPH_DILATE, kernel(5, 5), iterations=1)
138
139     image = cv2.morphologyEx(image, cv2.MORPH_CLOSE, kernel(10, 10))
140     # Thining again
762a5e 141     image = img_as_ubyte(morphology.skeletonize(image > 0.5))
9efc18 142     image = cv2.morphologyEx(image, cv2.MORPH_DILATE, kernel(10, 10))
5cb7c1 143     cv2.imwrite("enhancedSID.png", image)
762a5e 144     im2, ctrs, hier = cv2.findContours(
SP 145         image.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE
146     )
02e0f7 147     sorted_ctrs = sorted(ctrs, key=lambda ctr: cv2.boundingRect(ctr)[0])
SP 148
762a5e 149     sid_no = ""
5cb7c1 150     print(len(sid_mask), len(sorted_ctrs))
SP 151     sid_no = segment_by_contours(
152         image, sorted_ctrs[1:], classifier
153     )  # we remove largest contour that surrounds whole image
02e0f7 154     print(sid_no)
5cb7c1 155     if len(sid_no) != len(sid_mask):
SP 156         #print("Ooops have to find another way")
157         sid_warn.append("Trying second SID algorithm.")
158         sid_no = segment_by_sid_len(image, sid_mask, classifier)
159     return (sid_no, [], sid_warn)