IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 人工智能 -> 答题卡实战 -> 正文阅读

[人工智能]答题卡实战


import cv2
import matplotlib.pyplot as plt
import numpy as np
import myutils
import argparse
import imutils.contours

# 正确答案
ANSWER_KEY = {0: 1, 1: 4, 2: 0, 3: 3, 4: 1}


def cv_show(name, img):
    cv2.imshow(name, img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()


# 读取输入
image = cv2.imread("D:\\images\\text.jpg")
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)[0]
cv2.drawContours(contours_img, cnts, -1, (0, 0, 255), 3)
cv_show('contours_img', contours_img)


def order_points(pts):
    # 一共四个坐标点
    rect = np.zeros((4, 2), dtype="float32")
    #     按照顺序找到对应坐标0123分别是 左上,右上,右下,左下
    #     计算左上,右下
    s = pts.sum(axis=1)
    rect[0] = pts[np.argmin(s)]
    rect[2] = pts[np.argmax(s)]

    #     计算右上,左下
    d = np.diff(pts, axis=1)
    rect[1] = pts[np.argmin(d)]
    rect[3] = pts[np.argmax(d)]
    return rect


def four_point_transform(img, pts):
    #     获取输入坐标
    rect = order_points(pts)
    (tl, tr, br, bl) = rect
    #     计算输入的w和h值
    widthA = np.sqrt((br[0] - bl[0]) ** 2 + (br[1] - bl[1]) ** 2)
    widthB = np.sqrt((tr[0] - tl[0]) ** 2 + (tr[1] - tl[1]) ** 2)
    maxWidth = max(int(widthA), int(widthB))

    heightA = np.sqrt((tr[0] - br[0]) ** 2 + (tr[1] - br[1]) ** 2)
    heightB = np.sqrt((tl[0] - bl[0]) ** 2 + (tl[1] - bl[1]) ** 2)
    maxHeight = max(int(heightA), int(heightB))

    #     变换后对应坐标位置
    dst = np.array([[0, 0],
                    [maxWidth - 1, 0],
                    [maxWidth - 1, maxHeight - 1],
                    [0, maxHeight - 1]],
                   dtype="float32")
    #     计算变换矩阵
    M = cv2.getPerspectiveTransform(rect, dst)
    warped = cv2.warpPerspective(img, M, (maxWidth, maxHeight))
    #     反回变换后的结果
    return warped


def sort_contours(cnts, method="left-to-right"):
    reverse = False
    i = 0
    if method == 'right-to-left' or method == 'bottom-to-top':
        reverse = True
    if method == 'top-to-bottom' or method == 'bottom-to-top':
        i = 1
    boundingBoxes = [cv2.boundingRect(c) for c in cnts]
    (cnts, boundingBoxes) = zip(*sorted(zip(cnts, boundingBoxes),
                                        key=lambda b: b[1][i], reverse=reverse))
    return cnts, boundingBoxes


cnt = cnts
dotCnt = None
if len(cnt) > 0:
    cnt = sorted(cnt, key=cv2.contourArea, reverse=True)
    for c in cnt:
        peri = cv2.arcLength(c, True)
        approx = cv2.approxPolyDP(c, 0.02 * peri, True)
        if len(approx) == 4:
            dotCnt = approx
warp = four_point_transform(gray, dotCnt.reshape(4, 2))
# otsu's 阈值处理
thresh = cv2.threshold(warp, 0, 255, cv2.THRESH_BINARY_INV |
                       cv2.THRESH_OTSU)[1]
thresh_contours = thresh.copy()
# 找到每一个圆圈轮廓
cnt = cv2.findContours(thresh_contours, cv2.RETR_EXTERNAL,
                       cv2.CHAIN_APPROX_SIMPLE)[0]
cv2.drawContours(thresh_contours, cnt, -1, (0, 255, 0), 2)

questionCnts = []

cv_show('cnt', thresh_contours)

