如何将轮廓近似为四点

问题描述 投票:0回答:1

我有从分割模型获得的二进制掩模,我只想得到其轮廓的四个角,其中包括具有最小面积的大多数点,如下图所示:

角不一定形成矩形,并且掩模有噪声:

我尝试过轮廓检测、近似和

minAreaRect
,但矩形在很多情况下比形状更宽,并且没有最小化到我想要的极限:

#!/usr/bin/env python3

import os
from os import path as osp
import cv2
import numpy as np

path = "seg_masks"
im_list = os.listdir(path)

def lcc(binary_image:np.ndarray)->np.ndarray:
    # Find connected components
    print(binary_image.shape, binary_image.dtype)
    num_labels, labels, stats, centroids = cv2.connectedComponentsWithStats(binary_image, connectivity=8)
    # Find the label (index) of the largest connected component
    largest_component_label = np.argmax(stats[1:, cv2.CC_STAT_AREA]) + 1  # Skip background label (0)
    largest_component_mask = (labels == largest_component_label).astype(np.uint8)
    largest_component_mask = largest_component_mask.astype(np.uint8)
    return largest_component_mask

for img_name in im_list:
    bgr_img_mask = cv2.imread(osp.join(path, img_name), 0)
    cv2.imwrite(osp.join(path, "white", img_name), bgr_img_mask)
    lcc_mask = lcc(bgr_img_mask)
    # Erosion to clean the mask contour a bit
    cl_ker = 5
    kernel = np.ones((cl_ker, cl_ker), np.uint8)
    erosion = cv2.erode(lcc_mask,kernel,iterations = 3)

    contours, _ = cv2.findContours(
        lcc_mask, mode=cv2.RETR_TREE, 
        method=cv2.CHAIN_APPROX_NONE
    )
    if(len(contours)):
        max_cnt = max(contours, key=cv2.contourArea)
        epsilon = 0.008 * cv2.arcLength(max_cnt, True)
        approx = cv2.approxPolyDP(max_cnt, epsilon, True)
        approx = np.squeeze(np.array(approx, dtype=int), axis=1)

        rect = cv2.minAreaRect(approx) 
        box = cv2.boxPoints(rect) 
        box = np.int0(box) 
        bgr_img_mask = cv2.drawContours(bgr_img_mask, [box], 0, 200, 2) 

        cv2.drawContours(bgr_img_mask, [approx], -1, 128, 2)
        bgr_img_mask = cv2.putText(bgr_img_mask, f"{round(epsilon,2)}", (50, 50) , 
                                   cv2.FONT_HERSHEY_SIMPLEX , 1, 255, 2, cv2.LINE_AA)
    win_name = "img"
    cv2.namedWindow(win_name, cv2.WINDOW_NORMAL)
    cv2.imshow(win_name, bgr_img_mask)
    cv2.waitKey(0)

输出:

您能指导我如何做到这一点吗?谢谢。

python opencv image-processing computer-vision
1个回答
0
投票

(这个答案只是“如何做”,没有代码。)

我开始

minAreaRect
最大区域尺寸轮廓的结果,优化4顶点位置。

最小化的目标函数定义为沿正方形距轮廓边缘的平均距离。 这可以使用 OpenCV 的

distanceTransform
LineIterator
来计算。

每 3 个样本图像的结果:

© www.soinside.com 2019 - 2024. All rights reserved.