当前位置:   article > 正文

Opencv之python下车牌识别_python opencv 车牌识别

python opencv 车牌识别

大家评论中的问题主要是

  1. 运行后没有好的效果或没有结果,是因为我代码中当前的参数并不适合你们的数据集,所以你们需要自己调一下参数,比如verifySizes的长宽比等等。
  2. 报错,是因为我们OpenCV的版本不同,我的是3.4.2。只要百度一下对应的错误或者按照警告对应更改过来就没有问题了

目录

一、读入原始图片,灰度处理

二、高斯模糊处理,去噪

三、Sobel滤波,边缘检测

四、 Otsu大津算法自适应阈值二值化处理

五、形态学操作,闭操作

六、轮廓提取

 七、根据contours信息,构建外界矩形,并判断该轮廓是否合理

八、对合理矩形(区域),进行floodFill泛洪处理  &  综合后续

九、完整代码


基于《Mastering Opencv ...读书笔记系列》车牌识别(I)_taotao1233的博客-CSDN博客该博客下的Python实现

一、读入原始图片,灰度处理

  1. # Step1 读入灰度图
  2. initial_car = cv2.imread(r'F:\ml_summer\Opencv\Image\car.jpg') #(600, 800, 3) 行,列,通道数
  3. gray_car = cv2.cvtColor(initial_car,cv2.COLOR_BGR2GRAY)

原始图像

 灰度图像

二、高斯模糊处理,去噪

采用5*5模版对图像进行高斯模糊来退出由照相机或其他环境噪声(如果不这么做,我们会得到很多垂直边缘,导致错误检测。)

  1. # Step2 高斯模糊处理
  2. blur_car = cv2.GaussianBlur(gray_car,(5,5),0)

关于

cv2.GaussianBlur(img,kernel_size,sigMax)

函数的具体情况,参见Opencv之高斯模糊_啧啧啧biubiu的博客-CSDN博客_cv2高斯模糊

三、Sobel滤波,边缘检测

为了识别出车牌这个信息,我们有效利用车牌矩形的特征,边缘信息明显,故我们使用Sobel边缘检测的方法进行边缘的识别

cv2.Sobel(img,dtype,dx,dy)    【dx是进行垂直边缘检测,dy是对于水平边缘检测】

关于Sobel边缘检测,参见Opencv之边缘检测Sobel滤波_啧啧啧biubiu的博客-CSDN博客_opencv sobel滤波

  1. #Step3 Sobel计算水平导数
  2. sobel_car = cv2.Sobel(blur_car,cv2.CV_16S,1,0)
  3. sobel_car = cv2.convertScaleAbs(sobel_car) #转回uint8

四、 Otsu大津算法自适应阈值二值化处理

为去除掉背景的噪声,单独的处理车牌这一目标对象,我们将原始的灰度图像进行二值化处理。

利用Otus算法进行二值处理,利用

cv2.threshold(img,threshold, maxval,type)

实现,具体参见Opencv之图像固定阈值二值化处理threshold_啧啧啧biubiu的博客-CSDN博客_thresh_tozero (固定阈值的二值化处理可以实现大津算法)

更多过于二值化处理(自适应阈值二值化处理)参见Opencv之图像自适应阈值二值化处理adaptiveThreshold_啧啧啧biubiu的博客-CSDN博客

  1. #Step4 Otsu大津算法自适应阈值二值化
  2. _, otsu_car = cv2.threshold(sobel_car,0,255,cv2.THRESH_OTSU|cv2.THRESH_BINARY)

五、形态学操作,闭操作

利用形态学下的闭操作,将刚得到的二值化图像进行闭操作,消除黑色小块,填充闭合区域,将车牌区域连接起来,将车牌区域变成连通的区域,以便之后在轮廓提取的时候能将车牌作为一个区域提取出来

关于闭操作,参见Opencv之开操作和闭操作_啧啧啧biubiu的博客-CSDN博客_cv2 闭操作

  1. #Step5 闭操作
  2. kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(8,8))
  3. close_car = cv2.morphologyEx(otsu_car,cv2.MORPH_CLOSE,kernel)

六、轮廓提取

