TShopping

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

[教學] Python+OpenCV實現車牌區域識別及Sobel運算元

[複製鏈接]
發表於 2020-12-15 22:15:34 | 顯示全部樓層 |閱讀模式
 
Push to Facebook Push to Plurk  
步驟包括:
    1.灰度轉換:將彩色圖片轉換為灰度影象,常見的R=G=B=畫素平均值。
    2.高斯平滑和中值濾波:去除噪聲。
    3.Sobel運算元:提取影象邊緣輪廓,X方向和Y方向平方和開跟。
    4.二值化處理:影象轉換為黑白兩色,通常畫素大於127設定為255,小於設定為0。
    5.膨脹和細化:放大影象輪廓,轉換為一個個區域,這些區域內包含車牌。
    6.通過演算法選擇合適的車牌位置,通常將較小的區域過濾掉或尋找藍色底的區域。
    7.標註車牌位置,如果是花兒、人臉、牛角,可能需要特徵提取和訓練。


Python OpenCV 車牌域識 Sobel 運算元

Python OpenCV 車牌域識 Sobel 運算元


推薦我C++影象系列基礎知識:
https://blog.csdn.net/column/details/eastmount-mfc.html


一、讀取影象及灰度轉換
程式碼如下:
  1. #encoding:utf-8
  2. import cv2  
  3. import numpy as np  
  4. import matplotlib.pyplot as plt

  5. #讀取圖片
  6. imagePath = '10.jpg'
  7. img = cv2.imread(imagePath)

  8. #opencv預設的imread是以BGR的方式進行儲存的
  9. #而matplotlib的imshow預設則是以RGB格式展示
  10. #所以此處我們必須對圖片的通道進行轉換
  11. lenna_img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)

  12. #灰度影象處理
  13. GrayImage = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
  14. print(u"讀入lenna圖的shape為", GrayImage.shape)

  15. #顯示圖形
  16. titles = ['Source Image','Gray Image']  
  17. images = [lenna_img, GrayImage]  
  18. for i in range(2):  
  19.     plt.subplot(1,2,i+1),plt.imshow(images[i],'gray')  
  20.     plt.title(titles[i])  
  21.     plt.xticks([]),plt.yticks([])  
  22. plt.show()  

  23. cv2.imshow('Gray.bmp', GrayImage)
  24. cv2.waitKey(0)
複製代碼

輸出結果如下圖所示:

Python OpenCV 車牌域識 Sobel 運算元

Python OpenCV 車牌域識 Sobel 運算元

二、高斯平滑和中值濾波去噪
這裡原理推薦我以前C++影象處理的文章,如下:https://blog.csdn.net/column/details/eastmount-mfc.html

Python OpenCV 車牌域識 Sobel 運算元

Python OpenCV 車牌域識 Sobel 運算元

Python OpenCV 車牌域識 Sobel 運算元

Python OpenCV 車牌域識 Sobel 運算元

完整程式碼如下所示:
  1. #encoding:utf-8
  2. import cv2  
  3. import numpy as np  
  4. import matplotlib.pyplot as plt

  5. #讀取圖片
  6. imagePath = '10.jpg'
  7. img = cv2.imread(imagePath)

  8. #opencv預設的imread是以BGR的方式進行儲存的
  9. #而matplotlib的imshow預設則是以RGB格式展示
  10. #所以此處我們必須對圖片的通道進行轉換
  11. lenna_img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)

  12. #灰度影象處理
  13. GrayImage = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
  14. print(u"讀入lenna圖的shape為", GrayImage.shape)

  15. #直方圖均衡化
  16. #equ = cv2.equalizeHist(gray)

  17. #高斯平滑
  18. Gaussian = cv2.GaussianBlur(GrayImage, (3, 3), 0, 0, cv2.BORDER_DEFAULT)
  19. #Gaussian = cv2.GaussianBlur(GrayImage, (9, 9),0)

  20. #中值濾波
  21. Median = cv2.medianBlur(Gaussian, 5)

  22. #顯示圖形
  23. titles = ['Source Image','Gray Image', 'Gaussian Image', 'Median Image']  
  24. images = [lenna_img, GrayImage, Gaussian, Median]  
  25. for i in range(4):  
  26.     plt.subplot(2,2,i+1),plt.imshow(images[i],'gray')  
  27.     plt.title(titles[i])  
  28.     plt.xticks([]),plt.yticks([])  
  29. plt.show()  
