【问题标题】:How to extract diagram from an image?如何从图像中提取图表?
【发布时间】:2021-03-30 19:16:59
【问题描述】:

我使用了基于轮廓的方法,但它检测到的轮廓太多了。如何提取我的 ROI 轮廓?

image = cv2.imread('ULTI.png')
original = image.copy()
cv2.imwrite("bg.png",bg)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (3, 3), 0)
canny = cv2.Canny(blurred, 120, 255, 1)
kernel = np.ones((5,5),np.uint8)
dilate = cv2.dilate(canny, kernel, iterations=1)

# Find contours
cnts = cv2.findContours(dilate, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]

# Iterate thorugh contours and filter for ROI
image_number = 0
cnts = max(cnts, key = cv2.contourArea)
print("no ",len(cnts))
for c in cnts:
    x,y,w,h = cv2.boundingRect(c)
    cv2.rectangle(image, (x, y), (x + w, y + h), (36,255,12), 2)
    ROI = original[y:y+h, x:x+w]

    #cv2.imwrite("ROI_{}.png".format(image_number), ROI)
    image_number += 1

【问题讨论】:

    标签: python opencv image-processing computer-vision ocr


    【解决方案1】:

    您可以通过指定只使用面积最大的轮廓来获得投资回报率,也就是说,如果您的图表将生成一个面积大于图像中其他组件的轮廓。

    这是一个例子:

    import cv2
    
    def preprocess(img):
        img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        img_blur = cv2.GaussianBlur(img_gray, (5, 5), 1)
        img_canny = cv2.Canny(img_blur, 50, 50)
        return img_canny
    
    def get_roi(img, pad=3):
        contours, hierarchy = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
        max_area = 0
        
        for cnt in contours:
            peri = cv2.arcLength(cnt, True)
            approx = cv2.approxPolyDP(cnt, 0.02 * peri, True)
            x, y, w, h = cv2.boundingRect(approx)
            rect_area = w * h
            if rect_area > max_area:
                max_area = rect_area
                dim = x, y, w, h
    
        if max_area:
            x, y, w, h = dim
            return x - pad, y - pad, w + pad * 2, h + pad * 2 
    
    img = cv2.imread("ULTI.png")
    
    img_processed = preprocess(img)
    x, y, w, h = get_roi(img_processed)
    
    cv2.imshow("Image", img[y:y + h, x:x + w])
    cv2.waitKey(0)
    

    输出:

    解释:

    1. 导入必要的模块:
    import cv2
    
    1. 定义一个接收图像的函数,并返回图像的处理版本,使 python 能够正确检测必要的轮廓(您可以调整值以进一步满足您的需求):
    def preprocess(img):
        img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        img_blur = cv2.GaussianBlur(img_gray, (5, 5), 1)
        img_canny = cv2.Canny(img_blur, 50, 50)
        return img_canny
    
    1. 现在,让我们看看如何定义一个函数来检索图像的 ROI。首先,定义它,以便可以将处理后的图像数组和填充量(可选)作为参数传入:
    def get_roi(img, pad=3):
    
    1. 找到处理后图像的轮廓,并定义一个变量来存储轮廓的最大面积:
        contours, hierarchy = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
        max_area = 0
    
    1. 使用for循环遍历轮廓,求循环每次迭代的轮廓面积:
        for cnt in contours:
            peri = cv2.arcLength(cnt, True)
            approx = cv2.approxPolyDP(cnt, 0.02 * peri, True)
            area = cv2.contourArea(approx)
    
    1. 使用if 语句检查面积是否大于应存储最大面积的已定义变量。如果该迭代的轮廓的面积大于变量,则将变量的值更新为等于新区域。此外,将该迭代的轮廓保存到一个变量中:
            if area > max_area:
                max_area = area
                max_cnt = approx
    
    1. 在for 循环之后,如果max_area 变量不等于0,则还定义了max_cnt。使用cv2.boundingRect 获取x、y、w 和h 属性:
        if max_area:
            x, y, w, h = cv2.boundingRect(max_cnt)
            return x - pad, y - pad, w + pad * 2, h + pad * 2 
    
    1. 最后,将图像读入变量后,您可以利用我们定义的 2 个函数,并显示生成的图像:
    img = cv2.imread("ULTI.png")
    
    img_processed = preprocess(img)
    x, y, w, h = get_roi(img_processed)
    
    cv2.imshow("Image", img[y:y + h, x:x + w])
    cv2.waitKey(0)
    

    注意:代码可能不适用于所有图表。但同样,您可以调整 preprocess 函数中的值以满足您的需求。

    【讨论】:

      猜你喜欢
      • 2022-07-15
      • 2021-06-12
      • 2020-07-08
      • 1970-01-01
      • 1970-01-01
      • 2017-04-30
      • 1970-01-01
      • 2010-09-15
      • 1970-01-01
      相关资源
      最近更新 更多