当前位置:网站首页>Opencv learning notes 8 -- answer sheet recognition
Opencv learning notes 8 -- answer sheet recognition
2022-07-06 07:32:00 【Cloudy_ to_ sunny】
opencv Learning notes 8 -- Answer card recognition
Import toolkit
# Import toolkit
import numpy as np
import argparse
import imutils
import cv2
import matplotlib.pyplot as plt#Matplotlib yes RGB
# right key
ANSWER_KEY = {
0: 1, 1: 4, 2: 0, 3: 3, 4: 1}
Defined function
def order_points(pts):
# altogether 4 Coordinates
rect = np.zeros((4, 2), dtype = "float32")
# Find the corresponding coordinates in order 0123 Namely Top left , The upper right , The lower right , The lower left
# Calculate top left , The lower right
s = pts.sum(axis = 1)
rect[0] = pts[np.argmin(s)]
rect[2] = pts[np.argmax(s)]
# Count right up and left down
diff = np.diff(pts, axis = 1)
rect[1] = pts[np.argmin(diff)]
rect[3] = pts[np.argmax(diff)]
return rect
def four_point_transform(image, pts):
# Get the input coordinate point
rect = order_points(pts)
(tl, tr, br, bl) = rect
# Calculate the input w and h value
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))
# Corresponding coordinate position after transformation
dst = np.array([
[0, 0],
[maxWidth - 1, 0],
[maxWidth - 1, maxHeight - 1],
[0, maxHeight - 1]], dtype = "float32")
# Calculate the transformation matrix
M = cv2.getPerspectiveTransform(rect, dst)
warped = cv2.warpPerspective(image, M, (maxWidth, maxHeight))
# Return the result after transformation
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
# Show function
def cv_show(name,img):
b,g,r = cv2.split(img)
img_rgb = cv2.merge((r,g,b))
plt.imshow(img_rgb)
plt.show()
def cv_show1(name,img):
plt.imshow(img)
plt.show()
cv2.imshow(name,img)
cv2.waitKey()
cv2.destroyAllWindows()
scanning
# Preprocessing
image = cv2.imread("./images/test_01.png")
contours_img = image.copy()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (5, 5), 0) # Gauss filtering
cv_show1('blurred',blurred)
edged = cv2.Canny(blurred, 75, 200) # edge detection
cv_show1('edged',edged)


# Contour detection
cnts = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)[1]
cv2.drawContours(contours_img,cnts,-1,(0,0,255),3)
cv_show('contours_img',contours_img)
docCnt = None

# Make sure that... Is detected
if len(cnts) > 0:
# Sort by outline size
cnts = sorted(cnts, key=cv2.contourArea, reverse=True)
# Traverse every contour
for c in cnts:
# The approximate
peri = cv2.arcLength(c, True)
approx = cv2.approxPolyDP(c, 0.02 * peri, True)
# Prepare for perspective change
if len(approx) == 4:
docCnt = approx
break
# Perform perspective transformation
warped = four_point_transform(gray, docCnt.reshape(4, 2))
cv_show1('warped',warped)

Adaptive threshold processing
# Otsu's Threshold processing
thresh = cv2.threshold(warped, 0, 255,
cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]
thresh_Contours = thresh.copy()
cv_show1('thresh_Contours',thresh_Contours)

Detect the outline of each option
# Find the outline of each circle
cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)[1]
cv2.drawContours(thresh_Contours,cnts,-1,(0,0,255),3) # Because it is a binary image , So as long as it's not 255,255,255 Will turn black
print(len(cnts))
cv_show1('thresh_Contours',thresh_Contours)
questionCnts = []
82

