python答题卡识别_opencv+python机读卡识别(最终版)本⽂是对之前编写的机读卡进⾏完善,
只记录相关代码,不介绍具体编写流程,
具体流程:opencv+python机读卡识别(进阶版)
完善相关机读卡的适配,记录相关调试函数以及使⽤⽅法。
# -*- coding: utf-8 -*-
# @Author: [FENG] <1161634940@qq>
# @Date: 2020-05-12 12:35:58
# @Last Modified by: [FENG] <1161634940@qq>
# @Last Modified time: 2020-07-14 19:09:14
from imutils.perspective import four_point_transform
import imutils
import numpy
import cv2
import csv
import os
import re
import time
import matplotlib.pyplot as plt
from PIL import Image
# import tkinter as tk
from tkinter import filedialog
import win32api,win32con
class cardReading(object):
# 机读卡信息读取
def reading(self, url, count):
# 加载图⽚,将它转换为灰阶,轻度模糊,然后边缘检测。
image = cv2.imread(url)
#转换为灰度图像
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
#⾼斯滤波
blurred = cv2.GaussianBlur(gray, (7, 7), 0)
#⾃适应⼆值化⽅法
blurred=cv2.adaptiveThreshold(blurred,255,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,51,2)
pyMakeBorder(blurred,5,5,5,5,cv2.BORDER_CONSTANT,value=(255,255,255)) edged = cv2.Canny(blurred, 75, 200)
cnts = cv2.findContours(edged, cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[1] if imutils.is_cv3() else cnts[0]
docCnt = None
# 确保⾄少有⼀个轮廓被到
if len(cnts) > 0:
# 将轮廓按⼤⼩降序排序
cnts = sorted(cnts, urArea, 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
# (右下⾓特殊)对右下⾓坐标点进⾏处理
bottom_left = bottom_right = None
for x in range(0, len(docCnt)):
doc = list(docCnt[x][0]);
doc.append(x)
if doc[0] < 1000 and doc[1] > 1500:
bottom_left = doc
if doc[0] > 1000 and doc[1] > 1500:
bottom_right = doc
if bottom_left is not None and bottom_right is not None:
if abs(bottom_right[1] - bottom_left[1]) > 70:
docCnt[bottom_right[2]][0][1] = bottom_right[1] + 70
else:
docCnt[bottom_right[2]][0][0] = bottom_right[0] + 70
# 使⽤封装⽅法,获取相关坐标点
(fImage, cnts) = dinate_point(docCnt, image, 101, (5000,7000), (60,60), 8)
newImage = fImage
Answer = [] # 题号相关坐标
quyu = [] # 进⼀步获取答题区域
for c in cnts:
# 计算轮廓的边界框,然后利⽤边界框数据计算宽⾼⽐
(x, y, w, h) = cv2.boundingRect(c)
# if ((y>3320 and y<5400) or (y>2090 and y<3100)) and x > 400 and x < 4730 and w > 60 and h > 20: if w > 80 and h > 40:
M = s(c)
cX = int(M["m10"] / M["m00"])
cY = int(M["m01"] / M["m00"])
#绘制中⼼及其轮廓
cv2.drawContours(fImage, c, -1, (0, 0, 255), 5, lineType=0)
cv2.circle(fImage, (cX, cY), 7, (255, 255, 255), -1)
#保存题⽬坐标信息
quyu.append([cX, cY])
# 处理四点位置
quyu = self.bubble_sort(quyu)
if len(quyu) == 6: # 特殊点处理
quyu.pop(5)
quyu.pop(2)
quyu =[[v] for v in quyu]
quyu = numpy.array(list(zip(quyu)))
# 使⽤封装⽅法,获取相关坐标点
(fImage, cnts) = dinate_point(quyu, newImage, 201, (2000, 2800), (20,20), 80)
for c in cnts:
# 计算轮廓的边界框,然后利⽤边界框数据计算宽⾼⽐
(x, y, w, h) = cv2.boundingRect(c)
if ((y>774 and y<1200) or (y>1360 and y<2226)) and w > 40 and h > 15:
# if ((y>3320 and y<5400) or (y>2090 and y<3100)) and x > 400 and x < 4730 and w > 60 and h > 20: M = s(c)
cX = int(M["m10"] / M["m00"])
cY = int(M["m01"] / M["m00"])
#绘制中⼼及其轮廓
cv2.drawContours(fImage, c, -1, (0, 0, 255), 5, lineType=0)
cv2.circle(fImage, (cX, cY), 10, (255, 255, 255), -1)
#保存题⽬坐标信息
Answer.append((cX, cY))
# self.see_img(fImage)
xt0=[0,190,390,590,790,990,1190,1390,1590,1790,1990,2000]
yt0=[774,824,865,907,949,988,1031,1073,1115,1156,1200]
xt1=
[0,120,194,260,330,400,520,590,660,728,790,925,991,1058,1130,1200,1270,1339,1408,1476,1550,1630,1698,1768,1837
yt1=[1360,1421,1472,1525,1574,1640,1712,1763,1816,1866,1940,2006,2060,2110,2160,2226]
student = []
IDAnswer = []
# 获取对应题号与选项
for i in Answer:
if i[1] > yt0[0] and i[1] < yt0[-1]:
student.append(i)
python怎么读文件夹下的文件夹else :
for j in range(0,len(xt1)-1):
if i[0]>xt1[j] and i[0]
for k in range(0,len(yt1)-1):
if i[1]>yt1[k] and i[1]
option = self.judge0(j, k, i[0], i[1])
IDAnswer.append(option)
xuehao = '';
for i in self.bubble_sort(student):
for k in range(0,len(yt0)-1):
if i[1]>yt0[k] and i[1]
xuehao += str(k)
result = {'学号':str(xuehao), '备注':''}
IDAnswer.sort()
newIDAnswer = {x+1:'' for x in range(60)}
for answer in IDAnswer:
if answer[0] <= 60 and newIDAnswer[answer[0]] != answer[1]:
newIDAnswer[answer[0]] += answer[1]
# 循环判断相关选项
for k,v in newIDAnswer.items():
# print(k,v);
if k >= 0 and k <= 20:
result['备注'] += self.option_judgment(k, v, 'ABC')
elif k >= 36 and k <= 40:
result['备注'] += self.option_judgment(k, v, 'ABCDEFG', 0)
else:
result['备注'] += self.option_judgment(k, v)
result.update(newIDAnswer)
# print(result)
# self.see_img(fImage)
return result
# 画直线
def link_image(self, image, list, type='x', start=0, end=100, color=(0, 255, 0), thickness=2): for x in list:
if type == 'x':
cv2.line(image, (x, start), (x, end), color, thickness)
else:
cv2.line(image, (start, x), (end, x), color, thickness)
return image
# 预览图⽚
def see_img(self, image, type=0):
cv2.namedWindow("image",0);
cv2.imshow("image", image)
cv2.waitKey(0)
if type == 0:
exit()
# 相关选项判断
def option_judgment(self, num, option, list='ABCD', length=1):
list = [x for x in list]
explain = ''
if option == '':
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论