You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何计算OpenCV轮廓内不同区域点之间的最大距离

问题描述

处理图片时仅检测到1个轮廓,需计算该轮廓分隔出的两个区域内部点之间的最大距离,对应示意图如下:
单轮廓检测示意图

现有轮廓检测代码如下:

im1 = cv.imread('g1.jpg')
img_white = np.zeros([512,512,1],dtype=np.uint8)
img_white.fill(255)

src_gray = cv.cvtColor(im1, cv.COLOR_BGR2GRAY)
src_gray = cv.blur(src_gray, (3,3))
threshold = 100
canny_output = cv.Canny(src_gray, threshold, threshold * 2)
contours, _ = cv.findContours(canny_output, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
_ = cv.drawContours(img_white, contours,10,(0,255,0), 3)

需求为基于OpenCV实现上述最大距离的计算。

实现方案

单条闭合轮廓会将画面分割为轮廓内侧、外侧两个独立连通域,按以下步骤计算即可:

  • 提取目标轮廓:从检测到的轮廓中筛选出需要的单条目标轮廓,可通过面积阈值过滤噪点轮廓。
  • 生成区域掩码:通过轮廓填充操作,分别生成内侧区域、外侧区域的二值掩码。
  • 提取区域点集:从两个掩码中取出对应区域的所有像素坐标,整理为点集数组。
  • 计算跨区域最大距离:计算两个点集之间所有点对的欧氏距离,取最大值即可。大分辨率场景可先提取点集凸包减少计算量,不会影响最终结果精度。

完整可运行代码

import cv2 as cv
import numpy as np

# 计算两点欧氏距离
def calc_euc_dist(p1, p2):
    return np.sqrt((p1[0]-p2[0])**2 + (p1[1]-p2[1])**2)

im1 = cv.imread('g1.jpg')
h, w = im1.shape[:2]

# 原有预处理+轮廓检测逻辑
src_gray = cv.cvtColor(im1, cv.COLOR_BGR2GRAY)
src_gray = cv.blur(src_gray, (3,3))
threshold = 100
canny_output = cv.Canny(src_gray, threshold, threshold * 2)
contours, _ = cv.findContours(canny_output, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)

# 筛选目标轮廓:取面积最大的轮廓,避免边缘噪点干扰
target_contour = max(contours, key=cv.contourArea)

# 生成内外区域掩码
mask_outer = np.full((h, w), 255, dtype=np.uint8)
cv.drawContours(mask_outer, [target_contour], -1, 0, thickness=-1) # 挖空轮廓内部,剩余为外侧区域
mask_inner = np.zeros((h, w), dtype=np.uint8)
cv.drawContours(mask_inner, [target_contour], -1, 255, thickness=-1) # 填充轮廓内部,得到内侧区域

# 提取两个区域的点坐标,转为(x,y)格式
pts_outer = np.column_stack(np.where(mask_outer == 255))[:, ::-1]
pts_inner = np.column_stack(np.where(mask_inner == 255))[:, ::-1]

# 优化:仅保留凸包上的点计算最大距离,大幅降低计算量
hull_outer = cv.convexHull(pts_outer).squeeze()
hull_inner = cv.convexHull(pts_inner).squeeze()

# 遍历凸包点对找最大距离(无第三方依赖写法,大尺寸图推荐用scipy.cdist加速)
max_dist = 0
dist_p1 = None
dist_p2 = None
for p1 in hull_outer:
    for p2 in hull_inner:
        d = calc_euc_dist(p1, p2)
        if d > max_dist:
            max_dist = d
            dist_p1 = tuple(p1.astype(int))
            dist_p2 = tuple(p2.astype(int))

# 结果可视化
res_img = im1.copy()
cv.line(res_img, dist_p1, dist_p2, (0,0,255), 2)
cv.circle(res_img, dist_p1, 4, (0,255,0), -1)
cv.circle(res_img, dist_p2, 4, (0,255,0), -1)
print(f"两区域内部点最大距离:{max_dist:.2f}像素")

cv.imshow("result", res_img)
cv.waitKey(0)
cv.destroyAllWindows()

注:如果处理4K以上大分辨率图,可先对掩码做缩放降采样,或引入scipy的cdist函数批量计算距离矩阵,运行速度会比纯Python遍历提升10~100倍。

内容的提问来源于stack exchange,提问作者Felipe Trajano

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 20:12:18