#-*-coding:utf-8 -*- import cv2 import numpy as np from PIL import Image import imutils from imutils import contours from imutils.perspective import four_point_transform import os import json from PIL import Image,ImageDraw import pyzbar.pyzbar as pbar class CV2img: """识别出试卷上的类答题卡区域 """ def __init__(self,image_path="test.jpg",size="A4"): self.image_path = image_path self.image = cv2.imread(self.image_path) #图片的宽高度 self.width = self.image.shape[1] self.height = self.image.shape[0] #图片转成灰度图 self.gray = cv2.cvtColor(self.image, cv2.COLOR_BGR2GRAY) #边缘检测后的图 #self.edged = cv2.Canny(self.gray, 75, 200) self.blur = cv2.GaussianBlur(self.gray,(5,5),0) #对灰度图进行二值化处理 #ret,thresh = cv2.threshold(self.gray,0,255,cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU) ret,thresh = cv2.threshold(self.blur,0,255,cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU) #ret,thresh = cv2.threshold(self.gray,0,100,cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU) self.thresh = thresh #if size == "A4": # self.thresh = cv2.resize(thresh, (2480, 3480), interpolation=cv2.INTER_LANCZOS4) #else: # self.thresh = cv2.resize(thresh, (4870, 3480), interpolation=cv2.INTER_LANCZOS4) #输出二值化操作后的图像 spt_lst = os.path.splitext(self.image_path) close_path = spt_lst[0] + '_thresh_new' + spt_lst[1] cv2.imwrite(close_path,self.thresh) def _erode(self,w,h): ''' 图像腐蚀操作 ''' #腐蚀核大小 edsize = cv2.getStructuringElement(cv2.MORPH_RECT,(w,h)) self.erode_image = cv2.erode(self.thresh,edsize) #输出腐蚀操作后的图像 spt_lst = os.path.splitext(self.image_path) close_path = spt_lst[0] + '_erode' + spt_lst[1] cv2.imwrite(close_path,self.erode_image) return self.erode_image def _erode_dilate(self,w,h): ''' 图像腐蚀操作 ''' #腐蚀核大小 edsize = cv2.getStructuringElement(cv2.MORPH_RECT,(w,h)) self.erode_dilate_image = cv2.dilate(self.erode_image,edsize) #输出腐蚀操作后的图像 spt_lst = os.path.splitext(self.image_path) close_path = spt_lst[0] + '_erode_dilate' + spt_lst[1] cv2.imwrite(close_path,self.erode_dilate_image) return self.erode_dilate_image def _dilate(self,w,h): ''' 图像膨胀操作 ''' dilsize = cv2.getStructuringElement(cv2.MORPH_RECT,(w,h)) self.dilate_image = cv2.dilate(self.thresh,dilsize) #输出膨胀操作后的图像 spt_lst = os.path.splitext(self.image_path) close_path = spt_lst[0] + '_dilate' + spt_lst[1] cv2.imwrite(close_path,self.dilate_image) return self.dilate_image def _dilate_erode(self,w,h): ''' 图像膨胀操作 ''' dilsize = cv2.getStructuringElement(cv2.MORPH_RECT,(w,h)) self.dilate_erode_image = cv2.erode(self.dilate_image,dilsize) #输出膨胀操作后的图像 spt_lst = os.path.splitext(self.image_path) close_path = spt_lst[0] + '_dilate_erode' + spt_lst[1] cv2.imwrite(close_path,self.dilate_erode_image) return self.dilate_erode_image def _open(self,w=10,h=10): """开操作先腐蚀后膨胀 """ self._erode(w,h) #自定义开操作 self.open_image = self._erode_dilate(w,h) #输出闭操作后的图像 spt_lst = os.path.splitext(self.image_path) close_path = spt_lst[0] + '_open' + spt_lst[1] cv2.imwrite(close_path,self.open_image) return self.open_image def _close(self,w=20,h=40): """闭操作先膨胀后腐蚀 """ self._dilate() #自定义闭操作 self.close_image = self._dilate_erode(w,h) #输出闭操作后的图像 spt_lst = os.path.splitext(self.image_path) close_path = spt_lst[0] + '_close' + spt_lst[1] cv2.imwrite(close_path,self.close_image) return self.close_image def get_cnts(self,std_w=None,std_h=None): """识别出答案轮廓 """ self._open(std_w,std_h) cnts = cv2.findContours(self.open_image, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)[0] #cnts = cv2.findContours(self.open_image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[0] #cnts = cnts[0] if imutils.is_cv2() else cnts[0] all_c = [] if len(cnts) > 0: cnts = sorted(cnts, key=cv2.contourArea, reverse=True) all_c = [] for c in cnts: peri = 0.01*cv2.arcLength(c, False) approx = cv2.approxPolyDP(c, peri, True) if len(approx)==4 or True: (x, y, w, h) = cv2.boundingRect(c) #标识出识别出的机型轮廓并输出 cv2.drawContours(self.image,[c],-1,(255,0,255),3) spt_lst = os.path.splitext(self.image_path) draw_path = spt_lst[0] + '_draw' + spt_lst[1] cv2.imwrite(draw_path,self.image) all_c.append({'x':x,'y':y,'w':w,'h':h}) return all_c def get_std_points(self,ow,oh): """ """ std_points = [] cnts = self.get_cnts(ow,oh) for c in cnts: std_points.append(c) std_points = sorted(std_points,key=lambda x:x["x"]+x["y"]) return std_points def rec_ans(self,std_ans_list): """ """ ans_list = [] ans_dct = {0:"A",1:"B",2:"C",3:"D"} for index,point in enumerate(std_ans_list): x1 = point["x"] y1 = point["y"] x2 = point["x"]+point["w"] y2 = point["y"]+point["h"] count = 0 roi = self.open_image[y1:y2,x1:x2] width = roi.shape[0] height = roi.shape[1] for i in range(width): for j in range(height): if roi[i,j] == 255: count += 1 if count > 80: ans_list.append(ans_dct[index]) return ",".join(ans_list) def get_kh_qrcode(self): """ """ self._dilate(10,10) cnts = cv2.findContours(self.dilate_image, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)[0] if len(cnts) > 0: cnts = sorted(cnts, key=cv2.contourArea, reverse=True) all_c = [] for c in cnts: peri = 0.01*cv2.arcLength(c, False) approx = cv2.approxPolyDP(c, peri, True) if len(approx)==4 or True: (x, y, w, h) = cv2.boundingRect(c) if w > 100 and h >50: return x,y,w,h ##标识出识别出的机型轮廓并输出 #cv2.drawContours(self.image,[c],-1,(255,0,255),3) #spt_lst = os.path.splitext(self.image_path) #draw_path = spt_lst[0] + '_draw' + spt_lst[1] #cv2.imwrite(draw_path,self.image) #all_c.append({'x':x,'y':y,'w':w,'h':h}) return all_c def rec_qrcode_kh(self): """识别二维码考号信息 """ def rec_bar_code(imgpath): """识别条码 """ image = cv2.imread(imgpath) barcodes = pbar.decode(image) barcode = barcodes[0] barcode_data = barcode.data.decode("utf-8") return barcode_data def crop_img_local(orgimg, point=(),i=0): """ 切割图片 """ img = Image.open(orgimg) region = img.crop(point) new_img = "/tmp/" + os.path.split(orgimg)[-1].replace(".", "_crop{}.".format(i)) region.save(new_img, format="png") return new_img def get_std_points(imgpath): img = cv2.imread(imgpath) h,w = img.shape[:2] img1 = crop_img_local(imgpath,(0,0,w/8,h/8),1) img_dect = CV2img(img1) std_points = img_dect.get_std_points(10,10) return std_points def rec_ans(imgpath,std_ans_list): img_dect = CV2img(imgpath) img_dect._open() ans = img_dect.rec_ans(std_ans_list) return ans def rec_qrcode_kh(imgpath,point): """识别二维码考号信息 """ std_points = get_std_points(imgpath) std_x = std_points[0]["x"] std_y = std_points[0]["y"] x,y,w,h = point["x"]+std_x,point["y"]+std_y,point["w"],point["h"] img1 = crop_img_local(imgpath,(x,y,x+w,y+h),1) img_dect = CV2img(img1) x,y,w,h = img_dect.get_kh_qrcode() img2 = crop_img_local(img1,(x,y,x+w,y+h),2) kh = rec_bar_code(img2) def main(): std_points = get_std_points("/tmp/31_test01.png") if __name__ == "__main__": imgpath = "anscard.png" #std_ans_list = [{"h":22,"w":31,"x":78,"y":27,"z":82},{"h":22,"w":31,"x":123,"y":27,"z":125},{"h":23,"w":28,"x":173,"y":27,"z":175},{"h":22,"w":25,"x":219,"y":27,"z":220}] #ans = rec_ans(imgpath,std_ans_list) imgpath = "/tmp/33_test05.png" kh_point = {"h": 252.12448132780085, "w": 1558, "x": 12.506224066390049, "y": 223.84232365145232, "page": 0} rec_qrcode_kh(imgpath,kh_point)