Python 如何从图像中提取不同边缘强度的矩形?

Python 如何从图像中提取不同边缘强度的矩形?,python,opencv,scikit-image,Python,Opencv,Scikit Image,我试图从支票图像中提取账号。我的逻辑是,我试图找到包含帐号的矩形,对边界矩形进行切片,然后将切片输入OCR,从中提取文本 我面临的问题是,当矩形不是很突出且颜色较浅时,我无法获得矩形轮廓,因为边缘没有完全连接 如何克服这个问题? 我尝试过但没有成功的事情 我不能增加侵蚀迭代次数来进一步侵蚀,因为这样边缘就会与周围的黑色像素相连,形成不同的形状。 降低阈值偏移量可能会有所帮助,但似乎效率低下。因为代码必须处理几种类型的图像。我可以从偏移量10开始,不断增加偏移量并检查是否找到矩形。这将大大增加带有

我试图从支票图像中提取账号。我的逻辑是,我试图找到包含帐号的矩形,对边界矩形进行切片,然后将切片输入OCR,从中提取文本

我面临的问题是,当矩形不是很突出且颜色较浅时,我无法获得矩形轮廓,因为边缘没有完全连接

如何克服这个问题? 我尝试过但没有成功的事情

我不能增加侵蚀迭代次数来进一步侵蚀,因为这样边缘就会与周围的黑色像素相连,形成不同的形状。 降低阈值偏移量可能会有所帮助,但似乎效率低下。因为代码必须处理几种类型的图像。我可以从偏移量10开始,不断增加偏移量并检查是否找到矩形。这将大大增加带有突出矩形的支票的时间,这些支票在偏移量为20或更多时运行良好。因为我没有条件检查矩形的边是否突出,所以循环必须应用于所有的支票。 记住以上几点。有人能帮我解决这个问题吗

使用的库和版本

scikit-image==0.13.1
opencv-python==3.3.0.10
代码

步骤1:

步骤2:

使用自适应阈值从浏览中删除背景,这样我就可以得到帐号矩形框。这适用于矩形更明显的支票,但当矩形边缘较薄或颜色较浅时,阈值会导致 未连接的边,因此我无法找到轮廓。我在问题的后面附上了这方面的例子

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:原始图像

第二步:阈值化后去除背景

第三步:找到轮廓,找到帐号的矩形框

故障工作示例-轻型矩形边界

步骤1:读取原始图像

第二步:阈值化后去除背景。请注意,矩形的边没有连接,因此我无法从中获得轮廓

第三步:找到轮廓,找到帐号的矩形框

结果:03541140011724

结果:34785736216

结果:03541140011724


结果:34785736216

你能再发几张图片吗?当然可以@zindarod,再等几分钟。我会发的。你能再发几张照片吗?当然可以@zindarod,给我几分钟。我会发布的。很抱歉,我无法上传更多的样本。谢谢你的回答。我认为这里的关键是你所做的调整大小和cv2.adaptiveThreshold,对吗?在不影响tesseract识别的情况下,我们可以将尺寸减小到的最小值是多少?我会尝试一下,并接受答案。不同的图像的大小要求不同。对于您的图像,测试不同的大小,直到tesseract不再能够识别文本。伟大的直觉加上1!!很抱歉,我无法上传更多的样本。谢谢你的回答。我认为这里的关键是你所做的调整大小和cv2.adaptiveThreshold,对吗?在不影响tesseract识别的情况下,我们可以将尺寸减小到的最小值是多少?我会尝试一下,并接受答案。不同的图像的大小要求不同。对于您的图像,测试不同的大小,直到tesseract不再能够识别文本。伟大的直觉加上1!!
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]
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()