我正在尝试从文档中读取信息,在这些文档中,数据字段的类型只能在一个框中输入一个字母/数字。我设法为各个数据字段分割了框数组,但是在分割这些框数组中的各个框时遇到了问题。
我尝试使用cv2.approxPolyDP
和cv2.HoughLines
函数,但是两者均给出不可接受的结果。 sudoku问题在某一点上使用了这样一个事实,即垂直/水平线的长度比单个数字大得多。就我而言,数字有时会从包装箱中溢出,并且几乎总是碰到包装箱。
此功能无法单独检测小盒子:
def detect_boxes(img):
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
sharp_img = cv2.filter2D(np.asarray(gray), -1, kernel)
ret,thresh = cv2.threshold(sharp_img,180,255,1)
edges = cv2.Canny(sharp_img,50,150,apertureSize = 3)
_,contours,h = cv2.findContours(thresh,1,2)
boxes = []
for cnt in contours:
approx = cv2.approxPolyDP(cnt,0.01*cv2.arcLength(cnt,True),True)
temp = img
if len(approx)==4:
boxes.append(cnt)
print(cnt.shape)
print(max(cnt[0])-min(cnt[0]),max(cnt[1])-min(cnt[1]))
cv2.drawContours(temp,[cnt],0,(0,0,255),-1)
cv2_imshow(temp)
return boxes
approxPolyDP
的结果是:
另一个功能是:
def det_box(img):
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
sharp_img = cv2.filter2D(np.asarray(gray), -1, kernel)
ret,thresh = cv2.threshold(sharp_img,180,255,1)
edges = cv2.Canny(gray,50,150,apertureSize = 3)
cv2_imshow(edges)
lines = cv2.HoughLines(edges,1,np.pi/180,200)
temp = img
for rho,theta in lines[0]:
a = np.cos(theta)
b = np.sin(theta)
x0 = a*rho
y0 = b*rho
x1 = int(x0 + 1000*(-b))
y1 = int(y0 + 1000*(a))
x2 = int(x0 - 1000*(-b))
y2 = int(y0 - 1000*(a))
cv2.line(temp,(x1,y1),(x2,y2),(0,0,255),2)
cv2_imshow(temp)
return lines
HoughLines
的结果是:
我试图按顺序获取每个小盒子的盒子点/轮廓。任何帮助将不胜感激。即使删除框中的水平和垂直线也将很有帮助。
答案 0 :(得分:1)
花一些时间,但我自己想通了。
实际图片:
if len(img.shape) != 2:
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
else:
gray = img
kernel = np.array([[-1,-1,-1],[-1,9,-1],[-1,-1,-1]])
sharp_img = cv2.filter2D(np.asarray(gray), -1, kernel)
gray = cv2.bitwise_not(gray)
ret,bw = cv2.threshold(sharp_img,200,255,1)
#### HORIZONTAL TRANSFORMATIONS #######
hz_kernel = np.array([[1,2,1],[0,0,0],[-1,-2,-1]])
vert_kernel = np.array([[-1,0,1],[-2,0,2],[-1,0,1]])
hz_img = cv2.filter2D(np.asarray(bw),-1,hz_kernel)
dilated = cv2.dilate(hz_img, np.ones((1, 5)),iterations = 2)
hz_img = cv2.erode(dilated,np.ones((1,5)),iterations = 4)
#cv2_imshow(bw)
print('after hz sobel->')
cv2_imshow(hz_img)
在水平sobel滤波器之后:
_, contours, hierarchy = cv2.findContours(
hz_img,
cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
mask = np.ones(img.shape[:2], dtype="uint8") * 255
for cnt in contours:
x,y,w,h = cv2.boundingRect(cnt)
if w < (img.shape[1] - 10):
#print(w)
cv2.drawContours(mask, [cnt], -1, 0, -1)
hz_lines = cv2.bitwise_and(hz_img, hz_img, mask=mask)
if i == 0:
print("after removing noise")
cv2_imshow(hz_lines)
消除水平杂讯后:
######## VERTICAL TRANSFORMATIONS #########
vert_img = cv2.filter2D(np.asarray(bw),-1,vert_kernel)
dilated = cv2.dilate(vert_img, np.ones((3, 1)),iterations = 1)
vert_img = cv2.erode(dilated,np.ones((3,1)),iterations = 1)
print("after vertical soble->")
cv2_imshow(vert_img)
在垂直sobel滤波器之后:
_, vert_contours, _ = cv2.findContours(
vert_img,
cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
vert_mask = np.ones(img.shape[:2], dtype="uint8") * 255
for cnt in vert_contours:
x,y,w,h = cv2.boundingRect(cnt)
if h<vert_img.shape[0]-10 or w > 5:
#print(w)
cv2.drawContours(vert_mask, [cnt], -1, 0, -1)
vert_lines = cv2.bitwise_and(vert_img, vert_img, mask=vert_mask)
print('after removing noise ->')
cv2_imshow(vert_lines)
去除垂直噪声后:
####### COMBINATION ##########
boxes_array = cv2.bitwise_or(vert_lines,hz_lines)
print('box array')
cv2_imshow(boxes_array)
按位或结果:
dilated = cv2.dilate(boxes_array, np.ones((7, 7)),iterations = 3)
eroded = cv2.bitwise_not(cv2.erode(dilated,np.ones((7,7)),iterations = 3))
print('dilated and inverted->')
cv2_imshow(eroded)
膨胀,腐蚀和反转后:
# Finally find the contours and find the bounding boxes
imz,contours,_ = cv2.findContours(
eroded,
cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[::-1]
boxes = []
for cnt in contours:
rect = cv2.boundingRect(cnt)
if rect[2]/rect[3] < 0.6 or rect[3]/rect[2] < 0.6:
continue
boxes.append(rect)
num_img = img[rect[1]:rect[1]+rect[3],rect[0]:rect[0]+rect[2]]
cv2_imshow(num)
裁剪后的盒子: