我有一张图片
由5个并行排列的复选框组成。
我需要单独使用复选框按钮
和复选框文本
并分别保存。
以并行方式排列的图像中可以有任意数量的复选框,如何拆分复选框按钮和复选框文本并分别保存。
我是计算机视觉的新手。请指导我如何实现。
答案 0 :(得分:2)
我已经拆分了以并行方式排列的图像,并像下面的图像一样保存了它们。
这是我的工作代码,用于拆分方形复选框和该图像中的文本。
# Import necessary libraries
from matplotlib import pyplot as plt
import cv2
# Read image
image = cv2.imread('data_2/5.png')
# Height and width of the image
height, width = image.shape[:2]
print("Dimensions of the image.")
print("Height:",height)
print("Width:",width)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (5,5), 0)
# Finding Edges
edges = cv2.Canny(gray, 60, 255)
# contours -> an outline representing or bounding the shape.
_,cnts, hierarchy = cv2.findContours(edges.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = sorted(cnts, key=cv2.contourArea, reverse=True)[:10]
count = 1
for contour in contours:
if(count<=4):
#print("Count:",count)
count = count + 1
area = cv2.contourArea(contour)
if area > 100000 and area < 1000:
contours.remove(contour)
perimeter = cv2.arcLength(contour, True)
approx = cv2.approxPolyDP(contour, 0.01*perimeter, True)
if len(approx) == 4:
cv2.circle(image, (720, 360), 5, (255,0,0), 5)
cv2.drawContours(image, [approx], -1, (0, 255, 0), 2)
M = cv2.moments(approx)
centers = []
if M["m00"] != 0:
cX = int(M["m10"] / M["m00"])
cY = int(M["m01"] / M["m00"])
else:
cX, cY = 0, 0
P1 = approx[0]
P1x = P1[0][0]
P1y = P1[0][1]
P2 = approx[1]
P2x = P2[0][0]
P2y = P2[0][1]
P3 = approx[2]
P3x = P3[0][0]
P3y = P3[0][1]
P4 = approx[3]
P4x = P4[0][0]
P4y = P4[0][1]
plt.imshow(image)
plt.title('Detecting Square')
plt.show()
# Cropping the square_image using array slices -- it's a NumPy array
cropped_square = image[P1y:P3y, P2x:P3x]
# Cropping the text image
cropped_text = image[P1y:P3y,P3x+5:width]
# Displaying the cropped square and cropped text image.
plt.imshow(cropped_square)
plt.title('Cropped Square')
plt.show()
plt.imshow(cropped_text)
plt.title('Cropped Text')
plt.show()
# Now saving the cropped square and cropped text image
cv2.imwrite('results/square1.png',cropped_square)
cv2.imwrite('results/text1.png',cropped_text)
上述程序的输出:
答案 1 :(得分:2)
我的回答有点晚了,但是也许它将为别人提供一个替代性的想法。
首先,您在图像中搜索轮廓,并创建蒙版和最终图像以显示结果。
对于每个轮廓,您都可以找到轮廓的大小,这样可以帮助您从字母中过滤出框(框的尺寸较大)。对于复选标记,我找到了按大小以及到轮廓左侧和右侧的极值点的距离进行过滤的解决方案(您可以找到很多不同的标准来过滤检查点,并且可能会有很多更好的标准-我专注于仅在您在问题中发布的图片上。)
要进入感兴趣的区域,您可以使用cv2.boundingRect()找到x,y,h,w值
然后,您只需将其绘制在开始时创建的图像上(请注意,这些输出仅为黑白)。也许这种方法会给你一些想法。干杯!
代码示例:
import cv2
import numpy as np
img = cv2.imread('checkbox.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, threshold = cv2.threshold(gray,170,255,cv2.THRESH_BINARY_INV)
im, contours, hierarchy = cv2.findContours(threshold,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
final = np.zeros(gray.shape,np.uint8)
mask = np.zeros(gray.shape,np.uint8)
final2 = np.zeros(gray.shape,np.uint8)
list1 = []
for i in range(0, len(contours)):
cnt = contours[i]
epsilon = 0.1*cv2.arcLength(cnt,True)
approx = cv2.approxPolyDP(cnt,epsilon,True)
size = cv2.contourArea(approx)
extLeft = tuple(cnt[cnt[:, :, 0].argmin()][0])
extRight = tuple(cnt[cnt[:, :, 0].argmax()][0])
distance = np.sqrt((extLeft[0] - extRight[0])**2 + (extLeft[1] - extRight[1])**2)
x,y,w,h = cv2.boundingRect(cnt)
mask[x:x+h, y:y+w]=0
if 700 > size > 220:
cv2.drawContours(mask,contours,i,255,-1)
cv2.drawContours(final,contours,i,255,2)
elif 16 < distance < 17 and size > 60:
list1.append(cnt)
elif size < 250:
cv2.drawContours(final2,contours,i,(255,255,255),1)
for i in list1:
cv2.drawContours(final, [i], -1, (255,255,255), -1)
cv2.bitwise_not(final,final)
cv2.bitwise_not(final2,final2)
cv2.imwrite('c_orig.png', img)
cv2.imwrite('c_boxes.png', final)
cv2.imwrite('c_text.png', final2)
cv2.imshow('img', img)
cv2.imshow('img2', final)
cv2.imshow('img3', final2)
cv2.waitKey(0)
cv2.destroyAllWindows()
输出:
答案 2 :(得分:0)
假设不管复选框的数量如何,您的图像都将遵循网格状图案,那么不错的选择是尝试模板匹配。 MSTM是一个示例。
您应该尝试使用模板匹配在图像中找到选中或未选中的框,然后将区域提取到其右侧。既然您提到连续最多有5个复选框,那么您可以检查图像的宽度,将其除以5并获得文本区域的大致大小