複製代碼

輸出結果如下圖所示,分別是原圖、灰度影象、高斯處理和中值濾波處理。

Python OpenCV 車牌域識 Sobel 運算元

Python OpenCV 車牌域識 Sobel 運算元


三、Sobel運算元提取輪廓和二值化處理
有時還需要加強影象中景物的邊緣和輪廓,邊緣和輪廓通常位於影象中灰度突出的地方,因而可以直觀的想到用灰度的差分對邊緣和輪廓進行提取,通常可以通過梯度運算元進行提取。影象銳化的目的是提高影象的對比度,從而使影象更清晰,通過提高鄰域內畫素的灰度差來提高影象的對比度。本文采用Sobel運算元提取邊緣輪廓。

Python OpenCV 車牌域識 Sobel 運算元

Python OpenCV 車牌域識 Sobel 運算元
閾值又稱為臨界值,它的目的是確定出一個範圍,然後這個範圍內的部分使用同一種方法處理,而閾值之外的部分則使用另一種處理方法或保持原樣。常用的包括產生二值圖:當x<T時y=0,當x>=T時y=255(其中T是閾值)。閾值變換在生物學上的應用比較廣泛,常用語細胞影象分割等。本文采用二值化處理將大於等於170畫素的轉換為255,而下於的轉換為0,使得影象更加清晰。
完整程式碼如下所示:
  1. #encoding:utf-8
  2. import cv2  
  3. import numpy as np  
  4. import matplotlib.pyplot as plt

  5. #讀取圖片
  6. imagePath = '10.jpg'
  7. img = cv2.imread(imagePath)

  8. #opencv預設的imread是以BGR的方式進行儲存的
  9. lenna_img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)

  10. #灰度影象處理
  11. GrayImage = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
  12. print(u"讀入lenna圖的shape為", GrayImage.shape)

  13. #直方圖均衡化
  14. #equ = cv2.equalizeHist(gray)

  15. # 高斯平滑
  16. Gaussian = cv2.GaussianBlur(GrayImage, (3, 3), 0, 0, cv2.BORDER_DEFAULT)

  17. # 中值濾波
  18. Median = cv2.medianBlur(Gaussian, 5)

  19. # Sobel運算元 XY方向求梯度
  20. x = cv2.Sobel(Median, cv2.CV_8U, 1, 0, ksize = 3) #X方向
  21. y = cv2.Sobel(Median, cv2.CV_8U, 0, 1, ksize = 3) #Y方向
  22. absX = cv2.convertScaleAbs(x)   # 轉回uint8   
  23. absY = cv2.convertScaleAbs(y)   
  24. Sobel = cv2.addWeighted(absX, 0.5, absY, 0.5,0)
  25. cv2.imshow('dilation2', Sobel)
  26. cv2.waitKey(0)

  27. # 二值化處理 周圍畫素影響
  28. ret, Binary = cv2.threshold(Sobel, 170, 255, cv2.THRESH_BINARY)
  29. cv2.imshow('dilation2',Binary)
  30. cv2.waitKey(0)

  31. #顯示圖形
  32. titles = ['Source Image','Gray Image', 'Gaussian Image', 'Median Image',
  33.           'Sobel Image', 'Binary Image']  
  34. images = [lenna_img, GrayImage, Gaussian, Median, Sobel, Binary]  
  35. for i in range(6):  
  36.     plt.subplot(2,3,i+1),plt.imshow(images[i],'gray')  
  37.     plt.title(titles[i])  
  38.     plt.xticks([]),plt.yticks([])  
  39. plt.show()  
複製代碼

輸出結果如下所示:

Python OpenCV 車牌域識 Sobel 運算元

Python OpenCV 車牌域識 Sobel 運算元