# 遍历
for c in cnt:
    #     计算比例和大小
    (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.append(c)
#         按照从上到下进行排序
questionCnts = sort_contours(questionCnts, method='top-to-bottom')[0]
# cv2.drawContours(warp,questionCnts,1,(0,255,255),2)
# 每排有5个选项
correct = 0
for (q, i) in enumerate(np.arange(0, len(questionCnts), 5)):
    #     排序
    cnts = sort_contours(questionCnts[i:i + 5])[0]
    bubbled = None
    # 遍历每一个结果

    for (j, c) in enumerate(cnts):
        #         使用mask来判断结果
        mask = np.zeros(thresh.shape, dtype='uint8')
        cv2.drawContours(mask, [c], -1, 255, -1)
        cv_show('mask', mask)
        #         通过计算非零点数量来算是否选择这个答案
        mask = cv2.bitwise_and(thresh, thresh, mask=mask)
        total = cv2.countNonZero(mask)
        #         通过阈值判断

        if bubbled is None or total > bubbled[0]:
            bubbled = (total, j)

    #             对比正确答案
    color = (0, 0, 255)
    k = ANSWER_KEY[q]
    #     判断正确
    if k == bubbled[1]:
        color = (0, 255, 0)
        correct += 1
    #         绘图
    cv2.drawContours(warp, cnts[k], -1, color, 2)
cv2.imshow("warp", warp)
# print(correct)
score = (correct / 5.0) * 100
print("[INFO] score: {:.2f}%".format(score))
cv2.putText(warp, "{:.2f}%".format(score), (10, 30),
cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 0, 255), 2)
cv2.imshow("Exam", warp)
cv2.waitKey(0)
cv2.waitKey()
cv2.destroyAllWindows()

步骤:

1:轮廓检测

# 读取输入
image = cv2.imread("D:\\images\\text.jpg")
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)[0]
cv2.drawContours(contours_img, cnts, -1, (0, 0, 255), 3)
cv_show('contours_img', contours_img)

先进行灰度图-->平滑操作(高斯滤波去噪音)-->边缘检测-->轮廓检测(只检测最外层轮廓)

cv2.findContours函数中mode参数选择cv2.RETR_EXTERNAL(表示只检测外轮廓)

2:透视变换

def order_points(pts):
    # 一共四个坐标点
    rect = np.zeros((4, 2), dtype="float32")
    #     按照顺序找到对应坐标0123分别是 左上,右上,右下,左下
    #     计算左上,右下
    s = pts.sum(axis=1)
    rect[0] = pts[np.argmin(s)]
    rect[2] = pts[np.argmax(s)]

    #     计算右上,左下
    d = np.diff(pts, axis=1)
    rect[1] = pts[np.argmin(d)]
    rect[3] = pts[np.argmax(d)]
    return rect


def four_point_transform(img, pts):
    #     获取输入坐标
    rect = order_points(pts)
    (tl, tr, br, bl) = rect
    #     计算输入的w和h值
    widthA = np.sqrt((br[0] - bl[0]) ** 2 + (br[1] - bl[1]) ** 2)
    widthB = np.sqrt((tr[0] - tl[0]) ** 2 + (tr[1] - tl[1]) ** 2)
    maxWidth = max(int(widthA), int(widthB))

    heightA = np.sqrt((tr[0] - br[0]) ** 2 + (tr[1] - br[1]) ** 2)
    heightB = np.sqrt((tl[0] - bl[0]) ** 2 + (tl[1] - bl[1]) ** 2)
    maxHeight = max(int(heightA), int(heightB))

    #     变换后对应坐标位置
    dst = np.array([[0, 0],
                    [maxWidth - 1, 0],
                    [maxWidth - 1, maxHeight - 1],
                    [0, maxHeight - 1]],
                   dtype="float32")
    #     计算变换矩阵
    M = cv2.getPerspectiveTransform(rect, dst)
    warped = cv2.warpPerspective(img, M, (maxWidth, maxHeight))
    #     反回变换后的结果
    return warped

先获得图像的几个顶点坐标-->再计算图像的宽和高-->重新定义图像的坐标

