中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當前位置: 首頁 > news >正文

怎么做網(wǎng)站的軟文推廣seo外包方案

怎么做網(wǎng)站的軟文推廣,seo外包方案,路由器搭建wordpress,幼兒教育網(wǎng)站源碼目錄 透視變換矯正 選項識別匹配 QT 界面設計 引言:隨著信息化的發(fā)展,計算機閱卷已經(jīng)成為一種常規(guī)操作。在大型考試中,客觀題基本不再 需要人工閱卷。本項目旨在開發(fā)一個基于OpenCV的高效答題卡識別系統(tǒng),通過先進的圖像處理和?!?article class="baidu_pl">

目錄

透視變換矯正

選項識別匹配

QT 界面設計


引言:隨著信息化的發(fā)展,計算機閱卷已經(jīng)成為一種常規(guī)操作。在大型考試中,客觀題基本不再 需要人工閱卷。本項目旨在開發(fā)一個基于OpenCV的高效答題卡識別系統(tǒng),通過先進的圖像處理和模式識別技術(shù),實現(xiàn)對答題卡的快速準確分析。

文章所有資源請看文末!

透視變換矯正

假如有一張答題卡平放在地面上,那我們怎樣去找到答題卡的邊界輪廓呢?

答案是透視變換。首先我們需要找到答題卡的輪廓才能對選項做各種處理呀,接下來就是對透視變換的方法說明了。

假設原始圖像中的點為(x,y),目標圖像中的對應點為(X,Y)。透視變換可以用一個 3x3 的矩陣M來描述:

\begin{bmatrix} X\\ Y\\ 1 \end{bmatrix}=M\times \begin{bmatrix} x\\ y\\ 1 \end{bmatrix}

其中,矩陣M的元素取決于原始四邊形和目標四邊形頂點的坐標。其核心原理在于通過建立原始圖像和目標圖像之間的對應點關系,來計算一個變換矩陣。

綜上所述,使用透視變換掃描得到答題卡邊界具體步驟如下:

  1. 找到原始圖像的4個頂點和目標圖像的4個頂點
  2. 根據(jù)8個頂點構(gòu)造原始圖像到目標圖像的變換矩陣
  3. 依據(jù)變換矩陣,實現(xiàn)原始圖像到目標圖像的變換,完成傾斜矯正

注意:用于構(gòu)造變換矩陣使用的原始圖像的4個頂點和目標圖像的4個頂點的位置必須是匹配的,也就是說,要將左上、右上、左下、右下4個頂點按照相同的順序排列。

OK,下面我們直接根據(jù)代碼來進行說明。

import cv2
import math
import numpy as np# x坐標
def sortBy_x(pt):return pt[0]# y坐標
def sortBy_y(pt):return pt[1]def correct(path):try:answerSheet = cv2.imread(path)gray = cv2.cvtColor(answerSheet, cv2.COLOR_BGR2GRAY)blurred = cv2.GaussianBlur(gray, (3, 3), 0)canny = cv2.Canny(blurred, 75, 200)contours, Hierarchy = cv2.findContours(canny, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)if len(contours) == 1:result_contour = contours[0]else:max_length = -1index = -1for i, contour in enumerate(contours):length = cv2.arcLength(contour, True)if length > max_length:max_length = lengthindex = iresult_contour = contours[index]pts = cv2.approxPolyDP(result_contour, 0.02 * cv2.arcLength(result_contour, True), True)if len(pts) != 4:raise ValueError("透視變換需要四個點,但檢測到的點數(shù)量為{}".format(len(pts)))pts = np.array([pt[0] for pt in pts])  # 提取點坐標print(pts)pts = sorted(pts, key=sortBy_x)print(pts)pts = sorted(pts, key=sortBy_y)print(pts)print(pts[0][0])width1 = math.sqrt((pts[0][0] - pts[1][0]) ** 2 + (pts[0][1] - pts[1][1]) ** 2)width2 = math.sqrt((pts[2][0] - pts[3][0]) ** 2 + (pts[2][1] - pts[3][1]) ** 2)width = int(max(width1, width2))height1 = math.sqrt((pts[0][0] - pts[3][0]) ** 2 + (pts[0][1] - pts[3][1]) ** 2)height2 = math.sqrt((pts[2][0] - pts[1][0]) ** 2 + (pts[2][1] - pts[1][1]) ** 2)height = int(max(height1, height2))pts_dst = np.array([[0, 0], [width - 1, 0], [width - 1, height - 1], [0, height - 1]], dtype="float32")pts_src = np.array(pts, dtype="float32")M = cv2.getPerspectiveTransform(pts_src, pts_dst)birdMat = cv2.warpPerspective(answerSheet, M, (width, height))return birdMatexcept Exception as e:print(f"Error in correct: {e}")return None