四、膨脹和腐蝕處理
接下來進行膨脹和腐蝕處理,其中膨脹讓輪廓突出,腐蝕去掉細節。
  1. #encoding:utf-8
  2. import cv2  
  3. import numpy as np  
  4. import matplotlib.pyplot as plt

  5. #讀取圖片
  6. imagePath = '10.jpg'
  7. img = cv2.imread(imagePath)

  8. #opencv預設的imread是以BGR的方式進行儲存的
  9. lenna_img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)

  10. #灰度影象處理
  11. GrayImage = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
  12. print(u"讀入lenna圖的shape為", GrayImage.shape)

  13. #直方圖均衡化
  14. #equ = cv2.equalizeHist(gray)

  15. #高斯平滑 去噪
  16. Gaussian = cv2.GaussianBlur(GrayImage, (3, 3), 0, 0, cv2.BORDER_DEFAULT)
  17. #Gaussian = cv2.GaussianBlur(GrayImage, (9, 9),0)

  18. #中值濾波
  19. Median = cv2.medianBlur(Gaussian, 5)

  20. #Sobel運算元 XY方向求梯度 cv2.CV_8U
  21. x = cv2.Sobel(Median, cv2.CV_32F, 1, 0, ksize = 3) #X方向
  22. y = cv2.Sobel(Median, cv2.CV_32F, 0, 1, ksize = 3) #Y方向
  23. #absX = cv2.convertScaleAbs(x)   # 轉回uint8   
  24. #absY = cv2.convertScaleAbs(y)
  25. #Sobel = cv2.addWeighted(absX, 0.5, absY, 0.5, 0)
  26. gradient = cv2.subtract(x, y)
  27. Sobel = cv2.convertScaleAbs(gradient)
  28. cv2.imshow('dilation2', Sobel)
  29. cv2.waitKey(0)

  30. #二值化處理 周圍畫素影響
  31. blurred = cv2.GaussianBlur(Sobel, (9, 9),0) #再進行高斯去噪
  32. #注意170可以替換的
  33. ret, Binary = cv2.threshold(blurred , 90, 255, cv2.THRESH_BINARY)
  34. cv2.imshow('dilation2', Binary)
  35. cv2.waitKey(0)

  36. #膨脹和腐蝕操作的核函式
  37. element1 = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 1))
  38. element2 = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 7))

  39. # 膨脹讓輪廓突出
  40. Dilation = cv2.dilate(Binary, element2, iterations = 1)
  41. # 腐蝕去掉細節
  42. Erosion = cv2.erode(Dilation, element1, iterations = 1)
  43. # 再次膨脹
  44. Dilation2 = cv2.dilate(Erosion, element2,iterations = 3)
  45. cv2.imshow('Dilation2 ', Dilation2)
  46. cv2.waitKey(0)

  47. #顯示圖形
  48. titles = ['Source Image','Gray Image', 'Gaussian Image', 'Median Image',
  49.           'Sobel Image', 'Binary Image', 'Dilation Image', 'Erosion Image', 'Dilation2 Image']  
  50. images = [lenna_img, GrayImage, Gaussian,
  51.           Median, Sobel, Binary,
  52.           Dilation, Erosion, Dilation2]  
  53. for i in range(9):  
  54.     plt.subplot(3,3,i+1),plt.imshow(images[i],'gray')  
  55.     plt.title(titles[i])  
  56.     plt.xticks([]),plt.yticks([])  
  57. plt.show()  
複製代碼



輸出結果如下圖所示,可以看到輪廓區域已經被提取出來,接下來開始有選擇的進行獲取。

Python OpenCV 車牌域識 Sobel 運算元

Python OpenCV 車牌域識 Sobel 運算元

