OpenCV,用矩形覆盖轮廓

OpenCV, cover contour with rectangles

OpenCV 如何用多个矩形覆盖不规则形状?请参阅示例图。

矩形应该覆盖物体的最大面积并且可以是任何角度。重要的是它们不要相互重叠。如果矩形覆盖了一些背景,那完全没问题。

我找到了这个thread who split contours into small rectangles, but they do not merge into biggest rectangle possible. [https://answers.opencv.org/question/25912/split-contours-into-many-small-rectangles/]

我确实将 OpenCV 与 python 一起使用,但如果您有 C++ 示例代码,那完全没问题。

Before image

Wanted result

这是使用 Python/OpenCV 将其分成 4 个矩形的一种简单方法。

  • 读取输入
  • 转换为灰色
  • 阈值
  • 获取两个轮廓
  • 计算两条垂直线的长度,即外部(较大)轮廓高度的长度,但沿内部(较小)轮廓的两侧
  • 在阈值图像上绘制这些垂直线
  • 获取并绘制上一张图像的轮廓
  • 保存结果

输入:

import cv2
import numpy as np

# read image
img = cv2.imread('rectangles.png')
hh, ww = img.shape[:2]

# convert to grayscale
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

# threshold
thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY)[1]

# get contours and get the largest and smallest ones
contour_img = img.copy()
contours = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
min_area_thresh = hh * ww
max_area_thresh = 0
for cntr in contours:
    cv2.drawContours(contour_img, [cntr], -1, (0, 255, 0), 1)
    area = cv2.contourArea(cntr)
    if area < min_area_thresh:
        xs,ys,ws,hs = cv2.boundingRect(cntr)
        min_area_thresh = area
        small_contour = cntr
    if area > max_area_thresh:
        xl,yl,wl,hl = cv2.boundingRect(cntr)
        max_area_thresh = area
        large_contour = cntr


# compute vertical lines of height of large contour along the sides of the inner contours
x1 = xs
y1 = yl
x2 = x1
y2 = yl + hl - 1
x3 = xs + ws - 1
y3 = yl
x4 = x3
y4 = y2

# draw two vertical lines in black on thresholded image to separate segments
thresh2 = thresh.copy()
cv2.line(thresh2, (x1,y1), (x2,y2), 0, 1) 
cv2.line(thresh2, (x3,y3), (x4,y4), 0, 1) 

# get and draw contours from thresh2
result = thresh2.copy()
result = cv2.merge([result,result,result])
contours = cv2.findContours(thresh2, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
for cntr in contours:
    color = list(np.random.random(size=3) * 256)
    cv2.drawContours(result, [cntr], -1, color, 2)

# show thresh and result    
cv2.imshow("input", img)
cv2.imshow("thresh", thresh)
cv2.imshow("contours", contour_img)
cv2.imshow("thresh2", thresh2)
cv2.imshow("result", result)
cv2.waitKey(0)
cv2.destroyAllWindows()

# save resulting images
cv2.imwrite('rectangles_contours.png',contour_img)
cv2.imwrite('rectangles_thresh2.png',thresh2)
cv2.imwrite('rectangles_result.png',result)


阈值图像上的大小轮廓:

阈值图像上绘制的两条黑色垂直线:

在上一张图像上绘制的随机颜色轮廓作为结果: