Python 将盒子分割成不同的图像
我试图从文档中读取信息,其中的数据字段类型为只能在框中输入一个字母/数字。我设法为各自的数据字段分割了框数组,但是在分割这些框数组中的各个框时遇到了问题 我曾尝试使用Python 将盒子分割成不同的图像,python,opencv,image-processing,computer-vision,Python,Opencv,Image Processing,Computer Vision,我试图从文档中读取信息,其中的数据字段类型为只能在框中输入一个字母/数字。我设法为各自的数据字段分割了框数组,但是在分割这些框数组中的各个框时遇到了问题 我曾尝试使用cv2.approxPolyDP和cv2.HoughLines函数,但这两个函数都给出了不可接受的结果。有一个问题利用了垂直/水平线的长度远大于单个数字这一事实。在我的例子中,数字有时会从盒子里溢出,几乎总是碰到盒子 此功能无法单独检测小盒子: def检测盒(img): 灰色=cv2.CVT颜色(img,cv2.COLOR\U B
cv2.approxPolyDP
和cv2.HoughLines
函数,但这两个函数都给出了不可接受的结果。有一个问题利用了垂直/水平线的长度远大于单个数字这一事实。在我的例子中,数字有时会从盒子里溢出,几乎总是碰到盒子
此功能无法单独检测小盒子:
def检测盒(img):
灰色=cv2.CVT颜色(img,cv2.COLOR\U BGR2GRAY)
sharp\u img=cv2.filter2D(np.asarray(灰色),-1,内核)
ret,thresh=cv2.阈值(夏普•伊姆格,180255,1)
边缘=cv2.Canny(锋利,50150,孔径尺寸=3)
_,等高线,h=cv2。findContours(阈值,1,2)
框=[]
对于轮廓中的cnt:
近似=cv2.近似聚合度(cnt,0.01*cv2.弧长(cnt,真),真)
温度=img
如果len(近似值)=4:
框。追加(cnt)
打印(cnt.形状)
打印(最大值(cnt[0])-min(cnt[0]),最大值(cnt[1])-min(cnt[1]))
cv2.拉伸轮廓(温度[cnt],0,(0,0255),-1)
cv2_显示(温度)
返回框
approxPolyDP
结果是:
另一个功能是:
def检测盒(img):
灰色=cv2.CVT颜色(img,cv2.COLOR\U BGR2GRAY)
sharp\u img=cv2.filter2D(np.asarray(灰色),-1,内核)
ret,thresh=cv2.阈值(夏普•伊姆格,180255,1)
边缘=cv2.Canny(灰色,50150,光圈尺寸=3)
cv2_imshow(边缘)
线=cv2.霍夫线(边,1,np.pi/180200)
温度=img
对于ρ,θ在[0]行中:
a=np.cos(θ)
b=np.sin(θ)
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.线(温度,(x1,y1),(x2,y2),(0,0255),2)
cv2_显示(温度)
回程线
HoughLines
结果是:
我试图按顺序获得每个小盒子的盒子点/轮廓。任何帮助都将不胜感激。即使去掉框中的水平线和垂直线也会有帮助。花了我一些时间,但我自己解决了 实际图像:
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)
_, 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)
在垂直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)
_, 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)
结果的按位或按位排序:
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)
#最后找到轮廓并找到边界框
imz,等高线,=cv2.findContours(
侵蚀,
cv2.RETR_树,cv2.CHAIN_近似值(简单)
等高线=等高线[:-1]
框=[]
对于轮廓中的cnt:
rect=cv2.boundingRect(cnt)
如果rect[2]/rect[3]<0.6或rect[3]/rect[2]<0.6:
持续
box.append(rect)
num_img=img[rect[1]:rect[1]+rect[3],rect[0]:rect[0]+rect[2]]
cv2_imshow(num)
裁剪后的长方体:
如果您事先知道带有未填充框的文档,您可以使用matchTemplate或筛选/浏览空文档作为模板,只需硬编码每个框相对于模板的位置,或者从文档中减去模板,只得到手绘的模板parts@HugoRune我认为那是最后的办法。然而,我设法找到了一个没有它的解决方案。