如何从图像中提取不同边缘强度的矩形?
Posted
技术标签:
【中文标题】如何从图像中提取不同边缘强度的矩形?【英文标题】:How to extract rectangles of varying edge intensity from images? 【发布时间】:2018-10-30 21:50:49 【问题描述】:我正在尝试从支票图像中提取帐号。我的逻辑是,我试图找到包含帐号的矩形,对边界矩形进行切片,然后将切片输入 OCR 以从中获取文本。
我面临的问题是当矩形不是很突出和浅色时,由于边缘没有完全连接,我无法获得矩形轮廓。
如何克服这个问题? 我尝试过但没有奏效的事情是
-
我不能增加腐蚀迭代,以更多地腐蚀它,因为这样边缘会与周围的黑色像素连接并形成不同的形状。
降低阈值偏移量可能会有所帮助,但似乎效率低下。由于代码必须处理多种类型的图像。我可以从偏移量 10 开始并不断增加偏移量并检查是否找到了矩形。这将大大增加检查具有突出矩形的时间,这些矩形在偏移量 20 或更大时工作良好。而且由于我没有条件检查矩形的边缘是否突出,因此必须在所有支票中应用循环。
牢记以上几点。有人可以帮我解决这个问题吗?
使用的库和版本
scikit-image==0.13.1
opencv-python==3.3.0.10
代码
from skimage.filters import threshold_adaptive, threshold_local
import cv2
第 1 步:
image = cv2.imread('cropped.png')
第 2 步:
使用来自skimage的自适应阈值去除背景,这样我就可以得到帐号矩形框。这适用于矩形更明显的检查,但是当矩形边缘较薄或颜色较浅时,阈值会导致 未连接的边缘,因此我无法找到轮廓。我在问题的后面附上了这方面的例子。
account_number_block = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
account_number_block = threshold_adaptive(account_number_block, 251, offset=20)
account_number_block = account_number_block.astype("uint8") * 255
第 3 步:
稍微腐蚀图像以尝试连接边缘中的小断开连接
kernel = np.ones((3,3), np.uint8)
account_number_block = cv2.erode(account_number_block, kernel, iterations=5)
寻找轮廓
(_, cnts, _) = cv2.findContours(account_number_block.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
# cnts = sorted(cnts, key=cv2.contourArea)[:3]
rect_cnts = [] # Rectangular contours
for cnt in cnts:
approx = cv2.approxPolyDP(cnt,0.01*cv2.arcLength(cnt,True),True)
if len(approx) == 4:
rect_cnts.append(cnt)
rect_cnts = sorted(rect_cnts, key=cv2.contourArea, reverse=True)[:1]
工作示例
第 1 步:原始图像
第 2 步:阈值化后去除背景。
第3步:寻找轮廓找到账号的矩形框。
失败的工作示例 - 浅色矩形边界。
第一步:读取原图
第 2 步:阈值化后去除背景。请注意,矩形的边缘没有连接,因此我无法从中获取轮廓。
第3步:寻找轮廓找到账号的矩形框。
【问题讨论】:
你能再发几张图片吗? 当然@zindarod,给几分钟。我会发帖的。 【参考方案1】:import numpy as np
import cv2
import pytesseract as pt
from PIL import Image
#Run Main
if __name__ == "__main__" :
image = cv2.imread("image.jpg", -1)
# resize image to speed up computation
rows,cols,_ = image.shape
image = cv2.resize(image, (np.int32(cols/2),np.int32(rows/2)))
# convert to gray and binarize
gray_img = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
binary_img = cv2.adaptiveThreshold(gray_img, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 9, 9)
# note: erosion and dilation works on white forground
binary_img = cv2.bitwise_not(binary_img)
# dilate the image to fill the gaps
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3,3))
dilated_img = cv2.morphologyEx(binary_img, cv2.MORPH_DILATE, kernel,iterations=2)
# find contours, discard contours which do not belong to a rectangle
(_, cnts, _) = cv2.findContours(dilated_img, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
rect_cnts = [] # Rectangular contours
for cnt in cnts:
approx = cv2.approxPolyDP(cnt,0.01*cv2.arcLength(cnt,True),True)
if len(approx) == 4:
rect_cnts.append(cnt)
# sort contours based on area
rect_cnts = sorted(rect_cnts, key=cv2.contourArea, reverse=True)[:1]
# find bounding rectangle of biggest contour
box = cv2.boundingRect(rect_cnts[0])
x,y,w,h = box[:]
# extract rectangle from the original image
newimg = image[y:y+h,x:x+w]
# use 'pytesseract' to get the text in the new image
text = pt.image_to_string(Image.fromarray(newimg))
print(text)
cv2.namedWindow('Image', cv2.WINDOW_NORMAL)
cv2.imshow('Image', newimg)
cv2.waitKey(0)
cv2.destroyAllWindows()
结果:03541140011724
结果:34785736216
【讨论】:
抱歉,我无法上传更多示例。并感谢您的回答。我认为这里的关键是您所做的调整大小和 cv2.adaptiveThreshold 对吗?在不影响 tesseract 的识别的情况下,我们可以将大小缩小到最小是多少?我会试试这个,并接受答案。 调整大小要求因图像而异。对于您的图像,测试不同的尺寸,直到 tesseract 不再能够识别文本。 伟大的直觉加 1 !!以上是关于如何从图像中提取不同边缘强度的矩形?的主要内容,如果未能解决你的问题,请参考以下文章