美文网首页
python笔记 | 车牌识别如何做?

python笔记 | 车牌识别如何做?

作者: 力卉编程 | 来源:发表于2020-02-02 21:25 被阅读0次

    一、安装使用环境

    1、python3.7

    2、tesseract安装

    http://digi.bib.uni-mannheim.de/tesseract/tesseract-ocr-setup-4.00.00dev.exe
    https://github.com/tesseract-ocr/tessdata/find/master/chi_sim.traineddata
    chi_sim.traineddata放在C:\Program Files (x86)\Tesseract-OCR\tessdata目录下

    3、安装pytesseract

    4、pip install pillow

    二、了解图形文字识别的相关步骤

    1、预处理图像
    2、框出车牌号
    3、分割车牌与背景
    4、二值化生成黑白图
    5、image_to_string识别文字

    三、代码

    # -*- coding: utf-8 -*-
    """
    Created on 2020-02-01
    
    @author: 力卉编程
    """
    
    from cv2 import cv2
    import numpy as np
    
    
    def stretch(img):
        '''
        图像拉伸函数
        '''
        maxi = float(img.max())
        mini = float(img.min())
    
        for i in range(img.shape[0]):
            for j in range(img.shape[1]):
                img[i, j] = (255 / (maxi - mini) * img[i, j] - (255 * mini) / (maxi - mini))
    
        return img
    
    
    def dobinaryzation(img):
        '''
        二值化处理函数
        '''
        maxi = float(img.max())
        mini = float(img.min())
    
        x = maxi - ((maxi - mini) / 2)
        # 二值化,返回阈值ret  和  二值化操作后的图像thresh
        ret, thresh = cv2.threshold(img, x, 255, cv2.THRESH_BINARY)
        # 返回二值化后的黑白图像
        return thresh
    
    
    def find_rectangle(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, afterimg):
        '''
        定位车牌号
        '''
        contours, hierarchy = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    
        # 找出最大的三个区域
        block = []
        for c in contours:
            # 找出轮廓的左上点和右下点,由此计算它的面积和长度比
            r = find_rectangle(c)
            a = (r[2] - r[0]) * (r[3] - r[1])  # 面积
            s = (r[2] - r[0]) / (r[3] - r[1])  # 长度比
            # print("S:", s)
            if s > 2.5 and s < 3.5:
                print("S2:", s)
                block.append([r, a, s])
                
        # 选出面积最大的3个区域
        block = sorted(block, key=lambda b: b[1])[-3:]
    
        # 使用颜色识别判断找出最像车牌的区域
        maxweight, maxindex = 0, -1
        for i in range(len(block)):
            b = afterimg[block[i][0][1]:block[i][0][3], block[i][0][0]:block[i][0][2]]
            # BGR转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 n in w1:
                w2 += n
    
            # 选出最大权值的区域
            if w2 > maxweight:
                maxindex = i
                maxweight = w2
        # print("maxindex:", maxindex)
        if maxindex >= 0:
            return block[maxindex][0]
        return None
    
    
    def find_license(img):
        '''
        预处理函数
        '''
        if img is None:
            return None,None
        m = 400 * img.shape[0] / img.shape[1]
    
        # 压缩图像
        img = cv2.resize(img, (400, int(m)), interpolation=cv2.INTER_CUBIC)
    
        # BGR转换为灰度图像
        gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    
        # 灰度拉伸
        stretchedimg = stretch(gray_img)
    
        '''进行开运算,用来去除噪声'''
        r = 16
        h = w = r * 2 + 1
        kernel = np.zeros((h, w), np.uint8)
        cv2.circle(kernel, (r, r), r, 1, -1)
        # 开运算
        openingimg = cv2.morphologyEx(stretchedimg, cv2.MORPH_OPEN, kernel)
        # 获取差分图,两幅图像做差  cv2.absdiff('图像1','图像2')
        strtimg = cv2.absdiff(stretchedimg, openingimg)
    
        # 图像二值化
        binaryimg = dobinaryzation(strtimg)
    
        # canny边缘检测
        canny = cv2.Canny(binaryimg, binaryimg.shape[0], binaryimg.shape[1])
    
        '''消除小的区域,保留大块的区域,从而定位车牌'''
        # 进行闭运算
        kernel = np.ones((5, 19), np.uint8)
        closingimg = cv2.morphologyEx(canny, cv2.MORPH_CLOSE, kernel)
    
        # 进行开运算
        openingimg = cv2.morphologyEx(closingimg, cv2.MORPH_OPEN, kernel)
    
        # 再次进行开运算
        kernel = np.ones((11, 5), np.uint8)
        openingimg = cv2.morphologyEx(openingimg, cv2.MORPH_OPEN, kernel)
    
        # 消除小区域,定位车牌位置
        rect = locate_license(openingimg, img)
    
        return rect, img
    
    
    def cut_license(afterimg, rect):
        '''
        图像分割函数
        '''
        # 转换为宽度和高度
        rect[2] = rect[2] - rect[0]
        rect[3] = rect[3] - rect[1]
        rect_copy = tuple(rect.copy())
        rect = [0, 0, 0, 0]
        # 创建掩膜
        mask = np.zeros(afterimg.shape[:2], np.uint8)
        # 创建背景模型  大小只能为13*5,行数只能为1,单通道浮点型
        bgdModel = np.zeros((1, 65), np.float64)
        # 创建前景模型
        fgdModel = np.zeros((1, 65), np.float64)
        # 分割图像
        cv2.grabCut(afterimg, mask, rect_copy, bgdModel, fgdModel, 5, cv2.GC_INIT_WITH_RECT)
        mask2 = np.where((mask == 2) | (mask == 0), 0, 1).astype('uint8')
        img_show = afterimg * mask2[:, :, np.newaxis]
    
        return img_show
    
    
    def deal_license(licenseimg):
        '''
        车牌图片二值化
        '''
        # 车牌变为灰度图像
        gray_img = cv2.cvtColor(licenseimg, cv2.COLOR_BGR2GRAY)
    
        # 均值滤波  去除噪声
        kernel = np.ones((3, 3), np.float32) / 9
        gray_img = cv2.filter2D(gray_img, -1, kernel)
    
        # 二值化处理
        ret, thresh = cv2.threshold(gray_img, 120, 255, cv2.THRESH_BINARY)
    
        return thresh
    
    
    def find_end(start, arg, black, white, width, black_max, white_max):
        end = start + 1
        for m in range(start + 1, width - 1):
            if (black[m] if arg else white[m]) > (0.98 * black_max if arg else 0.98 * white_max):
                end = m
                break
        return end
    
    
    if __name__ == '__main__':
        fn = "b/b6.jpg"
        img = cv2.imread(fn, cv2.IMREAD_COLOR)
        # 预处理图像
        rect, afterimg = find_license(img)
        if afterimg is None or rect is None:
            print("NONE:", fn)
            exit(1)
    
        x = 10
        rect[0] = rect[0] - x
        rect[1] = rect[1] - x
        rect[2] = rect[2] + 5
        rect[3] = rect[3] + 5
    
        # 框出车牌号
        cv2.rectangle(afterimg, (rect[0], rect[1]), (rect[2], rect[3]), (0, 255, 0), 2)
        cv2.imshow('afterimg', afterimg)
    
        # 分割车牌与背景
        cutimg = cut_license(afterimg, rect)
        cv2.imshow('cutimg', cutimg)
    
        # 二值化生成黑白图
        thresh = deal_license(cutimg)
        cv2.imshow('thresh', thresh)
        cv2.waitKey(0)
    
        # 分割字符
        '''
        判断底色和字色
        '''
        # 记录黑白像素总和
        white = []
        black = []
        height = thresh.shape[0]  # 263
        width = thresh.shape[1]  # 400
        # print('height',height)
        # print('width',width)
        white_max = 0
        black_max = 0
        # 计算每一列的黑白像素总和
        for i in range(width):
            line_white = 0
            line_black = 0
            for j in range(height):
                if thresh[j][i] == 255:
                    line_white += 1
                if thresh[j][i] == 0:
                    line_black += 1
            white_max = max(white_max, line_white)
            black_max = max(black_max, line_black)
            white.append(line_white)
            black.append(line_black)
            # print('white', white)
            # print('black', black)
        # arg为true表示黑底白字,False为白底黑字
        arg = True
        if black_max < white_max:
            arg = False
    
        n = 1
        start = 1
        end = 2
        while n < width - 2:
            n += 1
            # 判断是白底黑字还是黑底白字  0.05参数对应上面的0.95 可作调整
            if (white[n] if arg else black[n]) > (0.02 * white_max if arg else 0.02 * black_max):
                start = n
                end = find_end(start, arg, black, white, width, black_max, white_max)
                n = end
                if end - start > 5:
                    cj = thresh[1:height, start:end]
                    cv2.imshow('cutlicense', cj)
                    cv2.waitKey(0)
    
        cv2.waitKey(0)
        cv2.destroyAllWindows()
    

    文|力卉编程

    相关文章

      网友评论

          本文标题:python笔记 | 车牌识别如何做?

          本文链接:https://www.haomeiwen.com/subject/exqcxhtx.html