這篇博客將介紹如何通過OpenCV和Python使用模板匹配執(zhí)行光學(xué)字符識別(OCR)。具體來說,將使用Python+OpenCV實現(xiàn)模板匹配算法,以自動識別卡的類型和以及16位卡號數(shù)字。
在字典中存儲卡類型映射關(guān)系(卡號的第一位數(shù)字代表卡類型)。獲取參考圖像并提取數(shù)字。將數(shù)字模板存儲在字典中。本地化四個信用卡號組,每個組有四位數(shù)字(總共16位)。提取要“匹配”的數(shù)字。對每個數(shù)字執(zhí)行模板匹配,將每個單獨的ROI與每個數(shù)字模板0-9進行比較,同時存儲每個嘗試匹配的分?jǐn)?shù)。查找每個候選數(shù)字的最高分?jǐn)?shù),并構(gòu)建一個名為“輸出”的列表。其中包含信用卡號。將信用卡號和信用卡類型輸出到終端,并將輸出圖像顯示到屏幕上。
# 信用卡類型及卡號OCR系統(tǒng)
# USAGE
# python ocr_template_match.py --reference images/ocr_a_reference.png --image images/credit_card_05.png
import argparse
import cv2
import imutils
import numpy as np
# 導(dǎo)入必要的包
from imutils import contours
# 構(gòu)建命令行參數(shù)及解析
# --image 必須 要進行OCR的輸入圖像
# --reference 必須 參考OCR-A圖像
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required=True,
help="path to input image")
ap.add_argument("-r", "--reference", required=True,
help="path to reference OCR-A image")
args = vars(ap.parse_args())
# 定義一個字典(映射信用卡第一位數(shù)字和信用卡類型的編號)
FIRST_NUMBER = {
"3": "American Express",
"4": "Visa",
"5": "MasterCard",
"6": "Discover Card"
}
# 從磁盤加載參考OCR-A圖像,轉(zhuǎn)換為灰度圖,閾值化圖像以顯示為白色前景和黑色背景
# 并反轉(zhuǎn)圖像
# and invert it, such that the digits appear as *white* on a *black*
ref_origin = cv2.imread(args["reference"])
cv2.imshow("ref_origin", ref_origin)
ref = ref_origin.copy()
ref = cv2.cvtColor(ref, cv2.COLOR_BGR2GRAY)
cv2.imshow("ref_gray", ref)
ref = cv2.threshold(ref, 180, 255, cv2.THRESH_BINARY)[1]
cv2.imshow("ref_threshhold", ref)
cv2.waitKey(0)
# 尋找OCR-A圖像中的輪廓(數(shù)字的外輪廓線)
# 并從左到右排序輪廓,初始化一個字典來存儲數(shù)字ROI
refCnts = cv2.findContours(ref.copy(), cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
print('findContours: ', len(refCnts))
refCnts = imutils.grab_contours(refCnts)
refCnts = contours.sort_contours(refCnts, method="left-to-right")[0]
digits = {}
# 遍歷OCR-A輪廓
for (i, c) in enumerate(refCnts):
# 計算數(shù)字的邊界框,提取它,縮放到固定的大小
(x, y, w, h) = cv2.boundingRect(c)
cv2.rectangle(ref_origin, (x, y), (x + w, y + h), (0, 255, 0), 2)
roi = ref[y:y + h, x:x + w]
roi = cv2.resize(roi, (57, 88))
# 更新數(shù)字字典,數(shù)字匹配ROI
digits[i] = roi
cv2.imshow("ref and digits", ref_origin)
cv2.waitKey(0)
# 初始化矩形和方形結(jié)構(gòu)內(nèi)核
# 在圖像上滑動它來進行(卷積)操作,如模糊、銳化、邊緣檢測或其他圖像處理操作。
# 使用矩形函數(shù)作為Top-hat形態(tài)學(xué)運算符,使用方形函數(shù)作為閉合運算。
rectKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 3))
sqKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
# 準(zhǔn)備進行OCR的輸入圖像
# 加載輸入圖像,保持縱橫比縮放圖像寬度為300,轉(zhuǎn)換為灰度圖
origin = cv2.imread(args["image"])
origin = imutils.resize(origin, width=300)
image = origin.copy()
cv2.imshow("origin", origin)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
cv2.imshow("gray", gray)
# 執(zhí)行形態(tài)學(xué)操作
# 應(yīng)用tophat(白帽)形態(tài)學(xué)操作以在暗的背景中提取出亮的區(qū)域(信用卡上的數(shù)字卡號)
# Top hat操作在深色背景(即信用卡號)下顯示淺色區(qū)域
tophat = cv2.morphologyEx(gray, cv2.MORPH_TOPHAT, rectKernel)
cv2.imshow("tophat", tophat)
# 計算Scharr梯度,計算梯度值
# 在白色禮帽上,計算x方向的Scharr梯度,然后縮放到范圍[0, 255]
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))
# 最小/最大歸一化, 由float轉(zhuǎn)換gradX到uint8范圍[0-255]
gradX = (255 * ((gradX - minVal) / (maxVal - minVal)))
gradX = gradX.astype("uint8")
cv2.imshow("gradient", gradX)
# 使用矩形框應(yīng)用閉合操作以幫助閉合信用卡數(shù)字之間的小的縫隙
# 應(yīng)用Otsu's閾值方法二值化圖像
gradX = cv2.morphologyEx(gradX, cv2.MORPH_CLOSE, rectKernel)
cv2.imshow("morphologyEx", gradX)
thresh = cv2.threshold(gradX, 0, 255,
cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
cv2.imshow("thresh1", thresh)
# 在二值化圖像上,應(yīng)用二次閉合操作
# 再一次方形框形態(tài)學(xué)操作,幫助閉合信用卡數(shù)字區(qū)域之間的縫隙
thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, sqKernel)
cv2.imshow("thresh2", thresh)
# 閾值圖像中查找輪廓,然后初始化數(shù)字位置列表
cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
locs = []
# 遍歷輪廓
for (i, c) in enumerate(cnts):
# 計算輪廓的邊界框,并計算縱橫比
(x, y, w, h) = cv2.boundingRect(c)
ar = w / float(h)
# 由于信用卡有固定的4組4數(shù)字,可以根據(jù)縱橫比來尋找潛在的輪廓
if ar > 2.5 and ar 4.0:
# 輪廓可以在最小/最大寬度上進一步修剪
if (w > 40 and w 55) and (h > 10 and h 20):
# 添加數(shù)字組輪廓的編輯框輪廓到位置list
locs.append((x, y, w, h))
cv2.rectangle(origin, (x, y), (x + w, y + h), (255, 0, 0), -1)
cv2.imshow("contours filter", origin)
# 突出顯示信用卡上四組四位數(shù)字(總共十六位)。
# 從左到右排序輪廓,并初始化list來存儲信用卡數(shù)字列表
locs = sorted(locs, key=lambda x: x[0])
output = []
# 遍歷四組四位數(shù)字
for (i, (gX, gY, gW, gH)) in enumerate(locs):
# 初始化存放每組數(shù)字的list
groupOutput = []
# 提取每組4位數(shù)字的灰度圖ROI
# 應(yīng)用閾值方法從背景信用卡中分割數(shù)字
group = gray[gY - 5:gY + gH + 5, gX - 5:gX + gW + 5]
group = cv2.threshold(group, 0, 255,
cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
# 檢測組中每個單獨數(shù)字的輪廓
# 從左到右排序輪廓
digitCnts = cv2.findContours(group.copy(), cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
digitCnts = imutils.grab_contours(digitCnts)
digitCnts = contours.sort_contours(digitCnts,
method="left-to-right")[0]
# 遍歷數(shù)字輪廓
for c in digitCnts:
# 計算每個單獨數(shù)字的邊界框
# 提取數(shù)字,縮放以擁有和參考OCR-A字體模板圖像相同的大小
(x, y, w, h) = cv2.boundingRect(c)
roi = group[y:y + h, x:x + w]
roi = cv2.resize(roi, (57, 88))
# 初始化模板匹配分?jǐn)?shù)list
scores = []
# 遍歷參考數(shù)字名和數(shù)字ROI
for (digit, digitROI) in digits.items():
# 應(yīng)用基于相關(guān)性的模板匹配,計算分?jǐn)?shù),更新分?jǐn)?shù)list
# apply correlation-based template matching, take the
# score, and update the scores list
result = cv2.matchTemplate(roi, digitROI,
cv2.TM_CCOEFF)
(_, score, _, _) = cv2.minMaxLoc(result)
scores.append(score)
# 數(shù)字ROI的分類將取 模板匹配分?jǐn)?shù)中分?jǐn)?shù)最大的參考數(shù)字
# the classification for the digit ROI will be the reference
# digit name with the *largest* template matching score
groupOutput.append(str(np.argmax(scores)))
# 圍繞每組畫一個矩形,并以紅色文本標(biāo)識圖像上的信用卡號
# 繪制每組的數(shù)字識別分類結(jié)果
cv2.rectangle(image, (gX - 5, gY - 5),
(gX + gW + 5, gY + gH + 5), (0, 0, 255), 2)
cv2.putText(image, "".join(groupOutput), (gX, gY - 15),
cv2.FONT_HERSHEY_SIMPLEX, 0.65, (0, 0, 255), 2)
# 更新輸出數(shù)字分組列表
# Pythonic的方法是使用extend函數(shù),它將iterable對象的每個元素(本例中為列表)追加到列表的末尾
output.extend(groupOutput)
# 顯示檢測到的信用卡類型和卡號到屏幕上
print("Credit Card Type: {}".format(FIRST_NUMBER[output[0]]))
print("Credit Card #: {}".format("".join(output)))
cv2.imshow("Image", image)
cv2.waitKey(0)
參考 https://www.pyimagesearch.com/2017/07/17/credit-card-ocr-with-opencv-and-python/
到此這篇關(guān)于使用Pyhton+OpenCV進行卡類型及16位卡號數(shù)字的OCR功能的文章就介紹到這了,更多相關(guān)Pyhton+OpenCV卡號數(shù)字識別內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!