本文将介绍一种运用opencv开源库进行车牌定位,投影法进行车牌字符分割,模板匹配法进行字符识别的一种车牌识别系统。

## 1、使用opencv进行图形处理操作。
在找到一张车辆照片后,你可能不知道它的大小尺寸,所以在进行操作时应先进行图像尺寸编辑。

def resize_photo(imgArr, MAX_WIDTH=800):
    img = imgArr
    rows, cols = img.shape[:2]  # 获取输入图像的高和宽
    if cols > MAX_WIDTH:
        change_rate = MAX_WIDTH / cols
        img = cv2.resize(img, (MAX_WIDTH, int(rows * change_rate)), interpolation=cv2.INTER_AREA)
    pic_hight, pic_width = img.shape[:2]
    return img, pic_hight, pic_width
在读取图像后,由于彩色图像不易处理,所以要将RGB格式图像转换为灰度格式,每一个像素有0~255的灰度值表示。之后进行滤波处理,去除图像中的噪点。之后进行阈值分割,将原灰度图像转换为二值图像,便于进行疑似车牌标记。对二值图像进行膨胀腐蚀操作,使灰度图像连接在一起。在进行形态学处理时,闭运算参数选择会对车牌识别有很大影响。

java opencv 车牌识别源码 opencv 车牌识别算法_计算机视觉

def predict(imgArr):
    img_copy = imgArr.copy()
    img_copy_ = cv2.GaussianBlur(img_copy, (5, 5), 0, 0, cv2.BORDER_DEFAULT)

    gray_img = cv2.cvtColor(img_copy_, cv2.COLOR_BGR2GRAY)

    # 高斯滤波

    kernel = np.ones((23, 23), np.uint8)
    # 形态学变化,开运算
    img_opening = cv2.morphologyEx(gray_img, cv2.MORPH_OPEN, kernel)

    # 图片混合
    img_opening = cv2.addWeighted(gray_img, 1, img_opening, -1, 0)
    cv2.imshow('text_.jpg', img_opening)
    # 图像阈值处理函数,阈值 = 0,最大值 = 255,算法 cv2.THRESH_BINARY大于阈值为255,小于阈值为0 ,cv2.THRESH_OTSU自己寻找阈值
    ret, img_thresh = cv2.threshold(img_opening, 0, 255, + cv2.THRESH_OTSU)
    # 边缘检测
    img_edge = cv2.Canny(img_thresh, 100, 200)
    # 再次闭运算 开运算使图像边缘形成整体
    kernel = np.ones((5, 15), np.uint8)
    img_edge1 = cv2.morphologyEx(img_edge, cv2.MORPH_CLOSE, kernel)
    img_edge2 = cv2.morphologyEx(img_edge1, cv2.MORPH_OPEN, kernel)
    kernel = np.ones((11, 20), np.uint8)
    img_edge3 = cv2.morphologyEx(img_edge2, cv2.MORPH_CLOSE, kernel)
    img_edge4 = cv2.morphologyEx(img_edge3, cv2.MORPH_OPEN, kernel)
    contours, hierarchy = cv2.findContours(img_edge4, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    return contours, img_edge4

java opencv 车牌识别源码 opencv 车牌识别算法_python_02


## 2、进行车牌定位。

在处理好的二值图像中,会出现疑似车牌的部分,我们要通过算法进行判断。在这里我首先对各个疑似车牌部分的长宽比进行计算,正常情况下,在图片中车牌长宽比为2.5~5.5之间,这种方法作为判断的第一个标准。但是也有可能会有多个这种矩形出现在图中。所以之后我们根据车牌的另一个特征,大部分为蓝色进行判断。(局限性:只可以判断蓝色车牌,感兴趣的朋友可以按照识别蓝色的方法在代码中添加识别其他颜色的方法),将原图转换为HSV格式(转换前要进行矫正处理以免发生错误),判断目标区域内蓝色像素的个数,若蓝色为大部分即可判断为车牌。

chose_licence_plate(contours, pic_hight, pic_width, img_Size):
    contours = [cnt for cnt in contours if cv2.contourArea(cnt) > 2000]
    car_contours = []
    for cnt in contours:
        rect = cv2.minAreaRect(cnt)
        area_width, area_height = rect[1]
        if area_width < area_height:
            area_width, area_height = area_height, area_width
        wh_ratio = area_width / area_height
        if wh_ratio > 2 and wh_ratio < 5.5:
            car_contours.append(rect)
            box = cv2.boxPoints(rect)
            box = np.int0(box)
            print(box)
        oldimg = cv2.drawContours(img_Size, [box], 0, (0, 0, 255), 2)
        cv2.imshow("Test", oldimg)
    print(car_contours)
    card_imgs = []
    for rect in car_contours:
        if rect[2] > -1 and rect[2] < 1:  # 创造角度,使得左、高、右、低拿到正确的值
            angle = 1
        else:
            angle = rect[2]
        rect = (rect[0], (rect[1][0] + 5, rect[1][1] + 5), angle)  # 扩大范围,避免车牌边缘被排除
        box = cv2.boxPoints(rect)
        heigth_point = right_point = [0, 0]
        left_point = low_point = [pic_width, pic_hight]
        for point in box:
            if left_point[0] > point[0]:
                left_point = point
            if low_point[1] > point[1]:
                low_point = point
            if heigth_point[1] < point[1]:
                heigth_point = point
            if right_point[0] < point[0]:
                right_point = point
        if left_point[1] <= right_point[1]:  # 正角度
            new_right_point = [right_point[0], heigth_point[1]]
            pts2 = np.float32([left_point, heigth_point, new_right_point])  # 字符只是高度需要改变
            pts1 = np.float32([left_point, heigth_point, right_point])
            M = cv2.getAffineTransform(pts1, pts2)
            dst = cv2.warpAffine(oldimg, M, (pic_width, pic_hight))
            card_img = dst[int(left_point[1]):int(heigth_point[1]), int(left_point[0]):int(new_right_point[0])]
            card_imgs.append(card_img)
        elif left_point[1] > right_point[1]:  # 负角度

            new_left_point = [left_point[0], heigth_point[1]]
            pts2 = np.float32([new_left_point, heigth_point, right_point])  # 字符只是高度需要改变
            pts1 = np.float32([left_point, heigth_point, right_point])
            M = cv2.getAffineTransform(pts1, pts2)
            dst = cv2.warpAffine(oldimg, M, (pic_width, pic_hight))
            card_img = dst[int(right_point[1]):int(heigth_point[1]), int(new_left_point[0]):int(right_point[0])]
            card_imgs.append(card_img)
            for card_index, card_img in enumerate(card_imgs):
    blue = other = 0
    card_img_hsv = cv2.cvtColor(card_img, cv2.COLOR_BGR2HSV)
    # cv2.imshow("card3", card_img_hsv)
    row_num, col_num = card_img_hsv.shape[:2]
    card_img_count = row_num * col_num
    for i in range(row_num):
        for j in range(col_num):
            H = card_img_hsv.item(i, j, 0)
            S = card_img_hsv.item(i, j, 1)
            if 99 < H <= 124 and S > 34:
                blue += 1
            else:
                other += 1
    print(blue)
    print(other)
    if blue * 3 >= card_img_count:
        blue_color = card_img
cv2.imshow("card1", blue_color)
return blue_color

车牌定位结果:

java opencv 车牌识别源码 opencv 车牌识别算法_java opencv 车牌识别源码_03

java opencv 车牌识别源码 opencv 车牌识别算法_opencv_04