车牌检测与定位

进行车牌识别包含车牌检测+车牌识别

车牌检测:图像分割+特征提取
车牌识别:对检测到的车牌进行内容识别

车牌检测的方法

车牌主要包括以下几种:

蓝牌白字:普通小型车(其中包括政府机关专用号段、政法部门警车以外的行政用车)的牌照

黄牌黑字:大型车辆、摩托车、驾校教练车牌照

黑牌白字:涉外车辆牌照,式样和蓝牌基本相同

白牌:政法部门(公安、法院、检察院、国安、司法)警车、武警部队车辆、解放军军车的牌照都是白牌

警车:公安警车的牌照样式为[某·A1234警],除“警”为红字外其他的都是黑字,一共4位数字,含义与普通牌照相同

车牌检测定位的方法:

  1. 基于边缘
  2. 基于颜色
  3. 基于机器学习

对于边缘图像,如果车牌在图像中占得比例不是很小,普通的差分或者全局二值化就可以达到很好的效果;

对于高清图像或场景很复杂的情况,车牌所占比例很小,或车牌处于较暗的地方,而整个场景很亮,此时差分不会得到很好的效果,可以对图像进行对比度增强,但对比度增强可能导致噪声点特别多,导致车牌区域检测不到边缘。

检测可以用到的特征:

  1. 颜色特征

    每种车牌的底色具有各自特殊的RGB值,例如程序中使用的蓝底车牌的典型RGB值为 R = 28,G = 63, B = 138;
    当RGB值接近时则认为可能是车牌,将该点像素赋值为255,否则0;利用颜色特征可以获取二值图像,可以去除大部分的其他物体,但是会有很多的干扰。

  2. 大小特征

    对二值图像进行膨胀处理和腐蚀处理之后,可以去掉很小的噪点。对于灰度图获取轮廓边缘,轮廓具有一定的面积。车牌应该具有一定的大小,如果面积过小则认为不是车牌。此法可以去除大部分的小面积的干扰物。

    颜色特征和大小特征是初选。形状特征是精选。

  3. 形状特征

    矩形度:提取轮廓之后,轮廓包围的面积和轮廓最小外接矩形的面积之比称为矩形度,值越接近1,则是矩形的概率越大。

    长宽比:正常车牌的长宽比为3:1,最小外接矩形的长宽比越接近1则认为是车牌的概率最大。

    如果三个筛选条件都符合,则是车牌的概率非常大。

流程:

  1. 对图像进行灰度转换(如果不利用颜色的话要先进行该步骤)
  2. 高斯滤波进行去噪
  3. 定位竖直边缘,利用sobel算子,因为车牌的字符主要是竖直方向分开的
  4. 阈值化提取边缘
  5. 闭操作对提取的边缘进行连通,找到连通区域,为后续定位做准备
  6. 去除背景干扰
  7. 利用矩阵找到矩形连通域,此时会有很多矩形框被认为可能是车牌区域
  8. 利用车牌的长:宽来去掉很多不可能是车牌区域的框
  9. 去掉因拍摄带来的仿射变换
  10. 得到若干个大小相同的矩形区域
  11. 调用已经利用正负样本训练好的SVM对是否为车牌区域进行分类,找到车牌区域
import cv2
import numpy as np
import math

""" 输入图像归一化 """


def stretch(img):
    max = float(img.max())
    min = float(img.min())

    for i in range(img.shape[0]):
        for j in range(img.shape[1]):
            img[i, j] = (255 / (max - min)) * img[i, j] - (255 * min) / (max - min)

    return img


def dobinaryzation(img):
    max = float(img.max())
    min = float(img.min())

    x = max - ((max - min) / 2)
    ret, thresholdimg = cv2.threshold(img, x, 255, cv2.THRESH_BINARY)

    return thresholdimg


def find_retangle(contour):
    y, x = [], []

    for p in contour:
        y.append(p[0][0])
        x.append(p[0][1])

    return [min(y), min(x), max(y), max(x)]


