1. 项目思路流程
本项目旨在实现对信用卡上的数字进行自动识别,并输出信用卡类型和信用卡号码。项目的主要步骤如下:
-
导入所需的库:导入OpenCV、imutils、matplotlib和numpy等库,以便进行图像处理和显示。
-
加载图像:读取信用卡和数字图像,并将其转换为灰度图像,以便后续处理。
-
数字图像预处理:对数字图像进行阈值化处理,将数字区域分离出来,并通过轮廓查找找到每个数字的位置。
-
数字图像分割:对数字图像进行排序和处理,将每个数字提取出来,并保存在一个字典中。
-
信用卡图像预处理:对信用卡图像进行形态学处理,提取出信用卡号码的区域。
-
信用卡号码分割:对信用卡号码区域进行处理,分割出每个数字,并通过模板匹配方法与保存的数字模板进行对比,得到最终的信用卡号码。
-
输出结果:输出信用卡类型和信用卡号码。
2. 核心代码实现
以下是项目的核心代码实现,展示了数字图像预处理、信用卡图像预处理、数字识别等关键步骤的代码:
2.1 数字图像的预处理:
# 对数字图像进行阈值化处理,并查找数字轮廓
plt.figure('numbers阈值化及轮廓查找')
_,gray_bin = cv2.threshold(num_gray, 10, 255, cv2.THRESH_BINARY_INV)
plt.subplot(1,2,1)
plt.imshow(gray_bin, cmap='gray')
num_contours,_ = cv2.findContours(gray_bin.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(number, num_contours, -1, (0, 255, 0), 3)
plt.subplot(1,2,2)
plt.imshow(number,cmap='gray')
# 对数字轮廓进行排序和处理,将每个数字放入digits字典中
num_contours = contours.sort_contours(num_contours,method='left-to-right')[0]
digits = {}
for (i,c) in enumerate(num_contours):
(x,y,w,h) = cv2.boundingRect(c)
roi = gray_bin[y:y+h,x:x+w]
roi = cv2.resize(roi,(57,88))
digits[i] = roi
2.2 信用卡图像预处理:
# 形态学处理和边缘查找
plt.figure('card形态学处理及边缘查找')
#算子初始化
rectKernel = cv2.getStructuringElement(cv2.MORPH_RECT,(9,3))
sqKernel = cv2.getStructuringElement(cv2.MORPH_RECT,(5,5))
#礼帽运算
tophat = cv2.morphologyEx(card_gray,cv2.MORPH_TOPHAT,rectKernel)
plt.subplot(2,3,1)
plt.imshow(tophat,cmap='gray')
#梯度运算
gradX = np.abs(cv2.Sobel(tophat,cv2.CV_32F,1,0,ksize=3))
#归一化处理
(minVal,maxVal) = (np.min(gradX),np.max(gradX))
gradX = (255*((gradX-minVal)/(maxVal-gradX))).astype(np.uint8)
plt.subplot(2,3,2)
plt.imshow(gradX,cmap='gray')
#闭运算
gradX = cv2.morphologyEx(gradX,cv2.MORPH_CLOSE,rectKernel)
plt.subplot(2,3,3)
plt.imshow(gradX,cmap='gray')
#阈值化
gradX_bin = cv2.threshold(gradX,0,255,cv2.THRESH_BINARY|cv2.THRESH_OTSU)[1]
plt.subplot(2,3,4)
plt.imshow(gradX_bin,cmap='gray')
gradX_bin = cv2.morphologyEx(gradX_bin,cv2.MORPH_CLOSE,sqKernel)
plt.subplot(2,3,5)
plt.imshow(gradX_bin,cmap='gray')
# 卡片数字轮廓查找
card_contours,_ = cv2.findContours(gradX_bin.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
card_copy = card.copy()
cv2.drawContours(card_copy,card_contours,-1,(0,255,0),3)
plt.subplot(2,3,6)
plt.imshow(card_copy[:,:,::-1])
2.3 数字识别:
# 数字识别
plt.figure('结果')
locs = []
for (i,c) in enumerate(card_contours):
(x,y,w,h) = cv2.boundingRect(c)
print('第',i,'组数字',(x,y,w,h),'\n')
ar = w/float(h)
if ar>3 and ar<4.0:
if(w>50 and w<60) and (h>10 and h<20):
locs.append((x,y,w,h))
locs = sorted(locs,key=lambda x:x[0])
print(locs)
output = []
k=1
for (i,(gX,gY,gW,gH)) in enumerate(locs):
groupOutput = []
group = card_gray[gY-5:gY+gH+5,gX-5:gX+gW+5]
group = cv2.threshold(group,0,255,cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
plt.subplot(2,2,k)
plt.imshow(group,cmap='gray')
k+=1
group_contours,_ = cv2.findContours(group.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
group_contours = contours.sort_contours(group_contours,method='left-to-right')[0]
for c in group_contours:
(x,y,w,h) = cv2.boundingRect(c)
roi = group[y:y+h,x:x+w]
roi = cv2.resize(roi,(57,88))
scores = []
for (digit,digit_roi) in digits.items():
result = cv2.matchTemplate(roi,digit_roi,cv2.TM_CCOEFF)
(_,score,_,_) = cv2.minMaxLoc(result)
scores.append(score)
groupOutput.append(str(np.argmax(scores)))
cv2.rectangle(card,(gX-5,gY-5),(gX+gW+5,gY+gH+5),(0,255,0),3)
cv2.putText(card,"".join(groupOutput),(gX,gY-15),cv2.FONT_HERSHEY_SIMPLEX,0.65,(0,255,0),2)
output.extend(groupOutput)
3.运行结果展示
4. 项目经验与总结
在这个项目中,我们通过使用OpenCV和相关库,成功实现了对信用卡上的数字进行自动识别。在这个过程中,我们涉及到了图像预处理、形态学处理、边缘查找和模板匹配等技术。以下是一些项目经验和总结:
-
图像预处理非常重要:在图像识别任务中,图像预处理是一个非常重要的步骤。适当的预处理可以提高数字识别的准确性,例如在本项目中,通过阈值化处理和轮廓查找,成功分离出了数字区域。
-
形态学处理的应用:形态学处理是图像处理中常用的技术,可以用来提取图像的特定结构或形状。在信用卡图像处理中,通过形态学处理成功提取出了信用卡号码的区域。
-
模板匹配的局限性:本项目中使用了模板匹配的方法对数字进行识别,虽然简单且有效,但模板匹配对图像的光照和尺度变化敏感。在实际应用中,可能需要更加复杂的算法来提高数字识别的准确性。
-
数据集的重要性:如果要将此项目用于实际应用,建议使用更大规模和多样化的信用卡图像数据集进行训练和测试,以提高数字识别的泛化能力。
-
opencv函数变动:在opencv4及之后的版本中,findContours函数的返回值变成了两个,一个为roi的轮廓信息,另一个为层次信息。
-
参数修改:文章中对于数字的识别部分需要根据实际情况进行合理修改,否则可能无法检测到信用卡数字!
总体来说,这个项目对于理解图像处理和数字识别的基本原理是非常有帮助的。通过实际动手实现,可以更深入地理解算法的原理和局限性。希望本博客能帮助到其他对图像处理感兴趣的程序员,欢迎交流和指正。谢谢阅读!
项目借鉴总体流程与方法讲解_哔哩哔哩_bilibili。如有疑问或意见,请在评论区留言,我将尽快回复。谢谢!