题目:将车牌的每个汉字和字母框出
本文涉及到的函数在我的上一篇文章Python opencv 加载、显示、保存、图像转换、轮廓检测
均有提及。
目录
1、图像预处理,导入,灰度转换、二值化、反色处理:
2、图像操作,腐蚀、膨胀,轮廓筛选
去除无用信息(边框、螺丝口)
轮廓筛选
3、文字整体检测,画出方框
汉字连接
轮廓检测再筛选
矩形绘制
4、补充
import cv2
import numpy as np
# 读取文件
img2=cv2.imread("opencv_img/img3.jpg")
cv2.imshow("img2",img2)
cv2.waitKey(0)
# 灰度
gray= cv2.cvtColor(img2,cv2.COLOR_BGR2GRAY)
cv2.imshow("gray",gray)
cv2.waitKey(0)
# 二值化
ret,thresh=cv2.threshold(gray,175,255,cv2.THRESH_BINARY)
cv2.imshow("thresh",thresh)
cv2.waitKey(0)
#反色
thresh = cv2.bitwise_not(thresh)
cv2.imshow("thresh0",thresh)
cv2.waitKey(0)
原图:
灰度:
二值化:
反色:
# 腐蚀 膨胀运算
kernel = np.ones((3,3),np.uint8)
thresh = cv2.dilate(thresh,kernel,iterations= 2)
cv2.imshow("thresh1",thresh)
cv2.waitKey(0)
thresh = cv2.erode(thresh,kernel,iterations= 2)
cv2.imshow("thresh2",thresh)
cv2.waitKey(0)
由于汉字笔画太细的问题,迭代次数设置为2。
注意!注意!以黑色为底色,变肥变瘦的对象为白色图形,所以图中先进行膨胀操作,后进行腐蚀操作。
经过操作可以看到螺丝的小圈圈已经消失,但是螺丝孔仍然还在,我们仍需要想办法去除螺丝孔。
# 小轮廓去除
contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
draw_img1 = cv2.cvtColor(thresh, cv2.COLOR_GRAY2RGB)
res=cv2.drawContours(draw_img1,contours,-1,(0,0,255),2)
cv2.imshow("res3",res)
cv2.waitKey(0)
fill=[]
for contour in contours:
area = cv2.contourArea((contour))
if area < 220:
fill.append(contour)
# print(area)
thresh=cv2.fillPoly(thresh,fill,(255,255,255))
cv2.imshow("thresh0",thresh)
cv2.waitKey(0)
使用轮廓检测查看所有轮廓:
注意:绘制轮廓 res=cv2.drawContours(draw_img1,contours,-1,(0,0,255),2) 中,将draw_img1进行颜色转换,把灰度图变回了RGB图像,否则会出现轮廓也为黑色分辨不出的问题。
使用for循环筛选周长较小的轮廓,并将其append到新列表fill
使用fillpoly函数将小轮廓堵上。就能得到干净的文字了。
#腐蚀 膨胀
thresh = cv2.erode(thresh,kernel,iterations= 6)
cv2.imshow("thresh2",thresh)
cv2.waitKey(0)
thresh = cv2.dilate(thresh,kernel,iterations= 6)
cv2.imshow("thresh3",thresh)
cv2.waitKey(0)
我们已经得到了干净的车牌号,但是汉字的轮廓有多个,我们需要将其变成一个轮廓,就需要用到开(闭)运算,也就是腐蚀和膨胀操作。
经过腐蚀膨胀操作,我们成功的让汉字的笔画都连在了一起,这样就可以进行轮廓检测了。
#找轮廓
contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
draw_img2=img2.copy()
#筛选轮廓:
need_contours=[]
for contour in contours:
x, y, w, h = cv2.boundingRect(contour)
rectangle_area=w*h
# print(rectangle_area)
if ( rectangle_area < 10000 and rectangle_area > 4000 ):
need_contours.append(contour)
res=cv2.drawContours(draw_img2,need_contours,-1,(0,0,255),2)
cv2.imshow("res",res)
cv2.waitKey(0)
再次轮廓检测,并且再次进行一次基于矩形面积的轮廓筛选,就只剩下汉字和字母的轮廓了
基于矩形面积筛选轮廓的原因是每个汉字和字母的矩形大小都差不多,可以有效筛选内轮廓和车牌大轮廓,矩形提取下一步会讲到。
#轮廓
draw_img2=img2.copy()
for contour in need_contours:
x,y,w,h = cv2.boundingRect(contour)
draw_img2 =cv2.rectangle(draw_img2,(x,y),(x+w,y+h),(0,0,255),2)
cv2.imshow("img3",draw_img2)
cv2.waitKey(0)
提取轮廓的 x,y,w,h 其中(x,y)是轮廓绘制的起始坐标,(w,h)是轮廓外接矩形的宽和高。
直接使用for循环在图上绘制即可。
本例中最大的困难是如何在不影响汉字的情况下去除螺丝孔,两个轮廓筛选的工作都是由人工不断尝试寻找阈值的。不同的汉字经过膨胀和腐蚀后的形态变换不同,可能也存在个别笔画被腐蚀消失的情况,也可能存在相近的两个数字膨胀之后粘连在一起的情况。读者可以使用在线网站生成多个车牌,寻找最佳阈值。
小汽车-车牌预览(在线版)
汉字与字母分割开后,可以使用模板匹配方法 cv2.matchTemplate() 匹配字符,转换为字符串。
本文涉及到的函数在我的上一篇文章Python opencv 加载、显示、保存、图像转换、轮廓检测
均有提及。