opencv實戰小結-銀行卡號識別

實戰1-銀行卡號識別

項目來源:opencv入門

項目目的:識別傳入的銀行卡照片中的卡號

難點:銀行卡上會有一些干擾項,如何排除這些干擾項,并且打印正確的號碼是一個問題

在這里插入圖片描述

最終效果如上圖

實現這樣的功能需要以下幾個步驟:

  1. 首先必須有與銀行卡中卡號數字基本一樣的數字模板,將模板中的數字提取出來并存儲起來(0-9)
  2. 將需要檢測的銀行卡圖片中的數字提取出來
  3. 將銀行卡的數字與模板數字一一對比,最終找到一個匹配度最高的數字,并把數字標注上

整個思路很簡單,但是難點就在于如何將圖片處理得更加容易讓計算機識別數字,所以整個項目要圍繞著圖片得的處理來做

第一步-提取數字模板

這是事先準備好的數字模板

在這里插入圖片描述

接下來要將圖片中的數字都找到,也就是找到各個數字在整個圖片上的像素點坐標(輪廓)

首先得到圖片的灰度圖,再進行二值化處理(這一切都是為了讓圖片中的數字更易于識別)

# 灰度圖
ref = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 二值圖像
ref = cv2.threshold(ref, 10, 255, cv2.THRESH_BINARY_INV)[1]#超過閾值部分取maxval ( 最大值 ),否則取0

然后會得到這樣的圖像
在這里插入圖片描述

好了,現在圖片已經很清晰了,不需要再進行其它的處理了,直接將其提取

那怎么提取呢?

可以通過cv2.findContours()找到數字的輪廓

函數 cv2.?ndContours() 有三個參數,第一個是輸入圖像,第二個是 輪廓檢索模式,第三個是輪廓近似方法。返回值有三個,第一個是圖像,第二個 是輪廓,第三個是(輪廓的)層析結構。輪廓(第二個返回值)是一個 Python 列表,其中存儲這圖像中的所有輪廓。每一個輪廓都是一個 Numpy 數組,包 含對象邊界點(x,y)的坐標。

注意新版本中這個api的返回值有變化

返回兩個參數contours和 hierarchy,contours就是每個數字的輪廓數組,包含邊界點的坐標

其中cv2.RETR_EXTERNAL是獲取外輪廓

contours, hierarchy = cv2.findContours(ref.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)

接下來可以將輪廓畫出來看看

會用到cv2.drawContours()函數

函數 cv2.drawContours() 可以被用來繪制輪廓。它可以根據你提供 的邊界點繪制任何形狀。它的第一個參數是原始圖像,第二個參數是輪廓,一 個 Python 列表。第三個參數是輪廓的索引(在繪制獨立輪廓是很有用,當設置 -1時繪制所有輪廓)。接下來的參數是輪廓的顏色和厚度等。

cv2.drawContours(img,contours,-1, (0, 0, 255), 3)

看下效果

在這里插入圖片描述

好,現在輪廓都找到了,并且我們也有了輪廓的坐標,這個時候我們應該將每個數字的像素點位置都存起來(并不是將圖片分割!,整個圖片仍然沒有任何變化)

好,現在有一個要注意的點,那就是我們在上面得到的contours數組并不是按圖片中各個數字從左到右排列的,也就是說數組中第一個坐標可能是圖片中8的坐標,那這個時候我們就必須對數組進行排序,排序順序就是從左到右存

那排序怎么實現呢,其實就是根據x坐標從小到大排序就行了

排完序之后,contours中0下標存的就是數字0的模板,這里很好的利用了數組下標的優點

好的,排序完之后,我們就可以來存這個數字的模板了

思路是遍歷contours數組,得到每個模板的坐標以及寬高,利用x+w就能得到圖片的x軸范圍,y+h就能得到y軸的范圍,把他們存起來就得到一個數字的模板了

digits = {}
#遍歷每一個輪廓
for (i,c) in enumerate(contours):#計算外接矩形并resize合適的大小(x, y, w, h) = cv2.boundingRect(c)# cv2.rectangle(img,(x,y),(x + w, y + h),(0, 0, 255), 2)roi = ref[y:y + h, x:x + w]# 第二個參數是輸出圖像的寬高roi = cv2.resize(roi, (57, 88))# 每一個數字對應每一個模板digits[i] = roi

至此,我們項目的第一步就完成了

接下來就是將要檢測的圖像中的數字提取出來,其實整個提取思路都是一樣的,但是銀行卡的圖像比我們的模板往往更加復雜,所以我們要對圖片增加一些處理的步驟