np.zeros函数的作用
返回来一个给定形状和类型的用0填充的数组;
zeros(shape, dtype=float, order=‘C’)
shape:形状
dtype:数据类型,可选参数,默认numpy.float64
order:可选参数,c代表与c语言类似,行优先;F代表列优先

s = pts.sum(axis=1)?

每行像素值进行相加,如果axis=0,则表示每列像素值相加

dotCnt = None
if len(cnt) > 0:
    cnt = sorted(cnt, key=cv2.contourArea, reverse=True)
    for c in cnt:
        peri = cv2.arcLength(c, True)
        approx = cv2.approxPolyDP(c, 0.02 * peri, True)
        if len(approx) == 4:
            dotCnt = approx
warp = four_point_transform(gray, dotCnt.reshape(4, 2))
cv2.arcLength:函数用于计算封闭轮廓的周长或曲线的长度
arcLength(InputArray curve, bool closed);
参数
curve,输入的二维点集(轮廓顶点),可以是 vector 或 Mat 类型。
closed,用于指示曲线是否封闭。
cv2.approxPolyDP: 使用 Douglas-Peucker 算法求得一条顶点较少的多折线/多边形,以指定的精度近似输入的曲线或多边形

参数:

curve:输入点集,二维点向量的集合
approxCurve:输出点集,表示拟合曲线或多边形,数据与输入参数 curve 一致
epsilon:指定的近似精度,原始曲线与近似曲线之间的最大距离
close: 闭合标志,True 表示闭合多边形,False 表示多边形不闭合

判断答案

# 每排有5个选项
correct = 0
for (q, i) in enumerate(np.arange(0, len(questionCnts), 5)):
    #     排序
    cnts = sort_contours(questionCnts[i:i + 5])[0]
    bubbled = None
    # 遍历每一个结果

    for (j, c) in enumerate(cnts):
        #         使用mask来判断结果
        mask = np.zeros(thresh.shape, dtype='uint8')
        cv2.drawContours(mask, [c], -1, 255, -1)
        cv_show('mask', mask)
        #         通过计算非零点数量来算是否选择这个答案
        mask = cv2.bitwise_and(thresh, thresh, mask=mask)
        total = cv2.countNonZero(mask)
        #         通过阈值判断

        if bubbled is None or total > bubbled[0]:
            bubbled = (total, j)

    #             对比正确答案
    color = (0, 0, 255)
    k = ANSWER_KEY[q]
    #     判断正确
    if k == bubbled[1]:
        color = (0, 255, 0)
        correct += 1
    #         绘图
    cv2.drawContours(warp, cnts[k], -1, color, 2)

选定掩膜:

 mask = np.zeros(thresh.shape, dtype='uint8')
        cv2.drawContours(mask, [c], -1, 255, -1)
        cv_show('mask', mask)
        #         通过计算非零点数量来算是否选择这个答案
        mask = cv2.bitwise_and(thresh, thresh, mask=mask)
        total = cv2.countNonZero(mask)

np.zeros(thresh.shape, dtype='uint8')把图像(像素)置为0变为全黑,

cv2.drawContours(mask, [c], -1, 255, -1)对掩膜操作得到一个个选项的位置效果为

mask = cv2.bitwise_and(thresh, thresh, mask=mask)
total = cv2.countNonZero(mask)

?cv2.bitwise_and(thresh, thresh, mask=mask)

给定指定的掩膜,得到选项

countNonZero():返回灰度值不为0的像素数,可用来判断图像是否全黑

最终效果:

?

  人工智能 最新文章
2022吴恩达机器学习课程——第二课(神经网
第十五章 规则学习
FixMatch: Simplifying Semi-Supervised Le
数据挖掘Java——Kmeans算法的实现
大脑皮层的分割方法
【翻译】GPT-3是如何工作的
论文笔记:TEACHTEXT: CrossModal Generaliz
python从零学(六)
详解Python 3.x 导入(import)
【答读者问27】backtrader不支持最新版本的
上一篇文章      下一篇文章      查看所有文章
加:2022-07-17 16:23:46  更:2022-07-17 16:27:35 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 0:56:17-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码