def locate_license(img, orgimg):
    img, contours, hierachy = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)

    # 找到最大的三个区域
    blocks = []
    for c in contours:
        # 找出轮廓的左上和右下点,计算出其面积和长宽比
        r = find_retangle(c)
        a = (r[2] - r[0]) * (r[3] - r[1])
        s = (r[2] - r[0]) / (r[3] - r[1])

        blocks.append([r, a, s])

    # 选出面积最大的3个区域
    blocks = sorted(blocks, key=lambda b: b[2])[-3:]

    # 使用颜色识别判断出最像车牌的区域
    maxweight, maxinedx = 0, -1

    for i in range(len(blocks)):
        b = orgimg[blocks[i][0][1]:blocks[i][0][3], blocks[i][0][0]:blocks[i][0][2]]
        # RGB 转HSV
        hsv = cv2.cvtColor(b, cv2.COLOR_BGR2HSV)

        # 蓝色车牌范围
        lower = np.array([100, 50, 50])
        upper = np.array([140, 255, 255])

        # 根据阈值构建掩膜
        mask = cv2.inRange(hsv, lower, upper)

        # 统计权值
        w1 = 0
        for m in mask:
            w1 += m / 255

        w2 = 0
        for w in w1:
            w2 += w

        # 选出最大权值的区域
        if w2 > maxweight:
            maxindex = i
            maxweight = w2

    return blocks[maxindex][0]


def find_license(img):
    '''预处理'''
    # 压缩图像
    a = 400 * img.shape[0] / img.shape[1]
    a = int(a)
    img = cv2.resize(img, (400, a))
    cv2.imshow('img',img)
    cv2.waitKey()

    # RGB转灰色
    grayimg = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    cv2.imshow('grayimg', grayimg)
    cv2.waitKey()

    # 灰度拉伸
    stretchedimg = stretch(grayimg)
    cv2.imshow('stretchedimg', stretchedimg)
    cv2.waitKey()

    # 进行开运算,用来去除噪声
    r = 16
    h = w = r * 2 + 1
    kernel = np.zeros((h, w), dtype=np.uint8)
    cv2.circle(kernel, (r, r), r, 1, -1)
    openingimg = cv2.morphologyEx(stretchedimg, cv2.MORPH_OPEN, kernel)
    cv2.imshow('openingimg', openingimg)
    cv2.waitKey()

    strtimg = cv2.absdiff(stretchedimg, openingimg)
    cv2.imshow('strtimg', strtimg)
    cv2.waitKey()

    # 图像二值化
    binaryimg = dobinaryzation(strtimg)
    cv2.imshow('binaryimg', binaryimg)
    cv2.waitKey()

    # Canny算子进行边缘检测
    cannyimg = cv2.Canny(binaryimg, binaryimg.shape[0], binaryimg.shape[1])
    cv2.imshow('cannyimg', cannyimg)
    cv2.waitKey()

    '''消除小区域,连通大区域'''
    # 进行闭运算
    kernel = np.ones((5, 19), np.uint8)
    closingimg = cv2.morphologyEx(cannyimg, cv2.MORPH_CLOSE, kernel)
    cv2.imshow('closingimg', closingimg)
    cv2.waitKey()

    # 进行开运算
    openingimg = cv2.morphologyEx(closingimg, cv2.MORPH_OPEN, kernel)
    cv2.imshow('openingimg', openingimg)
    cv2.waitKey()

    # 再次进行开运算
    kernel = np.ones((11, 5), np.uint8)
    openingimg = cv2.morphologyEx(openingimg, cv2.MORPH_OPEN, kernel)
    cv2.imshow('openingimg', openingimg)
    cv2.waitKey()

    # 消除小区域,定位车牌位置
    rect = locate_license(openingimg, img)
    return rect, img


if __name__ == '__main__':
    orgimg = cv2.imread('car3.jpg')
    rect, img = find_license(orgimg)

    cv2.rectangle(img, (rect[0], rect[1]), (rect[2], rect[3]), (0, 255, 0), 2)
    cv2.imshow('img', img)
    cv2.waitKey()
    cv2.destroyAllWindows()


  1. 原图
    这里写图片描述

  2. 灰度化
    这里写图片描述

  3. 灰度拉伸
    这里写图片描述

  4. 开运算
    这里写图片描述

  5. 将灰度拉伸后的图和开运算后的图的差的绝对值输出
    这里写图片描述

  6. 二值化
    这里写图片描述

  7. Canny边缘检测
    这里写图片描述

  8. 对边缘进行闭运算消除小区域,连通大区域
    这里写图片描述

  9. 开运算
    这里写图片描述

  10. 再次进行开运算

    这里写图片描述

  11. 消除小区域,使用颜色识别出车牌位置

    这里写图片描述

猜你喜欢

转载自blog.csdn.net/jiaoyangwm/article/details/81088578