0%

PyCosmed数字识别

PyCosmed数字识别程序回顾与优化。

图像预处理

首先要将截取的图片转为灰度图像,然后绘制灰度直方图,确定二值化阈值150,然后进行二值化:

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
# 获取图像
def get_img(index):
img = Image.open("E:\\Python\\PyCosmed\\v3.0\DIGIT2\\"+str(index)+".png")
plt.subplot(221)
plt.imshow(img)
return img

# 分析灰度直方图,从而选择合适的二值化阈值
def gray_hist(img):
img_arr = np.array(img.convert('L')) # convert - 转换图像格式 L - 八位黑白像素
# array - image格式转为array数组
plt.subplot(223)
plt.imshow(img_arr)

img_arr = img_arr.flatten() # flatten - 转化为一维数组
plt.subplot(222)
plt.hist(img_arr,bins=256) # hist - 绘制直方图 bins - 条形数
plt.ylim((0,50))

# 图像二值化
def binarize(img, threshold=threshold):
"""二值化"""
img = img.convert('L')
table = []
for i in range(256):
if i < threshold:
table.append(0)
else:
table.append(1)
bin_img = img.point(table, '1')
plt.subplot(222)
plt.imshow(bin_img)
return bin_img

图像分割

加入分割宽度机制,避免数字相连情况:

分割后的图像集:

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
def vertical_cut(img):
"""纵向切割"""
px = list(np.sum(np.array(img) == 0, axis=0))
py = list(np.sum(np.array(img) == 0, axis=1))

# 列表保存像素累加值大于0的列
x0 = []
for x in range(len(px)):
if px[x] > 0:
x0.append(x)
y0 = []
for y in range(len(py)):
if py[y] > 1:
y0.append(y)

# 找出边界
cut_list = [x0[0]]
for i in range(1, len(x0)):
if abs(x0[i] - x0[i - 1]) > 1:
if abs(x0[i-1] - cut_list[-1]) < 10:
cut_list.extend([x0[i - 1]+1, x0[i]])
elif abs(x0[i-1] - cut_list[-1]) < 16:
cut_list.extend([x0[i-1]+1, x0[i-1]+8])
cut_list.extend([x0[i-1]+8, x0[i]])
elif abs(x0[i-1] - cut_list[-1]) < 24:
cut_list.extend([x0[i-1]+1, x0[i-1]+8])
cut_list.extend([x0[i-1]+8, x0[i-1]+16])
cut_list.extend([x0[i-1]+16, x0[i]])
if abs(x0[-1] - cut_list[-1]) < 10:
cut_list.append(x0[-1]+1)
elif abs(x0[-1] - cut_list[-1]) < 17:
cut_list.extend([cut_list[-1]+8, cut_list[-1]+8])
cut_list.append(x0[-1]+1)
elif abs(x0[-1] - cut_list[-1]) < 25:
cut_list.extend([cut_list[-1]+8, cut_list[-1]+8])
cut_list.extend([cut_list[-1]+8, cut_list[-1]+8])
cut_list.append(x0[-1]+1)

cut_list_y = [y0[0]]
cut_list_y.append(y0[-1]+1)

cut_imgs = []
# 切割顺利的话应该是整对
if len(cut_list) % 2 == 0:
for i in range(len(cut_list) // 2):
cut_img = img.crop([cut_list[i * 2], cut_list_y[0], cut_list[i * 2 + 1], cut_list_y[1]])
plt.imshow(cut_img)
return cut_imgs
else:
print('Vertical cut failed.')
return

计算Hash码

分割后的图像被统一缩放到8*15的大小,然后计算其Hash码,并提取每个字符的标准Hash码:

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
# 标准Hash码
hash_vals = {
"0": "110000111000000110011001100110000001100000111100001111000011110000111100001111000001100010011001100110011000000111000011",
"1": "111000000000000000000000111110001111100011111000111110001111100011111000111110001111100011111000111110001111100011111000",
"2": "100000111000000111110001111110011111100111111001111110011111000111110011111000111100011111001111100111110000000000000000",
"3": "100000111000000111111000111111001111110011111001110000011100000111111000111111001111110011111100111110000000000110000011",
"4": "111100011111000111100001111000011100100111001001100110011001100100111001000000000000000011111001111110011111100111111001",
"5": "110000001100000010011111100111111001111110011111100000111000000011111000111111001111110011111100111110000000000100000011",
"6": "111110011110000111000111110011111001111110011111000000010000000100011000001111000011110000011100100110001000000111000011",
"7": "000000000000000011111001111110011111100111110011111100111111001111100111111001111100011111001111110011111000111110011111",
"8": "111000111100000110011000100111001001110010001001110000011100000110001000100111000001110000011100100111001000000011000011",
"9": "110000111000000110011001000110000011110000111100000111001001100010000000111010001111100111110001111000111000011110001111",
".": "111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000011100000"
}

def hashing(img):
"""计算哈希值"""
img = img.resize((8, 15), Image.LANCZOS)
px = np.array(img).flatten()
hash_val = (px > px.mean()).astype(int)
hash_val = ''.join(str(e) for e in hash_val)
return hash_val

def hamming(hash1, hash2):
"""计算汉明距离"""
if len(hash1) != len(hash2):
print('hash1: ', hash1)
print('hash2: ', hash2)
raise ValueError("Undefined for sequences of unequal length")

return sum(i != j for i, j in zip(hash1, hash2))

def recognize(img):
"""识别结果"""
# img = img.convert('L')
# img = binarize(img)
# chars = vertical_cut(img)

# 相近度列表
nearness = {}
# expr = ''
# for char in chars:
hash_val = hashing(img)
for h in hash_vals:
nearness[h] = hamming(hash_val, hash_vals[h])
expr = sorted(nearness.items(), key=lambda d: d[1])[0][0]

return expr

识别结果

分割数据集下的识别结果:

原始图像下的识别结果:

One More Thing

另外对分割图像集进行个 主成分分析(PCA),在第一主成分和第二主成分平面上不具有明显的可分性,故没有进一步研究: