123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271 |
- #-*-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)
|