跟著上面的來說,我們對復雜圖片的處理需要引入卷積核,這里我們定義兩個卷積核

# 初始化卷積核
rectKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 3))
sqKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))

一個是9x3的矩陣,一個是5x5

下面對圖像進行處理,老規矩,取灰度圖

在這里插入圖片描述

然后進行禮帽處理,目的是為了突出更明亮的區域

tophat = cv2.morphologyEx(gray, cv2.MORPH_TOPHAT, rectKernel)

在這里插入圖片描述

接下來再用 Sobel核子對圖片進行卷積,目的的為了得到圖像梯度,也就是邊緣檢測

我們現在要做的是把可能為數字的區域都找出來

gradX = cv2.Sobel(tophat, ddepth=cv2.CV_32F, dx=1, dy=0, ksize=-1)
gradX = np.absolute(gradX)
(minVal, maxVal) = (np.min(gradX), np.max(gradX))
gradX = (255 * ((gradX - minVal) / (maxVal - minVal)))
gradX = gradX.astype("uint8")

在這里插入圖片描述

上圖看上去更加模糊了,但是數字和非數字區域的明亮度變了

好的,接下來可以通過閉操作(先膨脹,再腐蝕),將數字連起來(是為了最后找到數字區域,因為卡號是4個數字連在一起的,我們把4個數字的區域找出來)

變成這樣

在這里插入圖片描述

再來一次閾值操作

thresh = cv2.threshold(gradX, 0, 255,cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]

變成這樣

在這里插入圖片描述

矩形區域好像白色沒有填滿,再來一次閉操作

在這里插入圖片描述

ok了,現在疑似數字的區域都很明顯了吧,那下一步就是將這個區域進行排除,找到真正為銀行卡號的區域,其他的區域就不要了

那怎么做呢?我們先把他們的輪廓都找出來,然后判斷這些輪廓的寬度,符合銀行卡號區域寬的的留下,不符合的去掉就可以了

在這里插入圖片描述

