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

#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 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，函数将估算点到轮廓最近边的距离。

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 "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>

using namespace cv;
using namespace std;

//return the biggest contour by size
vector<Point> FindBiggestContour(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 main( void )
{
/// Create an image
const int r = 100;
Mat src = Mat::zeros( Size( 4*r, 4*r ), CV_8U );

/// Create a sequence of points to make a contour
vector<Point2f> vert(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
for( int i = 0; i < 6; i++ )
{
line( src, vert[i],  vert[(i+1)%6], Scalar( 255 ), 3 );
}

/// Get the contours
vector<vector<Point> > contours;
findContours( src, contours, RETR_TREE, CHAIN_APPROX_SIMPLE);

/// Calculate the distances to the contour
Mat raw_dist( src.size(), CV_32F );
for( int i = 0; i < src.rows; i++ )
{
for( int j = 0; j < src.cols; j++ )
{
raw_dist.at<float>(i,j) = (float)pointPolygonTest( contours[0], Point2f((float)j, (float)i), true );
}
}

double minVal, maxVal;
minMaxLoc( raw_dist, &minVal, &maxVal );
minVal = abs(minVal);
maxVal = abs(maxVal);

/// Depicting the  distances graphically
Mat drawing = Mat::zeros( src.size(), CV_8UC3 );
for( int i = 0; i < src.rows; i++ )
{
for( int j = 0; j < src.cols; j++ )
{
if( raw_dist.at<float>(i,j) < 0 )
{
drawing.at<Vec3b>(i,j)[0] = (uchar)(255 - abs(raw_dist.at<float>(i,j)) * 255 / minVal);
}
else if( raw_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<Point> biggestContour = 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));
imshow( "Source", src );
imshow( "Distance and maximum enclosed circle", drawing );

waitKey();
return 0;
}

我的最终解：
/**
* @function pointPolygonTest_demo.cpp
* @brief Demo code to use the pointPolygonTest function...fairly easy
* @author OpenCV team
*         jsxyhelu(jsxyhelu@foxmail.com)
*/

#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>

using namespace cv;
using namespace std;

//get the biggest contour by size
static vector<Point> FindBiggestContour(Mat src){
int max_area_contour_idx = 0;
double max_area = -1;
vector<vector<Point> >contours;
findContours(src,contours,RETR_LIST,CHAIN_APPROX_SIMPLE);
//handle case if no contours are detected
CV_Assert(0 != contours.size());
for (uint i=0;i<contours.size();i++){
double temp_area = contourArea(contours[i]);
if (max_area < temp_area ){
max_area_contour_idx = i;
max_area = temp_area;
}
}
return contours[max_area_contour_idx];
}
/**
* @function main
*/
int main( void )
{
/// Create an image
const int r = 100;
Mat src = Mat::zeros( Size( 4*r, 4*r ), CV_8U );

/// Create a sequence of points to make a contour
vector<Point2f> vert(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
for( int i = 0; i < 6; i++ )
{
line( src, vert[i],  vert[(i+1)%6], Scalar( 255 ), 3 );
}

/// Get the contours
vector<vector<Point> > contours;
findContours( src, contours, RETR_TREE, CHAIN_APPROX_SIMPLE);

/// Calculate the distances to the contour
Mat raw_dist( src.size(), CV_32F );
for( int i = 0; i < src.rows; i++ )
{
for( int j = 0; j < src.cols; j++ )
{
raw_dist.at<float>(i,j) = (float)pointPolygonTest( contours[0], Point2f((float)j, (float)i), true );
}
}

double minVal, maxVal;
minMaxLoc( raw_dist, &minVal, &maxVal );
minVal = abs(minVal);
maxVal = abs(maxVal);

/// Depicting the  distances graphically
Mat drawing = Mat::zeros( src.size(), CV_8UC3 );
for( int i = 0; i < src.rows; i++ )
{
for( int j = 0; j < src.cols; j++ )
{
if( raw_dist.at<float>(i,j) < 0 )
{
drawing.at<Vec3b>(i,j)[0] = (uchar)(255 - abs(raw_dist.at<float>(i,j)) * 255 / minVal);
}
else if( raw_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<Point> biggestContour = FindBiggestContour(src);
//handle case if biggestContour is empty
CV_Assert(0 != biggestContour.size());
//find the maximum enclosed circle
double maxdist = 0;
Point center;
//get the rect bounding the BiggestContour
Rect rectBoundingBiggestContour = boundingRect(Mat(biggestContour));
for(int i=0;i<rectBoundingBiggestContour.width;i++)
{
for(int j=0;j<rectBoundingBiggestContour.height;j++)
{
Point tmpPoint = Point(rectBoundingBiggestContour.x + i,rectBoundingBiggestContour.y + j);
double dist = pointPolygonTest(biggestContour,tmpPoint,true);
if(dist>maxdist)
{
maxdist=dist;
center= tmpPoint;
}
}
}
circle(drawing,center,(int)maxdist,Scalar(255,255,255));

}