1、首先對讀取的圖像進行一系列預處理操作:灰度轉(zhuǎn)換、濾波、邊緣檢測等以凸顯圖像特征

2、使用cv2.findContours查找圖像輪廓

當輪廓數(shù)量為1時,直接將其結(jié)果作為輪廓。

否則通過計算 每個輪廓的弧長,找到弧長最長的輪廓作為結(jié)果輪廓。

3、使用cv2.approxPolyDP函數(shù)對結(jié)果輪廓進行多邊形逼近,得到近似的頂點坐標

4、將頂點坐標提取出來,并分別按照x坐標和y坐標進行排序,同時計算相鄰兩點之間的距離,取最大值作為寬度和高度,并據(jù)此計算目標頂點

5、cv2.getPerspectiveTransfor計算變換矩陣Mcv2.warpPerspective根據(jù)變換矩陣對原始圖像進行透視變換,得到矯正后的圖像

效果如下:

選項識別匹配

答題卡輪廓邊界得到之后就是對選項的處理了。

import cv2
import numpy as np
import mathdef sortBy_x(pt):return pt[0]def sortBy_y(pt):return pt[1]def recognition(path, imageIndex):try:answerSheet = cv2.imread(path)gray = cv2.cvtColor(answerSheet, cv2.COLOR_BGR2GRAY)blurred = cv2.GaussianBlur(gray, (3, 3), 0)canny = cv2.Canny(blurred, 75, 200)contours, _ = cv2.findContours(canny, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)if len(contours) == 1:result_contour = contours[0]else:max_length = -1index = -1for i, contour in enumerate(contours):length = cv2.arcLength(contour, True)if length > max_length:max_length = lengthindex = iresult_contour = contours[index]pts = cv2.approxPolyDP(result_contour, 0.02 * cv2.arcLength(result_contour, True), True)if len(pts) != 4:raise ValueError("識別需要四個點,但檢測到的點數(shù)量為{}".format(len(pts)))pts = np.array([pt[0] for pt in pts])pts = sorted(pts, key=sortBy_x)pts = sorted(pts, key=sortBy_y)width1 = math.sqrt((pts[0][0] - pts[1][0]) ** 2 + (pts[0][1] - pts[1][1]) ** 2)width2 = math.sqrt((pts[2][0] - pts[3][0]) ** 2 + (pts[2][1] - pts[3][1]) ** 2)width = int(max(width1, width2))height1 = math.sqrt((pts[0][0] - pts[3][0]) ** 2 + (pts[0][1] - pts[3][1]) ** 2)height2 = math.sqrt((pts[2][0] - pts[1][0]) ** 2 + (pts[2][1] - pts[1][1]) ** 2)height = int(max(height1, height2))pts_dst = np.array([[0, 0], [width - 1, 0], [width - 1, height - 1], [0, height - 1]], dtype="float32")pts_src = np.array(pts, dtype="float32")M = cv2.getPerspectiveTransform(pts_src, pts_dst)birdMat = cv2.warpPerspective(answerSheet, M, (width, height))cv2.imshow("original", birdMat)#################   識別   ##############################gray_birdMat = cv2.cvtColor(birdMat, cv2.COLOR_BGR2GRAY)_, target = cv2.threshold(gray_birdMat, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)cv2.imshow("Img", target)element = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))target = cv2.dilate(target, element)cv2.imshow("image", target)# 提取選項contours, _ = cv2.findContours(target, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)# print(contours)selected_contours = [c for c in contours if cv2.boundingRect(c)[2] > 20 and cv2.boundingRect(c)[3] > 20]answerSheet_con = cv2.cvtColor(target, cv2.COLOR_GRAY2BGR)cv2.drawContours(answerSheet_con, selected_contours, -1, (0, 0, 255), 2)# 選項定位、二維數(shù)組存儲radius = []center = []for contour in selected_contours:(x, y), r = cv2.minEnclosingCircle(contour)radius.append(r)center.append((int(x), int(y)))x_min = min(center, key=lambda x: x[0])[0]x_max = max(center, key=lambda x: x[0])[0]x_interval = (x_max - x_min) // 4y_min = min(center, key=lambda x: x[1])[1]y_max = max(center, key=lambda x: x[1])[1]y_interval = (y_max - y_min) // 4classed_contours = [[[] for _ in range(5)] for _ in range(5)]for i, point in enumerate(center):index_x = round((point[0] - x_min) / x_interval)index_y = round((point[1] - y_min) / y_interval)classed_contours[index_y][index_x] = selected_contours[i]colors = [(0, 0, 255), (255, 0, 255), (0, 255, 255), (255, 0, 0), (0, 255, 0)]test_result = cv2.cvtColor(target, cv2.COLOR_GRAY2BGR)for i in range(5):for j in range(5):if len(classed_contours[i][j]) > 0:cv2.drawContours(test_result, classed_contours[i][j], -1, colors[i], 2)# 答案自定義,只有 5個選項correct_answers = [0, 4, 4, 2, 1]# 定義選項位置result_count = np.zeros((5, 5), dtype=int)re_rect = [[cv2.boundingRect(contour) for contour in row] for row in classed_contours]count_roi = np.zeros((5, 5), dtype=np.float32)min_count = 999max_count = -1for i in range(5):for j in range(5):if len(classed_contours[i][j]) > 0:rect = re_rect[i][j]tem = target[rect[1]:rect[1] + rect[3], rect[0]:rect[0] + rect[2]]count = cv2.countNonZero(tem)if count > max_count:max_count = countif count < min_count:min_count = countcount_roi[i][j] = countmean = (max_count - min_count) // 2option_diff = np.abs(count_roi - max_count)for i in range(5):for j in range(5):if option_diff[i][j] < mean:result_count[i][j] += 1# 進行審閱label_answer = birdMat.copy()correct_count = 0wrong_answers = {}for i in range(5):selected = []for j in range(5):if result_count[i][j] == 1:selected.append(j)if j == correct_answers[i]:cv2.drawContours(label_answer, classed_contours[i][j], -1, (255, 0, 0), 2)else:cv2.drawContours(label_answer, classed_contours[i][j], -1, (0, 0, 255), 2)# 記錄題目數(shù)量、正確題數(shù)、錯題if len(selected) == 0:continue  # 未作答,不做任何處理elif len(selected) == 1:if selected[0] == correct_answers[i]:correct_count += 1else:wrong_answers[i + 1] = chr(65 + selected[0])  # 錯誤選項else:blue_count = sum(1 for j in selected if j == correct_answers[i])red_count = len(selected) - blue_countif blue_count > 0 and red_count > 0:wrong_answers[i + 1] = '多選'total_questions = len(correct_answers)score = correct_count / total_questions * 100data = {"序號": "{:02}".format(imageIndex + 1),"成績": score,"題目總數(shù)": total_questions,"錯題": str(wrong_answers),"正確題數(shù)": correct_count}return label_answer, dataexcept Exception as e:print(f"Error in recognition: {e}")return None, None

