OpenCV实现答题卡自动打分!

目录

1,主要原理以及函数介绍

全部代码,以

2 , 实现过程

3,结果展示


1,主要原理以及函数介绍

ap = argparse.ArgumentParser()

创建一个ArgumentParser对象,并将其赋值给变量ap。这个对象可以接受我们的脚本的命令行参数,从而实现根据命令行参数执行不同的操作。

ap.add_argument("-i", "--image", required=True,help="path to the input image")

添加一个命令行参数-i/--image,并指定它是必需的,用户必须提供一个图像路径作为输入。

args = vars(ap.parse_args())

解析命令行参数并将它们存储在args字典中

ANSWER_KEY = {0: 1, 1: 4, 2: 0, 3: 3, 4: 1}

定义一个字典,其中包含每道题目的正确答案。键是问题的索引、值是正确答案的编号

def order_points(pts):

定义函数order_points,用于按照指定顺序找到四个坐标点

def four_point_transform(image, pts):

定义函数four_point_transform,用于执行透视变换。

透视变换是一种在图像处理领域中常用的变换方式,它可以将一个平面上的图像投影到一个新的视平面上。透视变换通常用于纠正图像中的透视畸变,例如将斜着拍摄的照片转换为正常的平面视图。在透视变换中,图像中的平行线可能会变成不平行线,而原本不平行的线可能会变成平行线。函数four_point_transform就是利用四个特定的点来确定透视变换矩阵,并对输入的图像进行透视变换。

def sort_contours(cnts, method="left-to-right"):

定义函数sort_contours,用于对轮廓进行排序

def cv_show(name,img):

定义函数cv_show,用于显示图像。

image = cv2.imread(args["image"]):

读取输入的图像,并将其存储在变量image中

contours_img = image.copy():

复制图像,用于在图像上绘制轮廓

cnts = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[1]

查找图像中的轮廓,使用外部轮廓检查模式(RETR_EXTERNAL)只检测外部轮廓,使用简单的轮廓逼近算法(CHAIN_APPROX_SIMPLE)来减少点数。返回值是一个元组,其中第二个元素表示轮廓列表

cv2.drawContours(contours_img,cnts,-1,(0,0,255),3)

将找到的轮廓绘制在图像上,颜色为红色

docCnt = None

初始化docCnt变量,用于存储找到的四个坐标点

if len(cnts) > 0:

如果找到了轮廓,则执行以下操作

cnts = sorted(cnts, key=cv2.contourArea, reverse=True)

对轮廓根据其面积大小进行排序,从大到小排列

peri = cv2.arcLength(c, True)     计算轮廓周长

approx = cv2.approxPolyDP(c, 0.02 * peri, True)

使用迭代逼近算法获取轮廓的近似形状。如果近似的轮廓拥有四个顶点,则将其作为找到的四个坐标点。

if len(approx) == 4:  如果找到了四个坐标点,则将它们保存到docCnt变量中,并跳出循环。

warped = four_point_transform(gray, docCnt.reshape(4, 2))

对图像进行透视变换,将找到的四个坐标点映射到新的矩阵中

thresh = cv2.threshold(warped, 0, 255,cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]

对变换后的图像进行二值化处理,使用Otsu's自适应阈值处理算法来获取最优阈值。返回值是一个元组,其中第二个元素是处理后的图像。

hresh_Contours = thresh.copy()

复制处理后的图像,用于在上面绘制轮廓

cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)[1]

查找处理后图像中的轮廓,并使用RETR_EXTERNAL和CHAIN_APPROX_SIMPLE参数。

cv2.drawContours(thresh_Contours,cnts,-1,(0,0,255),3)

将找到的轮廓绘制在二值化图像上

cv_show('thresh_Contours',thresh_Contours)

调用cv_show函数,显示绘制轮廓后的图像

questionCnts = []:初始化questionCnts列表。

for c in cnts::遍历所有轮廓:

(x, y, w, h) = cv2.boundingRect(c):获取表示轮廓区域位置和大小的矩形。

ar = w / float(h):计算矩形的宽高比。

if w >= 20 and h >= 20 and ar >= 0.9 and ar <= 1.1::如果矩形满足指定的条件,则将其添加到questionCnts列表中。