从闭操作得到的结果图像,提取图像中的轮廓信息(点集),该点集是有一个list包裹的,list中的每一个元素都是一个numpy.ndarray 点的集合。该点的集合就是我们提取到的一个区域的轮廓信息。

关于

cv2.findContours()

参见

  1. #Step6 提取外部轮廓
  2. img, contours, hierarchy = cv2.findContours(close_car,cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)

其中contours就是我们提取到的点集list

 七、根据contours信息,构建外界矩形,并判断该轮廓是否合理

因为车牌是规则的矩形,有其长宽的信息,我们可以对构建的外接矩形的长宽信息进行处理来判断该外接矩形是否和车牌接近。

【阈值:长宽比为4.727272,允许误差范围正负40%,面积范围15*15至125*125】

故定义verifySizes函数

  1. # 对minAreaRect获得的最小外接矩形,用纵横比进行判断
  2. def verifySizes(RotatedRect):
  3. error = 0.4
  4. aspect = 4.7272
  5. min = 15 * aspect * 15
  6. max = 125 * aspect * 125
  7. rmin = aspect - aspect * error
  8. rmax = aspect + aspect * error
  9. height,width = RotatedRect[1]
  10. if height==0 or width==0:
  11. return False
  12. area = height * width
  13. r = width/height
  14. if r < 1:
  15. r = height/width
  16. if (area < min or area > max) or (r < rmin or r > rmax):
  17. return False
  18. else:
  19. return True

依据定义的验证函数,使用for循环一次遍历轮廓大点集中的点集集合

  1. # 对minAreaRect获得的最小外接矩形,用纵横比进行判断
  2. save = [] #存储合理轮廓
  3. rectall = [] #存储对应的在最小面积矩形
  4. for contour in contours:
  5. rect = cv2.minAreaRect(contour)
  6. if verifySizes(rect):
  7. save.append(contour)
  8. rectall.append(rect)

下图为经过验证函数处理后得到的合理轮廓的点集,画成的轮廓图

cv2.drawContours(initial_car,save,-1,(0,0,255),2)

 

八、对合理矩形(区域),进行floodFill泛洪处理  &  综合后续

为了进一步提高效果,因为刚得到的合理的矩形所包括的车牌区域可能并不完整,所以我们使用泛洪处理来将得到的区域更为完整

step 1 : 利用合理矩形的中心点(rect[0])为中心,生成十个周围的随机种子点

Step 2:对生成的十个随机种子点,依次使用cv2.floodFill泛洪算法进行处理

生成的随机种子点图片(种子点:黄色,以矩形中心作圆:红色)

关于

cv2.floodFill(img,mask,(seed_x,seed_y),newvalue(b,g,r),(loDiff,loDiff,loDiff),(upDiff,upDiff,upDiff),flag)

