opencv 绘制内切圆

本文介绍如何使用OpenCV库中的cv2.pointPolygonTest和cv2.minMaxLoc函数,通过计算图像中点与轮廓的距离,找出内切圆的圆心坐标和半径。过程包括灰度处理、二值化、轮廓识别和距离计算,最后在原图上标记出内切圆。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

先上效果图:
在这里插入图片描述
原图:
在这里插入图片描述

思路:

主要使用 cv2.pointPolygonTest 来寻找图像中所有点与轮廓的最短距离,根据函数的特性,轮廓外为负轮廓内为正,再使用 cv2.minMaxLoc 筛选,提取我们取最大值索引就是圆心坐标,最大值就是圆心半径。

详细说明:cv2.pointPolygonTest
Point Polygon Test
求解图像中的一个点到一个对象轮廓的最短距离。如果点在轮廓的外部,
返回值为负。如果在轮廓上,返回值为 0。如果在轮廓内部,返回值为正。
下面我们以点(50,50)为例:
dist = cv2.pointPolygonTest(cnt,(50,50),True) 此函数的第三个参数是 measureDist。如果设置为 True,就会计算最
短距离。如果是 False,只会判断这个点与轮廓之间的位置关系(返回值为
+1,-1,0)。

import cv2
import numpy as np


# 读取图片,转灰度
mask = cv2.imread("6.jpg")
mask_gray = cv2.cvtColor(mask, cv2.COLOR_BGR2GRAY)
# 二值化
ret, mask_gray = cv2.threshold(mask_gray, 127, 255, cv2.THRESH_BINARY)

# 识别轮廓
contours, _ = cv2.findContours(mask_gray, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

# 计算到轮廓的距离
raw_dist = np.empty(mask_gray.shape, dtype=np.float32)
for i in range(mask_gray.shape[0]):
    for j in range(mask_gray.shape[1]):
        raw_dist[i, j] = cv2.pointPolygonTest(contours[0], (j, i), True)

# 获取最大值即内接圆半径,中心点坐标
minVal, maxVal, _, maxDistPt = cv2.minMaxLoc(raw_dist)


# 半径:maxVal  圆心:maxDistPt
# 转换格式
maxVal = abs(maxVal)
radius = int(maxVal)

# 原图转换格式
result = cv2.cvtColor(mask_gray, cv2.COLOR_GRAY2BGR)


# 绘制内切圆
cv2.circle(result, maxDistPt, radius, (0, 255, 0), 2, 1, 0)
# 绘制圆心
cv2.circle(result, maxDistPt, 1, (0, 255, 0), 2, 1, 0)
cv2.imshow('0', result)
cv2.waitKey(0)
### 使用C++在OpenCV中找到轮廓的最大内切圆 为了在OpenCV中使用C++实现寻找最大内切圆的功能,可以采用`distanceTransform`方法结合`minMaxLoc`函数来定位距离变换后的最远点作为可能的圆心位置,并以此为基础计算半径。这种方法能够有效地处理各种形状的轮廓。 下面是一个具体的实现方案: #### 距离变换与最小-最大值查找 通过调用`cv::distanceTransform`对二值化图像执行欧几里得距离转换操作,该过程会生成一张新图,在这张图上每一个像素点都表示其到最近背景像素的距离。随后应用`cv::minMaxLoc`找出全局最大值及其坐标,这组数据即代表了潜在的最大内切圆中心以及对应的半径长度[^2]。 ```cpp Mat dist; distanceTransform(src, dist, CV_DIST_L2, 3); double minVal, maxVal; Point minLoc, maxLoc; minMaxLoc(dist, &minVal, &maxVal, &minLoc, &maxLoc); // 圆心位于maxLoc处,而maxVal则对应于半径大小 circle(outputImage, maxLoc, static_cast<int>(maxVal), Scalar(0, 255, 0), 2, LINE_8); ``` #### 边缘检测与轮廓提取 在此之前还需要完成边缘检测并获得目标对象的闭合边界曲线——也就是所谓的“轮廓”。通常情况下会选择先做一次形态学膨胀以填补细小缝隙确保得到完整的封闭路径;之后再利用`findContours`捕获这些连续线条的信息用于后续分析[^1]。 ```cpp vector<vector<Point>> contours; vector<Vec4i> hierarchy; morphologyEx(edgeDetectedImg, edgeDetectedImg, MORPH_CLOSE, Mat()); findContours(edgeDetectedImg, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE); ``` #### 绘制结果 最后一步则是将上述所得的结果可视化出来以便验证算法准确性。这里可以通过简单的绘图指令把最终确定下来的圆形标记显示给用户查看[^3]。 ```cpp for (size_t i = 0; i < contours.size(); ++i){ drawContours(dst, contours, static_cast<int>(i), Scalar(0, 0, 255)); } imshow("Result", dst); waitKey(); ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

默执_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值