questionCnts = sort_contours(questionCnts,method="top-to-bottom")[0]:对questionCnts列表中的轮廓按照从上到下的顺序进行排序。

for (q, i) in enumerate(np.arange(0, len(questionCnts), 5)):对每一行问题进行处理。

cnts = sort_contours(questionCnts[i:i + 5])[0]:对每个问题中的五个选项进行排序。

bubbled = None:初始化变量bubbled,用于保存所选答案。

for (j, c) in enumerate(cnts)::遍历每个选项。

mask = np.zeros(thresh.shape, dtype="uint8") :创建一个全黑图像,大小与thresh相同。

cv2.drawContours(mask, [c], -1, 255, -1):绘制选项的轮廓。

mask = cv2.bitwise_and(thresh, thresh, mask=mask):将二值化图像thresh与mask相乘,只保留交集部分。

total = cv2.countNonZero(mask):计算非零像素的数目,用于判断是否选择了这个选项。

if bubbled is None or total > bubbled[0]::如果之前没有选择过或者当前选择的像素数更多,则更新选择。

bubbled = (total, j):将当前选择的像素数以及选项索引保存到bubbled变量中。

color = (0, 0, 255):初始化颜色为红色。

k = ANSWER_KEY[q]:获取当前问题的正确答案。

if k == bubbled[1]::如果当前选项是正确的,则将颜色设置为绿色,并增加正确计数器。

color = (0, 255, 0)
correct += 1

cv2.drawContours(warped, [cnts[k]], -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):等待用户按下任意键。

全部代码,以

2 , 实现过程

  1. 导入所需的库和模块:首先导入numpy、argparse、imutils和cv2等库,用于进行科学计算、命令行参数解析、图像处理和机器视觉任务。

  2. 解析命令行参数:使用argparse库创建ArgumentParser对象,并添加一个命令行参数-i/--image,要求用户提供一个输入图像的路径。然后使用ap.parse_args()方法解析命令行参数,并将结果存储在args字典中。

  3. 定义正确答案字典:创建一个字典,其中包含每道题目的正确答案编号。

  4. 函数定义:定义了四个函数,分别用于找到四个坐标点、执行透视变换、对轮廓进行排序以及显示图像。

  5. 读取输入图像:使用cv2.imread()函数读取输入的图像,并将其存储在变量image中。

  6. 图像预处理:将图像转换为灰度图像,然后应用高斯模糊以平滑边缘并减少噪声。接下来使用Canny算法进行边缘检测,得到二值化的边缘图像。

  7. 查找轮廓:使用cv2.findContours()函数查找图像中的轮廓,并使用外部轮廓检查模式(RETR_EXTERNAL)只检测外部轮廓,使用简单的轮廓逼近算法(CHAIN_APPROX_SIMPLE)来减少点数。获取到的轮廓存储在cnts变量中。

  8. 找到答题卡区域:遍历轮廓,计算轮廓周长和近似形状,并通过一系列条件判断找到包含答题卡的轮廓。将找到的四个坐标点保存到docCnt变量中。

  9. 执行透视变换:使用four_point_transform()函数对图像进行透视变换,将找到的四个坐标点映射到新的矩阵中。

  10. 对变换后的图像进行二值化处理:使用Otsu's自适应阈值处理算法对图像进行二值化处理,得到二值化的图像。

  11. 查找轮廓:使用cv2.findContours()函数再次查找处理后图像中的轮廓,并使用RETR_EXTERNAL和CHAIN_APPROX_SIMPLE参数。

  12. 处理每个问题的选项:遍历每个问题所在的行,对该行中的五个选项进行处理。首先对选项进行排序,然后使用遍历的方式计算每个选项中非零像素的数量,根据数量确定是否选择了该选项,同时记录最多选择的选项和其索引。

  13. 计算得分:根据正确的选项数量和总题数计算得分,同时输出得分。

  14. 显示结果:在变换后的图像上绘制得分,并显示原始图像和处理结果。

  15. 等待用户按下任意键结束程序。

3,结果展示

高斯滤波后结果

边缘检测结果

图像轮廓检测结果:

透视变换结果:

二值化处理结果:

mask,只保留交集部分

遍历每一个结果,计算非零像素的数目,用于判断是否选择了这个选项

计算的得分并显示

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值