车牌检测(分别使用Haar级联 和轮廓裁剪)

使用两种方法对比识别车牌

1.轮廓查找

首先对读取图片,做基本处理

将原图片转为灰度图片

再进行双边滤波

img = cv2.imread("img")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 双边滤波
gray1 = cv2.bilateralFilter(gray, 13, 15, 15)

plt.imshow(gray,cmap="gray")
plt.imshow(gray1,cmap="gray")
plt.show()

如图

 寻找轮廓

imutils是一个 OpenCV 的 Python 封装库,简化了图像的处理,可以更方便的实现图像显示(使用 Matplotlib)、平移(Translate)、旋转(Rotate)、缩放(Resize)、骨架化(Skeletonizate)等操作。

 contours = cv2.findContours(edged.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    
    contours = imutils.grab_contours(contours)
    # 根据区域大小排序取前十个
    contours = sorted(contours, key=cv2.contourArea, reverse=True)[:10]
    screenCnt = None
    # 遍历轮廓,找到车牌轮廓
    for c in contours:
        # 计算轮廓周长(轮廓,是否闭合)
        peri = cv2.arcLength(c, True)
        # 折线化(轮廓,阈值(越小越接近曲线),是否闭合)返回折线顶点坐标
        approx = cv2.approxPolyDP(c, 0.018 * peri, True)
        # 获取四个顶点(即四边形)
        if len(approx) == 4:
            screenCnt = approx
            break
    # 如果找到了四边形
    if screenCnt is not None:
        # 根据四个顶点坐标对img画线(图像矩阵,轮廓坐标集,轮廓索引,颜色,线条粗细)
        cv2.drawContours(img, [screenCnt], -1, (0, 0, 255), 3)

标记车牌区域:

 

# 创建一个灰度图一样大小的图像矩阵
    mask = np.zeros(gray.shape, np.uint8)
    # 将创建的图像矩阵的车牌区域画成白色
    cv2.drawContours(mask, [screenCnt], 0, 255, -1, )
    # 图像位运算进行遮罩
    new_image = cv2.bitwise_and(img, img, mask=mask)

对车牌进行处理:

 

将车牌区域裁剪

# 获取车牌区域的所有坐标点
    (x, y) = np.where(mask == 255)
    # 获取底部顶点坐标
    (topx, topy) = (np.min(x), np.min(y))
    # 获取底部坐标
    (bottomx, bottomy,) = (np.max(x), np.max(y))
    # 剪裁
    Cropped = gray[topx:bottomx, topy:bottomy]

最后使用pytesseract库进行车牌内容识别

 text = ts.image_to_string(Cropped, config='--psm 11')
 print("车牌结果:", text)

 运行结果:

 

 附上完整代码

import cv2
import matplotlib.pyplot as plt
import imutils
import pytesseract as ts
import numpy as np
if __name__ == '__main__':
    img = cv2.imread("img")
    
    img = cv2.resize(img, (620, 480))

    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    # 双边滤波
    gray1 = cv2.bilateralFilter(gray, 13, 15, 15)

    # 显示效果
    plt.subplot(1,2,1)
    plt.imshow(gray,cmap="gray")
    plt.subplot(1,2,2)
    plt.imshow(gray1,cmap="gray")
    plt.show()

    edged = cv2.Canny(gray, 50, 200)
    plt.imshow(edged,cmap="gray")
    plt.show()
    contours = cv2.findContours(edged.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    
    contours = imutils.grab_contours(contours)
    # 根据区域大小排序取前十个
    contours = sorted(contours, key=cv2.contourArea, reverse=True)[:10]
    screenCnt = None
    # 遍历轮廓,找到车牌轮廓
    for c in contours:
        # 计算轮廓周长(轮廓,是否闭合)
        peri = cv2.arcLength(c, True)
        # 折线化(轮廓,阈值(越小越接近曲线),是否闭合)返回折线顶点坐标
        approx = cv2.approxPolyDP(c, 0.018 * peri, True)
        # 获取四个顶点(即四边形)
        if len(approx) == 4:
            screenCnt = approx
            break
    # 如果找到了四边形
    if screenCnt is not None:
        # 根据四个顶点坐标对img画线(图像矩阵,轮廓坐标集,轮廓索引,颜色,线条粗细)
        cv2.drawContours(img, [screenCnt], -1, (0, 0, 255), 3)
    """遮罩"""
    # 创建一个灰度图一样大小的图像矩阵
    mask = np.zeros(gray.shape, np.uint8)
    # 将创建的图像矩阵的车牌区域画成白色
    cv2.drawContours(mask, [screenCnt], 0, 255, -1, )
    # 图像位运算进行遮罩
    new_image = cv2.bitwise_and(img, img, mask=mask)
    """图像剪裁"""
    # 获取车牌区域的所有坐标点
    (x, y) = np.where(mask == 255)
    # 获取底部顶点坐标
    (topx, topy) = (np.min(x), np.min(y))
    # 获取底部坐标
    (bottomx, bottomy,) = (np.max(x), np.max(y))
    # 剪裁
    Cropped = gray[topx:bottomx, topy:bottomy]
    #显示效果
    cv2.imshow('img', img)
    cv2.imshow('gray', gray)
    cv2.imshow('edged', edged)
    cv2.imshow('new_image ',new_image )
    cv2.imshow('Cropped',Cropped)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    plt.imshow(Cropped,cmap='gray')
    plt.show()
    text = ts.image_to_string(Cropped, config='--psm 11')
    print("车牌结果:", text)

在这里可能会出现pytesseract库调用识别导致无法识别车牌内容,详情请参考pytesseract的下载和调用。

2.使用Haar级联模型车牌检测

依旧是先读取图片

carplate_img = cv2.imread('img')
carplate_img_rgb = cv2.cvtColor(carplate_img, cv2.COLOR_BGR2RGB)

plt.subplot(1, 2, 1)
plt.imshow(carplate_img)
plt.subplot(1,2,2)
plt.imshow(carplate_img_rgb);
plt.show()

 

 写一个可以调整图片大小的函数,并且进行保存

def enlarge_plt_display(image, scale_factor):
    width = int(image.shape[1] * scale_factor / 100)
    height = int(image.shape[0] * scale_factor / 100)
    dim = (width, height)
    plt.figure(figsize = dim)
    plt.axis('off') 
    plt.imshow(image)

使用方法enlarge_plt_display(carplate_img, 1)

其中数字参数表示对该图片的大小处理的倍数

接下来我们调用Haar级联的车牌检测模型

Haar级联检测5个特征:边缘特征、线特征、四角-矩形的特征,计算特征需要从黑色区域下的像素总和中减去白色区域下的像素总和。

这里我们所用的是Haar级联已经训练好的模型,本质上属于四角-矩形的特征检测

这里是一些常用的模型简介   可以点击此处从官方github中下载

  • haarcascade_frontalface_default.xml:检测面部
  • haarcascade_eye.xml:检测左眼和右眼
  • haarcascade_smile.xml:检测面部是否存在嘴部
  • haarcascade_eye_tree_eyeglasses.xml:检测是否带墨镜🕶
  • haarcascade_frontalcatface.xml:检测猫脸
  • haarcascade_frontalcatface_extended.xml:检测猫脸延伸
  • haarcascade_frontalface_alt.xml:检测人脸属性
  • haarcascade_frontalface_alt_tree.xml
  • haarcascade_frontalface_alt2.xml
  • haarcascade_fullbody.xml:检测全身
  • haarcascade_lefteye_2splits.xml:检测左眼
  • haarcascade_licence_plate_rus_16stages.xml:检测证件
  • haarcascade_lowerbody.xml:检测下半身
  • haarcascade_profileface.xml
  • haarcascade_righteye_2splits.xml:检测右眼
  • haarcascade_russian_plate_number.xml:检测俄罗斯字母车牌号
  • haarcascade_upperbody.xml:检测上半身

调用模型,并使用模型标记出车牌

carplate_haar_cascade = cv2.CascadeClassifier('./haar_cascades/haarcascade_russian_plate_number.xml')
def carplate_detect(image):
    carplate_overlay = image.copy() #将原图复制
    carplate_rects =carplate_haar_cascade.detectMultiScale(carplate_overlay,scaleFactor=1.1, minNeighbors=3) 

    for x,y,w,h in carplate_rects: 
        cv2.rectangle(carplate_overlay, (x,y), (x+w,y+h), (255,0,0), 5) 
        
    return carplate_overlay

最后将车牌裁剪:

def carplate_extract(image):
    
    carplate_rects = carplate_haar_cascade.detectMultiScale(image,scaleFactor=1.1, minNeighbors=5) 

    for x,y,w,h in carplate_rects: 
        carplate_img = image[y-10:y+h+10 ,x+27:x+w+15] 
        
    return carplate_img
carplate_extract_img = carplate_extract(carplate_img_rgb)
plt.imshow(carplate_extract_img)

 

附上完整代码:

 

import cv2
import numpy as np
import matplotlib.pyplot as plt

import pytesseract as ts


def car_plate_detection(img):
    def enlarge_plt_display(image, scale_factor):
        width = int(image.shape[1] * scale_factor / 100)
        height = int(image.shape[0] * scale_factor / 100)
        dim = (width, height)
        plt.figure(figsize=dim)
        plt.axis('off')
        plt.imshow(image)

    def carplate_detect(image):
        carplate_overlay = image.copy()  # Create overlay to display red rectangle of detected car plate
        carplate_rects = carplate_haar_cascade.detectMultiScale(carplate_overlay, scaleFactor=1.1, minNeighbors=1)

        for x, y, w, h in carplate_rects:
            cv2.rectangle(carplate_overlay, (x, y), (x + w, y + h), (255, 0, 0), 5)

        return carplate_overlay

    def carplate_extract(image):

        carplate_rects = carplate_haar_cascade.detectMultiScale(image, scaleFactor=1.1, minNeighbors=5)

        for x, y, w, h in carplate_rects:
            carplate_img = image[y - 10:y + h + 10, x + 27:x + w + 15]

        return carplate_img

    def enlarge_img(image, scale_percent):
        width = int(image.shape[1] * scale_percent / 100)
        height = int(image.shape[0] * scale_percent / 100)
        dim = (width, height)
        resized_image = cv2.resize(image, dim, interpolation=cv2.INTER_AREA)
        return resized_image
       

    carplate_img = cv2.imread(img)
    carplate_img_rgb = cv2.cvtColor(carplate_img, cv2.COLOR_BGR2RGB)

    carplate_haar_cascade = cv2.CascadeClassifier('./Car-Plate-Detection-OpenCV-TesseractOCR-main/haar_cascades/haarcascade_russian_plate_number.xml')

    detected_carplate_img = carplate_detect(carplate_img_rgb)
    enlarge_plt_display(detected_carplate_img, 1)
    carplate_extract_img = carplate_extract(carplate_img_rgb)
    car_plate_area = enlarge_img(carplate_extract_img, 150)

    return car_plate_area


car_plate_area=car_plate_detection("img")
plt.imshow(car_plate_area,cmap="gray")
plt.show()

总结:

相比较使用轮廓检测来剪裁车牌的效果要弱于使用Haar级联模型,在Haar级联模型中,对图像的轮廓进行了多次的标识,最终通过参数决定标记大于多少次的轮廓将其保留下来,有更好的鲁棒性。

  • 5
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

入门两年的练习生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值