【问题标题】:How to get these ROIs for these images in OpenCV如何在 OpenCV 中为这些图像获取这些 ROI
【发布时间】:2021-09-16 01:00:02
【问题描述】:

我有一些示例图片如下

我要做的是从图像中删除标签,因此生成的图像应如下所示

最后我想得到如图所示的矩形

到目前为止,我有代码可以使用模板并删除边框以获得第一个结果

import cv2
import numpy as np


def remove_templates(image):
    templates = ['images/sample1.jpeg', 'images/sample2.jpeg']
    for template in templates:
        template = cv2.imread(template)
        h, w, _ = template.shape
        res = cv2.matchTemplate(cv2.cvtColor(img, cv2.COLOR_BGR2GRAY), cv2.cvtColor(template, cv2.COLOR_BGR2GRAY), cv2.TM_CCOEFF)
        min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
        top_left = max_loc
        bottom_right = (top_left[0] + w, top_left[1] + h)
        cv2.rectangle(img, top_left, bottom_right, (1, 1, 1), -1)


def crop_borders(img):
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    gray = 255 * (gray < 128).astype(np.uint8)  # To invert the text to white
    gray = cv2.morphologyEx(gray, cv2.MORPH_OPEN, np.ones((2, 2), dtype=np.uint8))  # Perform noise filtering
    canny = cv2.Canny(gray, 0, 150)
    coords = cv2.findNonZero(canny)  # Find all non-zero points (text)
    x, y, w, h = cv2.boundingRect(coords)  # Find minimum spanning bounding box
    rect = img[y:y + h, x:x + w + 20]  # Crop the image - note we do this on the original image
    return rect


img = cv2.imread('images/res5.jpg')
remove_templates(img)
img = crop_borders(img)

cv2.imwrite('output/op1.png', img)
cv2.imwrite('output/op2.png', cv2.cvtColor(img, cv2.COLOR_BGR2GRAY))


height = img.shape[0]
width = img.shape[1]
# Cut the image in half
width_cutoff = (width // 2)
left = img[:, :width_cutoff+5]
right = img[:, width_cutoff+25:]


cv2.imwrite('output/left.png', left)
cv2.imwrite('output/right.png', right)

上面的代码确实给了我第一个结果,但是当徽标的纵横比或大小不同时失败。

我怎样才能做到这一点,任何帮助都会非常有帮助。

我是opencv的新手,所以任何方向都会有所帮助。我现在拥有的大部分代码都是从不同的教程中挑选的。如果代码有问题,请指导我。

【问题讨论】:

  • 为此,您有什么想法或在网上找到的?
  • 您需要在图像上绘制矩形。我正在分享相同的参考。我希望你能实现它。 docs.opencv.org/3.4/da/d0c/tutorial_bounding_rects_circles.html
  • @ChristophRackwitz 在代码中,我试图找到模板并用黑色反应角替换它们,然后裁剪图像以删除边框。但是,如果纵横比或大小不同,则模板不匹配。之后我打算画线可能使用精明和轮廓检测
  • 那么,哪个图像是起点?第二个还是第三个?
  • 还有,ROI 的数量……这是一个常数吗……如果不是,它是否以起始图像而闻名?

标签: python opencv tesseract


【解决方案1】:

概念

  1. 定义一个函数,将 BGR 图像处理为具有增强框边​​缘的二值图像。

  2. 定义一个函数,该函数接收 BGR 图像并返回从图像中检测到的轮廓(使用前一个函数处理),这些轮廓在特定区域范围内。

  3. 绘制每个轮廓的边界框,并裁剪图像,将所有轮廓连接起来,得到所有轮廓的边界框,用于对图像进行切片。

代码

import cv2
import numpy as np

def process(img):
    img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    img_gray[img_gray < 5] = 255
    return cv2.dilate(cv2.Canny(img_gray, 50, 75), np.ones((4, 4)), iterations=2)

def get_cnts(img):
    cnts, _ = cv2.findContours(process(img), cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
    return [cnt for cnt in cnts if 80000 > cv2.contourArea(cnt) > 40000]
    
img = cv2.imread("image.png")
cnts = get_cnts(img)

for cnt in cnts:
    x, y, w, h = cv2.boundingRect(cnt)
    cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 3)

x, y, w, h = cv2.boundingRect(np.concatenate(cnts))
cv2.imshow("Image", img[y: y + h, x: x + w])

cv2.waitKey(0)
cv2.destroyAllWindows()

输出

以下是提供的两个示例图像的结果图像:

解释

  1. 导入所有必要的模块:
import cv2
import numpy as np
  1. 定义一个函数process(),它接受一个 BGR 图像数组作为其参数:
def process(img):
  1. 处理从将图像转换为灰度开始。然后我们将灰度数组中小于5 的每个值替换为更大的数字(我使用了255。这样做的原因是为了减轻图像的背景,以便更容易检测到框的边缘:
    img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    img_gray[img_gray < 5] = 255
  1. 我们现在可以使用 canny 边缘检测器来检测框的边缘。 2 膨胀的迭代将很好地增强检测到的边缘。然后返回膨胀后的图像(二进制格式)
    return cv2.dilate(cv2.Canny(img_gray, 50, 75), np.ones((4, 4)), iterations=2)
  1. 定义一个函数get_pts(),它接受一个 BGR 图像数组作为其参数:
def get_cnts(img):
  1. 使用cv2.findContours()方法,我们找到图像的轮廓(使用我们之前定义的process()函数处理),并返回所有在@987654341之上的轮廓的列表@ 在区域内及以下80000 在区域内。显着不同的盒子尺寸需要调整这些值:
    cnts, _ = cv2.findContours(process(img), cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
    return [cnt for cnt in cnts if 80000 > cv2.contourArea(cnt) > 40000]
  1. 读入图像文件,获取其轮廓,并使用cv2.boundingRect()cv2.rectangle() 方法绘制每个轮廓的边界矩形:
img = cv2.imread("image.png")
cnts = get_cnts(img)

for cnt in cnts:
    x, y, w, h = cv2.boundingRect(cnt)
    cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 3)
  1. 最后,为了裁剪图像,得到组合列表中所有轮廓的边界矩形(可以通过使用np.concatenate()方法连接轮廓来完成)并显示结果:
x, y, w, h = cv2.boundingRect(np.concatenate(cnts))
cv2.imshow("Image", img[y: y + h, x: x + w])

cv2.waitKey(0)
cv2.destroyAllWindows()

【讨论】:

  • 很有魅力,非常感谢
  • @EkanshRastogi 我很高兴!
  • 最后一个问题,我如何获得将其发送到 tesserect 的投资回报率。我想调用 tersseract 来阅读文本,我正在尝试调用方法 text = pytesseract.image_to_string(roi, config=config)
  • @EkanshRastogi 您可以通过边界矩形对原始图像进行切片,就像对最终图像进行切片一样,例如img[y: y + h, x: x + w]
猜你喜欢
  • 2013-12-28
  • 2019-07-20
  • 2017-05-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-08
  • 1970-01-01
相关资源
最近更新 更多