計算機視覺cv2入門之車牌號碼識別

????前邊我們已經講解了使用cv2進行圖像預處理與邊緣檢測等方面的知識,這里我們以車牌號碼識別這一案例來實操一下。

大致思路

????????車牌號碼識別的大致流程可以分為這三步:圖像預處理-尋找車牌輪廓-車牌OCR識別

接下來我們按照這三步來進行講解。

圖像預處理

首先,在網上隨便找一張車牌照:

讀取圖像?

#讀取原始圖像
import cv2
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif']=['SimHei']
src_path=r'LicensePlate.jpg'
src_image=cv2.imread(filename=src_path,flags=cv2.IMREAD_COLOR_RGB)
print(src_image.shape)
plt.title('原始圖像')
plt.imshow(src_image)

????????這里我使用matplotlib的imshow函數來顯示圖像,這樣在jupyter環境中可以不打開任何彈窗直接顯示圖像,比較方便。

轉為灰度圖

#轉為灰度圖
gray_image=cv2.cvtColor(src=src_image,code=cv2.COLOR_RGB2GRAY)
plt.title('原始圖像(灰度圖)')
plt.imshow(gray_image,cmap='gray')

????????將原始圖像轉化為灰度圖是為了后續的檢測等操作,在計算機視覺任務中,基本上所有的操作都是針對灰度圖來進行的,灰度圖是將原始圖像的多個通道按照一定權重求和疊加而來,這樣一來多通道變成了單通道(Gray=w_1*B+w_2*G+w_3*R),在計算量上也會比較友好。

?閾值化

#閾值化
thresh,binary_image=cv2.threshold(src=gray_image,thresh=128,maxval=255,type=cv2.THRESH_OTSU+cv2.THRESH_BINARY)
plt.imshow(binary_image,cmap='gray')

????????閾值化是為了后續的邊緣檢測,通常在邊緣檢測前都需要對圖像進行閾值化操作,這樣識別出來的邊緣相對準確。這里閾值化我們使用cv2.THRESH+cv2.THRESH-OTSU方法來自動對圖像進行二值化閾值分割。?

邊緣檢測

#canny邊緣檢測
edges=cv2.Canny(image=binary_image,threshold1=0.5*thresh,threshold2=thresh,apertureSize=5,L2gradient=True)
plt.imshow(edges,cmap='gray')

????????邊緣檢測是為了初步提取出車牌的輪廓,便于后續的輪廓查找。常用的邊緣檢測算法有Canny、Sobel、Prewitt等,其中Canny算法具有較高的準確性和魯棒性,因此在本系統中采用Canny算法進行邊緣檢測。不太熟悉邊緣檢測的小伙伴可以去看看我的往期文章:

https://blog.csdn.net/weixin_73953650/article/details/146284620?sharetype=blogdetail&sharerId=146284620&sharerefer=PC&sharesource=weixin_73953650&spm=1011.2480.3001.8118https://blog.csdn.net/weixin_73953650/article/details/146284620?sharetype=blogdetail&sharerId=146284620&sharerefer=PC&sharesource=weixin_73953650&spm=1011.2480.3001.8118

?車牌輪廓查找

#尋找矩形區域輪廓
contours,hiercahy=cv2.findContours(edges,mode=cv2.RETR_TREE,method=cv2.CHAIN_APPROX_SIMPLE)
contours=sorted(contours,key=cv2.contourArea,reverse=True)[:10]
rectangle=None
for point in contours:peri=cv2.arcLength(point,True)polygons=cv2.approxPolyDP(curve=point,epsilon=0.018*peri,closed=True)if len(polygons)==4:rectangle=polygonsplateArea=pointbreak
gray_image_copy=gray_image.copy()
src_image_copy=src_image.copy()
cv2.drawContours(image=src_image_copy,contours=[rectangle],contourIdx=0,color=(255,0,0),thickness=5)
cv2.drawContours(image=gray_image_copy,contours=[rectangle],contourIdx=0,color=255,thickness=5)
figure=plt.figure(figsize=(10,10),dpi=100)
plt.subplot(1,2,1),plt.imshow(src_image_copy),plt.title('車牌定位結果(原始圖像)')
plt.subplot(1,2,2),plt.imshow(gray_image_copy,cmap='gray'),plt.title('車牌定位結果(灰度圖)')

?

?

