def process_the_template(template_ref): # 读取图片 template_ref_image =cv2.imread(template_ref) # 转化为灰度图片 template_ref_gray= cv2.cvtColor(template_ref_image,cv2.COLOR_BGR2GRAY) # 二值图像 ret,ref = cv2.threshold(template_ref_gray, 10, 255, cv2.THRESH_BINARY_INV) # cv_show('ref', ref) # 计算轮廓 # cv2.findContours()函数接受的参数为二值图,即黑白的(不是灰度图),cv2.RETR_EXTERNAL只检测外轮廓,cv2.CHAIN_APPROX_SIMPLE只保留终点坐标 # 返回的list中每个元素都是图像中的一个轮廓 #获得维度的轮廓 ref_, refCnts, hierarchy = cv2.findContours(ref.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) cv2.drawContours(template_ref_image, refCnts, -1, (0, 0, 255), 3) # cv_show('ref_with_refCnts',template_ref_image) #一共有10个外轮廓 print("Contours Mount of the ref is ",np.array(refCnts).shape[0]) # 对轮廓进行排序,从左到右,从上到下 refCnts = myutils.sort_contours(refCnts, method="left-to-right")[0] ref_dict={} # 遍历每一个轮廓,0,1,2,3,4,5,6,7,8,9,进行resize,提取ROI for (i, c) in enumerate(refCnts): # 计算外接矩形并且resize成合适大小 (x, y, w, h) = cv2.boundingRect(c) roi = ref[y:y + h, x:x + w] roi = cv2.resize(roi, (57, 88)) # 每一个数字对应每一个模板 ref_dict[i] = roi return ref_dict
def read_process_template(template_path): # 读取一个模板图像 img = cv2.imread(template_path) # 灰度图 ref = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 二值图像 一般的(BINARY)效果是: # 将一个灰色的图片,变成要么是白色要么就是黑色。 # (大于规定thresh值就是设置的最大值(常为255,也就是白色)) ref = cv2.threshold(ref, 10, 255, cv2.THRESH_BINARY_INV)[1] # cv_show('',ref) # 计算轮廓 # cv2.findContours()函数接受的参数为二值图,即黑白的(不是灰度图), # cv2.RETR_EXTERNAL只会返回最外边的的轮廓,所有的子轮廓都会被忽略掉。, # cv2.CHAIN_APPROX_SIMPLE会压缩轮廓,将轮廓上冗余点去掉,比如说四边形就会只储存四个角点。 _, refCnts, _ = cv2.findContours(ref.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 画出所有的边框 cv2.drawContours(img, refCnts, -1, (0, 0, 255), 3) # cv_show('',img) refCnts = myutils.sort_contours(refCnts, method="left-to-right")[0] # 排序,从左到右,从上到下 digits = {} # 遍历每一个轮廓 for (i, c) in enumerate(refCnts): # 计算外接矩形并且resize成合适大小 (x, y, w, h) = cv2.boundingRect(c) roi = ref[y:y + h, x:x + w] roi = cv2.resize(roi, (template_high, template_wigth)) # cv_show("",roi) # 每一个数字对应每一个模板 digits[i] = roi return digits
# 二值图像,因为做轮廓检测输入进去的一般都为一个二值图像 ref = cv2.threshold(ref, 10, 255, cv2.THRESH_BINARY_INV)[1] cv_show('ref', ref) # 计算轮廓 #cv2.findContours()函数接受的参数为二值图,即黑白的(不是灰度图),cv2.RETR_EXTERNAL只检测外轮廓,cv2.CHAIN_APPROX_SIMPLE只保留终点坐标 #返回的list中每个元素都是图像中的一个轮廓 ref_, refCnts, hierarchy = cv2.findContours( ref.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) #注意传进去的图像要进行一个.copy(),返回的参数refCnts是轮廓 cv2.drawContours(img, refCnts, -1, (0, 0, 255), 3) #-1表示显示所有轮廓 cv_show('img', img) #将轮廓画出来看一下 print(np.array(refCnts).shape) #打印出来为10,表示10个轮廓 refCnts = myutils.sort_contours(refCnts, method="left-to-right")[0] #对轮廓进行排序,从左到右,从上到下 digits = {} # 遍历每一个轮廓,i是数值,c是对应的轮廓 for (i, c) in enumerate(refCnts): # 计算外接矩形并且resize成合适大小 (x, y, w, h) = cv2.boundingRect(c) roi = ref[y:y + h, x:x + w] roi = cv2.resize(roi, (57, 88)) #调整矩形框的大小 # 每一个数字对应每一个模板 digits[i] = roi # 初始化卷积核 rectKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 3)) sqKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
gray_tem = cv.cvtColor(template, cv.COLOR_BGR2GRAY) ret, bi_tem = cv.threshold(gray_tem, 127, 255, cv.THRESH_BINARY) # cv_show("res", bi_tem) # 展示模板的二值图像 # 轮廓检测(outside) bt = bi_tem.copy() contours, hierarchy = cv.findContours(bt, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE) # draw contours contours_res = cv.drawContours(template, contours, -1, (0, 255, 0), 3) # 在二值图上得到, 需要画在原图上, # cv_show("contours_res", contours_res) print(np.array(contours).shape) # 对轮廓进行了排序从左到右 contours = myutils.sort_contours(contours, method="left-to-right")[0] digits = {} # 存模板的数字 print(digits) # 遍历轮廓, 外接矩形 for (i, c) in enumerate(contours): # c 是每个轮廓的终点坐标 讲一个可遍历的数据对象组合成一个索引序列 (x, y, w, h) = cv.boundingRect(c) # 计算外接矩形, resize 成合适大小 # 扣模板 roi = gray_tem[y:y + h, x:x + w] # 每个roi对应一个数字 roi = cv.resize(roi, (57, 85)) # 模板拆分数字 digits[i] = roi # 每个数字对应一个模板 # image of detecting # 初始化卷积核 rectKernel = cv.getStructuringElement(cv.MORPH_RECT, (9, 3)) #
#灰度图 ref = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) cv_show('灰度图', ref) #二值图 ref = cv2.threshold(ref, 10, 255, cv2.THRESH_BINARY_INV)[1] cv_show('二值图', ref) # 计算轮廓 # cv2.findContours()函数接受的参数为二值图,即黑白的(不是灰度图),cv2.RETR_EXTERNAL只检测外轮廓,cv2.CHAIN_APPROX_SIMPLE只保留终点坐标 # 返回的list中每个元素都是图像中的一个轮廓 #三个返回值:图像,轮廓,轮廓的层析结构 ref_, refCnts, hierarchy = cv2.findContours(ref.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) cv2.drawContours(img, refCnts, -1, (0, 0, 255), 3) cv_show('画出模板轮廓', img) print(np.array(refCnts).shape) refCnts = myutils.sort_contours(refCnts, method='left-to-right')[0] #排序,从左到右,从上到下 digits = {} #遍历每一个轮廓 for (i, c) in enumerate(refCnts): # 计算外接矩形并且resize成合适大小 (x, y, w, h) = cv2.boundingRect(c) roi = ref[y:y + h, x:x + w] roi = cv2.resize(roi, (57, 88)) # 每一个数字对应每一个数字模板矩形 digits[i] = roi #****************************模板处理结束,开始输入数据处理 #print(digits) #初始化卷积核 rectKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 3))
# 【二、模板处理流程】: 轮廓检测, 外接矩形, 抠出模板, 让模板对应每个数值 # 1.计算轮廓 ''' cv2.findContours()函数接受的参数为二值图,即黑白的(不是灰度图), cv2.RETR_EXTERNAL只检测外轮廓, cv2.CHAIN_APPROX_SIMPLE只保留终点坐标 返回的list中每个元素都是图像中的一个轮廓 ''' refCnts = cv2.findContours( ref.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[0] # copy是因为以后还要用到ref,用copy以保留 img = cv2.drawContours(img, refCnts, -1, (0, 255, 0), 2) # 轮廓在二值图上得到, 画是画在原图上( 参数-1代表画所有的轮廓 ) cv_show('template_Contours', img) print(np.array(refCnts, dtype=object).shape) # 10个轮廓,所以是10 refCnts = myutils.sort_contours(refCnts, method="left-to-right")[0] # 排序 digits = {} # 2.遍历每一个轮廓,外接矩形 for (i, c) in enumerate(refCnts): # c是每个轮廓的终点坐标 # 计算外接矩形并且resize成合适大小 (x, y, w, h) = cv2.boundingRect(c) # 3.抠出模板 roi = ref[y:y + h, x:x + w] # 每个roi对应一个数字 # print(roi.shape) roi = cv2.resize(roi, (57, 88)) # 太小,调大点 # 4.每一个数字对应每一个模板 digits[i] = roi # cv2.imshow('roi_'+str(i),roi) # cv2.waitKey(0) # print(digits)
def cv_credit_card(img,image): FIRST_NUMBER = { #字典 "3":"American Express", "4":"Visa", "5":"MasterCart", "6":"Discover Card", } #cv_show('template',img) gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)#转为灰度图 #cv_show('gray',gray) binary = cv2.threshold(gray,10,255,cv2.THRESH_BINARY_INV)[1] #注意阈值二值化函数返回的参数有两个!! #cv_show('binary',binary) #计算轮廓 #cv2.findContours()函数接受的参数为二值图。cv2.RETR_EXTERNAL只检测最外围的图像,cv2.CHAIN_APPROX_SIMPLE只保留中点坐标 #返回的list中每个元素都是图像中的一个轮廓 refCnts,hierarchy = cv2.findContours(binary.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE) cv2.drawContours(img,refCnts,-1,(0,0,255),3) #画出轮廓 #cv_show('img',img) #从左到右排序。0-9 refCnts = myutils.sort_contours(refCnts,method="left-to-right")[0] digits= {} for (i,c) in enumerate(refCnts): #计算外接矩形 (x,y,w,h) = cv2.boundingRect(c) #截取图像 roi = binary[y:y+h,x:x+w] #重新设定大小 roi = cv2.resize(roi,(57,88)) #设定digits digits[i]=roi ###以上为模板的处理,以下为图片处理 #初始化卷积核 rectKernel = cv2.getStructuringElement(cv2.MORPH_RECT,(9,3)) sqKernel = cv2.getStructuringElement(cv2.MORPH_RECT,(5,5)) #cv_show('image',image) image = myutils.resize(image,width=300) image_gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY) #转化为灰度图 image_tophat = cv2.morphologyEx(image_gray,cv2.MORPH_TOPHAT,rectKernel) #礼帽处理,突出更明亮的区域 #cv_show('tophat',image_tophat) gradX = cv_sobel_x(image_tophat) #水平方向梯度滤波处理 #cv_show('gradX',gradX) gradX = cv2.morphologyEx(gradX,cv2.MORPH_CLOSE,rectKernel) #闭操作,让数字连在一起 #cv_show('gradX_MORPH_CLOSE',gradX) image_threshold = cv2.threshold(gradX,0,255,cv2.THRESH_BINARY|cv2.THRESH_OTSU)[1] #THRESH_OTSU自动寻找合适的阈值,适合双峰,需把阈值下限设为0 #cv_show('image_threshold',image_threshold) image_threshold = cv2.morphologyEx(image_threshold,cv2.MORPH_CLOSE,sqKernel) threshCnts,hierarchy = cv2.findContours(image_threshold.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE) #计算最外层轮廓 cnts = threshCnts cur_img = image.copy() cv2.drawContours(cur_img,cnts,-1,(0,0,255),3) #画出轮廓 #cv_show('cur_img',cur_img) locs=[] #轮廓位置 for (i,c) in enumerate(cnts): (x,y,w,h) = cv2.boundingRect(c) #寻找矩形 ar = w/float(h) #求宽和高的比例 if ar>2.5 and ar<4.0: #把不符合的筛出去 if(w>40 and w <55)and(h>10 and h <20): locs.append((x,y,w,h)) locs = sorted(locs,key=lambda x:x[0]) #排个序 output = [] for (i,(gX,gY,gW,gH)) in enumerate(locs): groupOutput = [] group = image_gray[gY - 5:gY + gH + 5,gX-5:gX + gW + 5] group = cv2.threshold(group,0,255,cv2.THRESH_BINARY|cv2.THRESH_OTSU)[1] #自适应二值化处理 digitCnts,hierarchy = cv2.findContours(group.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE) #计算最外层轮廓 digitCnts = contours.sort_contours(digitCnts,method = "left-to-right")[0] for c in digitCnts: (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) #print(roi) #匹配度 scores=[] for (digit,digitROI) in digits.items(): #遍历求匹配度,在模板中计算每一个得分 result = cv2.matchTemplate(roi,digitROI,cv2.TM_CCOEFF) (_,score,_,_) = cv2.minMaxLoc(result) scores.append(score) #得到最合适的数字 groupOutput.append(str(np.argmax(scores))) #画出来 cv2.rectangle(image,(gX-5,gY-5),(gX+gW+5,gY+gH+5),(0,0,255),1) cv2.putText(image, "".join(groupOutput),(gX,gY-15),cv2.FONT_HERSHEY_SIMPLEX,0.65,(0,0,255),2) output.extend(groupOutput) return image,output
# 灰度 ref = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) cv_show(ref, 'ref') # 二值化 ref = cv2.threshold(ref, 127, 255, cv2.THRESH_BINARY_INV)[1] cv_show(ref, 'ref') # 计算轮廓 ref_, refCnts, hierarchy = cv2.findContours(ref.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) cv2.drawContours(img, refCnts, -1, (0, 0, 255), 3) cv_show(img, 'img') # print(np.array(refCnts).shape) refCnts = myutils.sort_contours(refCnts)[0] digits = {} # 遍历每一个轮廓 for (i, c) in enumerate(refCnts): # 计算外接矩形且resize成合适大小 (x, y, w, h) = cv2.boundingRect(c) roi = ref[y:y + h, x:x + w] roi = cv2.resize(roi, (57, 88)) # 每个数字对应一个模板 digits[i] = roi # 初始化卷积核 rectKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 3)) sqKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
cv_show('ref', ref) # 二值图像 ref = cv2.threshold(ref, 10, 255, cv2.THRESH_BINARY_INV)[1] cv_show('ref', ref) # 计算轮廓 # cv2.findContours()函数接受的参数为二值图,即黑白的(不是灰度图),cv2.RETR_EXTERNAL只检测外轮廓,cv2.CHAIN_APPROX_SIMPLE只保留终点坐标 # 返回的list中每个元素都是图像中的一个轮廓 ref_, ref_counts, hierarchy = cv2.findContours(ref.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) cv2.drawContours(img, ref_counts, -1, (0, 0, 255), 3) cv_show('img', img) print(np.array(ref_counts).shape) ref_counts = myutils.sort_contours(ref_counts, method="left-to-right")[0] # 排序, 从左到右, 从上到下 digits = {} # 遍历每一个轮廓 for (i, c) in enumerate(ref_counts): # 计算外接矩形并且resize成合适大小 (x, y, w, h) = cv2.boundingRect(c) roi = ref[y:y + h, x:x + w] roi = cv2.resize(roi, (57, 88)) # 每一个数字对应每一个模板 digits[i] = roi # 初始化卷积核 rectKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 3))
def process_the_target_image(srcImage,ref_dict): # 初始化卷积核 rectKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 3)) sqKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5)) # 读取输入图像,预处理 image = cv2.imread(srcImage) # cv_show('image', image) image = myutils.resize(image, width=300) gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # cv_show('gray', gray) # 礼帽操作,突出更明亮的区域 tophat = cv2.morphologyEx(gray, cv2.MORPH_TOPHAT, rectKernel) # cv_show('tophat', tophat) # 计算X方向的梯度,突出edage gradX = cv2.Sobel(tophat, ddepth=cv2.CV_32F, dx=1, dy=0, # ksize=-1相当于用3*3的 ksize=-1) #对梯度进行归一化操作 gradX = np.absolute(gradX) (minVal, maxVal) = (np.min(gradX), np.max(gradX)) gradX = (255 * ((gradX - minVal) / (maxVal - minVal))) gradX = gradX.astype("uint8") print(np.array(gradX).shape) # cv_show('gradX', gradX) # 通过闭操作(先膨胀,再腐蚀)将数字连在一起 gradX = cv2.morphologyEx(gradX, cv2.MORPH_CLOSE, rectKernel) # cv_show('gradX', gradX) # THRESH_OTSU会自动寻找合适的阈值,适合双峰,需把阈值参数设置为0 thresh = cv2.threshold(gradX, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1] # cv_show('thresh', thresh) # 再来一个闭操作 thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, sqKernel) # 再来一个闭操作 # cv_show('thresh2', thresh) # 计算轮廓 thresh_, threshCnts, hierarchy = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) cnts = threshCnts cur_img = image.copy() cv2.drawContours(cur_img, cnts, -1, (0, 0, 255), 3) # cv_show('img', cur_img) locs = [] # 遍历轮廓 for (i, c) in enumerate(cnts): # 计算外接矩形 (x, y, w, h) = cv2.boundingRect(c) #计算长宽比 ar = w / float(h) # 选择合适的区域,根据实际任务来,这里的基本都是四个数字一组 #比较长宽比 if ar > 2.5 and ar < 4.0: #比较w,h具体长度 if (w > 40 and w < 55) and (h > 10 and h < 20): # 符合的留下来 locs.append((x, y, w, h)) print(len(locs)) # 将符合的轮廓从左到右排序,空间顺序 locs = sorted(locs, key=lambda x: x[0]) #展示一下结果 my_curImage = image.copy() for boudingbox in locs: cv2.rectangle(my_curImage,(boudingbox[0],boudingbox[1]),(boudingbox[0]+boudingbox[2],boudingbox[1]+boudingbox[3]), (0,0,255),2) # cv_show("rect",my_curImage) '''提取每个boundingbox的图片信息''' output=[] # 遍历每一个轮廓中的数字 for (i, (gX, gY, gW, gH)) in enumerate(locs): # initialize the list of group digits groupOutput = [] # 根据坐标提取每一个组 # 稍微扩充一下这个roi group = gray[gY - 5:gY + gH + 5, gX - 5:gX + gW + 5] # cv_show('group', group) # 预处理,OTSU阈值化 ret,group = cv2.threshold(group, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU) # cv_show('group', group) # 计算每一组的轮廓 group_, digitCnts, hierarchy = cv2.findContours(group.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) #对轮廓进行空间排序 digitCnts = myutils.sort_contours(digitCnts, method="left-to-right")[0] #显示这个轮廓 # mygroup=group.copy() # cv2.drawContours(mygroup, digitCnts, -1, (0, 0, 255), 3) # cv_show("group_contours",mygroup) # 计算每一组中的每一个数值 for c in digitCnts: # 找到当前数值的轮廓,resize成合适的的大小 (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) # 计算匹配得分 scores = [] # 在模板中计算每一个得分 for (digit, digitROI) in ref_dict.items(): # 模板匹配 ''' cv2.TM_CCOEFF (系数匹配法) cv2.TM_CCOEFF_NORMED(相关系数匹配法) cv2.TM_CCORR (相关匹配法) cv2.TM_CCORR_NORMED (归一化相关匹配法) cv2.TM_SQDIFF (平方差匹配法) cv2.TM_SQDIFF_NORMED (归一化平方差匹配法 ''' result = cv2.matchTemplate(roi, digitROI, cv2.TM_CCOEFF) #根据 匹配方法不同,选择最大还是最小 (minval, maxval, minloc,maxloc) = cv2.minMaxLoc(result) scores.append(maxval) # 得到最合适的数字 groupOutput.append(str(np.argmax(scores))) # 画出来 cv2.rectangle(image, (gX - 5, gY - 5), (gX + gW + 5, gY + gH + 5), (0, 0, 255), 1) cv2.putText(image, "".join(groupOutput), (gX, gY - 15), cv2.FONT_HERSHEY_SIMPLEX, 0.65, (0, 0, 255), 2) # 得到结果 output.extend(groupOutput) cv_show("img",image) return output
# read template img = cv2.imread(args['template']) cv_show(img) # 灰階 ref = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) cv_show(ref) # 二值 ref = cv2.threshold(ref, 10, 255, cv2.THRESH_BINARY_INV)[1] cv_show(ref) # 輪廓檢測 ref_cnts, hierarchy = cv2.findContours(ref.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 只檢測外輪廓 cv2.drawContours(img, ref_cnts, -1, (0, 0, 255), 3) cv_show(img) print(np.array(ref_cnts).shape) # 排序 ref_cnts = myutils.sort_contours(ref_cnts, method='left-to-right')[0] digits = {} # 遍歷輪廓 for (i, c) in enumerate(ref_cnts): (x, y, w, h) = cv2.boundingRect(c) roi = ref[y: y+h, x: x+w] roi = cv2.resize(roi, (57, 88)) # 每個數字對應一個模板 digits[i] = roi # 對輸入圖像操作 # 初始化捲積核 rect_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 3)) sq_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5)) # 圖像輸入及預處理 image = cv2.imread(args['image'])
# (2.3) convert template to binary image ref = cv2.threshold(ref, 10, 255, cv2.THRESH_BINARY_INV)[1] cv_show('ref',ref) # (2.4) compute external contours with function: cv2.findContours() # (2.4) parameter 1: ref.copy(): binary image (black-white) # (2.4) parameter 2: cv2.RETR_EXTERNAL: only check external contours # (2.4) parameter 3: cv2.CHAIN_APPROX_SIMPLE: only save terminal coordinate refCnts = cv2.findContours(ref.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # return contour of each number in template image refCnts = refCnts[1] if imutils.is_cv3() else refCnts[0] # check opencv version # print('refCnts:',refCnts) cv2.drawContours(img, refCnts, -1, (0,0,255), 3) # -1: means it draws all contours cv_show('img',img) print('shape of refCnts:', np.array(refCnts).shape) refCnts = myutils.sort_contours(refCnts, method="left-to-right")[0] # sort every contour by left-to-right order # (2.5) traverse template contours list and save it in a dictionary digits = {} # traverse contour of each number in template image for (i, c) in enumerate(refCnts): # compute external rectangle and resize it (x, y, w, h) = cv2.boundingRect(c) roi = ref[y:y+h, x:x+w] roi = cv2.resize(roi, (57,88)) # map each contour with number (0---0, 1---1, ......) with a dictionary digits[i] = roi # PART III: operations for test image # (3.1) initialize convolutional kernel
def process_the_image(image): # 首先是预处理,包括灰度图片,高斯滤波和Canny边缘提取 contours_img = image.copy() gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) blurred = cv2.GaussianBlur(gray, (5, 5), 0) # cv_show('blurred', blurred) edged = cv2.Canny(blurred, 75, 200) # cv_show('edged', edged) # 轮廓检测,检测外轮廓 cnts = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[1] #轮廓画图 cv2.drawContours(contours_img, cnts, -1, (0, 0, 255), 3) # cv_show('contours_img', contours_img) docCnt = None # 外轮廓不一定是一个矩形,根据轮廓面积排序 # 确保检测到了最外围的四大点作为矩形, if len(cnts) > 0: # 根据轮廓大小进行排序 cnts = sorted(cnts, key=cv2.contourArea, reverse=True) # 遍历每一个轮廓 for c in cnts: # 多边形近似 peri = cv2.arcLength(c, True) approx = cv2.approxPolyDP(c, 0.02 * peri, True) # 准备做透视变换,确保是一个矩形 if len(approx) == 4: docCnt = approx break # print(docCnt.shape) # shape is (4,1,2) '''docCnt 进行坐标变换''' warped = Four_points_transform(gray, docCnt) # cv_show('warped', warped) warped_copy = warped.copy() ''' 提取圆形的轮廓 ''' # 对变换后的图像进行Ostu阈值处理 ret, thresh = cv2.threshold(warped, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU) # cv_show('thresh', thresh) # 二值的轮廓 thresh_Contours = thresh.copy() # 进行轮廓检查 cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[1] cv2.drawContours(thresh_Contours, cnts, -1, (0, 255, 0), 3) # cv_show('thresh_Contours', thresh_Contours) questionCnts = [] # 遍历,得到自己想要的轮廓信息信息,放在quesetionCnts中 for c in cnts: # 计算比例和大小 (x, y, w, h) = cv2.boundingRect(c) ar = w / float(h) # 根据实际情况指定标准,提取比较大的轮廓,长宽比在0.9到1.1 if w >= 20 and h >= 20 and ar >= 0.9 and ar <= 1.1: questionCnts.append(c) # 显示自己要提取的部分轮廓 cv2.drawContours(warped_copy, questionCnts, -1, (0, 255, 0), 3) # cv_show('circles', warped_copy) print(len(questionCnts)) # 将提取出来的轮廓按照空间顺序进行排序 # 按照从上到下进行排序 questionCnts = sort_contours(questionCnts, method="top-to-bottom")[0] correct = 0 # 每排有5个选项,q代表第几行,i=0,i=5,i=10,i=15,i=20 for (q, i) in enumerate(np.arange(0, len(questionCnts), 5)): # 排序,默认从左向右排序 cnts = sort_contours(questionCnts[i:i + 5])[0] # 学生选择的那个的非零的值应该是最大的 student_seleted = None # 遍历每一个结果 for (j, c) in enumerate(cnts): # 使用mask来判断结果 mask = np.zeros(thresh.shape, dtype="uint8") cv2.drawContours(mask, [c], -1, 255, -1) # 最后一个-1表示填充 # cv_show('mask', mask) # 通过计算非零点数量来算是否选择这个答案,被涂抹的那个零点个数一定是最多的 mask = cv2.bitwise_and(thresh, thresh, mask=mask) # 统计此时的非零点的个数 total = cv2.countNonZero(mask) # 通过阈值判断 if student_seleted is None or total > student_seleted[0]: # 记录此时最大的total,并且此时的位置 j 代表学生选的那个选项 student_seleted = (total, j) # 正确的答案 color = (0, 0, 255) correct_answer = ANSWER_KEY[q] if student_seleted[1] == correct_answer: color = (0, 255, 0) correct = correct + 1 # 把真正的答案画出来绘图 cv2.drawContours(warped, [cnts[correct_answer]], -1, color, 3) #计算机最后的得分 score = (correct / 5.0) * 100 print("[INFO] score: {:.2f}%".format(score)) cv2.putText(warped, "{:.2f}%".format(score), (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 0, 255), 2) cv2.imshow("Original", image) cv2.imshow("Exam", warped) cv2.waitKey(0)