1、首先仍就是圖像預處理,這通常會使得我們更易于提取選項,得到其位置。將變換后的圖像轉(zhuǎn)為灰度圖并進行反二閾值化凸顯選項,隨后進行膨脹操作以連接斷開的部分或填充小的空洞。

2、提取選項輪廓。通過cv2.findContours得到所有輪廓,隨后對每個輪廓進行篩選,只有寬度和高度均大于20像素的輪廓才會被保留下來,這樣就能夠得到選項了。

3、選項定位與分類。計算每個符合條件的輪廓的最小外接圓的圓心和半徑。根據(jù)圓心坐標,將選項按照水平和垂直方向進行分類并存儲到二維數(shù)組中。

4、答案識別與審閱。

  • 自定義正確答案,用數(shù)字標識答案位置,默認從0開始。
  • 為每個選項區(qū)域計算非零像素的數(shù)量。
  • 通過計算得到的數(shù)量與平均值,確定每個選項的選擇情況并存儲到二維數(shù)組中。

5、審閱結(jié)果展示與數(shù)據(jù)統(tǒng)計。比較二維數(shù)組與正確答案,繪制正確和錯誤選項的輪廓,正確為藍色,錯誤為紅色;同時統(tǒng)計正確題數(shù)、計算分數(shù),并將相關數(shù)據(jù)存儲到字典中。