的详细信息,参见Opencv之cv2.floodFill算法详解_啧啧啧biubiu的博客-CSDN博客_cv2.floodfill

  1. 我们使用floodFill算法,对掩码层进行处理,则我们可以通过掩码层中被标记为255的像素点来判断是不是目标区域。
  2. 再将目标区域的点都保存成一个新点集,使用minAreaRect函数来提取最小面积矩形。
  3. 对最小面积矩形再次应用verifySize函数进行处理,得到合理的矩形
  4. 对得到的合理矩形的区域,在原图上进行图像切割
  5. 对切割后的图像,进行高斯模糊,去噪,直方图均衡化处理
  6. 保存
  1. #Step7 得到矩形中心附近随机数点
  2. for step,rect in enumerate(rectall):
  3. x,y = rect[0] #x:列数,y:行数
  4. x = int(x)
  5. y = int(y)
  6. cv2.circle(initial_car,(x,y),3,(0,255,0),2)
  7. width, height = rect[1]
  8. minimum = width if width<height else height
  9. minimum = 0.5*minimum
  10. h,w=initial_car.shape[:2] #600,
  11. mask = np.zeros((h + 2, w + 2), dtype=np.uint8)
  12. for i in range(10):
  13. seed_x = int(x+0.5*(np.random.random_integers(0,100000)%int(minimum)-(minimum/2)))
  14. seed_y = int(y+0.5*(np.random.random_integers(0,100000)%int(minimum)-(minimum/2)))
  15. cv2.circle(initial_car,(seed_x,seed_y),1,(0,255,255))
  16. loDiff = 7.95
  17. upDiff = 30
  18. Connectivity = 4
  19. flag = Connectivity + (255<<8) + cv2.FLOODFILL_MASK_ONLY
  20. cv2.floodFill(initial_car,mask,(seed_x,seed_y),(255,0,0),(loDiff,loDiff,loDiff),(upDiff,upDiff,upDiff),flag)
  21. # cv2.imshow(str(step),mask)
  22. points = []
  23. row,column = mask.shape
  24. for i in range(row):
  25. for j in range(column):
  26. if mask[i][j]==255:
  27. points.append((j,i)) #点应该输入点坐标(列,行)
  28. points = np.asarray(points)
  29. new_rect = cv2.minAreaRect(points)
  30. if verifySizes(new_rect):
  31. # 宽,高
  32. x,y = new_rect[0]
  33. new_width, new_height = new_rect[1]
  34. angel = new_rect[2]
  35. point1 = cv2.boxPoints(new_rect)[0]
  36. point2 = cv2.boxPoints(new_rect)[1]
  37. point3 = cv2.boxPoints(new_rect)[2]
  38. point4 = cv2.boxPoints(new_rect)[3]
  39. # cv2.line(initial_car,tuple(point1),tuple(point2),(255,255,255),2)
  40. # cv2.line(initial_car, tuple(point2), tuple(point3), (255, 255, 255), 2)
  41. # cv2.line(initial_car, tuple(point3), tuple(point4), (255, 255, 255), 2)
  42. # cv2.line(initial_car, tuple(point4), tuple(point1), (255, 255, 255), 2) #width
  43. rotate = cv2.getRotationMatrix2D((x,y),90+angel,1)
  44. res = cv2.warpAffine(initial_car,rotate,initial_car.shape[:2])
  45. #img,(列,行),(中心)
  46. res = cv2.getRectSubPix(res,(int(new_height),int(new_width)),(x,y))
  47. #img,(列,行)
  48. res = cv2.resize(res,(105,25),interpolation=cv2.INTER_AREA)
  49. res = cv2.cvtColor(res,cv2.COLOR_BGR2GRAY)
  50. res = cv2.GaussianBlur(res,(3,3),0)
  51. res = cv2.equalizeHist(res)
  52. path = './Image/Sample/sample_'+str(step)+'.jpg'
  53. cv2.imwrite(path,res)

