使用OpenCV的findContours函数查找轮廓,当参数为CV_RETR_LIST时,查找到的轮廓不建立等级关系,也就是当前模式下不存在父轮廓或内嵌轮廓的位置关系,所以当图中存在环形轮廓内外嵌套时(如下图所示数字轮廓8),如果要判断轮廓位置关系,需要自行判断。判断方法是可通过遍历轮廓点,计算每个轮廓点的四邻域点的灰度值来判断,方法一调用OpenCV的pointPolygonTest函数来判断点是否在轮廓内部,方法二则是通过点的灰度值来判断是否在轮廓内部,方法二相较于方法一运行速度更快。
方法一:
cv::Mat src;//二值图像
std::vector> allContours;//轮廓
std::vector allHierarchy;//层次结构信息
//查找轮廓
cv::findContours(src, allContours, allHierarchy, cv::RETR_LIST, cv::CHAIN_APPROX_NONE, cv::Point(0, 0));
int cnt = 0;
std::vector Contourpts = allContours [0];
for (int i = 0; i < Contourpts.size(); i++)
{
cv::Point point1, point2, point3, point4;
point1 = cv::Point(Contourpts[i].x, std::min(Contourpts[i].y + 1, src.rows - 1));
point2 = cv::Point(std::min(Contourpts[i].x + 1, src.cols - 1), Contourpts[i].y);
point3 = cv::Point(std::max(Contourpts[i].x - 1, 0), Contourpts[i].y);
point4 = cv::Point(Contourpts[i].x, std::max(Contourpts[i].y - 1, 0));
int grayvalue1 = src.ptr(point1.y)[point1.x];
int grayvalue2 = src.ptr(point2.y)[point2.x];
int grayvalue3 = src.ptr(point3.y)[point3.x];
int grayvalue4 = src.ptr(point4.y)[point4.x];
bool isinnner = false;
if (grayvalue1 == 0)
{
//判断灰度值为0的点是否在轮廓内部
if (cv::pointPolygonTest(Contourpts, point1, false) == 1)
{
isinnner = true;
}
}
if (grayvalue2 == 0 && !isinnner)
{
//判断灰度值为0的点是否在轮廓内部
if (cv::pointPolygonTest(Contourpts, point2, false) == 1)
{
isinnner = true;
}
}
if (grayvalue3 == 0 && !isinnner)
{
//判断灰度值为0的点是否在轮廓内部
if (cv::pointPolygonTest(Contourpts, point3, false) == 1)
{
isinnner = true;
}
}
if (grayvalue4 == 0 && !isinnner)
{
//判断灰度值为0的点是否在轮廓内部
if (cv::pointPolygonTest(Contourpts, point4, false) == 1)
{
isinnner = true;
}
}
if (isinnner)
{
cnt++;
}
}
if (cnt == Contourpts.size())
{
return true;//灰度值为零且在轮廓内部的四邻域点的个数与轮廓点个数相等的轮廓是内部轮廓
}
else
{
return false;
}
方法二:
cv::Mat src;//二值图像
std::vector> allContours;//轮廓
std::vector allHierarchy;//层次结构信息
//查找轮廓
cv::findContours(src, allContours, allHierarchy, cv::RETR_LIST, cv::CHAIN_APPROX_NONE, cv::Point(0, 0));
cv::Mat conimg = cv::Mat::zeros(src.size(), CV_8UC1);
cv::drawContours(conimg, allContours, 0, cv::Scalar(255), cv::FILLED);//轮廓画到图上,内部填充为白色
int cnt = 0;
std::vector Contourpts = allContours [0];
int allptsize = Contourpts.size();
for (int i = 0; i < allptsize; i++)
{
cv::Point point1, point2, point3, point4;
point1 = cv::Point(Contourpts[i].x, std::min(Contourpts[i].y + 1, src.rows - 1));
point2 = cv::Point(std::min(Contourpts[i].x + 1, src.cols - 1), Contourpts[i].y);
point3 = cv::Point(std::max(Contourpts[i].x - 1, 0), Contourpts[i].y);
point4 = cv::Point(Contourpts[i].x, std::max(Contourpts[i].y - 1, 0));
int grayvalue1 = src.ptr(point1.y)[point1.x];
int grayvalue2 = src.ptr(point2.y)[point2.x];
int grayvalue3 = src.ptr(point3.y)[point3.x];
int grayvalue4 = src.ptr(point4.y)[point4.x];
bool isinnner = false;
if (grayvalue1 == 0)
{
if (conimg.ptr(point1.y)[point1.x] == 255)
{
isinnner = true;
}
}
if (grayvalue2 == 0 && !isinnner)
{
if (conimg.ptr(point2.y)[point2.x] == 255)
{
isinnner = true;
}
}
if (grayvalue3 == 0 && !isinnner)
{
if (conimg.ptr(point3.y)[point3.x] == 255)
{
isinnner = true;
}
}
if (grayvalue4 == 0 && !isinnner)
{
if (conimg.ptr(point4.y)[point4.x] == 255)
{
isinnner = true;
}
}
if (isinnner)
{
cnt++;
}
}
if (cnt == allptsize)
{
return true;//灰度值为零且在轮廓内部的四邻域点的个数与轮廓点个数相等的轮廓是内部轮廓
}
else
{
return false;
}