【CV】Python+Opencv4+字符分割識別及車牌識別矯正


1.字符分割識別

在這裏插入圖片描述
在這裏插入圖片描述

import cv2
#/////////////////////1、讀取圖像,並把圖像轉換爲灰度圖像並顯示
img = cv2.imread("D:/xunlei/2.png")  # 讀取圖片
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  # 轉換了灰度化
cv2.imshow('gray', img_gray)  # 顯示圖片
cv2.waitKey(0)

#/////////////////////////2、將灰度圖像二值化,設定閾值是100
img_thre = img_gray
cv2.threshold(img_gray, 100, 255, cv2.THRESH_BINARY_INV, img_thre)
cv2.imshow('threshold', img_thre)
cv2.waitKey(0)

#///////////////////////////////////////3、保存黑白圖片
cv2.imwrite('thre_res.png', img_thre)

#///////////////////////////////////////4、分割字符
white = []  # 記錄每一列的白色像素總和
black = []  # ..........黑色.......
height = img_thre.shape[0]
width = img_thre.shape[1]
white_max = 0
black_max = 0
# 計算每一列的黑白色像素總和
for i in range(width):
    s = 0  # 這一列白色總數
    t = 0  # 這一列黑色總數
    for j in range(height):
        if img_thre[j][i] == 255:
            s += 1
        if img_thre[j][i] == 0:
            t += 1
    white_max = max(white_max, s)
    black_max = max(black_max, t)
    white.append(s)
    black.append(t)
    print(s)
    print(t)

arg = False  # False表示白底黑字;True表示黑底白字
if black_max > white_max:
    arg = True


# 分割圖像
def find_end(start_):
    end_ = start_ + 1
    for m in range(start_ + 1, width - 1):
        if (black[m] if arg else white[m]) > (0.95 * black_max if arg else 0.95 * white_max):  # 0.95這個參數請多調整,對應下面的0.05
            end_ = m
            break
    return end_


n = 1
start = 1
end = 2
while n < width - 2:
    n += 1
    if (white[n] if arg else black[n]) > (0.05 * white_max if arg else 0.05 * black_max):
        # 上面這些判斷用來辨別是白底黑字還是黑底白字
        # 0.05這個參數請多調整,對應上面的0.95
        start = n
        end = find_end(start)
        n = end
        if end - start > 5:
            cj = img_thre[1:height, start:end]
            cv2.imshow('caijian', cj)
            cv2.waitKey(0)

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

2.車牌識別矯正

2.1 車牌識別項目安裝

1.git clone 最新的文檔

cd /opt/deploy
git clone  https://github.com/sergiomsilva/alpr-unconstrained.git

2.下載預訓練模型

 cd alpr-unconstrained/
 bash get-networks.sh 

3.刪除項目自帶 Darknet 替換爲官方自帶darknet

rm -rf darknet
git clone https://github.com/pjreddie/darknet

4.更改官方darknet 支持gpu 並且 make 由於我的cudn 驅動裝在了默認位置 所以 我只需要 更改三處即可

cd darknet/
vim Makefile

將第12行的  已支持GPU
GPU=0
CUDNN=0
修改成: 
GPU=1
CUDNN=124行的  支持 cudnn
NVCC=nvcc
修改成:
NVCC=/usr/local/cuda/bin/nvcc

:wq

5.編譯

make all -j6 根據自己核數調整

6.重新進入主目錄