效果如下:

QT 界面設計

????????本次界面設計使用的是pyqt5,我也只是初學,所以做的界面不是很好,但也勉強還算看的過眼吧。這個界面其實就是把變換后的圖像和識別檢測的結(jié)果弄到展示窗口,然后把記錄的數(shù)據(jù)信息這些保存到excel表而已,說實在的還是太簡陋了呀。OK,下面我們直接看效果吧。

答題卡識別

????????好的,以上就是本次項目的所有內(nèi)容了,希望對大家有所幫助呀,有疑問的可以評論或私聊我解答喲!

文章所有資源有需要的可自取

百度網(wǎng)盤鏈接: https://pan.baidu.com/s/1pFeaKRGAwF1zfip_wqt_dQ ????????提取碼: 0bw7

http://www.risenshineclean.com/news/4707.html

相關文章:

  • java開發(fā)是做什么的seoaoo
  • 網(wǎng)站搭建投稿平臺
  • 畫品展現(xiàn)手機網(wǎng)站seo排名優(yōu)化有哪些
  • 重慶網(wǎng)站備案大廳杭州網(wǎng)站seo優(yōu)化
  • 網(wǎng)頁制作做網(wǎng)站左側(cè)導航網(wǎng)站建設方案內(nèi)容
  • 網(wǎng)站建設規(guī)范搜狗搜索引擎推廣
  • 在線免費貨源網(wǎng)站入口站長之家下載
  • 房地產(chǎn)開發(fā)公司取名網(wǎng)站關鍵詞優(yōu)化排名軟件
  • 做網(wǎng)站需要的大圖電商網(wǎng)站策劃
  • 汽車之家這樣的網(wǎng)站怎么做杭州網(wǎng)站運營十年樂云seo
  • 微網(wǎng)站制作價格金華關鍵詞優(yōu)化平臺
  • 可不可以用帝國cms做企業(yè)網(wǎng)站鄭州網(wǎng)站推廣公司
  • 建設銀行簽名通在網(wǎng)站哪里下載免費制作自己的網(wǎng)頁
  • jq 網(wǎng)站模板技能培訓網(wǎng)站
  • 西安哪家網(wǎng)絡公司做網(wǎng)站小說百度搜索風云榜
  • 安陽工學院圖書館找做網(wǎng)站的書在哪免費新聞源發(fā)布平臺
  • 彩票網(wǎng)站里的統(tǒng)計怎么做短視頻推廣渠道
  • 房地產(chǎn)網(wǎng)站怎么推廣優(yōu)化軟件下載
  • 2015年做啥網(wǎng)站能致富網(wǎng)絡營銷策劃的概念
  • 網(wǎng)站建設要考關鍵詞查詢工具包括哪些
  • 網(wǎng)站首頁動畫效果怎么弄推廣廣告
  • 怎么看網(wǎng)站日志文件seo官網(wǎng)優(yōu)化
  • 房屋 哪個網(wǎng)站做的最好百度上的廣告多少錢一個月
  • 一個獨立IP做幾個網(wǎng)站比較合適seo網(wǎng)站建設優(yōu)化
  • 人妖和美女做視頻網(wǎng)站如何建立公司網(wǎng)站網(wǎng)頁
  • 網(wǎng)站建設合同糾紛問題百度廣告聯(lián)盟賺廣告費
  • 官方網(wǎng)站建設要點最近三天的新聞大事簡短
  • 太平洋保險網(wǎng)站做的這么爛打廣告推廣怎么做
  • 分類網(wǎng)站建設方案廣州網(wǎng)站優(yōu)化
  • 怎么找網(wǎng)站模板seo搜索引擎入門教程