修改经典sobel算法
经典的不足:
- 只采用了两个方向模板(水平和垂直),导致检测出来的边缘有断裂现象
- 认为凡是灰度新值>=阈值的像素点都是边缘点,不合理。
因为对于纹理复杂的车辆图像,边缘检测效果很差,并且容易导致在车牌识别系统中造成车辆图像中含有噪声太多、车牌定位难度大、车牌自负模糊
修改方案:
3. 将边缘检测模板增加到八个方向:0、45、90、135、180、225、270、315
4. 采用边缘跟踪的方法排除早点:噪声点会引起像素灰度值的跳变,造成改点灰度新值大于或等于阈值。采用边缘跟踪方法判别像素点是边缘点还是噪声点。
其他算法具体解释:
参考博客
这里仅仅观察两个方向上的sobel算法:
import cv2
import numpy as np
img = cv2.imread('test2D.jpg')
sobelx=cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)
sobelx = cv2.convertScaleAbs(sobelx) #绝对值转换
sobely=cv2.Sobel(img,cv2.CV_64F,0,1,ksize=3)
sobely= cv2.convertScaleAbs(sobely) #绝对值转换
#分别为计算x和y,再求和
sobelxy=cv2.addWeighted(sobelx,0.5,sobely,0.5,0) #将x和y融合起来
cv2.imshow('img',img)
cv2.imshow('sobelx',sobelx)
cv2.imshow('sobely',sobely)
cv2.imshow('sobelxy',sobelxy)
cv2.waitKey(0)
优化后的边缘检测
from PIL import Image
import numpy as np
import cv2
img_name = input("输入要处理的图片\n")
img = cv2.imread(img_name,0)
cv2.imshow("gray",img)
cv2.waitKey(0)
img_array = np.array(img) # 转化为数组
w, h = img_array.shape
img_border = np.zeros((w-1, h-1))
for x in range(1, w - 1):
for y in range(1, h - 1):
Sx = img_array[x + 1][y - 1] + 2 * img_array[x + 1][y] + img_array[x + 1][y + 1] - img_array[x - 1][y - 1] - 2 * img_array[x - 1][y] - img_array[x - 1][y + 1]
Sy = img_array[x - 1][y + 1] + 2 * img_array[x][y + 1] + img_array[x + 1][y + 1] - img_array[x - 1][y - 1] - 2 * img_array[x][y - 1] - img_array[x + 1][y - 1]
img_border[x][y] = (Sx * Sx + Sy * Sy) ** 0.5
img2 = Image.fromarray(img_border)
img2.show()
定位车牌区域
使用了github开源项目已有的分类器cascade.xml(点击下载),效果顶呱呱,具体使用方法如下:
import cv2
import numpy as np
import matplotlib.pyplot as plt
def detect(img):
# 导入定位器
cascade_path = 'cascade.xml'
cascade = cv2.CascadeClassifier(cascade_path)
# 修改图片大小
resize_h = 400
height = img.shape[0]
scale = img.shape[1] / float(height)
img = cv2.resize(img,(int(scale*resize_h),resize_h))
# 转为灰度值
img_gray = cv2.cvtColor(img,cv2.COLOR_RGB2GRAY)
# 车牌定位
car_plates = cascade.detectMultiScale(img_gray,1.1,2,minSize=(36,9),maxSize=(36*40,9*40))
print("检测到车牌数",len(car_plates))
if len(car_plates)>0:
i = 0
for car_plate in car_plates:
x,y,w,h = car_plate # 循环遍历每个车牌
plate = img[y-10:y+h+10,x-10:x+w+10]
cv2.rectangle(img,(x-10,y-10),(x+w+10,y+h+10),(255,0,0),2)
cut_img = img[y-10:y+h+10, x-10:x+w+10]
cv2.imshow('imgs'+str(i),cut_img)
i+=1
cv2.imshow("img",img)
if __name__ == '__main__':
img = cv2.imread('testMultiply.jpg')
detect(img)
cv2.waitKey(0)
其中如果不影响观察的话,可以直接读入灰度图像,也就不需要后面的灰度化处理的操作了
img = cv2.imgread('picturename.jpg',0)
最后结果如下:
接下来会对提取出的车牌区域进行二值化处理后字符识别,敬请期待