# Traverse
for c in cnts:
# Calculate scale and size
(x, y, w, h) = cv2.boundingRect(c)
ar = w / float(h)
# Specify the standard according to the actual situation
if w >= 20 and h >= 20 and ar >= 0.9 and ar <= 1.1:
questionCnts.append(c)
Sort the outline to get the sequence number
# Sort from top to bottom
questionCnts = sort_contours(questionCnts,
method="top-to-bottom")[0]
correct = 0
# Each row has 5 An option
for (q, i) in enumerate(np.arange(0, len(questionCnts), 5)):
# Sort
cnts = sort_contours(questionCnts[i:i + 5])[0]
bubbled = None
# Traverse every result
for (j, c) in enumerate(cnts):
# Use mask To judge the result
mask = np.zeros(thresh.shape, dtype="uint8")
cv2.drawContours(mask, [c], -1, 255, -1) #-1 Indicates filling
# Choose this answer by calculating the number of nonzero points
mask = cv2.bitwise_and(thresh, thresh, mask=mask)
total = cv2.countNonZero(mask)
cv_show1('mask',mask)
# Judging by threshold
if bubbled is None or total > bubbled[0]:
bubbled = (total, j)
# Compare the right answers
color = (0, 0, 255)
k = ANSWER_KEY[q]
# To judge correctly
if k == bubbled[1]:
color = (0, 255, 0)
correct += 1
# mapping
cv2.drawContours(warped, [cnts[k]], -1, color, 3)
![]() | ![]() | ![]() | ![]() | ![]() |
![]() | ![]() | ![]() | ![]() | ![]() |
![]() | ![]() | ![]() | ![]() | ![]() |
![]() | ![]() | ![]() | ![]() | ![]() |
![]() | ![]() | ![]() | ![]() | ![]() |
Print the results
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)
cv_show("Original", image)
cv_show1("Exam", warped)
[INFO] score: 80.00%


Reference resources
边栏推荐
- Word delete the contents in brackets
- C # display the list control, select the file to obtain the file path and filter the file extension, and RichTextBox displays the data
- OpenJudge NOI 2.1 1749:数字方格
- The ECU of 21 Audi q5l 45tfsi brushes is upgraded to master special adjustment, and the horsepower is safely and stably increased to 305 horsepower
- Multi attribute object detection on rare aircraft data sets: experimental process using yolov5
- Typescript interface and the use of generics
- The ECU of 21 Audi q5l 45tfsi brushes is upgraded to master special adjustment, and the horsepower is safely and stably increased to 305 horsepower
- word中如何删除某符号前面或后面所有的文字
- The way to learn go (II) basic types, variables and constants
- C - Inheritance - hidden method
猜你喜欢

Simulation of Teman green interferometer based on MATLAB

QT color is converted to string and uint

Three no resumes in the software testing industry. What does the enterprise use to recruit you? Shichendahai's resume

Excel的相关操作
![[computer skills]](/img/30/2a4506adf72eb4cb188dd64cce417d.jpg)
[computer skills]
![If Jerry needs to send a large package, he needs to modify the MTU on the mobile terminal [article]](/img/57/12a97ab3d2dabfaf06bbe1788450cf.png)
If Jerry needs to send a large package, he needs to modify the MTU on the mobile terminal [article]

杰理之BLE【篇】

Ali's redis interview question is too difficult, isn't it? I was pressed on the ground and rubbed

Relevant introduction of clip image

The ECU of 21 Audi q5l 45tfsi brushes is upgraded to master special adjustment, and the horsepower is safely and stably increased to 305 horsepower
随机推荐
Bit operation XOR
GET/POST/PUT/PATCH/DELETE含义
Introduction to the basics of network security
How MySQL merges data
Word delete the contents in brackets
Ble of Jerry [chapter]
Simple and understandable high-precision addition in C language
Lesson 12 study notes 2022.02.11
C - Inheritance - hidden method
word设置目录
On the world of NDK (2)
js對象獲取屬性的方法(.和[]方式)
NiO programming introduction
http缓存,强制缓存,协商缓存
杰理之蓝牙设备想要发送数据给手机,需要手机先打开 notify 通道【篇】
杰理之需要修改 gatt 的 profile 定义【篇】
Cf1036c class numbers solution
#systemverilog# 可綜合模型的結構總結
Ble of Jerry [chapter]
Pre knowledge reserve of TS type gymnastics to become an excellent TS gymnastics master
























