首页 > 解决方案 > 多个矩形的Python OpenCv交集

问题描述

我目前正在开展一个项目来识别图像中的文本部分。我在它们周围画了矩形,如下所示:

在此处输入图像描述

然后将它们切成每个矩形以对它们做更多的事情。像这样:在此处输入图像描述

在此处输入图像描述

我不想要的是,如图 2 所示,让一个矩形的一部分成为另一个矩形的一部分,例如。pic3 是 pic2 的一部分。这意味着这些部分应该被剪掉或变成白色,我不知道该怎么做。对于这些矩形的绘制,我使用以下代码部分:

image = cv2.imread(Photopath)
CopyImg = np.copy(image)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, ((1, 1)), 0)
thresh = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]

# Create rectangular structuring element and dilate
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (6, 9))
dilate = cv2.dilate(thresh, kernel, iterations=4)

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

for c in cnts:
    x,y,w,h = cv2.boundingRect(c)
    cv2.rectangle(image, (x, y), (x + w, y + h), (36,255,12), 2)
    paragraph = CopyImg[y:y+h,x:x+w]

    cv2.imwrite(outpath, paragraph)
    

我想我需要以某种方式将它们相交并从一个矩形中切出与所有其他触摸它的坐标的矩形?

这是未处理的图像:在此处输入图像描述

标签: pythonpython-3.xopencv

解决方案


这是一种可能的方法。首先,我将尝试检测每个文本块。块(或边界框)是否重叠并不重要。在获取图像上所有 blob 的所有边界框后,我将检测边界框重叠。如果边界框与其他边界框重叠,这意味着相同的文本块将在两个或多个图像之间共享。我将裁剪该部分并用白色矩形填充重叠区域,这样内容将仅显示在一张图像上。

这些是重要的步骤:

  1. 使用形态来获得漂亮的文本块。

  2. 检测这些块上的轮廓并将这些轮廓转换为 边界框

  3. 遍历所有边界框并:

    • 裁剪每个边界框

    • 检查可能的重叠。如果发现重叠(或相交),请使用边界框信息在该区域上绘制一个白色矩形。

这是代码,首先我们需要得到那些漂亮的文本块:

import numpy as np
import cv2

# image path
path = "C:/opencvImages/"
fileName = "sheet05.png"

# Reading an image in default mode:
inputImage = cv2.imread(path + fileName)

# Some deep copies of the input mat:
inputCopy = inputImage.copy()
cleanInputCopy = inputCopy.copy()

# Grayscale conversion:
grayscaleImage = cv2.cvtColor(inputImage, cv2.COLOR_BGR2GRAY)

# Thresholding:
threshValue, binaryImage = cv2.threshold(grayscaleImage, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
binaryImage = 255 - binaryImage

很标准的东西。只是read图像,将其转换为grayscale并通过Otsu. 您会注意到我创建了一些输入的深层副本。这些主要用于可视化结果,因为我最初绘制了每个bounding box找到的和每个重叠的区域。

应用一些非常强烈的形态来获得最好的文本块。我在这里应用扩张 + 侵蚀,每个操作有 10 次迭代:

# Dilate and Erode with a big Structuring Element:
kernelSize = 5
structuringElement = cv2.getStructuringElement(cv2.MORPH_RECT, (kernelSize, kernelSize))
iterations = 10
dilatedImage = cv2.morphologyEx(binaryImage, cv2.MORPH_DILATE, structuringElement, None, None, iterations,
                                cv2.BORDER_REFLECT101)
erodedImage = cv2.morphologyEx(dilatedImage, cv2.MORPH_ERODE, structuringElement, None, None, iterations,
                               cv2.BORDER_REFLECT101)

最后一个片段为您提供此图像:

现在,获取该图像的外轮廓并计算边界框:

# Find the big contours/blobs on the filtered image:
contours, hierarchy = cv2.findContours(erodedImage, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE)

contours_poly = [None] * len(contours)
boundRect = []

# Alright, just look for the outer bounding boxes:
for i, c in enumerate(contours):
    if hierarchy[0][i][3] == -1:
        contours_poly[i] = cv2.approxPolyDP(c, 3, True)
        boundRect.append(cv2.boundingRect(contours_poly[i]))

现在,重要的部分来了。我们将遍历每个bounding box. 裁剪图像,并检查最近bounding box用于裁剪图像的图像是否在另一个内部bounding box(重叠)。如果是这种情况,只需在该区域内绘制一个大的白色矩形并继续进行新的裁剪:

# Loop thru all bounding boxes:
for i in range(len(boundRect)):

    # Get current boundRect:
    sourceRect = boundRect[i]

    # Crop the roi:
    croppedImg = cleanInputCopy[sourceRect[1]:sourceRect[1] + sourceRect[3],
                 sourceRect[0]:sourceRect[0] + sourceRect[2]]

    # Check against other bounded rects:
    for j in range(len(boundRect)):

        # Get target boundRect:
        targetRect = boundRect[j]

        # Check for intersections:
        if i != j:

            foundIntersect, overlappedRect = checkIntersection(sourceRect, targetRect)

            if foundIntersect:

                # Found some overlapped rects, draw white rectangle at this location:
                cv2.rectangle(cleanInputCopy, (int(overlappedRect[0]), int(overlappedRect[1])),
                              (int(overlappedRect[0] + overlappedRect[2]), int(overlappedRect[1] + overlappedRect[3])),
                              (255, 255, 2550), -1)

    cv2.rectangle(inputCopy, (int(boundRect[i][0]), int(boundRect[i][1])),
                  (int(boundRect[i][0] + boundRect[i][2]), int(boundRect[i][1] + boundRect[i][3])), color, 5)

这些是为每个二进制 blob 检测到的边界框:

代码检测重叠区域并在交叉点上绘制一个白色矩形,这样它将不再显示在以下裁剪上:

这些是作物(请注意,这些是单独的图像):

现在,检测边界框相交的辅助函数是这样的:

# Check for boxA and boxB intersection
def checkIntersection(boxA, boxB):
    
    x = max(boxA[0], boxB[0])
    y = max(boxA[1], boxB[1])
    w = min(boxA[0] + boxA[2], boxB[0] + boxB[2]) - x
    h = min(boxA[1] + boxA[3], boxB[1] + boxB[3]) - y

    foundIntersect = True
    if w < 0 or h < 0:
        foundIntersect = False

    return(foundIntersect, [x, y, w, h])

这非常简单。它只是获取两个边界矩形的坐标并计算相交区域。如果widthorheight小于零,则不存在交集。


推荐阅读