
As mentioned in the previous method, the thickness of the printed font may affect the judgment of the result; moreover, the difference in binary statistics is not so significant. So, can we, through image preprocessing, remove the interference of the printed content, increase the difference between filled and unfilled areas, and thereby facilitate the statistical and judgment of the results?
1.First, read the image and converted into a grayscale image.
ori_img = cv2.imread(img_path, cv2.IMREAD_ANYCOLOR)
display_img = ori_img.copy()
gray = cv2.cvtColor(ori_img, cv2.COLOR_BGR2GRAY)
#增强图像对比度
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
gray_c = clahe.apply(gray)
#高斯滤波
gray_c = cv2.GaussianBlur(gray_c, (3, 3), 0)
2.Binaryization, then perform closing operation, eliminate the influence caused by uneven filling and coloring.
# 二值化处理,使用OTSU自动阈值
g_threshold, binary = cv2.threshold(gray_c, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
kernel_c= cv2.getStructuringElement(cv2.MORPH_RECT,(3,3))
closed = cv2.morphologyEx(binary, cv2.MORPH_CLOSE, kernel_c)
3.Observe the characteristics of the above binary image, Carry out a horizontal corrosion and a vertical corrosion separately, in the hope of eliminating the printed borders and letters.
kernel_h = cv2.getStructuringElement(cv2.MORPH_RECT,(11,1))
kernel_v = cv2.getStructuringElement(cv2.MORPH_RECT,(1,5))
c_binary = closed.copy()
#img_show(c_binary)
eroded = cv2.erode(c_binary, kernel_h, iterations=1)
#img_show(eroded)
eroded = cv2.erode(eroded, kernel_v, iterations=1)
#img_show(eroded)
target_bin = eroded.copy()
display_bin = cv2.cvtColor(target_bin, cv2.COLOR_GRAY2BGR)
At this point, we will find that through some preprocessing methods, the printed content has been largely eliminated.
4.It is better to appropriately expand the target area provided by the template. Since the erosion operation has been performed, the expansion range can be reduced. Use the expanded rectangle as the target area and calculate the filling ratio.
input_rate = []
for i in range(len(template_block_pos)):
block_lt_pt = template_block_pos[i]
ex_block_ltpt = (block_lt_pt[0] - 5, block_lt_pt[1] - 1)
ex_block_size = (template_block_size[0] + 10, template_block_size[1] + 2)
ex_block_rbpt = (ex_block_ltpt[0] + ex_block_size[0] , ex_block_ltpt[1] + ex_block_size[1])
cv2.rectangle(display_bin, (ex_block_ltpt[0], ex_block_ltpt[1]), (ex_block_rbpt[0] , ex_block_rbpt[1]), (0,255,0), 1)
ex_block_arr = target_bin[ex_block_ltpt[1] : ex_block_rbpt[1], ex_block_ltpt[0] : ex_block_rbpt[0]]
non_zero_count = np.count_nonzero(ex_block_arr)
input_rate.append(non_zero_count / (ex_block_size[0] * ex_block_size[1]))
img_show(display_bin)
input_rate_arr = np.reshape(input_rate,(5, 4))
print("填涂情况统计数据:")
print(input_rate_arr)

5.Line chart analysis

By looking at the line graph, it is clearly observable that the differences between the filled-in items and the non-filled-in items have become more pronounced.In this way, we can avoid using K-means clustering and directly use a fixed filling ratio to divide the filled items and the non-filled items.
6.The result matrix obtained from the fixed roi threshold division
ans = np.where(input_rate_arr > 0.1 , 1,0)
7.Visualization of the final result
for i in range(ans.shape[0]):
for j in range(ans.shape[1]):
if(ans[i][j] > 0 ):
str_answer = calculate_next_char('A', j)
font = cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(display_img,str_answer,ans_area[i],font,0.5,(0,0,255),2,cv2.LINE_AA)
img_show(display_img)
Shortcomings of this method:
1.The removal of printed content depends on the degree of corrosion, and different standards may apply to the test papers of different examinations.
2.For the options that are filled in with very light strokes but can still be identified as the correct answers by the human eye, there may be cases of blanking out.
3.To a certain extent, it still relies on the standardization of the filling process.
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。