九、完整代码

  1. import cv2
  2. import numpy as np
  3. from matplotlib import pyplot as plt
  4. # Step1 读入灰度图
  5. initial_car = cv2.imread(r'F:\ml_summer\Opencv\Image\car.jpg') #(600, 800, 3) 行,列,通道数
  6. gray_car = cv2.cvtColor(initial_car,cv2.COLOR_BGR2GRAY)
  7. # Step2 高斯模糊处理
  8. blur_car = cv2.GaussianBlur(gray_car,(5,5),0)
  9. #Step3 Sobel计算水平导数
  10. sobel_car = cv2.Sobel(blur_car,cv2.CV_16S,1,0)
  11. sobel_car = cv2.convertScaleAbs(sobel_car) #转回uint8
  12. #Step4 Otsu大津算法自适应阈值二值化
  13. _, otsu_car = cv2.threshold(sobel_car,0,255,cv2.THRESH_OTSU|cv2.THRESH_BINARY)
  14. #Step5 闭操作
  15. kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(8,8))
  16. close_car = cv2.morphologyEx(otsu_car,cv2.MORPH_CLOSE,kernel)
  17. # cv2.imshow('sss',close_car)
  18. #Step6 提取外部轮廓
  19. img, contours, hierarchy = cv2.findContours(close_car,cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
  20. save = [] #存储合理轮廓
  21. rectall = [] #存储对应的在最小面积矩形
  22. # 对minAreaRect获得的最小外接矩形,用纵横比进行判断
  23. def verifySizes(RotatedRect):
  24. error = 0.4
  25. aspect = 4.7272
  26. min = 15 * aspect * 15
  27. max = 125 * aspect * 125
  28. rmin = aspect - aspect * error
  29. rmax = aspect + aspect * error
  30. height,width = RotatedRect[1]
  31. if height==0 or width==0:
  32. return False
  33. area = height * width
  34. r = width/height
  35. if r < 1:
  36. r = height/width
  37. if (area < min or area > max) or (r < rmin or r > rmax):
  38. return False
  39. else:
  40. return True
  41. for contour in contours:
  42. rect = cv2.minAreaRect(contour)
  43. if verifySizes(rect):
  44. save.append(contour)
  45. rectall.append(rect)
  46. # cv2.drawContours(initial_car,save,-1,(0,0,255),2)
  47. #Step7 得到矩形中心附近随机数点
  48. for step,rect in enumerate(rectall):
  49. x,y = rect[0] #x:列数,y:行数
  50. x = int(x)
  51. y = int(y)
  52. cv2.circle(initial_car,(x,y),3,(0,255,0),2)
  53. width, height = rect[1]
  54. minimum = width if width<height else height
  55. minimum = 0.5*minimum
  56. h,w=initial_car.shape[:2] #600,
  57. mask = np.zeros((h + 2, w + 2), dtype=np.uint8)
  58. for i in range(10):
  59. seed_x = int(x+0.5*(np.random.random_integers(0,100000)%int(minimum)-(minimum/2)))
  60. seed_y = int(y+0.5*(np.random.random_integers(0,100000)%int(minimum)-(minimum/2)))
  61. cv2.circle(initial_car,(seed_x,seed_y),1,(0,255,255))
  62. loDiff = 7.95
  63. upDiff = 30
  64. Connectivity = 4
  65. flag = Connectivity + (255<<8) + cv2.FLOODFILL_MASK_ONLY
  66. cv2.floodFill(initial_car,mask,(seed_x,seed_y),(255,0,0),(loDiff,loDiff,loDiff),(upDiff,upDiff,upDiff),flag)
  67. # cv2.imshow(str(step),mask)
  68. points = []
  69. row,column = mask.shape
  70. for i in range(row):
  71. for j in range(column):
  72. if mask[i][j]==255:
  73. points.append((j,i)) #点应该输入点坐标(列,行)
  74. points = np.asarray(points)
  75. new_rect = cv2.minAreaRect(points)
  76. if verifySizes(new_rect):
  77. # 宽,高
  78. x,y = new_rect[0]
  79. new_width, new_height = new_rect[1]
  80. angel = new_rect[2]
  81. point1 = cv2.boxPoints(new_rect)[0]
  82. point2 = cv2.boxPoints(new_rect)[1]
  83. point3 = cv2.boxPoints(new_rect)[2]
  84. point4 = cv2.boxPoints(new_rect)[3]
  85. # cv2.line(initial_car,tuple(point1),tuple(point2),(255,255,255),2)
  86. # cv2.line(initial_car, tuple(point2), tuple(point3), (255, 255, 255), 2)
  87. # cv2.line(initial_car, tuple(point3), tuple(point4), (255, 255, 255), 2)
  88. # cv2.line(initial_car, tuple(point4), tuple(point1), (255, 255, 255), 2) #width
  89. rotate = cv2.getRotationMatrix2D((x,y),90+angel,1)
  90. res = cv2.warpAffine(initial_car,rotate,initial_car.shape[:2])
  91. #img,(列,行),(中心)
  92. res = cv2.getRectSubPix(res,(int(new_height),int(new_width)),(x,y))
  93. #img,(列,行)
  94. res = cv2.resize(res,(105,25),interpolation=cv2.INTER_AREA)
  95. res = cv2.cvtColor(res,cv2.COLOR_BGR2GRAY)
  96. res = cv2.GaussianBlur(res,(3,3),0)
  97. res = cv2.equalizeHist(res)
  98. # 绘制直方图
  99. # hist = cv2.calcHist([res],[0],None,[256],[0,255])
  100. # plt.plot(hist,'r')
  101. # plt.hist(res.ravel(), 256, [0, 256],color='r')
  102. # plt.show()
  103. path = './Image/Sample/sample_'+str(step)+'.jpg'
  104. cv2.imwrite(path,res)
  105. # cv2.imshow('now',initial_car)
  106. cv2.waitKey(0)

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/732117
推荐阅读
相关标签
  

闽ICP备14008679号