
E:\python\opencv\bankCard OCR.py对模版图片的处理1转为灰度图tem_graycv.cvtColor(digitalTemplate,cv.COLOR_BGR2GRAY)2转为二值图方便查找轮廓要求前景为白色背景为黑色的tem_binarycv.threshold(tem_gray,10,255,cv.THRESH_BINARY_INV)[1]3查找轮廓contours,_cv.findContours(tem_binary.copy(),cv.RETR_EXTERNAL,cv.CHAIN_APPROX_SIMPLE)4将轮廓的外接矩阵进行排序根据外接矩阵的x坐标将矩阵进行从左到右的排序def sort_contours(contours, methodLeft-to-right): reverseFalse i0 if methodright-to-left or methodbottom-to-top: reverseTrue if methodtop-to-bottom or methodbottom-to-top: i1 boundingBoxes[cv.boundingRect(c) for c in contours] (contours,boundingBoxes)zip(*sorted(zip(contours,boundingBoxes), keylambda b:b[1][i],reversereverse)) return contours,boundingBoxes contours,boundingBoxessort_contours(contours,methodLeft-to-right)5构建字典用于存储数字与各个数字图像的对应关系#构建字典用于存储数字与图像的对应 digits{} #遍历每一个轮廓 for (i,b) in enumerate(boundingBoxes): #获取外接矩形并且resize成合适大小 (x,y,w,h)b roitem_binary[y:yh,x:xw] roicv.resize(roi,(57,88)) digits[i]roi对银行卡的处理1转为灰度图bankCard_graycv.cvtColor(bankCard,cv.COLOR_BGR2GRAY)2礼帽操作突出明亮的部分bankCard_tophatcv.morphologyEx(bankCard_gray,cv.MORPH_TOPHAT,rectKernel)3通过sobel算子找到图像的边缘分别在x轴和y轴进行梯度计算最后系数加和#sobel算子找到边缘 gradXcv.Sobel(bankCard_tophat,ddepthcv.CV_32F,dx1,dy0,ksize-1) #对比一下直接缩放再绝对值的操作 # gradX1cv.convertScaleAbs(gradX) # cv_show(gradX1) gradXnp.absolute(gradX) (minmal,maxmal)(np.min(gradX),np.max(gradX)) gradX(255*((gradX-minmal)/(maxmal-minmal))) gradXgradX.astype(uint8) # print(np.array(gradX).shape) # cv_show(gradX) gradYcv.Sobel(bankCard_tophat,ddepthcv.CV_32F,dx0,dy1,ksize-1) gradYnp.absolute(gradY) (minmal,maxmal)(np.min(gradY),np.max(gradY)) gradY(255*((gradY-minmal)/(maxmal-minmal))) gradYgradY.astype(uint8) # print(np.array(gradY).shape) # cv_show(gradY) gradXYcv.addWeighted(gradX,0.5,gradY,0.5,0)4通过膨胀和闭操作先膨胀再腐蚀将数字粘连到一起gradXYcv.dilate(gradXY,rectKernel)gradXYcv.morphologyEx(gradXY,cv.MORPH_CLOSE,rectKernel)5将图像转为二值图方便寻找轮廓threshcv.threshold(gradXY,0,255,cv.THRESH_BINARY|cv.THRESH_OTSU)[1]6寻找轮廓threshcontours,_cv.findContours(thresh.copy(),cv.RETR_EXTERNAL,cv.CHAIN_APPROX_SIMPLE) contoursthreshcontours7挑选出银行卡所在位置的轮廓的外接矩阵locs[] for (i,c) in enumerate(contours): (x,y,w,h)cv.boundingRect(c) arw/float(h) if y/bankCard.shape[1]0.32 and y/bankCard.shape[1]0.35: locs.append((x,y,w,h)) locssorted(locs,keylambda x:x[0])8对每个数字块进行处理1.将数字块区域转为二值图2.进行一个小小的膨胀确保每个数字都是一个整体核也不能太大防止粘连到其他数字3.寻找数字块中每个数字的轮廓并排序4.获取每个数字轮廓的外接矩阵并排序5.将数字矩阵与0--9数字模板进行匹配得到数字矩阵与每个数字的相似得分根据得分输出对应的数字output[] for (i,(gx,gy,gw,gh)) in enumerate(locs): groupOutput[] group1bankCard_gray[gy-5:gygh5,gx-5:gxgw5] cv_show(group1) # print(gy/bankCard.shape[1]) groupcv.threshold(group1,0,255,cv.THRESH_BINARY|cv.THRESH_OTSU)[1] cv_show(group) group_dilatecv.dilate(group,kernelnp.ones((3,3),np.uint8)) # cv_show(group_dilate) digitscnts,_cv.findContours(group_dilate,cv.RETR_EXTERNAL,cv.CHAIN_APPROX_SIMPLE) # imgcntscv.drawContours(group1,digitscnts,-1,(0,0,0),1) # cv_show(imgcnts) # print(len(digitscnts)) digitscntssort_contours(digitscnts,methodLeft-to-right)[0] for c in digitscnts: (x,y,w,h)cv.boundingRect(c) # cv.rectangle(group,(x,y),(xw,yh),(255,255,255),1) # cv_show(group) roigroup[y:yh,x:xw] roicv.resize(roi,(57,88)) # cv_show(roi) scores[] for (digit,digitROi) in digits.items(): resultcv.matchTemplate(roi,digitROi,cv.TM_CCOEFF_NORMED) (_,score,_,_)cv.minMaxLoc(result) scores.append(score) groupOutput.append(str(np.argmax(scores))) cv.rectangle(bankCard,(gx-5,gy-5),(gxgw5,gygh5),(0,0,255),1) cv.putText(bankCard,.join(groupOutput),(gx,gy-15),cv.FONT_HERSHEY_SIMPLEX,0.65,(0,0,255),2) output.extend(groupOutput) cv_show(bankCard)完整代码import cv2 as cv import matplotlib.pyplot as plt import numpy as np from matplotlib.pyplot import gray def cv_show(img,imgnameres): cv.imshow(imgname,img) cv.waitKey(0) cv.destroyAllWindows() templatesrc./data/digital template.png datasrc./data/bankCard/bankCard2.png digitalTemplatecv.imread(templatesrc) bankCardcv.imread(datasrc) # cv_show(digitaltemplate,digitalTemplate) # cv_show(bankCard,bankCard) #灰度图 tem_graycv.cvtColor(digitalTemplate,cv.COLOR_BGR2GRAY) # cv_show(tem_gray) #二值图像 tem_binarycv.threshold(tem_gray,10,255,cv.THRESH_BINARY_INV)[1] # cv_show(tem_binary) #计算轮廓 contours,_cv.findContours(tem_binary.copy(),cv.RETR_EXTERNAL,cv.CHAIN_APPROX_SIMPLE) # cv.drawContours(digitalTemplate,contours,-1,(0,0,255),3) # cv_show(digitalTemplate) # print(len(contours)) #排序从左到右从上到下 def sort_contours(contours, methodLeft-to-right): reverseFalse i0 if methodright-to-left or methodbottom-to-top: reverseTrue if methodtop-to-bottom or methodbottom-to-top: i1 boundingBoxes[cv.boundingRect(c) for c in contours] (contours,boundingBoxes)zip(*sorted(zip(contours,boundingBoxes), keylambda b:b[1][i],reversereverse)) return contours,boundingBoxes contours,boundingBoxessort_contours(contours,methodLeft-to-right) #验证 # for b in boundingBoxes: # cv.rectangle(digitalTemplate,(b[0],b[1]),(b[0]b[2],b[1]b[3]),(0, 0, 255), 3) # cv_show(digitalTemplate) #构建字典用于存储数字与图像的对应 digits{} #遍历每一个轮廓 for (i,b) in enumerate(boundingBoxes): #获取外接矩形并且resize成合适大小 (x,y,w,h)b roitem_binary[y:yh,x:xw] roicv.resize(roi,(57,88)) digits[i]roi #查看分隔后的图片 # for i in range(len(boundingBoxes)): # plt.subplot(2,5,i1),plt.imshow(digits[i]) # plt.title(f{i}),plt.xticks([]),plt.yticks([]) # plt.show() # cv_show(digits[i]) #初始化卷积核 rectKernelcv.getStructuringElement(cv.MORPH_RECT,(9,3)) sqKernelcv.getStructuringElement(cv.MORPH_RECT,(5,5)) #获取输入图像预处理 bankCardcv.resize(bankCard,dsizeNone,fx0.8,fy0.8) # cv_show(bankCard) #灰度图 bankCard_graycv.cvtColor(bankCard,cv.COLOR_BGR2GRAY) # cv_show(bankCard_gray) #礼帽操作突出更明亮的区域 bankCard_tophatcv.morphologyEx(bankCard_gray,cv.MORPH_TOPHAT,rectKernel) # cv_show(bankCard_tophat) #sobel算子找到边缘 gradXcv.Sobel(bankCard_tophat,ddepthcv.CV_32F,dx1,dy0,ksize-1) #对比一下直接缩放再绝对值的操作 # gradX1cv.convertScaleAbs(gradX) # cv_show(gradX1) gradXnp.absolute(gradX) (minmal,maxmal)(np.min(gradX),np.max(gradX)) gradX(255*((gradX-minmal)/(maxmal-minmal))) gradXgradX.astype(uint8) # print(np.array(gradX).shape) # cv_show(gradX) gradYcv.Sobel(bankCard_tophat,ddepthcv.CV_32F,dx0,dy1,ksize-1) gradYnp.absolute(gradY) (minmal,maxmal)(np.min(gradY),np.max(gradY)) gradY(255*((gradY-minmal)/(maxmal-minmal))) gradYgradY.astype(uint8) # print(np.array(gradY).shape) # cv_show(gradY) gradXYcv.addWeighted(gradX,0.5,gradY,0.5,0) # cv_show(gradXY) #通过闭操作先膨胀再腐蚀将数字连在一起 gradXYcv.dilate(gradXY,rectKernel) # cv_show(gradXY) gradXYcv.morphologyEx(gradXY,cv.MORPH_CLOSE,rectKernel) # cv_show(gradXY) threshcv.threshold(gradXY,0,255,cv.THRESH_BINARY|cv.THRESH_OTSU)[1] # cv_show(thresh) # threshcv.morphologyEx(thresh,cv.MORPH_CLOSE,sqKernel) # cv_show(thresh) threshcontours,_cv.findContours(thresh.copy(),cv.RETR_EXTERNAL,cv.CHAIN_APPROX_SIMPLE) contoursthreshcontours # cur_imgbankCard.copy() # cv.drawContours(cur_img,contours,-1,(0,0,255),3) # cv_show(cur_img) locs[] # cur_imgbankCard.copy() for (i,c) in enumerate(contours): (x,y,w,h)cv.boundingRect(c) if y/bankCard.shape[1]0.32 and y/bankCard.shape[1]0.35: locs.append((x,y,w,h)) # cv.rectangle(cur_img,(x,y),(xw,yh),(0,0,255),2) # cv_show(cur_img) locssorted(locs,keylambda x:x[0]) output[] for (i,(gx,gy,gw,gh)) in enumerate(locs): groupOutput[] group1bankCard_gray[gy-5:gygh5,gx-5:gxgw5] cv_show(group1) # print(gy/bankCard.shape[1]) groupcv.threshold(group1,0,255,cv.THRESH_BINARY|cv.THRESH_OTSU)[1] cv_show(group) group_dilatecv.dilate(group,kernelnp.ones((3,3),np.uint8)) # cv_show(group_dilate) digitscnts,_cv.findContours(group_dilate,cv.RETR_EXTERNAL,cv.CHAIN_APPROX_SIMPLE) # imgcntscv.drawContours(group1,digitscnts,-1,(0,0,0),1) # cv_show(imgcnts) # print(len(digitscnts)) digitscntssort_contours(digitscnts,methodLeft-to-right)[0] for c in digitscnts: (x,y,w,h)cv.boundingRect(c) # cv.rectangle(group,(x,y),(xw,yh),(255,255,255),1) # cv_show(group) roigroup[y:yh,x:xw] roicv.resize(roi,(57,88)) # cv_show(roi) scores[] for (digit,digitROi) in digits.items(): resultcv.matchTemplate(roi,digitROi,cv.TM_CCOEFF_NORMED) (_,score,_,_)cv.minMaxLoc(result) scores.append(score) groupOutput.append(str(np.argmax(scores))) cv.rectangle(bankCard,(gx-5,gy-5),(gxgw5,gygh5),(0,0,255),1) cv.putText(bankCard,.join(groupOutput),(gx,gy-15),cv.FONT_HERSHEY_SIMPLEX,0.65,(0,0,255),2) output.extend(groupOutput) cv_show(bankCard)