?????????查找輪廓時我們通常使用findContours函數來進行查找(返回值為所有可能的輪廓點contours以及這些點之間的拓撲結構hierachy),考慮到車牌是矩形區域,因此我們可以在查找到的輪廓點中使用cv2.approxPolyDP函數來對查找到的輪廓進行多邊形擬合(返回值為各個頂點的坐標構成的列表)只要擬合出的多邊形頂點個數為4,那么必然是車牌位置。

? ? ? ?然后,我們再使用cv2.drawContours函數將其在原始圖像中標記出來即可。

車牌分割

# #分割提取車牌
x=[location[0][0] for location in plateArea]
y=[location[0][1] for location in plateArea]
Licenseplate=gray_image[min(y):max(y),min(x):max(x)]#切片圖像
plt.imshow(Licenseplate,cmap='gray')
cv2.imwrite('Plate.jpg',Licenseplate)

?

?

????????將車牌從原始圖像中分割出來的思路也很簡單,就是根據我們查找到的輪廓點,來查找其在圖像中的位置。PlatArea是矩形車牌輪廓點構成的列表,其內部為各個點的坐標,其中對于任意一點location來說,location[0][0]表示x坐標,location[0][1]表示y坐標。那么,我們只需找到所有x坐標中的最小值與最大值,y坐標中的最小值與最大值,即可確定這個矩形區域在原圖像中的范圍。?

?最后,我們還需將這個車牌號碼保存一下以便后續的字符識別

OCR識別

????????考慮到車牌是標準的印刷體,這里我們使用現成的OCR字符識別庫,這里我使用的是ddddocr

獲取方式

pip install ddddocr

OCR識別

