作者 | 李秋鍵
責編 | Carol
頭圖 | CSDN 付費下載自視覺中國
隨著計算機視覺在我們生活中的應用越來越廣泛,大量的字符識別和提取應用逐漸變得越來越受歡迎,同時也便利了我們的生活。像我們生活中的憑藉身份碼取快遞、超市掃碼支付的機器等等。字符識別是模式識別的一個重要應用,首先提取待識別字符的特徵;然後對提取出來的特徵跟字符模板的特徵匹配;最後根據準則判定該字符所屬的類別。不同的訓練方法,不同的特徵提取, 不同的匹配規則,就相應的有不同的字符識別方法,基本上很多就是在這些地方做改進,或者是採用新的規則。但是萬變不離其宗。1、模板匹配字符識別算法。模板匹配字符識別算法是圖像識別中的經典算法之一,該算法的核心思想是:通過比較待識別字符圖像的字符特徵和標準模板的字符特徵,計算兩者之間的相似性,相似性最大的標準模板的字符即為待識別的字符。2、神經網絡字符識別算法主要思想:通過神經網絡學習大量字符樣本,從而得到字符的樣本特徵。當對待識別的字符進行識別時,神經網絡就會將待識別字符的特徵和之前得到的樣本特徵匹配,從而識別出字符。3、支持向量機主要思想:同上,都是先得到樣本特徵,進行訓練,然後再分類。SVM應該算是用的最多的分類方法,一般大多適合於二分類問題,在這裡就需要使用多分類器來構造。
今天我們就簡單的利用OpenCV處理通過提取輪廓和匹配等方式來實現模式匹配的字符識別。
效果圖如下:
實驗前的準備
首先我們使用的python版本是3.6.5所用到的庫有cv2庫用來圖像處理;
Numpy庫用來矩陣運算,這裡主要用來對圖像像素值相關性處理;imutils庫可以輕鬆實現基本圖像處理功能,如平移,旋轉,調整大小,骨架化和顯示Matplotlib圖像。
程序的搭建
1、參考圖像的讀取和處理:
參考圖像如下,因為銀行卡號主要只有0~9這幾個數字,為了方便識別數字,我們直接利用這張圖片裡的數值作為匹配樣式:
所以下面我們要做的事很明顯,就是要將其中每個數字隔開方便後面匹配。
代碼如下:
#定義了一個字典 FIRST_NUMBER ,它將第一個數字映射到相應的信用卡類型。
FIRST_NUMBER = {
"3": "American Express",
"4": "Visa",
"5": "MasterCard",
"6": "Discover Card"
}
#參考數字圖像,用於匹配
#灰度化及二值化
ref=cv2.imread("1.png")
ref = cv2.cvtColor(ref, cv2.COLOR_BGR2GRAY)
ref = cv2.threshold(ref, 10, 255, cv2.THRESH_BINARY_INV)[1]
#查找輪廓,從左往右排序
refCnts = cv2.findContours(ref.copy, cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
refCnts = imutils.grab_contours(refCnts)
refCnts = contours.sort_contours(refCnts, method="left-to-right")[0]
digits = {}
#對於其中每一個輪廓進行提循環,i為數字名稱,c為輪廓,我們將每個數字0-9(字典鍵)與第30行的每個roi 圖像(字典值)相關聯 。
for (i,c) in enumerate(refCnts):
(x,y,w,h)=cv2.boundingRect(c)
roi=ref[y:y+h,x:x+w]
roi=cv2.resize(roi,(57,88))
digits[i]=roi
#初始化幾個結構化內核,構造了兩個這樣的內核 - 一個矩形和一個正方形。我們將使用矩形的一個用於Top-hat形態運算符,將方形一個用於關閉操作。
rectKernel=cv2.getStructuringElement(cv2.MORPH_RECT,(9,3))
sqKernel=cv2.getStructuringElement(cv2.MORPH_RECT,(5,5))
2、獲取數字位置分組:
這裡需要識別的圖片為:
我們需要進行的處理包括二值化和Top-hat形態操作,最後通過findContours函數框出位置。
其中代碼如下:
#加載信用卡圖像
image=cv2.imread("3.jpg")
image=imutils.resize(image,width=300)
gray=cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
#執行Top-hat形態操作,將結果存儲為 tophat,Top-hat操作顯示了深色背景下的亮區(即信用卡號)
tophat=cv2.morphologyEx(gray,cv2.MORPH_TOPHAT,rectKernel)
#計算沿x方向的漸變在計算gradX 數組中每個元素的絕對值之後 ,我們採取一些步驟將值縮放到範圍[0-255](因為圖像當前是浮點數據類型)。要做到這一點,我們計算 MINVAL
# 和 MAXVAL 的 gradX (線72),然後由我們的縮放方程上顯示 線73(即,最小/最大歸一化)。最後一步是將gradX轉換 為 uint8 ,其範圍為[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))
gradx=(255*((gradx-minval)/(maxval-minval)))
gradx=gradx.astype("uint8")
#執行gradX 圖像的Otsu和二進位閾值,然後是另一個關閉操作,對數字分段
gradx=cv2.morphologyEx(gradx,cv2.MORPH_CLOSE,rectKernel)
thresh=cv2.threshold(gradx,0,255,cv2.THRESH_BINARY|cv2.THRESH_OTSU)[1]
thresh=cv2.morphologyEx(thresh,cv2.MORPH_CLOSE,sqKernel)
#找到輪廓並初始化數字分組位置列表
cnts=cv2.findContours(thresh,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cnts=imutils.grab_contours(cnts)
3、切割字符:
接著循環遍歷輪廓,同時根據每個的寬高比進行過濾,允許我們從信用卡的其他不相關區域修剪數字組位置,然後從左到右對分組進行排序,並初始化信用卡數字列表。
部分代碼如下:
locs =
#循環遍歷輪廓,同時根據每個的寬高比進行過濾,允許我們從信用卡的其他不相關區域修剪數字組位置
for (i, c) in enumerate(cnts):
# compute the bounding box of the contour, then use the
# bounding box coordinates to derive the aspect ratio
(x, y, w, h) = cv2.boundingRect(c)
ar = w / float(h)
# since credit cards used a fixed size fonts with 4 groups
# of 4 digits, we can prune potential contours based on the
# aspect ratio
if ar > 2.5 and ar < 4.0:
# contours can further be pruned on minimum/maximum width
# and height
if (w > 40 and w < 55) and (h > 10 and h < 20):
# append the bounding box region of the digits group
# to our locations list
locs.append((x, y, w, h))
#從左到右對分組進行排序,並初始化信用卡數字列表
locs = sorted(locs, key=lambda x:x[0])
output =
#遍歷四個排序的分組並確定其中的數字,循環的第一個塊中,我們在每一側提取並填充組5個像素(第125行)
# ,應用閾值處理(第126和127行),並查找和排序輪廓(第129-135行)。
for (i, (gX, gY, gW, gH)) in enumerate(locs):
# initialize the list of group digits
groupOutput =
# extract the group ROI of 4 digits from the grayscale image,
# then apply thresholding to segment the digits from the
# background of the credit card
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]
# detect the contours of each individual digit in the group,
# then sort the digit contours from left to right
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]
# loop over the digit contours
for c in digitCnts:
# compute the bounding box of the individual digit, extract
# the digit, and resize it to have the same fixed size as
# the reference OCR-A images
(x, y, w, h) = cv2.boundingRect(c)
roi = group[y:y + h, x:x + w]
roi = cv2.resize(roi, (57, 88))
# initialize a list of template matching scores
scores =
# loop over the reference digit name and digit ROI
for (digit, digitROI) in digits.items:
# 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)
# the classification for the digit ROI will be the reference
# digit name with the *largest* template matching score
groupOutput.append(str(np.argmax(scores)))
# draw the digit classifications around the group
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)
# update the output digits list
output.extend(groupOutput)
# display the output credit card information to the screen
print("Credit Card Type: {}".format(FIRST_NUMBER[output[0]]))
print("Credit Card #: {}".format("".join(output)))
cv2.imshow("Image", image)
cv2.waitKey(0)
到這裡,我們整體的程序就搭建完成,下面為我們程序的運行結果:
源碼地址:
提取碼:k5ra
作者簡介:李秋鍵,CSDN博客專家,CSDN達人課作者。碩士在讀於中國礦業大學,開發有taptap競賽獲獎等等。
全球Python調查報告:Python 2正在消亡,PyCharm比VS Code更受歡迎來了來了!趨勢預測算法大PK!10行Python代碼能實現什麼高端操作?無代碼來了,還要程式設計師嗎?沒錯,你離分布式搜索只差一個Elasticsearch入門!再見,Eclipse | 原力計劃區塊鏈共識算法總結 | 原力計劃