TShopping

 找回密碼
 註冊
搜索
查看: 3281|回復: 0
打印 上一主題 下一主題

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

[複製鏈接]
跳轉到指定樓層
1#
發表於 2020-12-18 16:18:07 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
 
Push to Facebook
  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, 2024-5-11 08:35 , Processed in 0.082175 second(s), 22 queries .

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

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

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