小项目:手写数字识别,可识别小数点(二)
完整代码已经上传 GitHub(https://github.com/wwwwkd/Digit-Recognition)有帮助的话给个小星星!!!
代码是自己写的,有些不严谨,有更好的方法或者思路,希望大家之间相互指点相互进步。首先提供思路,然后在提供部分代码,然后在展示效果图。
功能要求:可以根据自己手工书写一个数字得带小数,拍照后,程序能将该手写数字转换成对应的数字。
经过查阅资料,将其大致分为一下三个部分:
① 数字的定位、分割、保存.
② 小数点的识别.
③ 网络的训练、测试和最佳模型参数保存加载.
小数点得识别
针对第三点:小数点的识别,我采用经验的方法,由于小数点的外接轮廓面接要远远小于其他数字的轮廓面积,数字中1是面积最小的,但是其面积也没有小于其他数字面积太多。因此这里设置判断,若满足5*min_area < max_area那么这个分割图像必然是小数点,这里我们也采用x轴方向顺序来保存面积,然后获得满足条件的小数点的索引,若不满足则返回None。小数点识别如图所示。小数点完美识别!!!
小数点识别部分代码如下图所示。完整代码见 GitHub
# 对有无小数点进行判断
'''
经验值判断 因为最大面积一般是大于小数点面积的5倍以上
当没有小数点时同样数字不可能比最大面积大三倍以上
'''
if 5*min(areas) < max(areas):
min_areas_idx = areas.index(min(areas)) # 返回最小面积得索引
print('小数点索引位置', min_areas_idx)
else:
min_areas_idx = None
print('无小数点')
将其与(一)数字得定位和分割进行结合,如下:
def digital_segmentation(image):
image = cv.GaussianBlur(image, (3, 3), 0) #高斯去噪
gray = cv.cvtColor(image,cv.COLOR_BGR2GRAY) #转灰度图像
gray = cv.medianBlur(gray, 5) #中值滤波去除椒盐噪声
ret, binary = cv.threshold(gray,0,255,cv.THRESH_OTSU|cv.THRESH_BINARY_INV) #获取二值化图像
kernelX = cv.getStructuringElement(cv.MORPH_RECT, (5, 5)) # 17在x方向膨胀力度更大 返回指定形状和尺寸的结构元素。cv2.MORPH_RECT返回得是个矩形
#print(kernelX)
binary1 = cv.morphologyEx(binary, cv.MORPH_CLOSE, kernelX, iterations=3)
# 下面的膨胀、腐蚀或者腐蚀、膨胀根据个人需求自行设定即可
kerne2X = cv.getStructuringElement(cv.MORPH_RECT, (5, 5)) #设置卷积核
# kernelY = cv.getStructuringElement(cv.MORPH_RECT, (1, 5))
# 膨胀,腐蚀
binary1 = cv.dilate(binary1, kerne2X)
#binary = cv.erode(binary, kernelX)
contours,hireachy = cv.findContours(binary1,cv.RETR_EXTERNAL,cv.CHAIN_APPROX_SIMPLE) #只检测外轮廓即可
numbers = []
number_image = []
areas = []
i = 0
for item in contours:
i = i+1
area = cv.contourArea(item) #获取每个轮廓面积
x,y,w,h = cv.boundingRect(item) #获取轮廓的外接矩形
rate = min(w,h)/max(w,h) #获取外接矩形宽高比,可以起到一定的筛选作用
cv.rectangle(image, (x, y), (x + w, y + h), (255, 0, 255), 3) # 根据轮廓外接矩形返回数据,画出外接矩形
number = []
number.append(x) # 将矩形轮廓得四点坐标添加到number
number.append(y)
number.append(w)
number.append(h)
numbers.append(number) #再将所有number添加到numbers
area1 = []
area1.append(x) # 将x坐标和轮廓area添加到area1
area1.append(area)
areas.append(area1) # 再将所有area1添加到areas
numbers = sorted(numbers, key=lambda s: s[0], reverse=False) # 按照x方向顺序来进行保存分割数字
areas = sorted(areas, key=lambda s: s[0], reverse=False) #按照x得方向来保存每个分割数字得面积
areas = [i[1] for i in areas] # 获得二维列表得第一列 这一列是按顺序保存得面积
# 对有无小数点进行判断
'''
经验值判断 因为最大面积一般是大于小数点面积的5倍以上
当没有小数点时同样数字不可能比最大面积大三倍以上
'''
if 5*min(areas) < max(areas):
min_areas_idx = areas.index(min(areas)) # 返回最小面积得索引
print('小数点索引位置', min_areas_idx)
else:
min_areas_idx = None
print('无小数点')
i = 0
for number in numbers:
i = i + 1
splite_image = binary[(number[1]-2):(number[1]-2) + (number[3]+2), (number[0]-2):(number[0]-2) + (number[2]+2)]
number_image.append(splite_image)
cv.imwrite('./get_nums_img/' + str(i-1) + '.png', splite_image)
print('手写数字得定位、分割、保存,已完成')
return number_image , min_areas_idx # 返回分割图像列表和分割图像中最小面积得索引用于后期识别小数点得依据