TShopping

 找回密碼
 註冊
搜索
查看: 105|回復: 0

[教學] OpenCV圖像識別:車牌定位算法源碼,Python語言實現

[複製鏈接]
發表於 2020-12-18 16:18:07 | 顯示全部樓層 |閱讀模式
 
Push to Facebook Push to Plurk  
  1. import cv2
  2. import numpy as np
  3. from PIL import Image
  4. import os.path
  5. from skimage import io, data

  6. def stretch(img):
  7.     '''
  8.     圖像拉伸函數
  9.     '''
  10.     maxi = float(img.max())
  11.     mini = float(img.min())
  12.    
  13.     for i in range(img.shape[0]):
  14.         for j in range(img.shape[1]):
  15.             img[i, j] = (255/(maxi - mini)*img[i, j] - (255 * mini)/(maxi - mini))
  16.             
  17.     return img

  18. def dobinaryzation(img):
  19.     '''
  20.     二位元處理函數
  21.     '''
  22.     maxi = float(img.max())
  23.     mini = float(img.min())
  24.    
  25.     x = maxi - ((maxi-mini)/2)
  26.     # 二位元,返回闕值 ret 和 二位元操作後的圖像thresh
  27.     ret, thresh = cv2.threshold(img, x, 255, cv2.THRESH_BINARY)
  28.     #返回二位元的黑白圖像
  29.     return thresh

  30. def find_rectangle(contour):
  31.     '''
  32.     尋找矩形輪廓
  33.     '''
  34.     y, x = [],[]
  35.    
  36.     for p in contour:
  37.         y.append(p[0][0])
  38.         x.append(p[0][1])
  39.    
  40.     return [min(y), min(x), max(y), max(x)]

  41. def locate_license(img, afterimg):
  42.     '''
  43.     定位車牌號碼
  44.     '''
  45.     contours, hierarchy = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
  46.    
  47.     #找出最大的三個區域
  48.     block = []
  49.     for c in contours:
  50.         #找出輪廓的左下點和右下點,由此計算它的面積與長度筆
  51.         r = find_rectangle(c)
  52.         a = (r[2]-r[0]) * (r[3]-r[1])
  53.         s = (r[2]-r[0]) / (r[3]-r[1])
  54.         
  55.         block.append([r,a,s])
  56.         #選出面積最大的三個區域
  57.         block = sorted(block, key=lambda b: b[1])[-3:]
  58.         
  59.         #使用顏色識別判斷找出最像的車牌區域
  60.         maxweight, maxindex = 0, -1
  61.         for i in range(len(block)):
  62.             b = afterimg[block[i][0][1]:block[i][0][3],block[i][0][0]:block[i][0][2]]
  63.             #BGR轉 HSV
  64.             hsv = cv2.cvtColor(b, cv2.COLOR_BGR2HSV)
  65.             #藍色車牌的範圍
  66.             lower = np.array([100, 50 ,50])
  67.             upper = np.array([140, 255 ,255])
  68.             #根據闕值建模
  69.             mask = cv2.inRange(hsv, lower, upper)
  70.             #統計權值
  71.             w1 = 0
  72.             for m in mask:
  73.                 w1 += m/255
  74.             
  75.             w2 = 0
  76.             for n in mask:
  77.                 w2 += n
  78.                
  79.             #選出最大權值的區域
  80.             if w2.all() > maxweight:
  81.                 maxindex = i
  82.                 maxweight = w2
  83.                
  84.     return block[maxindex][0]

  85. def find_license(img):
  86.     '''
  87.     預處理函數
  88.     '''
  89.     m = 300 * img.shape[0]/img.shape[1]
  90.     #壓縮圖像
  91.     img = cv2.resize(img, (300, int(m)), interpolation=cv2.INTER_CUBIC)
  92.     #BGR轉換為灰度圖像
  93.     gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
  94.     #灰度拉伸
  95.     stretchedimg = stretch(gray_img)
  96.     '''進行 開運算, 用來去除降噪'''
  97.     r = 16
  98.     h = w = r * 2 + 1
  99.     kernel = np.zeros((h,w), np.uint8)
  100.     cv2.circle(kernel, (r,r), r, 1, -1)
  101.     #開運算
  102.     openingimg = cv2.morphologyEx(stretchedimg, cv2.MORPH_OPEN, kernel)
  103.     #獲取差分圖,兩幅圖像做差 cv2.absdiff('圖像1','圖像2')
  104.     strting = cv2.absdiff(stretchedimg, openingimg)
  105.     #圖像二位元化
  106.     binaryimg = dobinaryzation(strting)
  107.     #canny邊緣檢測
  108.     canny = cv2.Canny(binaryimg, binaryimg.shape[0], binaryimg.shape[1])
  109.     '''清除小的區域,保留大塊的區域,從那定位車牌'''
  110.     #進行閉運算
  111.     kernel = np.ones((5,19), np.uint8)
  112.    
  113.     closingimg = cv2.morphologyEx(canny, cv2.MORPH_CLOSE, kernel)
  114.     #進行開運算
  115.     openingimg = cv2.morphologyEx(closingimg, cv2.MORPH_OPEN,kernel)
  116.     #再次進行閉運算
  117.     kernel = np.ones((5,19), np.uint8)
  118.     closingimg = cv2.morphologyEx(openingimg, cv2.MORPH_CLOSE, kernel)
  119.     #清除小區域,定位車牌
  120.     rect = locate_license(openingimg, img)
  121.    
  122.     return rect, img

  123. def cut_licence(afterimg, rect):
  124.     '''圖像分割函數'''
  125.     #轉換為寬度和高度
  126.     rect[2] = rect[2] - rect[0]
  127.     rect[3] = rect[3] - rect[1]
  128.     rect_copy = tuple(rect.copy())
  129.     rect = [0, 0, 0, 0]
  130.     #創建模
  131.     mask = np.zeros(afterimg.shape[:2], np.uint8)
  132.     #print ('mask',mask)
  133.     #創建前景模型 大小只能13*5. 行數只能為1. 單通道浮點型
  134.     bgdModel = np.zeros((1, 65), np.float64)
  135.     #cv2.imshow('bgdModel',bgdModel)
  136.     #建前景模型
  137.     fgdModel = np.zeros((1, 65), np.float64)
  138.     #cv2.imshow('fgdModel',fgdModel)
  139.     #分割圖像
  140.     cv2.grabCut(afterimg, mask, rect_copy, bgdModel, fgdModel, 5, cv2.GC_INIT_WITH_RECT)
  141.     mask2 = np.where((mask==2)|(mask==0),0,1).astype('uint8')
  142.     img_show = afterimg*mask2[:,:,np.newaxis]
  143.    
  144.     return img_show

  145. def deal_license(licenseimg):
  146.     '''
  147.     車牌圖片二位元化
  148.     '''
  149.     #車牌變為灰度圖像
  150.     gray_img = cv2.cvtColor(licenseimg, cv2.COLOR_BGR2GRAY)
  151.    
  152.     #均值濾波 去除噪音
  153.     kernel = np.ones((3,3), np.float32)/9
  154.     gray_img = cv2.filter2D(gray_img, -1, kernel)
  155.    
  156.     #二位元處理
  157.     ret, thresh = cv2.threshold(gray_img, 120, 255, cv2.THRESH_BINARY)
  158.    
  159.     return thresh

  160. def find_end(start, arg, block, white, width, black_max, white_max):
  161.     end = start + 1
  162.     for m in range(start+1, width-1):
  163.         if (block[m] if arg else white[m]) > (0.98*black_max if arg else 0.98*white_max):
  164.             end = m
  165.             break
  166.    
  167.     return end

  168. if __name__ == '__main__':
  169.     img = cv2.imread('a.jpg', cv2.IMREAD_COLOR)
  170.     #預處理圖像
  171.     rect, afterimg = find_license(img)
  172.     #cv2.imshow('img',img)
  173.     #框出車牌號碼
  174.     #cv2.rectangle(img, (x,y), (x+w,y+h), (0,255,0), 2)畫出矩形
  175.     cv2.rectangle(afterimg, (rect[0], rect[1]), (rect[2], rect[3]), (0, 255, 0),2)
  176.     cv2.imshow('afterimg', afterimg)
  177.    
  178.     #分割車牌與背景
  179.     cutimg = cut_licence(afterimg, rect)
  180.     cv2.imshow('cutimg', cutimg)
  181.    
  182.     #二位元生成黑白圖
  183.     thresh = deal_license(cutimg)
  184.     cv2.imshow('thresh', thresh)
  185.     cv2.waitKey(0)
  186.    
  187.     #分割字符
  188.     '''
  189.     判斷底色和字色
  190.     '''
  191.     #紀錄黑白像素總和
  192.     white = []
  193.     black = []
  194.     height = thresh.shape[0] #263
  195.     width = thresh.shape[1] #400
  196.     #print('height',height)
  197.     #print('width',width)
  198.     white_max = 0
  199.     black_max = 0
  200.     # 計算每一列的黑白像素總和
  201.     for i in range(width):
  202.         line_white = 0
  203.         line_black = 0
  204.         for j in range(height):
  205.             if thresh[j][i] == 255:
  206.                 line_white += 1
  207.             if thresh[j][i] == 0:
  208.                 line_black += 1
  209.         white_max = max(white_max, line_white)
  210.         black_max = max(black_max, line_black)
  211.         white.append(line_white)
  212.         black.append(line_black)
  213.     #arg為true表示黑底白字, False為白底黑字
  214.     arg = True
  215.     if black_max < white_max:
  216.         arg = False
  217.    
  218.     n = 1
  219.     start = 1
  220.     end = 2
  221.     s_width = 28
  222.     s_height = 28
  223.     while n < width -2:
  224.         n += 1
  225.         #判斷是白底黑字還是黑底白字 0.05參數對應上面的0.95 可做調整
  226.         if (white[n] if arg else black[n]) > (0.02*white_max if arg else 0.02 * black_max):
  227.             start = n
  228.             end = find_end(start, arg, black, white, width, black_max, white_max)
  229.             n =end
  230.             if end - start > 5:
  231.                 cj = thresh[1: height, start:end]
  232.                
  233.                 #new_image = cj.resize((s_width, s_height), Image.BILINEAR)
  234.                 #cj = cj.reshape(28, 28)
  235.                 print("result%s.jpg" % (n))
  236.                 #保存分割的圖片
  237.                 #cj.save("result%s.jpg" % (n))
  238.                 #infile = "result%s.jpg" % (n)
  239.                 #io.imsave(infile, cj)
  240.                 print(n)
  241.                 #im = IMage.open(infile)
  242.                 #out = im.resize((s_width, s_height), Image.BILINEAR)
  243.                 #out.save(infile)
  244.                 cv2.imshow('cutlincese', cj)
  245.                 cv2.waitKey(0)
  246.    
  247.     cv2.waitKey(0)
  248.     cv2.destroyAllWindows()
複製代碼


參考文章
https://www.itdaan.com/tw/9574009e55291df19eabb41ed6569b99
https://www.itread01.com/content/1556791200.html

文章出處
網頁設計,網站架設 ,網路行銷,網頁優化,SEO - NetYea 網頁設計

 

臉書網友討論
您需要登錄後才可以回帖 登錄 | 註冊 |

本版積分規則



Archiver|手機版|小黑屋|免責聲明|TShopping

GMT+8, 2021-1-20 07:31 , Processed in 0.055112 second(s), 22 queries .

本論壇言論純屬發表者個人意見,與 TShopping綜合論壇 立場無關 如有意見侵犯了您的權益 請寫信聯絡我們。

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回復 返回頂部 返回列表