1 说明:
=====
1.1 环境:
python3.8,深度操作系统deepin-linux,微软编辑器vscode,opencv版本4.2.0。
1.2 上一篇:
《强!全套完整中文车牌识别,纯python来实现和代码分析》
1.3 本次讲解:超级详细,一步一步,注释分析,小白都会。
1.4 注意:代码为注释讲解版,有点繁琐,但是可读性较高,大神可以封装成函数,去掉注释和窗口显示过程。
2 图片:来自今日头条免费正版图库:
===代码逐步分析===
3 读取图片并显示原始图片:额外知识
=============================
3.1 cv2法:显示是原图,省略。牵涉到知识点是图片的通道的拆分和合并。
import cv2origin_image = cv2.imread('/home/xgj/Desktop/car911/2.jpeg')cv2.imshow('image', origin_image)cv2.waitKey(0)
3.2 matplotlib法:
import cv2#---第2步:读取待检测原始的图片---origin_image = cv2.imread('/home/xgj/Desktop/car911/2.jpeg')#---第3步:显示图片法---'''# cv2显示图片法:原图cv2.imshow('image', origin_image)cv2.waitKey(0)''''''# matplotlib法直接显示,不是原图from matplotlib import pyplot as pltplt.imshow(origin_image)plt.show()'''# 调整通道的顺序,显示原图# 分割通道from matplotlib import pyplot as plt#说明cv2读取的顺序是bgr#而matplotlib显示rgb,故显示plt原图法需要转换b,g,r = cv2.split(origin_image)# 合并通道img = cv2.merge([r, g, b])plt.imshow(img)plt.show()
3.3 图:
4 提取蓝色车牌:
============
4.1 代码:
#---第1步:导入所需模块---import cv2from matplotlib import pyplot as plt#---第2步:读取待检测原始的图片---origin_image = cv2.imread('/home/xgj/Desktop/car911/2.jpeg')# 可注释掉# 调整通道的顺序# 分割通道b,g,r = cv2.split(origin_image)# 合并通道img = cv2.merge([r, g, b])#用matplotlib的plt显示图片plt.imshow(img)plt.show()#---第3步:提取车牌部分图片---#图像去噪灰度处理# 3-1:对原始图片origin_image进行高斯模糊Gausiian_image = cv2.GaussianBlur(origin_image, (3, 3), 0)#可注释掉plt.imshow(Gausiian_image)plt.show()# 3-2:灰度化处理图像gray_image = cv2.cvtColor(Gausiian_image, cv2.COLOR_RGB2GRAY)#可注释掉plt.imshow(gray_image)plt.show()# 3-3:Sobel算子Sobel_x = cv2.Sobel(gray_image, cv2.CV_16S, 1, 0) # 对x求一阶导,垂直检测#Sobel_y = cv2.Sobel(gray_image, cv2.CV_16S, 0, 1) # 附注:对y求一阶导,水平检测absX = cv2.convertScaleAbs(Sobel_x) # 转回uint8#定义车牌imagechepai = absX# 3-4:图像二值化ret, image2 = cv2.threshold(imagechepai, 0, 255, cv2.THRESH_OTSU)# 3-5:闭操作可以将目标区域连成一个整体,便于后续轮廓的提取。kernelX = cv2.getStructuringElement(cv2.MORPH_RECT, (17, 5))image3 = cv2.morphologyEx(image2, cv2.MORPH_CLOSE, kernelX,iterations = 3)#可注释掉plt.imshow(image3)plt.show()# 3-6:膨胀和腐蚀#通过膨胀连接相近的图像区域,通过腐蚀去除孤立细小的色块。kernelX = cv2.getStructuringElement(cv2.MORPH_RECT, (20, 1))kernelY = cv2.getStructuringElement(cv2.MORPH_RECT, (1, 19))#膨胀第1次image4 = cv2.dilate(image3, kernelX)plt.imshow(image4)plt.show()#腐蚀第1次image5 = cv2.erode(image4, kernelX)plt.imshow(image5)plt.show()#腐蚀第2次image6 = cv2.erode(image5, kernelY)plt.imshow(image6)plt.show()#膨胀第2次image7 = cv2.dilate(image6, kernelY)plt.imshow(image7)plt.show()# 3-7:中值滤波:去除图像或者其它信号中的噪声。image8 = cv2.medianBlur(image7, 15)plt.imshow(image8)plt.show()# 3-8:查找轮廓contours, hierarchy = cv2.findContours(image8, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)# 3-9:判断车牌区域:for item in contours: rect = cv2.boundingRect(item) x = rect[0] y = rect[1] weight = rect[2] height = rect[3] if (weight > (height * 3)) and (weight < (height * 4)): image9 = origin_image[y:y + height, x:x + weight] #侧位车牌和黄色车牌报错 #提取车牌,生成车牌图片 cv2.imwrite('/home/xgj/Desktop/car911/chepai1.png', image9) cv2.imshow('image', image9) cv2.waitKey(0)
4.2 操作和效果图:
4.3 正位绿色车牌:OK,省略。(新能源汽车车牌,正面非侧位OK)
5 bug分析:
============
5.1 图:
6 黄色车牌定位和提取(图:3.jpeg):
=============================
6.1 代码:换一种思维
#---第1步:导入模块--import cv2import numpy as np#---第2步:读取原图---img = cv2.imread('/home/xgj/Desktop/car911/3.jpeg')#可注释掉cv2.imshow("pic1",img) #显示原图cv2.waitKey(0)#---第3步:预处理---# 包括灰度处理,高斯滤波平滑处理,Sobel提取边界,图像二值化# 3-1:灰度处理gray_img = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)cv2.imshow("pic2", gray_img)cv2.waitKey(0)# 3-2:高斯滤波平滑处理GaussianBlur_img = cv2.GaussianBlur(gray_img, (3, 3), 0)cv2.imshow("pic3", GaussianBlur_img)cv2.waitKey(0)# 3-3:Sobel提取边界Sobel_img = cv2.Sobel(GaussianBlur_img, -1, 1, 0, ksize=3)cv2.imshow("pic4", Sobel_img)cv2.waitKey(0)# 3-4:图像二值化ret, binary_img = cv2.threshold(Sobel_img, 127, 255, cv2.THRESH_BINARY)#---第4步:形态学运算---kernel = np.ones((5, 15), np.uint8)# 先闭运算将车牌数字部分连接,再开运算将不是块状的或是较小的部分去掉close_img = cv2.morphologyEx(binary_img, cv2.MORPH_CLOSE, kernel)open_img = cv2.morphologyEx(close_img, cv2.MORPH_OPEN, kernel)# 再来一次:修改部分图像得到的轮廓边缘不整齐kernel2 = np.ones((10, 10), np.uint8)open_img2 = cv2.morphologyEx(open_img, cv2.MORPH_OPEN, kernel2)#结构元素可以是矩形/椭圆/十字形,可以用cv2.getStructuringElement()来生成不同形状的结构元素element = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5)) #矩形结构dilation_img = cv2.dilate(open_img, element, iterations=3)cv2.imshow("pic4", dilation_img)cv2.waitKey(0)#---第5步:获取轮廓---# 5-1:2个指标,易报错,与opencv版本有关contours, hierarchy = cv2.findContours(dilation_img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)# 测试边框识别结果,注释掉,否则汽车车牌提取后有绿色轮廓,不好看#cv2.drawContours(img, contours, -1, (0, 255, 0), 3)#cv2.imshow("pic5", img) #绘制轮廓图#cv2.waitKey(0)# 5-2:从轮廓中提取坐标# 将轮廓规整为长方形rectangles = []for c in contours: x = [] y = [] for point in c: y.append(point[0][0]) x.append(point[0][1]) r = [min(y), min(x), max(y), max(x)] rectangles.append(r) # 5-3:用颜色识别出车牌区域dist_r = []max_mean = 0for r in rectangles: carmask = img[r[1]:r[3], r[0]:r[2]] #车牌区域面积大小 hsv = cv2.cvtColor(carmask, cv2.COLOR_BGR2HSV) ''' #蓝色车牌,可以使用 low = np.array([100, 60, 60]) up = np.array([140, 255, 255]) ''' #黄色车牌 low = np.array([15, 55, 55]) up = np.array([50, 255, 255]) ''' #绿色车牌:系能源汽车报错,因为车牌底色不是全绿,白色渐变绿色 low = np.array([50, 50, 50]) up = np.array([100, 255, 255]) ''' result = cv2.inRange(hsv, low, up) # 用计算均值的方式找蓝色最多的区块 mean = cv2.mean(result) if mean[0] > max_mean: max_mean = mean[0] dist_r = r# 画出识别结果,定位用,截取车牌时就不要了,否则车牌上有绿色框,不好看#cv2.rectangle(img, (dist_r[0]+3, dist_r[1]), (dist_r[2]-3, dist_r[3]), (0, 255, 0), 2)#参数格式:cv2.rectangle(image, (x,y), (x+w,y+h), (0,255,0), 2)#一般格式#qichechepai = img[y:y + height, x:x + weight]qichechepai = img[dist_r[1]:dist_r[3], dist_r[0]+3:dist_r[2]-3]#提取车牌,生成车牌图片cv2.imwrite('/home/xgj/Desktop/car911/chepai3.png', qichechepai)cv2.imshow('qichechepaitiqu', qichechepai)cv2.waitKey(0)
6.2 操作和效果图:
6.3 新能源汽车车牌就不适合。
7 侧面车牌定位和提取:
=================
7.1 分类器:下载地址
https://github.com/zeusees/HyperLPR/blob/master/model/cascade.xml #分类器来自别人,感谢
7.2 代码:
#---第1步:导出模块--import cv2import numpy as np#---第2步:定义侦测函数def detect(image): # 调用分类器,提前下载好 cascade_path = '/home/xgj/Desktop/car911/cascade.xml' cascade = cv2.CascadeClassifier(cascade_path) # 修改图片大小 resize_h = 400 height = image.shape[0] scale = image.shape[1] / float(height) image = cv2.resize(image, (int(scale * resize_h), resize_h)) # 转为灰度图 image_gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY) #查找车牌 car_plates = cascade.detectMultiScale(image_gray, 1.1, 2, minSize=(36, 9), maxSize=(36 * 40, 9 * 40)) # print("检测到车牌数", len(car_plates)) #判断 if len(car_plates) > 0: for car_plate in car_plates: x, y, w, h = car_plate #画汽车车牌矩形并截取 qichechepai = image[y-10: y + h + 10, x-10: x + w + 10] cv2.imshow('plate', qichechepai) #显示车牌窗口 cv2.imwrite('/home/xgj/Desktop/car911/ccnew.png', qichechepai) #保存提取汽车车牌 #画车牌识别定位框 cv2.rectangle(image, (x - 10, y - 10), (x + w + 10, y + h + 10), (0, 255, 0), 2) cv2.imshow("image", image) #显示原图上定位并画出识别框 if __name__ == '__main__': #导入原图 image = cv2.imread('/home/xgj/Desktop/1-chepai-dingwei/fenleiqi/cc.jpeg') detect(image) cv2.waitKey(0) cv2.destroyAllWindows()
7.3 操作和效果图:
7.4 侧面新能源汽车车牌,可以搞定,小bug:
===汽车车牌定位和提取大全===
高手可以整合、定义函数、封装
不管了,好东西就应该分享。