#使用ddddocr進行光學識別
import ddddocr
ocr=ddddocr.DdddOcr(show_ad=False,beta=True)
image=open('Plate.jpg','rb')
answer=ocr.classification(image.read())
image.close()
print(f'車牌號為:{answer.upper()}')
plt.imshow(src_image,cmap='gray')
plt.text(x=src_image.shape[1]//4,y=src_image.shape[0]/2,s=f'車牌號為:{answer.upper()}',size=20,color='red')

?

????????使用ddddocr時需要傳入的圖像數據是Bytes類型,因此我們使用open(‘.jpg’,'rb').read()語句即可實現讀取圖像的bytes數據,最后我們再將得到的結果其標注在原始圖像上。?

?

完整代碼

#讀取原始圖像
import cv2
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif']=['SimHei']
src_path=r'LicensePlate.jpg'
src_image=cv2.imread(filename=src_path,flags=cv2.IMREAD_COLOR_RGB)
print(src_image.shape)
plt.title('原始圖像')
plt.imshow(src_image)
#轉為灰度圖
gray_image=cv2.cvtColor(src=src_image,code=cv2.COLOR_RGB2GRAY)
plt.title('原始圖像(灰度圖)')
plt.imshow(gray_image,cmap='gray')
#閾值化
thresh,binary_image=cv2.threshold(src=gray_image,thresh=128,maxval=255,type=cv2.THRESH_OTSU+cv2.THRESH_BINARY)
plt.imshow(binary_image,cmap='gray')
#canny邊緣檢測
edges=cv2.Canny(image=binary_image,threshold1=0.5*thresh,threshold2=thresh,apertureSize=5,L2gradient=True)
plt.imshow(edges,cmap='gray')
#尋找矩形區域輪廓
contours,hiercahy=cv2.findContours(edges,mode=cv2.RETR_TREE,method=cv2.CHAIN_APPROX_SIMPLE)
contours=sorted(contours,key=cv2.contourArea,reverse=True)[:10]
rectangle=None
for point in contours:peri=cv2.arcLength(point,True)polygons=cv2.approxPolyDP(curve=point,epsilon=0.018*peri,closed=True)if len(polygons)==4:rectangle=polygonsplateArea=pointbreak
gray_image_copy=gray_image.copy()
src_image_copy=src_image.copy()
cv2.drawContours(image=src_image_copy,contours=[rectangle],contourIdx=0,color=(255,0,0),thickness=5)
cv2.drawContours(image=gray_image_copy,contours=[rectangle],contourIdx=0,color=255,thickness=5)
figure=plt.figure(figsize=(10,10),dpi=100)
plt.subplot(1,2,1),plt.imshow(src_image_copy),plt.title('車牌定位結果(原始圖像)')
plt.subplot(1,2,2),plt.imshow(gray_image_copy,cmap='gray'),plt.title('車牌定位結果(灰度圖)')
# #分割提取車牌
x=[location[0][0] for location in plateArea]
y=[location[0][1] for location in plateArea]
Licenseplate=gray_image[min(y):max(y),min(x):max(x)]#切片圖像
plt.imshow(Licenseplate,cmap='gray')
cv2.imwrite('Plate.jpg',Licenseplate)
#使用ddddocr進行光學識別
import ddddocr
ocr=ddddocr.DdddOcr(show_ad=False,beta=True)
image=open('Plate.jpg','rb')
answer=ocr.classification(image.read())
image.close()
print(f'車牌號為:{answer.upper()}')
plt.imshow(src_image,cmap='gray')
plt.text(x=src_image.shape[1]//4,y=src_image.shape[0]/2,s=f'車牌號為:{answer.upper()}',size=20,color='red')

總結?

?

????????以上便是計算機視覺cv2入門之車牌號碼識別的所有內容,如果本文對你有用,還勞駕各位一鍵三連支持一下博主。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/76317.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/76317.shtml
英文地址,請注明出處:http://en.pswp.cn/web/76317.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

CExercise_13_1排序算法_3快速排序算法,包括單向分區以及雙向分區

題目: 請手動實現快速排序算法,包括單向分區以及雙向分區: // 單向分區快速排序算法 void quick_sort_one_way(int arr[], int len); //雙向分區快速排序算法 void quick_sort_two_way(int arr[], int len); 關鍵點 分析: &#x…

FPGA-VGA

目錄 前言 一、VGA是什么? 二、物理接口 三、VGA顯示原理 四、VGA時序標準 五、VGA顯示參數 六、模塊設計 七、波形圖設計 八、彩條波形數據 前言 VGA的FPGA驅動 一、VGA是什么? VGA(Video Graphics Array)是IBM于1987年推出的…

Linux和Ubuntu的驅動適配情況

舊 一、Linux Yocto3.0 二、Ubuntu 1.驅動 1.rtc正常 2.led正常 3.加密芯片正常 4.硬件看門狗不行,驅動已經適配好,等硬件修復后,直接使用腳本就可以 5.千兆網口可以,兩個百兆網口不行 6.USB上面和下面都可以(插u盤…

Python 文本和字節序列(處理文本文件)

本章將討論下述話題: 字符、碼位和字節表述 bytes、bytearray 和 memoryview 等二進制序列的獨特特性 全部 Unicode 和陳舊字符集的編解碼器 避免和處理編碼錯誤 處理文本文件的最佳實踐 默認編碼的陷阱和標準 I/O 的問題 規范化 Unicode 文本,進行安全的…

【Android學習記錄】工具使用

文章目錄 一. 精準找視圖資源ID1. 準備工作2. 使用 uiautomator 工具2.1. 獲取設備的窗口內容2.2. Pull XML 文件2.3. 查看 XML 文件 3. 直接使用 ADB 命令4. 使用 Android Studio 的 Layout Inspector總結 二. adb shell dumpsys activity1. 如何使用 ADB 命令2. 輸出內容解析…

Kafka系列之:計算kafka集群topic占的存儲大小

Kafka系列之:計算kafka集群topic占的存儲大小 topic存儲數據格式統計topic存儲大小定時統計topic存儲大小topic存儲數據格式 單位是字節大小 size_bytes{directory="/data/datum/kafka/optics-all" } 782336計算topic存儲大小腳本邏輯是: 計算指定目錄或文件的大小…

C# 高級編程:Lambda 表達式

在 C# 的高級編程中,Lambda 表達式是一個強大而靈活的工具,廣泛應用于 LINQ 查詢、委托、事件處理以及函數式編程等多個領域。它不僅使代碼更簡潔、表達更直接,而且在某些場景中能極大提高代碼的可讀性與可維護性。本文將從 Lambda 表達式的基本語法入手,深入探討其原理、常…

《軟件設計師》復習筆記(11.5)——測試原則、階段、測試用例設計、調試

目錄 1. 測試基礎概念 2. 測試方法分類 3. 測試階段 真題示例: 題目1 題目2 題目3 4. 測試策略 5. 測試用例設計 真題示例: 6. 調試與度量 真題示例: 1. 測試基礎概念 定義:系統測試是為發現錯誤而執行程序的過程&…

方案解讀:虛擬電廠標桿項目整體建設方案【附全文閱讀】

在電力市場背景下,傳統電力現貨市場存在電能定價不合理、分布式電源并網困難等問題。本虛擬電廠標桿項目旨在研究全時間尺度虛擬電廠智能管控關鍵技術,通過研制虛擬電廠控制器樣機、開發運行管理平臺,實現對分布式能源的合理優化配置。項目內容涵蓋虛擬調控、建設目標、建設…

PyTorch 深度學習實戰(37):分布式訓練(DP/DDP/Deepspeed)實戰

在上一篇文章中,我們探討了混合精度訓練與梯度縮放技術。本文將深入介紹分布式訓練的三種主流方法:Data Parallel (DP)、Distributed Data Parallel (DDP) 和 DeepSpeed,幫助您掌握大規模模型訓練的關鍵技術。我們將使用PyTorch在CIFAR-10分類…

OpenAI重返巔峰:o3與o4-mini引領AI推理新時代

引言 2025年4月16日,OpenAI發布了全新的o系列推理模型:o3和o4-mini,這兩款模型被官方稱為“迎今為止最智能、最強大的大語言模型(LLM)”。它們不僅在AI推理能力上實現了質的飛躍,更首次具備了全面的工具使…

【AI插件開發】Notepad++ AI插件開發實踐:支持配置界面

一、引用 此前的系列文章已基本完成了Notepad的AI插件的功能開發,但是此前使用的配置為JSON配置文件,不支持界面配置。 本章在此基礎上集成支持配置界面,這樣不需要手工修改配置文件,直接在界面上操作,方便快捷。 注…

Android12 ServiceManager::addService源碼解讀

源碼 Status ServiceManager::addService(const std::string& name, const sp<IBinder>& binder, bool allowIsolated, int32_t dumpPriority) {auto ctx mAccess->getCallingContext();// apps cannot add servicesif (multiuser_get_app_id(ctx.uid) >…

第十四節:實戰場景-何實現全局狀態管理?

React.createElement調用示例 Babel插件對JSX的轉換邏輯 React 全局狀態管理實戰與 JSX 轉換原理深度解析 一、React 全局狀態管理實現方案 1. Context API useReducer 方案&#xff08;輕量級首選&#xff09; // 創建全局 Context 對象 const GlobalContext createConte…

第四十八篇 電信行業數倉建設實戰指南:從架構設計到場景落地

目錄 一、云原生架構設計實戰1.1 計算存儲分離架構搭建1.2 實時離線融合方案 二、維度建模深度解析2.1 電信業務建模方法論2.2 典型模型設計示例 三、ETL流程優化實踐3.1 增量同步技術選型3.2 數據清洗規范 四、核心場景實現方案4.1 用戶流失預警模型 五、數據治理實施指南5.1 …

2025年山東燃氣瓶裝送氣工考試真題練習

燃氣瓶裝送氣工考試真題練習 單選題 1、液化石油氣主要成分是&#xff08; &#xff09;。 A. 甲烷 B. 丙烷、丁烷 C. 一氧化碳和氫氣 答案&#xff1a;B 2、燃氣鋼瓶搬運過程中&#xff0c;正確的做法是&#xff08; &#xff09;。 A. 滾動鋼瓶 B. 踢鋼瓶 C. 輕拿輕…

《AI大模型應知應會100篇》第24篇:限定輸出格式:如何讓AI回答更加結構化

第24篇&#xff1a;限定輸出格式&#xff1a;如何讓AI回答更加結構化 摘要 在日常使用AI的過程中&#xff0c;我們經常希望得到的不僅僅是“正確”的答案&#xff0c;更是一個清晰、規范、易于處理的回答。無論是生成數據分析報告、代碼片段&#xff0c;還是教學內容&#xff…

【MySQL】數據庫和表的操作詳解

目錄 一、數據庫&#xff1a; 1、查看數據庫&#xff1a; 2、創建數據庫&#xff1a; 3、刪除數據庫&#xff1a; 4、數據庫的編碼問題&#xff1a; 5、校驗規則對數據庫的影響&#xff1a; 6、修改數據庫&#xff1a; 7、庫的備份與恢復&#xff1a; 8、查看鏈接情況…

Docker--Docker鏡像原理

docker 是操作系統層的虛擬化&#xff0c;所以 docker 鏡像的本質是在模擬操作系統。 聯合文件系統&#xff08;UnionFS&#xff09; 聯合文件系統&#xff08;UnionFS&#xff09; 是Docker鏡像實現分層存儲的核心技術&#xff0c;它通過將多個只讀層&#xff08;Image Laye…

雙層Key緩存

雙層 Key 緩存是一種針對 緩存擊穿 和 雪崩問題 的優化方案&#xff0c;其核心思想是通過 主備雙緩存 的機制&#xff0c;確保在熱點數據過期時仍能提供可用服務&#xff0c;同時降低對數據庫的瞬時壓力。以下是其核心原理、實現細節及適用場景的深度解析&#xff1a; 一、核心…