zhangshiming
2022-03-25 dcc1ad9462d964e63d1d09d4a7e570ad0efdbc6d
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
 
 
 
 
#样品
from imutils import contours
import cv2
import os
 
def cv_show(name, img):
    cv2.imshow(name, img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
 
 
def resize(image, width=None, height=None, inter=cv2.INTER_AREA):
    dim = None
    (h, w) = image.shape[:2]
    if width is None and height is None:
        return image
    if width is None:
        r = height / float(h)
        dim = (int(w * r), height)
    else:
        r = width / float(w)
        dim = (width, int(h * r))
    resized = cv2.resize(image, dim, interpolation=inter)
    return resized
 
 
def load_digits():
    # 加载数字模板
    path = numbers_address
    filename = os.listdir(path)
    for file in filename:
        # print(file)
        img = cv2.imread(
            numbers_address + "\\" + file)
        img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        img_temp = cv2.threshold(
            img_gray, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]
        cnt = cv2.findContours(img_temp, cv2.RETR_EXTERNAL,
                               cv2.CHAIN_APPROX_NONE)[0]
        x, y, w, h = cv2.boundingRect(cnt[0])
        digit_roi = cv2.resize(img_temp[y:y+h, x:x+w], (57, 88))
        # 将数字模板存到列表中
        digits.append(digit_roi)
 
 
def demo(index):
    rectKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (25, 25))
    sqKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (6, 6))
    target_path = now_dir + "\\" + "demo_" + str(index) + ".png"
    img_origin = cv2.imread(target_path)
    img_origin = resize(img_origin, width=300)
    img_gray = cv2.cvtColor(img_origin, cv2.COLOR_BGR2GRAY)
    gaussian = cv2.GaussianBlur(img_gray, (5, 5), 1)
    img_temp = cv2.threshold(
        gaussian, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]
    img_top = cv2.morphologyEx(img_temp, cv2.MORPH_TOPHAT, rectKernel)
    img_sobel_x = cv2.Sobel(img_top, cv2.CV_64F, 1, 0, ksize=7)
    img_sobel_x = cv2.convertScaleAbs(img_sobel_x)
    img_sobel_y = cv2.Sobel(img_top, cv2.CV_64F, 0, 1, ksize=7)
    img_sobel_y = cv2.convertScaleAbs(img_sobel_y)
    img_sobel_xy = cv2.addWeighted(img_sobel_x, 1, img_sobel_y, 1, 0)
    img_closed = cv2.morphologyEx(img_sobel_xy, cv2.MORPH_CLOSE, rectKernel)
    thresh = cv2.threshold(
        img_closed, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
    img_closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, sqKernel)
    cnts = cv2.findContours(
        img_closed.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[0]
    (cnts, boundingBoxes) = contours.sort_contours(cnts, "top-to-bottom")
    draw_img = img_origin.copy()
    draw_img = cv2.drawContours(draw_img, cnts, -1, (0, 0, 255), 1)
    cv_show("666", draw_img)
 
    # 存放正确数字序列(包含逗号)的轮廓,即过滤掉不需要的轮廓
    right_loc = []
    for c in cnts:
        x, y, w, h = cv2.boundingRect(c)
        ar = w/float(h)
        if ar > 2:
            right_loc.append((x, y, w, h))
    for (gx, gy, gw, gh) in right_loc:
        # 用于存放识别到的数字
        digit_out = []
        if (gy-10 < 0):
            now_gy = gy
        else:
            now_gy = gy-10
        if (gx - 10 < 0):
            now_gx = gx
        else:
            now_gx = gx-10
        img_digit = gaussian[now_gy:gy+gh+10, now_gx:gx+gw+10]
        # 二值化处理
        img_thresh = cv2.threshold(
            img_digit, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]
        # 寻找轮廓 找出每个数字的轮廓(包含逗号) 正确的话应该有9个轮廓
        digitCnts = cv2.findContours(
            img_thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[0]
        # 从左到右排列
        (cnts, boundingBoxes) = contours.sort_contours(digitCnts, "left-to-right")
        cnts = list(cnts)
        flag = 0
        if len(cnts) == 9:
            del cnts[1]
            del cnts[2]
            del cnts[3]
            del cnts[4]
            cnts = tuple(cnts)
            num_roi = []
            for c in cnts:
                x, y, w, h = cv2.boundingRect(c)
                num_roi.append((x, y, w, h))
            for (rx, ry, rw, rh) in num_roi:
                roi = img_digit[ry:ry+rh, rx:rx+rw]
                roi = cv2.resize(roi, (57, 88))
                roi = cv2.GaussianBlur(roi, (5, 5), 1)
                roi = cv2.threshold(
                    roi, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]
                source = []
                for digitROI in digits:
                    res = cv2.matchTemplate(
                        roi, digitROI, cv2.TM_CCOEFF_NORMED)
                    max_val = cv2.minMaxLoc(res)[1]
                    source.append(max_val)
                digit_out.append(str(source.index(max(source))))
            cv2.rectangle(img_origin, (gx-5, gy-5),
                          (gx+gw+5, gy+gh+5), (0, 0, 255), 1)
            print(digit_out)
        else:
            print("读取失败")
            flag = 1
        t = ''
        with open(now_dir + "\\temp.txt", 'a+') as q:
            if flag == 0:
                for content in digit_out:
                    t = t + str(content) + " "
                q.write(t.strip(" "))
                q.write('\n')
                t = ''
            else:
                q.write("读取失败")
                q.write('\n')
 
 
if __name__ == "__main__":
    # 存放数字模板列表
    digits = []
    # 当前运行目录
    now_dir = os.getcwd()
    print("当前运行目录:" + now_dir)
    numbers_address = now_dir + "\\numbers"
    load_digits()
    times = input("请输入程序运行次数:")
    for i in range(1, int(times) + 1):
        demo(i)
    print("输出成功,请检查本地temp.txt文件")
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    while True:
        if input("输入小写‘q’并回车退出") == 'q':
            break