五、指定演算法選擇車牌區域
該部分程式碼膨脹和腐蝕略有區別,採用closed變數實現。同時獲取最理想的區域,完整程式碼如下所示:

  1. #encoding:utf-8
  2. #BY:Eastmount CSDN 2018-08-06
  3. import cv2  
  4. import numpy as np  
  5. import matplotlib.pyplot as plt

  6. #讀取圖片
  7. imagePath = '10.jpg'
  8. img = cv2.imread(imagePath)

  9. #opencv預設的imread是以BGR的方式進行儲存的
  10. lenna_img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)

  11. #灰度影象處理
  12. GrayImage = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
  13. print(u"讀入lenna圖的shape為", GrayImage.shape)

  14. #直方圖均衡化
  15. #equ = cv2.equalizeHist(gray)

  16. #高斯平滑 去噪
  17. Gaussian = cv2.GaussianBlur(GrayImage, (3, 3), 0, 0, cv2.BORDER_DEFAULT)
  18. #Gaussian = cv2.GaussianBlur(GrayImage, (9, 9),0)

  19. #中值濾波
  20. Median = cv2.medianBlur(Gaussian, 5)

  21. #Sobel運算元 XY方向求梯度 cv2.CV_8U
  22. x = cv2.Sobel(Median, cv2.CV_32F, 1, 0, ksize = 3) #X方向
  23. y = cv2.Sobel(Median, cv2.CV_32F, 0, 1, ksize = 3) #Y方向
  24. #absX = cv2.convertScaleAbs(x)   # 轉回uint8   
  25. #absY = cv2.convertScaleAbs(y)
  26. #Sobel = cv2.addWeighted(absX, 0.5, absY, 0.5, 0)
  27. gradient = cv2.subtract(x, y)
  28. Sobel = cv2.convertScaleAbs(gradient)
  29. cv2.imshow('dilation2', Sobel)
  30. cv2.waitKey(0)

  31. #二值化處理 周圍畫素影響
  32. blurred = cv2.GaussianBlur(Sobel, (9, 9),0) #再進行一次高斯去噪
  33. #注意170可以替換的
  34. ret, Binary = cv2.threshold(blurred , 170, 255, cv2.THRESH_BINARY)
  35. cv2.imshow('dilation2', Binary)
  36. cv2.waitKey(0)

  37. # 膨脹和腐蝕操作的核函式
  38. element1 = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 1))
  39. element2 = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 7))
  40. # 膨脹一次,讓輪廓突出
  41. Dilation = cv2.dilate(Binary, element2, iterations = 1)
  42. # 腐蝕一次,去掉細節
  43. Erosion = cv2.erode(Dilation, element1, iterations = 1)
  44. # 再次膨脹,讓輪廓明顯一些
  45. Dilation2 = cv2.dilate(Erosion, element2,iterations = 3)
  46. cv2.imshow('Dilation2 ', Dilation2)
  47. cv2.waitKey(0)


  48. ##########################################

  49. #建立一個橢圓核函式
  50. kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (25, 25))
  51. #執行影象形態學, 細節直接查文件,很簡單
  52. closed = cv2.morphologyEx(Binary, cv2.MORPH_CLOSE, kernel)
  53. closed = cv2.erode(closed, None, iterations=4)
  54. closed = cv2.dilate(closed, None, iterations=4)
  55. cv2.imshow('erode dilate', closed)
  56. cv2.waitKey(0)

  57. ##########################################


  58. #顯示圖形
  59. titles = ['Source Image','Gray Image', 'Gaussian Image', 'Median Image',
  60.           'Sobel Image', 'Binary Image', 'Dilation Image', 'Erosion Image', 'Dilation2 Image']  
  61. images = [lenna_img, GrayImage, Gaussian,
  62.           Median, Sobel, Binary,
  63.           Dilation, Erosion, closed]  
  64. for i in range(9):  
  65.     plt.subplot(3,3,i+1),plt.imshow(images[i],'gray')  
  66.     plt.title(titles[i])  
  67.     plt.xticks([]),plt.yticks([])  
  68. plt.show()  

  69. cv2.imshow('Gray', GrayImage)
  70. cv2.waitKey(0)

  71. """
  72. 接下來使用Dilation2圖片確定車牌的輪廓
  73. 這裡opencv3返回的是三個引數
  74.   引數一:二值化影象
  75.   引數二:輪廓型別 檢測的輪廓不建立等級關係
  76.   引數三:處理近似方法  例如一個矩形輪廓只需4個點來儲存輪廓資訊
  77. """
  78. (_, cnts, _) = cv2.findContours(closed.copy(),
  79.                                 cv2.RETR_LIST,               #RETR_TREE
  80.                                 cv2.CHAIN_APPROX_SIMPLE)

  81. #畫出輪廓
  82. c = sorted(cnts, key=cv2.contourArea, reverse=True)[0]
  83. print(c)

  84. #compute the rotated bounding box of the largest contour
  85. rect = cv2.minAreaRect(c)
  86. print('rectt', rect)
  87. Box = np.int0(cv2.boxPoints(rect))
  88. print('Box', Box)

  89. #draw a bounding box arounded the detected barcode and display the image
  90. Final_img = cv2.drawContours(img.copy(), [Box], -1, (0, 0, 255), 3)

  91. cv2.imshow('Final_img', Final_img)
  92. cv2.waitKey(0)
複製代碼

輸出結果如下圖所示,可以看到車牌被選中了。

Python OpenCV 車牌域識 Sobel 運算元

Python OpenCV 車牌域識 Sobel 運算元

Python OpenCV 車牌域識 Sobel 運算元

Python OpenCV 車牌域識 Sobel 運算元





 

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

本版積分規則



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

GMT+8, 2021-3-4 04:10 , Processed in 0.089431 second(s), 24 queries .

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

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

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