如何尋找已知輪廓的最大內接圓


問題的提出:
所謂內切圓,是指“與 多邊形各邊都 相切“。我們這里需要找的是所謂”內接圓“,可以簡單認為是”圓點在輪廓中,到輪廓中所有點的距離一樣的圖像“。在這所有的”內接圓“中,尋找半徑最大的哪一個。
這個問題已經廣泛討論了,比如
這樣的圖像,尋找輪廓的最大內接圓。

解決方法:
利用計算機圖像學技術中輪廓的相關思路,可以直接從圓的定義解決此問題。基於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 ,它是返回一個從點到最近的邊的帶符號距離。
結果:

優化的思路:
這里對圓心的遍歷,是遍歷了所有的圖像上面的點。然而根據”內接圓心一定在輪廓內部“這個先驗知識,可以縮小循環范圍,提高算法效率。

2018年7月27日22:01:01 對opencv的官方例子進行修改,並提交github

/**
 * @function pointPolygonTest_demo.cpp
 * @brief Demo code to use the pointPolygonTest function...fairly easy
 * @author OpenCV team
 */
#include "stdafx.h"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>
using namespace cv;
using namespace std;
//return the biggest contour by size
vector<PointFindBiggestContour(Mat src){    
    int icount = 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 ){
            icount = i;
            imaxcontour = itmp;
        }
    }
    return contours[icount];
}
/**
 * @function main
 */
int mainvoid )
{
    /// Create an image
    const int r = 100;
    Mat src = Mat::zerosSize( 4*r, 4*r ), CV_8U );
    /// Create a sequence of points to make a contour
    vector<Point2fvert(6);
    vert[0] = Point( 3*r/2, static_cast<int>(1.34*r) );
    vert[1] = Point( 1*r, 2*r );
    vert[2] = Point( 3*r/2, static_cast<int>(2.866*r) );
    vert[3] = Point( 5*r/2, static_cast<int>(2.866*r) );
    vert[4] = Point( 3*r, 2*r );
    vert[5] = Point( 5*r/2, static_cast<int>(1.34*r) );
    /// Draw it in src
    forint i = 0; i < 6; i++ )
    {
        linesrcvert[i],  vert[(i+1)%6], Scalar( 255 ), 3 );
    }
    /// Get the contours
    vector<vector<Point> > contours;
    findContourssrccontoursRETR_TREECHAIN_APPROX_SIMPLE);
    /// Calculate the distances to the contour
    Mat raw_distsrc.size(), CV_32F );
    forint i = 0; i < src.rowsi++ )
    {
        forint j = 0; j < src.colsj++ )
        {
            raw_dist.at<float>(i,j) = (float)pointPolygonTestcontours[0], Point2f((float)j, (float)i), true );
        }
    }
    double minValmaxVal;
    minMaxLocraw_dist, &minVal, &maxVal );
    minVal = abs(minVal);
    maxVal = abs(maxVal);
    /// Depicting the  distances graphically
    Mat drawing = Mat::zerossrc.size(), CV_8UC3 );
    forint i = 0; i < src.rowsi++ )
    {
        forint j = 0; j < src.colsj++ )
        {
            ifraw_dist.at<float>(i,j) < 0 )
            {
                drawing.at<Vec3b>(i,j)[0] = (uchar)(255 - abs(raw_dist.at<float>(i,j)) * 255 / minVal);
            }
            else ifraw_dist.at<float>(i,j) > 0 )
            {
                drawing.at<Vec3b>(i,j)[2] = (uchar)(255 - raw_dist.at<float>(i,j) * 255 / maxVal);
            }
            else
            {
                drawing.at<Vec3b>(i,j)[0] = 255;
                drawing.at<Vec3b>(i,j)[1] = 255;
                drawing.at<Vec3b>(i,j)[2] = 255;
            }
        }
    }
    //get the biggest Contour
    vector<PointbiggestContour = FindBiggestContour(src);
    //find the maximum enclosed circle 
    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(biggestContour,cv::Point(i,j),true);
            if(dist>maxdist)
            {
                maxdist=dist;
                center=cv::Point(i,j);
            }
        }
    }
    circle(drawing,center,maxdist,Scalar(255,255,255));
    /// Show your results
    imshow"Source"src );
    imshow"Distance and maximum enclosed circle"drawing );
    waitKey();
    return 0;
}





附件列表

     


    免責聲明!

    本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



     
    粵ICP備18138465號   © 2018-2025 CODEPRJ.COM