Opencv车牌号字符分割
字符分割的任务,就是把多字符图像中的每个字符从整体图像中分割出来,使其成为单个的字符图像,为下一步单个字符的图像识别做准备。
字符分割是字符识别的基础,字符分割的质量直接影响到字符识别的效果。
一、算法流程
输入原始图片,将其resize到(320, 100)尺寸,灰度化处理:
利用cv2.bilateralFilter函数,在保持边界清晰的情况下有效去除噪声:
利用cv2.Canny函数,检测图像的边缘信息:
对纹理图片进行裁减,主要为了消除边框纹理对后续分割带来的干扰。由于前面已经把图片固定到(320, 100)尺寸,所以边框的裁减尺寸也可以固定下来。
利用cv2.findContours函数,基于前面提取的纹理信息进行聚类。此时聚类出现很多无效区域,并且单个字符也会被聚类成不同区域块,不符合要求。
添加各种if语句做判断,筛除不合理聚类区域:
此时仍会出现单个字符被聚类成不同区域块的情况。借助垂直投影的思路,在水平方向上统计被投影、未被投影的位置,进而确定每个字符的起始点和结束点。
二、效果展示
该算法对图片分辨率要求较高。在图片清晰的情况下,分割效果能非常好。从测试集中任意选取10张车牌号图片,分割结果如下:
我从网上任意找了50张车牌号图片,字符分割精度能达到75%以上。如果图片分辨率足够,算法精度还能更高。
三、源码
车牌号字符分割:
import numpy as np
import cv2
if __name__ == "__main__":
accuracy_num = 0
for i in range(50):
# img : original image
path = '/home/archer/CODE/Number_Segmentation/dataset2/' + str(i+1) + '.png'
img = cv2.imread(path)
# img1 : resize image
img1 = cv2.resize(img, (320, 100), interpolation=cv2.INTER_AREA)
# img2 : gray image
img2 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
# img3 : noise reduction image
img3 = cv2.bilateralFilter(img2, 11, 17, 17)
# img4 : texture information image
img4 = cv2.Canny(img3, 50, 150)
# img5 : image removal image
img5 = img4[10:90, 10:310]
crop_img = img1[10:90, 10:310, :]
contours, hierarchy = cv2.findContours(img5, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
candidate = []
for cnt in contours:
x, y, w, h = cv2.boundingRect(cnt)
if w*h < 500:
continue
if w * h > 4000:
continue
if h < 20:
continue
if w > 80:
continue
candidate.append([x, (x + w)])
loc = np.zeros(300)
for j in range(len(candidate)):
x1 = candidate[j][0]
x2 = candidate[j][1]
loc[x1:x2] = 1
start = []
end = []
if loc[0] == 1:
start.append(0)
for j in range(300-1):
if loc[j] == 0 and loc[j+1] == 1:
start.append(j)
if loc[j] == 1 and loc[j+1] == 0:
end.append(j)
if loc[299] == 1:
end.append(299)
print('Character start coordination : ', start, len(start))
print('Character end coordination : ', end, len(start))
if len(start) == 7 and len(end) == 7:
print('The Segmentation looks well ! ')
cv2.rectangle(crop_img, (0, 0), (start[1]-5, 80), (0, 0, 255), 2)
for j in range(1, 7):
x1 = start[j]
x2 = end[j]
y1 = 0
y2 = 80
cv2.rectangle(crop_img, (x1, y1), (x2, y2), (0, 0, 255), 2)
accuracy_num = accuracy_num + 1
cv2.namedWindow("final_crop_img")
cv2.imshow("final_crop_img", crop_img)
cv2.waitKey(0)
cv2.imwrite('/home/archer/CODE/Number_Segmentation/demo/' + str(i+1) + '.jpg', crop_img)
print('The character segmentation accuracy : ', accuracy_num/50)
四、项目链接
如果代码跑不通,或者想直接使用我自己制作的数据集,可以去下载项目链接:
https://blog.youkuaiyun.com/Twilight737