# 計算輪廓
contours_, hierarchy_ = cv2.findContours(thresh.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cnts = contours_
cur_img = image.copy()
cv2.drawContours(cur_img, cnts, -1, (0, 0, 255), 3)
cv_show('img', cur_img)
locs = []
# 遍歷輪廓
for (i, c) in enumerate(cnts):# 計算矩形(x, y, w, h) = cv2.boundingRect(c)ar = w / float(h)# 選擇合適的區域,根據實際任務來,這里的基本都是四個數字一組if ar > 2.5 and ar < 4.0:if (w > 40 and w < 55) and (h > 10 and h < 20):# 符合的留下來locs.append((x, y, w, h))

得到卡號輪廓后,同樣對其從左至右排序

好了,那接下來干嘛呢,我們剛剛得到的是四個數字組成的區域的輪廓,這個時候我們應該遍歷這些區域,得到里面的四個數字的輪廓

同樣也是個遍歷操作

for (i, (gX, gY, gW, gH)) in enumerate(locs):groupOutput = []# 根據坐標提取每一個組group = gray[gY - 5:gY + gH + 5, gX - 5:gX + gW + 5]cv_show('group', group)

會得到四個這樣的組

在這里插入圖片描述

然后就獲取這個組的輪廓,就像第一步驟一樣,將數字提取出來就可以了

#計算每一組的輪廓digitCnts, hierarchy = cv2.findContours(group.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)# 從左到右排序digitCnts = myutils.sort_contours(digitCnts, method="left-to-right")[0]

好的,接下來就是最重要的第三部操作了,將模板與上面得到的數字匹配,找到匹配度最高的那個模板數字就是我們要找的數字了

 #計算每一組的每一個數值for c in digitCnts:# 找到當前數值的輪廓,resize成合適的的大小(x, y, w, h) = cv2.boundingRect(c)roi = group[y:y + h, x:x + w]roi = cv2.resize(roi, (57, 88))# cv_show('roi', roi)# 計算匹配得分scores = []for (digit, digitROI) in digits.items():# 模板匹配result = cv2.matchTemplate(roi, digitROI,cv2.TM_CCOEFF)# print('result',result)# 獲取匹配度最高的數值(_, score, _, _) = cv2.minMaxLoc(result)scores.append(score)print("scores",scores)# 得到最合適的數字groupOutput.append(str(np.argmax(scores)))print('groupOutput',groupOutput)

完成上述步驟之后,我們的groupOutput就存放了我們識別出來的銀行卡號了,我們只需要在圖片上將卡號繪制出來就可以了

  # 畫出來cv2.rectangle(image, (gX - 5, gY - 5),(gX + gW + 5, gY + gH + 5), (0, 0, 255), 1)cv2.putText(image, "".join(groupOutput), (gX, gY - 15),cv2.FONT_HERSHEY_SIMPLEX, 0.65, (0, 0, 255), 2)# 得到結果output.extend(groupOutput)

最終效果如下

在這里插入圖片描述


好了,以上就是此小項目的實現過程

總結:這是我學cv的第一個小實戰項目,確實感覺蠻有意思的,學之前覺得這個東西很神奇,學習之后會發現其實一切都是按照邏輯一步步來的,沒有那么"高大上",繼續努力吧

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

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

相關文章

基于Amazon Linux使用pip安裝certbot并使用Apache配置證書的完整步驟

配置證書 1. 更新系統和安裝必要的軟件包 首先&#xff0c;確保系統和包管理器是最新的&#xff1a; sudo dnf update -y sudo dnf install -y python3 python3-pip python3-virtualenv httpd mod_ssl2. 創建并激活虛擬環境 為了避免依賴沖突&#xff0c;使用virtualenv創建…

算法導論實戰(三)(算法導論習題第二十四章)

&#x1f308; 個人主頁&#xff1a;十二月的貓-CSDN博客 &#x1f525; 系列專欄&#xff1a; &#x1f3c0;算法啟示錄 &#x1f4aa;&#x1f3fb; 十二月的寒冬阻擋不了春天的腳步&#xff0c;十二點的黑夜遮蔽不住黎明的曙光 目錄 前言 第二十四章 24.1-3 24.1-4 2…

筆記:DST與HPPC測試方法

一、DST測試方法&#xff1a; DST全稱為Dynamic Stress Test,是一種動態壓力測試方法&#xff0c;主要用于評估電池在實際使用條件下的綜合性能&#xff0c;模擬了車輛在行駛過程中可能會遇到的各種動態負載變化&#xff0c;如加速、減速、怠速等工況。 它的目的是評估電池在…

setattr前端接收方法深度解析

setattr前端接收方法深度解析 在前端開發中&#xff0c;setattr可能是一個較為陌生的概念&#xff0c;但它卻在某些場景下扮演著關鍵角色。setattr是一個Python內置函數&#xff0c;用于設置對象屬性的值。然而&#xff0c;在前端與后端交互的過程中&#xff0c;我們有時需要處…

【Week-R2】使用LSTM實現火災預測(tf版本)

【Week-R2】使用LSTM實現火災預測&#xff08;tf版本&#xff09; 一、 前期準備1.1 設置GPU1.2 導入數據1.3 數據可視化 二、數據預處理(構建數據集)2.1 設置x、y2.2 歸一化2.3 劃分數據集 三、模型創建、編譯、訓練、得到訓練結果3.1 構建模型3.2 編譯模型3.3 訓練模型3.4 模…

超詳細的java Comparable,Comparator接口解析

前言 Hello大家好呀&#xff0c;在java中我們常常涉及到對象的比較&#xff0c;不同于基本數據類型&#xff0c;對于我們的自定義對象&#xff0c;需要我們自己去建立比較標準&#xff0c;例如我們自定義一個People類&#xff0c;這個類有name和age兩個屬性&#xff0c;那么問…

[數據集][圖像分類]蘑菇分類數據集3122張215類別

數據集類型&#xff1a;圖像分類用&#xff0c;不可用于目標檢測無標注文件 數據集格式&#xff1a;僅僅包含jpg圖片&#xff0c;每個類別文件夾下面存放著對應圖片 圖片數量(jpg文件個數)&#xff1a;3122 分類類別數&#xff1a;215 類別名稱:[“almond_mushroom”,“amanita…

實驗筆記之——DPVO(Deep Patch Visual Odometry)

本博文記錄本文測試DPVO的過程&#xff0c;本博文僅供本人學習記錄用~ 《Deep Patch Visual Odometry》 代碼鏈接&#xff1a;GitHub - princeton-vl/DPVO: Deep Patch Visual Odometry 目錄 配置過程 測試記錄 參考資料 配置過程 首先下載代碼以及創建conda環境 git clo…

Data Management Controls

Data Browsing and Analysis Data Grid 以標準表格或其他視圖格式&#xff08;例如&#xff0c;帶狀網格、卡片、瓷磚&#xff09;顯示數據。Vertical Grid 以表格形式顯示數據&#xff0c;數據字段顯示為行&#xff0c;記錄顯示為列。Pivot Grid 模擬微軟Excel的樞軸表功…

有待挖掘的金礦:大模型的幻覺之境

人工智能正在迅速變得無處不在&#xff0c;在科學和學術研究中&#xff0c;自回歸的大型語言模型&#xff08;LLM&#xff09;走在了前列。自從LLM的概念被整合到自然語言處理&#xff08;NLP&#xff09;的討論中以來&#xff0c;LLM中的幻覺現象一直被廣泛視為一個顯著的社會…

Oracle EBS AP發票創建會計科目提示:APP-SQLAP-10710:無法聯機創建會計分錄

系統版本 RDBMS : 12.1.0.2.0 Oracle Applications : 12.2.6 問題癥狀: 提交“創建會計科目”請求提示錯誤信息如下: APP-SQLAP-10710:無法聯機創建會計分錄。 請提交應付款管理系統會計流程,而不要為此事務處理創建會計分錄解決方法 數據修復SQL腳本: UPDATE ap_invoi…

LabVIEW閥性能試驗臺測控系統

本項目開發的閥性能試驗臺測控系統是為滿足國家和企業相關標準而設計的&#xff0c;主要用于汽車氣壓制動系統控制裝置和調節裝置等產品的綜合性能測試。系統采用工控機控制&#xff0c;配置電器控制柜&#xff0c;實現運動控制、開關量控制及傳感器信號采集&#xff0c;具備數…

vue封裝一個查詢URL參數方法

vue封裝一個查詢URL參數方法 在 Vue 中&#xff0c;你可以封裝一個查詢 URL 參數的方法來獲取 URL 中的查詢參數。以下是一個示例代碼&#xff1a; export const getQueryParam (param) > {const urlParams new URLSearchParams(window.location.search);return urlPara…

算法-分治策略

概念 分治算法&#xff08;Divide and Conquer&#xff09;是一種解決問題的策略&#xff0c;它將一個問題分解成若干個規模較小的相同問題&#xff0c;然后遞歸地解決這些子問題&#xff0c;最后合并子問題的解得到原問題的解。分治算法的基本思想是將復雜問題分解成若干個較…

東方博宜1565 - 成績(score)

問題描述 牛牛最近學習了 C 入門課程&#xff0c;這門課程的總成績計算方法是&#xff1a; 總成績作業成績 20% 小測成績 30% 期末考試成績 50%。 牛牛想知道&#xff0c;這門課程自己最終能得到多少分。 輸入 三個非負整數 A、B、C &#xff0c;分別表示牛牛的作業成績、…

計算機網絡 期末復習(謝希仁版本)第3章

對于點對點的鏈路&#xff0c;目前使用得最廣泛的數據鏈路層協議是點對點協議 PPP (Point-to-Point Protocol)。局域網的傳輸媒體&#xff0c;包括有線傳輸媒體和無線傳輸媒體兩個大類&#xff0c;那么有線傳輸媒體有同軸電纜、雙絞線和光纖&#xff1b;無線傳輸媒體有微波、紅…

計算引擎:Flink核心概念

Apache Flink 是一個流處理框架,擅長處理實時數據流和批處理任務。Flink 提供了強大的功能來處理和分析大量數據。以下是 Flink 的核心概念: 1. DataStream 和 DataSet API DataStream API: 用于處理無界數據流,即不斷生成和流動的數據。例如,傳感器數據、日志等。DataSet…

基于Texture2D 實現Unity 截屏功能

實現 截屏 Texture2D texture new Texture2D(Screen.width, Screen.height, TextureFormat.RGB24, false); texture.ReadPixels(new Rect(0, 0, Screen.width, Screen.height), 0, 0); texture.Apply(); 存儲 byte[] array ImageConversion.EncodeToPNG(texture); if (!…

分享萬能點擊器免費版,吾愛大佬出品,這個太贊了!

小伙伴們&#xff01;阿星又來給大家推薦神奇的小軟件啦&#xff01;這次的主角可是個神器——鼠標連點器&#xff01;你聽過沒&#xff1f;這玩意兒簡直是個“自動小助手”&#xff0c;讓你的鼠標在屏幕上飛舞&#xff0c;點得飛快&#xff0c;解放你的雙手&#xff0c;讓你網…

【ARM 常見匯編指令學習 6.2 -- ARMv8 匯編指令 SDIV 詳細介紹】

文章目錄 SDIV指令格式使用示例注意事項總結 SDIV ARMv8 架構中的 SDIV 指令用于執行帶符號整數除法操作。這意味著它可以處理負數除法&#xff0c;與 UDIV&#xff08;執行無符號整數除法&#xff09;形成對比。SDIV 將兩個寄存器中的帶符號整數相除&#xff0c;將除法結果存…