首页 > 代码库 > 如何寻找已知轮廓的最大内接圆

如何寻找已知轮廓的最大内接圆

问题的提出:

所谓内切圆,是指“与多边形各边都相切的圆“。我们这里需要找的是所谓”内接圆“,可以简单认为是”圆点在轮廓中,到轮廓中所有点的距离一样的图像“。在这所有的”内接圆“中,寻找半径最大的哪一个。

这个问题已经广泛讨论了,比如
技术分享
这样的图像,寻找轮廓的最大内接圆。
 
解决方法:
利用计算机图像学技术中轮廓的相关思路,可以直接从圆的定义解决此问题。基于OpenCV的代码和注释如下:
#include "stdafx.h"
#include <iostream>
 
using namespace std;
using namespace cv;
 
VP FindBigestContour(Mat src){    
    int imax = 0//代表最大轮廓的序号
    int imaxcontour = -1//代表最大轮廓的大小
    std::vector<std::vector<cv::Point>>contours;    
    findContours(src,contours,CV_RETR_LIST,CV_CHAIN_APPROX_SIMPLE);
    for (int i=0;i<contours.size();i++){
        int itmp =  contourArea(contours[i]);//这里采用的是轮廓大小
        if (imaxcontour < itmp ){
            imax = i;
            imaxcontour = itmp;
        }
    }
    return contours[imax];
}
int main(int argc, char* argv[])
{
    Mat src = imread("e:/template/cloud.png");
    Mat temp;
    cvtColor(src,temp,COLOR_BGR2GRAY);
    threshold(temp,temp,100,255,THRESH_OTSU);
    imshow("src",temp);
    //寻找最大轮廓
    VP VPResult = FindBigestContour(temp);
    //寻找最大内切圆
    int dist = 0;
    int maxdist = 0;
    Point center;
    for(int i=0;i<src.cols;i++)
    {
        for(int j=0;j<src.rows;j++)
        {
            dist = pointPolygonTest(VPResult,cv::Point(i,j),true);
            if(dist>maxdist)
            {
                maxdist=dist;
                center=cv::Point(i,j);
            }
        }
    }
    //绘制结果
    circle(src,center,maxdist,Scalar(0,0,255));
    imshow("dst",src);
    waitKey();
}
    
其中
PointPolygonTest
测试点是否在多边形中
double cvPointPolygonTest( const CvArr* contour, CvPoint2D32f pt, int measure_dist );
contour 输入轮廓.
pt 针对轮廓需要测试的点。
measure_dist 如果非0,函数将估算点到轮廓最近边的距离。
函数cvPointPolygonTest 决定测试点是否在轮廓内,轮廓外,还是轮廓的边上(或者共边的交点上),它的返回值是正负零,相对应的,当measure_dist=0时,返回值是1, -1,0, 同样当 measure_dist≠0 ,它是返回一个从点到最近的边的带符号距离。
结果:
技术分享
 
优化的思路:
这里对圆心的遍历,是遍历了所有的图像上面的点。然而根据”内接圆心一定在轮廓内部“这个先验知识,可以缩小循环范围,提高算法效率。
 

 

如何寻找已知轮廓的最大内接圆