cd /opt/alpr-unconstrained
cp -R data/* darknet/data/

7.更改names文件

vim data/ocr/ocr-net.names 

0
1
2
3
4
5
6
7
8
9
A
B
C
D
E
F
G
H
I
J
K
L
M
N
P
Q
R
S
T
U
V
W
X
Y
Z
京
滬
津
渝
冀
晉
蒙
遼
吉
黑
蘇
浙
皖
閩
贛
魯
豫
鄂
湘
粵
桂
瓊
川
貴
雲
藏
陝
甘
青
寧
新

8.修改對應的類 訓練文件所在的位置

vim data/ocr/ocr-net.data

classes=66
names=data/ocr/ocr-net.names
train=data/ocr/train.txt
backup=data/ocr/output

9.創建output 目錄

mkdir -p data/ocr/output

10.修改CFG網絡層的層數和訓練參數

cp /opt/deploy/darknet/cfg/yolov3.cfg data/ocr/ocr-net.cfg

vim data/ocr/ocr-net.cfg 

據自己GPU 和內存來指定 cfg 部分

訓練的時候將第34行的  已支持GPU
batch=64
subdivisions=4

[net]
# Testing
# batch=1
# subdivisions=1
# Training
 batch=64
 subdivisions=8

......

[convolutional]
size=1
stride=1
pad=1
filters=33###75

activation=linear

[yolo]
mask = 6,7,8
anchors = 10,13,  16,30,  33,23,  30,61,  62,45,  59,119,  116,90,  156,198,  373,326
classes=6###20
num=9
jitter=.3
ignore_thresh = .5
truth_thresh = 1
random=0###1

......

[convolutional]
size=1
stride=1
pad=1
filters=33###75
activation=linear

[yolo]
mask = 3,4,5
anchors = 10,13,  16,30,  33,23,  30,61,  62,45,  59,119,  116,90,  156,198,  373,326
classes=6###20
num=9
jitter=.3
ignore_thresh = .5
truth_thresh = 1
random=0###1

......

[convolutional]
size=1
stride=1
pad=1
filters=33###75
activation=linear

[yolo]
mask = 0,1,2
anchors = 10,13,  16,30,  33,23,  30,61,  62,45,  59,119,  116,90,  156,198,  373,326
classes=6###20
num=9
jitter=.3
ignore_thresh = .5
truth_thresh = 1
random=0###1
————————————
filters數目是怎麼計算的:3x(classes數目+5),和聚類數目分佈有關,論文中有說明;
比如說我有66類  那麼 3*66+5=213

2.2 車牌矯正的方法

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

def findContoursAndDrawBoundingBox(image_rgb):
#部分源代碼(我加了點註釋) 參考:https://github.com/zeusees/HyperLPR
    line_upper  = [];
    line_lower = [];
 
    line_experiment = []
    grouped_rects = []
    gray_image = cv2.cvtColor(image_rgb,cv2.COLOR_BGR2GRAY)
 
    # for k in np.linspace(-1.5, -0.2,10):
    for k in np.linspace(-50, 0, 15):
 
        # thresh_niblack = threshold_niblack(gray_image, window_size=21, k=k)
        # binary_niblack = gray_image > thresh_niblack
        # binary_niblack = binary_niblack.astype(np.uint8) * 255
 
        # 當一幅圖像上的不同部分具有不同亮度時,我們需要採用自適應閾值.此時的閾值是根據圖像上的每一個小區域計算與其
        # 對應的閾值.因此,在同一幅圖像上的不同區域採用的是不同的閾值,從而使我們能在亮度不同的情況下得到更好的結果.
        """
        Args:
         - src, 原圖像,應該是灰度圖
         -  x, 指當像素值高於(有時是低於)閾值時應該被賦予新的像素值, 255是白色
         - adaptive_method, CV_ADAPTIVE_THRESH_MEAN_C 或 CV_ADAPTIVE_THRESH_GAUSSIAN_C
         - threshold_type: 指取閾值類型
          . CV_THRESH_BINARY, 二進制閾值化
          . CV_THRESH_BINARY_INV, 反二進制閾值化
         - block_size: 用來計算閾值的像素鄰域大小(塊大小):3,5,7,...
         - param1: 指與方法有關的參數.對方法CV_ADAPTIVE_THRESH_MEAN_C和CV_ADAPTIVE_THRESH_GAUSSIAN_C,它是一個從均值或加權均值提取的常數,儘管它可以是負數。
          . 對方法 CV_ADAPTIVE_THRESH_MEAN_C,先求出塊中的均值,再減掉param1。
          . 對方法 CV_ADAPTIVE_THRESH_GAUSSIAN_C ,先求出塊中的加權和(gaussian), 再減掉param1。
        """
        binary_niblack = cv2.adaptiveThreshold(gray_image,255,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,17,k) #鄰域大小17是不是太大了??
        #cv2.imshow("image1",binary_niblack)
        #cv2.waitKey(0)
        #imagex, contours, hierarchy = cv2.findContours(binary_niblack.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
        contours, hierarchy = cv2.findContours(binary_niblack.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)  # modified by bigz
        for contour in contours:
            #用一個最小的矩形,把找到的形狀包起來
            bdbox = cv2.boundingRect(contour)
            if (bdbox[3]/float(bdbox[2])>0.7 and bdbox[3]*bdbox[2]>100 and bdbox[3]*bdbox[2]<1200) or (bdbox[3]/float(bdbox[2])>3 and bdbox[3]*bdbox[2]<100):
                # cv2.rectangle(rgb,(bdbox[0],bdbox[1]),(bdbox[0]+bdbox[2],bdbox[1]+bdbox[3]),(255,0,0),1)
                line_upper.append([bdbox[0],bdbox[1]])
                line_lower.append([bdbox[0]+bdbox[2],bdbox[1]+bdbox[3]])
 
                line_experiment.append([bdbox[0],bdbox[1]])
                line_experiment.append([bdbox[0]+bdbox[2],bdbox[1]+bdbox[3]])
                # grouped_rects.append(bdbox)
 
    """
    想爲圖像周圍建一個邊使用訪函數,這經常在卷積運算或0填充時被用到
    Args:
     - src: 輸入圖像
     - top,bottom,left,right 對應邊界的像素數目
     - borderType: 要添加哪種類型的邊界
       - BORDER_CONSTANT #邊緣填充用固定像素值,比如填充黑邊,就用0,白邊255
       - BORDER_REPLICATE #用原始圖像相應的邊緣的像素去做填充,看起來有一種把圖像邊緣"拉糊了"的效果
    """
    rgb = cv2.copyMakeBorder(image_rgb,30,30,0,0,cv2.BORDER_REPLICATE)
    leftyA, rightyA = fitLine_ransac(np.array(line_lower),3)
    rows,cols = rgb.shape[:2]
 
    # rgb = cv2.line(rgb, (cols - 1, rightyA), (0, leftyA), (0, 0, 255), 1,cv2.LINE_AA)
 
    leftyB, rightyB = fitLine_ransac(np.array(line_upper),-3)
 
    rows,cols = rgb.shape[:2]
 
    # rgb = cv2.line(rgb, (cols - 1, rightyB), (0, leftyB), (0,255, 0), 1,cv2.LINE_AA)
    pts_map1  = np.float32([[cols - 1, rightyA], [0, leftyA],[cols - 1, rightyB], [0, leftyB]])
    pts_map2 = np.float32([[136,36],[0,36],[136,0],[0,0]])
    mat = cv2.getPerspectiveTransform(pts_map1,pts_map2)
    image = cv2.warpPerspective(rgb,mat,(136,36),flags=cv2.INTER_CUBIC)
    #校正角度
    #cv2.imshow("校正前",image)
    #cv2.waitKey(0)
    image,M = deskew.fastDeskew(image)
    #cv2.imshow("校正後",image)
    #cv2.waitKey(0)
    return image
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章