即使图像有破损区域,如何使用 cv2.minAreaRect 获得最大轮廓?

Cre*_*eek 0 opencv image-processing

这是原始图像。 在此输入图像描述

我想使用 cv2.minAreaRect 来获取最大轮廓,如下图所示。 在此输入图像描述

尝试 1 - 失败

在此输入图像描述

cnt, hierarchy  = cv2.findContours(im_bw, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
min_rect = cv2.minAreaRect(cnt[0])
box = np.int0(cv2.boxPoints(min_rect))
cv2.drawContours(temp_result, [box], 0, (255, 0, 0), 2)
Run Code Online (Sandbox Code Playgroud)

尝试 2 - 失败

我参考这篇文章来获取绘图的有序坐标。但是,我得到了以下结果,其中线条不匹配,并且四个点不能与 cv2.minAreaRect 一起使用。 在此输入图像描述

def order_points(pts):
    # initialzie a list of coordinates that will be ordered
    # such that the first entry in the list is the top-left,
    # the second entry is the top-right, the third is the
    # bottom-right, and the fourth is the bottom-left
    rect = np.zeros((4, 2), dtype = "float32")

    # the top-left point will have the smallest sum, whereas
    # the bottom-right point will have the largest sum
    s = np.sum(pts, axis = 1)
    rect[0] = pts[np.argmin(s)] # top-left
    rect[2] = pts[np.argmax(s)] # bottom-right

    # now, compute the difference between the points, the
    # top-right point will have the smallest difference,
    # whereas the bottom-left will have the largest difference
    diff = np.diff(pts, axis = 1)
    rect[1] = pts[np.argmin(diff)] # top-right
    rect[3] = pts[np.argmax(diff)] # bottom-left

    # return the ordered coordinates
    return rect
#########################################################################
# pts = [(93, 50), (109, 82), (76, 47), (93, 77), (58, 38), (76, 72), (36, 32), (54, 67), (20, 27), (35, 62), (3, 22), (18, 56), (111, 54), (128, 87)]

t = order_points(pts)
cv2.line(temp_result, pt1=(int(t[0][0]), int(t[0][1])), pt2=(int(t[1][0]), int(t[1][1])), color=(0, 0, 255), thickness=2)
cv2.line(temp_result, pt1=(int(t[3][0]), int(t[3][1])), pt2=(int(t[2][0]), int(t[2][1])), color=(0, 0, 255), thickness=2)

Run Code Online (Sandbox Code Playgroud)

任何帮助将不胜感激。

Rot*_*tem 5

我们可以找到合并轮廓的凸包:

merged_cnt = cv2.convexHull(np.vstack(cnt))
Run Code Online (Sandbox Code Playgroud)

代码示例:

import cv2
import numpy as np

im_bw = cv2.imread('im_bw.png', cv2.IMREAD_GRAYSCALE)  # Read im_bw as grayscale

temp_result = cv2.cvtColor(im_bw, cv2.COLOR_GRAY2BGR)

cnt, hierarchy  = cv2.findContours(im_bw, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

# Merge all the contours into one large contour - the result is the convex hull of all contour.
merged_cnt = cv2.convexHull(np.vstack(cnt))

cv2.drawContours(temp_result, [merged_cnt], 0, (255, 0, 0), 2)

# Show result for testing
cv2.imshow('temp_result', temp_result)
cv2.waitKey()
cv2.destroyAllWindows()
Run Code Online (Sandbox Code Playgroud)

结果:
在此输入图像描述


如果目标是将轮廓近似为矩形多边形,我们可以使用以下答案simplify_contour中的方法

approx = simplify_contour(merged_cnt)

cv2.drawContours(temp_result, [approx], 0, (0, 0, 255), 2)
Run Code Online (Sandbox Code Playgroud)

结果: 在此输入图像描述


如果目标是找到minAreaRect标题中所述的:

min_rect = cv2.minAreaRect(merged_cnt)  # Fine minAreaRect of the merged contours
box = np.int0(cv2.boxPoints(min_rect))
Run Code Online (Sandbox Code Playgroud)

我们得到以下输出:
在此输入图像描述