Python使用OpenCV實(shí)現(xiàn)銀行卡卡號(hào)識(shí)別
一、流程概述
采用經(jīng)典的圖像處理流程,主要分為兩個(gè)核心階段:
- 模板預(yù)處理階段:預(yù)先處理標(biāo)準(zhǔn)OCR-A字體模板,提取并存儲(chǔ)每個(gè)數(shù)字的特征模板
- 卡號(hào)識(shí)別階段:對(duì)輸入的銀行卡圖像進(jìn)行多步處理,定位卡號(hào)區(qū)域,分割單個(gè)數(shù)字,通過(guò)模板匹配實(shí)現(xiàn)識(shí)別


整個(gè)系統(tǒng)基于OpenCV庫(kù)實(shí)現(xiàn)。
二、環(huán)境配置與參數(shù)設(shè)置
import numpy as np import argparse import cv2 import myutils from imutils import contours
模塊作用分析:
numpy:提供高效的數(shù)值計(jì)算和數(shù)組操作argparse:Python內(nèi)置庫(kù),用于解析命令行參數(shù)cv2:OpenCV庫(kù),核心圖像處理功能myutils:自定義工具模塊,包含輪廓排序等輔助函數(shù)imutils.contours:提供輪廓處理的便捷函數(shù)
三、命令行參數(shù)配置
# 設(shè)置參數(shù)
ap = argparse.ArgumentParser() # 創(chuàng)建ArgumentParser對(duì)象,用于定義和解析命令行參數(shù)
ap.add_argument("-i", "--image", required=True, help="path to input image")
ap.add_argument("-t", "--template", required=True, help="path to template OCR-A image")
args = vars(ap.parse_args()) # 將參數(shù)轉(zhuǎn)換為字典格式,便于訪問(wèn)
# 使用示例:
# python demo47.py -i card1.png -t kahao.png

參數(shù)說(shuō)明:
-i/--image:必需參數(shù),指定待識(shí)別的銀行卡圖像路徑-t/--template:必需參數(shù),指定OCR-A模板圖像路徑
四、銀行卡類(lèi)型定義
# 根據(jù)卡號(hào)首位數(shù)字判斷銀行卡類(lèi)型
FIRST_NUMBER = {
"3": "American Express", # 美國(guó)運(yùn)通卡
"4": "Visa", # Visa卡
"5": "MasterCard", # 萬(wàn)事達(dá)卡
"6": "Discover Card" # 發(fā)現(xiàn)卡
}
這個(gè)字典基于銀行卡號(hào)的行業(yè)標(biāo)準(zhǔn):首位數(shù)字3代表美國(guó)運(yùn)通,4代表Visa,5代表萬(wàn)事達(dá),6代表發(fā)現(xiàn)卡。
五、輔助函數(shù)定義
def cv_show(name, img): # 圖像顯示函數(shù)
"""顯示圖像并等待按鍵響應(yīng)"""
cv2.imshow(name, img)
cv2.waitKey(0)
這是一個(gè)簡(jiǎn)單的圖像顯示封裝函數(shù),便于在開(kāi)發(fā)過(guò)程中可視化各個(gè)處理階段的結(jié)果。
六、模板圖像預(yù)處理
6.1 模板加載與初步處理
# 讀取并顯示模板圖像
img = cv2.imread(args["template"])
cv_show('img', img)
# 轉(zhuǎn)換為灰度圖像
ref = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv_show('ref', ref)
# 二值化處理:黑底白字,便于輪廓檢測(cè)
ref = cv2.threshold(ref, 10, 255, cv2.THRESH_BINARY_INV)[1]
cv_show('ref', ref)

關(guān)鍵步驟解析:
- 灰度轉(zhuǎn)換:將彩色 圖像轉(zhuǎn)換為單通道灰度圖,減少計(jì)算復(fù)雜度
- 二值化:使用閾值處理,將圖像轉(zhuǎn)換為純黑白兩色,便于輪廓提取
THRESH_BINARY_INV:反向二值化,生成黑底白字效果
6.2 輪廓提取與數(shù)字模板建立
# 檢測(cè)輪廓(只檢測(cè)外輪廓)
_, refCnts, hierarchy = cv2.findContours(ref.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 在原始圖像上繪制輪廓(紅色)
cv2.drawContours(img, refCnts, -1, (0, 0, 255), 3)
cv_show('refCnts', img)
# 對(duì)輪廓從左到右排序
refCnts = myutils.sort_contours(refCnts, method="left-to-right")[0]
digits = {} # 存儲(chǔ)數(shù)字模板的字典
# 提取每個(gè)數(shù)字作為模板
for (i, c) in enumerate(refCnts): # 遍歷每個(gè)數(shù)字輪廓
# 計(jì)算輪廓的外接矩形
(x, y, w, h) = cv2.boundingRect(c)
# 提取數(shù)字區(qū)域并縮放到統(tǒng)一尺寸
roi = ref[y:y + h, x:x + w]
roi = cv2.resize(roi, (57, 88)) # 標(biāo)準(zhǔn)化尺寸
cv_show('roi', roi)
digits[i] = roi # 存儲(chǔ)模板:鍵為數(shù)字,值為模板圖像

技術(shù)細(xì)節(jié):
cv2.findContours():在二值圖像中查找輪廓RETR_EXTERNAL:僅檢測(cè)最外層輪廓CHAIN_APPROX_SIMPLE:壓縮輪廓點(diǎn),減少內(nèi)存使用- 模板標(biāo)準(zhǔn)化:將所有數(shù)字縮放到57×88像素,確保后續(xù)匹配的準(zhǔn)確性
七、銀行卡圖像處理流程
7.1 圖像加載與初步調(diào)整
# 讀取待識(shí)別圖像
image = cv2.imread(args["image"])
cv_show('image', image)
# 調(diào)整圖像尺寸,保持寬高比
image = myutils.resize(image, width=300)
# 轉(zhuǎn)換為灰度圖像
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
cv_show('gray', gray)
寬度統(tǒng)一調(diào)整為300像素,既保證處理速度,又維持足夠的分辨率。
7.2 形態(tài)學(xué)處理突出數(shù)字區(qū)域
# 定義形態(tài)學(xué)操作的卷積核
rectKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 3))
sqKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
# 頂帽操作:突出亮色細(xì)節(jié),抑制背景
tophat = cv2.morphologyEx(gray, cv2.MORPH_TOPHAT, rectKernel)
open_img = cv2.morphologyEx(gray, cv2.MORPH_OPEN, rectKernel)
cv_show('open', open_img)
cv_show('tophat', tophat)

形態(tài)學(xué)操作原理:
- 頂帽操作:原始圖像減去開(kāi)運(yùn)算結(jié)果,突出比背景亮的細(xì)小區(qū)域
- 開(kāi)運(yùn)算:先腐蝕后膨脹,消除小物體,平滑邊界
- 銀行卡數(shù)字通常比背景亮,頂帽操作能有效突出這些數(shù)字
7.3 數(shù)字區(qū)域定位與提取
# 第一次閉操作:連接相近的數(shù)字
closeX = cv2.morphologyEx(tophat, cv2.MORPH_CLOSE, rectKernel)
cv_show('close1', closeX)
# 自適應(yīng)閾值二值化
thresh = cv2.threshold(closeX, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
cv_show('thresh', thresh)
# 第二次閉操作:進(jìn)一步連接數(shù)字區(qū)域
thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, sqKernel)
cv_show('close2', thresh)

閉操作的作用:通過(guò)先膨脹后腐蝕,連接相鄰的白色區(qū)域(數(shù)字),將分散的數(shù)字點(diǎn)連接成完整的數(shù)字組。
7.4 數(shù)字組輪廓檢測(cè)與篩選
# 檢測(cè)輪廓
_, cnts, _ = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 可視化所有輪廓
cnts_img = image.copy()
cv2.drawContours(cnts_img, cnts, -1, (0, 0, 255), 3)
cv_show('cnts_img', cnts_img)
# 篩選符合條件的輪廓(銀行卡號(hào)區(qū)域)
locs = []
for c in cnts:
(x, y, w, h) = cv2.boundingRect(c) # 獲取外接矩形
ar = w / float(h) # 寬高比
# 篩選條件:寬高比和尺寸范圍
if 2.5 < ar < 4.0: # 銀行卡號(hào)區(qū)域的典型寬高比
if (40 < w < 55) and (10 < h < 20): # 尺寸范圍
locs.append((x, y, w, h))
# 按x坐標(biāo)排序(從左到右)
locs = sorted(locs, key=lambda x: x[0])


