ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

opencv答题卡识别项目

2022-02-20 16:04:51  阅读:168  来源: 互联网

标签:src img cvSHow cv2 答题卡 opencv warped cnts 识别


代码所用图片:
在这里插入图片描述

直接上代码:
datika.py

# @time: 2022/2/17 18:20
# @Author: wangshubo
# @File: datika.py
# @description:
# @author_email: '971490321@qq.com'
import cv2
import numpy as np
from myutils import sort_contours

from utilsW.utils import cvSHow, CalDistance

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

def four_point_transform(image, pts):
    # rect = order_points(pts)
    rect = pts.squeeze().astype(np.float32)
    (tl, tr, bl, br) = rect[1], rect[2], rect[0], rect[3],
    # 计算输入的w和h值
    widthA = CalDistance(tl, tr)
    widthB = CalDistance(bl, br)
    maxWidth = max(int(widthA), int(widthB))

    heightA = CalDistance(tl, bl)
    heightB = CalDistance(tr, br)
    maxHeight = max(int(heightA), int(heightB))

    # 变换后对应坐标位置
    dst = np.array([
        [0, 0],
        [maxWidth - 1, 0],
        [maxWidth - 1, maxHeight - 1],
        [0, maxHeight - 1]], dtype="float32")
    src_points = np.array([bl, br, tr, tl])
    # 计算变换矩阵
    M = cv2.getPerspectiveTransform(src_points, dst)
    warped = cv2.warpPerspective(image, M, (maxWidth, maxHeight))

    # 返回变换后结果
    return warped

if __name__ == '__main__':
    src = cv2.imread("D:/images/datika.png")
    cvSHow("src", src)
    gray = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
    blur_img = cv2.GaussianBlur(gray, (5, 5), 0)
    cvSHow("blur_img", blur_img)
    edge_img = cv2.Canny(blur_img, 75, 200)
    cvSHow("edge_img", edge_img)

    cnts = cv2.findContours(edge_img.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[0]
    cv2.drawContours(src, cnts, -1, (0, 0, 255), 2)
    cvSHow("draw", src)
    docCnt = None

    if len(cnts) > 0:
        cnts = sorted(cnts, key=cv2.contourArea, reverse=True)  # reverse为TRUE则为降序,FALSE则为升序

        for c in cnts:
            peri = cv2.arcLength(c, True)
            approx = cv2.approxPolyDP(c, 0.02 * peri, True)  # 主要功能是把一个连续光滑曲线折线化

            if len(approx) == 4:
                docCnt = approx
                break

    #透视变换
    warped = four_point_transform(gray, docCnt.reshape(4, 2))
    cvSHow("warped", warped)

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

    thresh_Contours = thresh.copy()

    cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[0]
    cv2.drawContours(warped, cnts, -1, (0,0,255),2)
    cvSHow("thresh_Contours", warped)
    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.append(c)

    questionCnts = sort_contours(questionCnts, method="top-to-bottom")[0]
    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)  # -1表示填充
            cvSHow('mask', mask)
            # 通过计算非零点数量来算是否选择这个答案
            mask = cv2.bitwise_and(thresh, thresh, mask=mask)
            cvSHow("mask1",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(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", src)
    cv2.imshow("Exam", warped)
    cv2.waitKey(0)

引用文件
myutils.py

# @time: 2022/1/17 16:22
# @Author: wangshubo
# @File: myutils.py
# @description:
# @author_email: '971490321@qq.com'


import cv2

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] #用一个最小的矩形,把找到的形状包起来x,y,h,w
    (cnts, boundingBoxes) = zip(*sorted(zip(cnts, boundingBoxes),
                                        key=lambda b: b[1][i], reverse=reverse))

    return cnts, boundingBoxes
def resize(image, width=None, height=None, inter=cv2.INTER_AREA):
    dim = None
    (h, w) = image.shape[:2]
    if width is None and height is None:
        return image
    if width is None:
        r = height / float(h)
        dim = (int(w * r), height)
    else:
        r = width / float(w)
        dim = (width, int(h * r))
    resized = cv2.resize(image, dim, interpolation=inter)
    return resized

utils.py

# @time: 2022/1/6 11:06
# @Author: wangshubo
# @File: utilsW.py
# @description: 封装的工具函数
# @author_email: '971490321@qq.com'
import cv2 as cv
import numpy as np


def cvSHow(name, img):
    cv.imshow(name, img)
    cv.waitKey(0)
    cv.destroyAllWindows()

#计算两点距离之和
def CalDistance(pt1, pt2):
    x1, y1, x2, y2 = pt1[0], pt1[1], pt2[0], pt2[1]
    distance = np.sqrt(((y2 - y1) ** 2) + ((x2 - x1) ** 2))
    return distance

# 计算列表中元素之和
def listSum(list):
    total = 0
    ele = 0
    while (ele < len(list)):
        total = total + list[ele]
        ele += 1
    return total

标签:src,img,cvSHow,cv2,答题卡,opencv,warped,cnts,识别
来源: https://blog.csdn.net/qq_25232685/article/details/123031645

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有