使用OpenCV的findContours函數查找輪廓,當參數爲CV_RETR_LIST時,查找到的輪廓不建立等級關係,也就是當前模式下不存在父輪廓或內嵌輪廓的位置關係,所以當圖中存在環形輪廓內外嵌套時(如下圖所示數字輪廓8),如果要判斷輪廓位置關係,需要自行判斷。判斷方法是可通過遍歷輪廓點,計算每個輪廓點的四鄰域點的灰度值來判斷,方法一調用OpenCV的pointPolygonTest函數來判斷點是否在輪廓內部,方法二則是通過點的灰度值來判斷是否在輪廓內部,方法二相較於方法一運行速度更快。
方法一:
cv::Mat src;//二值圖像
std::vector<std::vector<cv::Point>> allContours;//輪廓
std::vector<cv::Vec4i> allHierarchy;//層次結構信息
//查找輪廓
cv::findContours(src, allContours, allHierarchy, cv::RETR_LIST, cv::CHAIN_APPROX_NONE, cv::Point(0, 0));
int cnt = 0;
std::vector<cv::Point> 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<uchar>(point1.y)[point1.x];
int grayvalue2 = src.ptr<uchar>(point2.y)[point2.x];
int grayvalue3 = src.ptr<uchar>(point3.y)[point3.x];
int grayvalue4 = src.ptr<uchar>(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<std::vector<cv::Point>> allContours;//輪廓
std::vector<cv::Vec4i> 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<cv::Point> 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<uchar>(point1.y)[point1.x];
int grayvalue2 = src.ptr<uchar>(point2.y)[point2.x];
int grayvalue3 = src.ptr<uchar>(point3.y)[point3.x];
int grayvalue4 = src.ptr<uchar>(point4.y)[point4.x];
bool isinnner = false;
if (grayvalue1 == 0)
{
if (conimg.ptr<uchar>(point1.y)[point1.x] == 255)
{
isinnner = true;
}
}
if (grayvalue2 == 0 && !isinnner)
{
if (conimg.ptr<uchar>(point2.y)[point2.x] == 255)
{
isinnner = true;
}
}
if (grayvalue3 == 0 && !isinnner)
{
if (conimg.ptr<uchar>(point3.y)[point3.x] == 255)
{
isinnner = true;
}
}
if (grayvalue4 == 0 && !isinnner)
{
if (conimg.ptr<uchar>(point4.y)[point4.x] == 255)
{
isinnner = true;
}
}
if (isinnner)
{
cnt++;
}
}
if (cnt == allptsize)
{
return true;//灰度值爲零且在輪廓內部的四鄰域點的個數與輪廓點個數相等的輪廓是內部輪廓
}
else
{
return false;
}