篩選邏輯:
- 寬高比2.5-4.0:匹配銀行卡號(hào)區(qū)域的長(zhǎng)條形特征
- 寬度40-55像素,高度10-20像素:匹配標(biāo)準(zhǔn)尺寸
八、數(shù)字識(shí)別核心算法
8.1 單個(gè)數(shù)字組處理
output = [] # 存儲(chǔ)最終識(shí)別結(jié)果
# 遍歷每個(gè)數(shù)字組(通常一組4個(gè)數(shù)字)
for (gx, gy, gw, gh) in locs:
groupOutput = [] # 存儲(chǔ)當(dāng)前組的識(shí)別結(jié)果
# 提取數(shù)字組區(qū)域,添加5像素邊界
group = gray[gy - 5:gy + gh + 5, gx - 5:gx + gw + 5]
cv_show('group', group)
# 對(duì)數(shù)字組進(jìn)行二值化
group = cv2.threshold(group, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
cv_show('group', group)
# 檢測(cè)組內(nèi)每個(gè)數(shù)字的輪廓
_, digitCnts, _ = cv2.findContours(group.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
digitCnts = myutils.sort_contours(digitCnts, method="left-to-right")[0]
8.2 模板匹配識(shí)別數(shù)字
# 識(shí)別組內(nèi)每個(gè)數(shù)字
for c in digitCnts:
# 提取單個(gè)數(shù)字區(qū)域
(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)
# 模板匹配:計(jì)算與每個(gè)模板的相似度
scores = []
for (digit, digitROI) in digits.items():
# 使用相關(guān)系數(shù)匹配法
result = cv2.matchTemplate(roi, digitROI, cv2.TM_CCOEFF)
(_, score, _, _) = cv2.minMaxLoc(result)
scores.append(score)
# 選擇最高得分的數(shù)字
groupOutput.append(str(np.argmax(scores)))

模板匹配原理:
cv2.matchTemplate():在輸入圖像中搜索與模板匹配的區(qū)域TM_CCOEFF:相關(guān)系數(shù)匹配方法,對(duì)光照變化魯棒np.argmax(scores):返回最高得分的索引,即識(shí)別出的數(shù)字
8.3 結(jié)果可視化
# 繪制數(shù)字組矩形框(紅色)
cv2.rectangle(image, (gx - 5, gy - 5), (gx + gw + 5, gy + gh + 5), (0, 0, 255), 1)
# 在矩形上方顯示識(shí)別結(jié)果(紅色)
cv2.putText(image, "".join(groupOutput), (gx, gy - 15),
cv2.FONT_HERSHEY_SIMPLEX, 0.65, (0, 0, 255), 2)
# 添加到總結(jié)果
output.extend(groupOutput)
九、最終結(jié)果輸出
# 輸出銀行卡類(lèi)型和完整卡號(hào)
print("Credit Card Type: {}".format(FIRST_NUMBER.get(output[0], "Unknown")))
print("Credit Card #: {}".format("".join(output)))
# 顯示最終處理結(jié)果
cv2.imshow("Image", image)
cv2.waitKey(0)
cv2.destroyAllWindows()


以上就是Python使用OpenCV實(shí)現(xiàn)銀行卡卡號(hào)識(shí)別的詳細(xì)內(nèi)容,更多關(guān)于Python OpenCV銀行卡卡號(hào)識(shí)別的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Python使用WebSocket和SSE實(shí)現(xiàn)HTTP服務(wù)器消息推送方式
本文介紹了兩種實(shí)時(shí)數(shù)據(jù)獲取的技術(shù):WebSocket和SSE,WebSocket是全雙工通信協(xié)議,支持雙向通信,但需要專門(mén)定義數(shù)據(jù)協(xié)議,SSE是一種單工通信技術(shù),基于HTTP的流式數(shù)據(jù)傳輸,客戶端開(kāi)發(fā)簡(jiǎn)單,但只能單工通信2024-11-11
python?字符串常用方法超詳細(xì)梳理總結(jié)
字符串是Python中基本的數(shù)據(jù)類(lèi)型,幾乎在每個(gè)Python程序中都會(huì)使用到它。本文為大家總結(jié)了Python中必備的31個(gè)字符串方法,需要的可以參考一下2022-03-03
python實(shí)現(xiàn)多線程的方式及多條命令并發(fā)執(zhí)行
這篇文章主要為大家詳細(xì)介紹了python實(shí)現(xiàn)多線程的方式及多條命令并發(fā)執(zhí)行,感興趣的小伙伴們可以參考一下2016-06-06
python實(shí)現(xiàn)對(duì)excel的覆蓋和追加操作
這篇文章主要為大家詳細(xì)介紹了如何使用python實(shí)現(xiàn)對(duì)excel的覆蓋和追加操作,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2026-05-05
Python網(wǎng)絡(luò)編程中urllib2模塊的用法總結(jié)
使用urllib2模塊進(jìn)行基于url的HTTP請(qǐng)求等操作大家也許都比較熟悉,這里我們?cè)偕钊雭?lái)了解一下urllib2針對(duì)HTTP的異常處理相關(guān)功能,一起來(lái)看一下Python網(wǎng)絡(luò)編程中urllib2模塊的用法總結(jié):2016-07-07
tensorflow實(shí)現(xiàn)訓(xùn)練變量checkpoint的保存與讀取
今天小編就為大家分享一篇tensorflow實(shí)現(xiàn)訓(xùn)練變量checkpoint的保存與讀取,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-02-02

