opencv中的轮廓选择
Contour selection in opencv
我有源图片
我已经应用了合适的阈值并得到了这个
现在我使用轮廓来找到内部的黑色斑点。我用绿色表示外边界,用红色表示内边界。这就是我得到的:-
我使用红色提取了斑点。但我想只提取那些内部没有绿色的,或者至少只给那些内部没有其他轮廓的内部边界。还是要做?
EDIT-1:- 我想找到绿色和红色像素的坐标,如果它们彼此非常接近,则将所有读取的像素转换为绿色。但是有人知道如何获取坐标吗?
EDIT-2 我按照 Derman 的方法,得到了 80% 的结果。查看另一张源图片及其遮罩
现在根据 Derman 的输入,我得到了这个
代码清楚地识别标记为 1 和 3(绿色和红色)的轮廓,基于它们有或没有子轮廓的事实。但是轮廓 2 显然与轮廓 1 相同并且具有子轮廓但仍被视为红色。我会和你们分享代码,我知道它可能只需要一个小的修改,但它似乎让我望而却步-
Mat binMask;
Mat lung_src;
vector<std::vector<cv::Point>> contours;
vector<cv::Vec4i> hierarchy;
int count = 0;
findContours(binMask, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, cv::Point(0, 0));
for (int i = 0; i < contours.size(); i++)
{
if (hierarchy[i][2] != -1) // means it has child contour
{
if (count>1)// number of child countors,if its greater than 1 then green else red
{
drawContours(lung_src, contours, i, Scalar(0, 255, 0), 1, 8, hierarchy, 0, Point());
}
else // means it's count is 1 or less
{
drawContours(lung_src, contours, i, Scalar(0, 0, 255), 1, 8, hierarchy, 0, Point());
}
count++;
}
else // means it doesn't have any child contour
{
drawContours(lung_src, contours, i, Scalar(0, 0, 255), 1, 8, hierarchy, 0, Point());
}
}
imshow("lung", lung_src);
imwrite("lung.tiff", lung_src);
lung_src 就是上面显示的 red/green 等高线图像。
为了判断一个轮廓是否在另一个轮廓内,您可以使用轮廓的层次结构特征。例如,在您的情况下,您可能首先使用如下方式检测轮廓:
cv::Mat inputImg = cv::imread("keVZc.png", CV_LOAD_IMAGE_GRAYSCALE);
cv::Mat binMask = cv::Mat::zeros(inputImg.size(), inputImg.type());
cv::threshold(inputImg, binMask, 28, 255, CV_THRESH_BINARY);
cv::Mat cannyOutput = cv::Mat::zeros(binMask.size(), binMask.type());
cv::Canny(binMask, cannyOutput, 28, 28 * 2, 3);
std::vector<std::vector<cv::Point>> contours;
std::vector<cv::Vec4i> hierarchy;
cv::findContours(cannyOutput, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, cv::Point(0, 0));
然后利用hierarchy判断那个轮廓有没有parent、child等。hierarchy的一般结构是这样的:
[next contour, previous contour, child contour, parent contour]
previous
和next
等高线是与输入等高线属于同一级别的等高线。如果输入轮廓有 child,那么它会给你 child 标签,否则,它的值将是 -1
,这与 parents 的情况类似。
因此,您可以像这样检查轮廓是否在另一个轮廓内:
for(int i = 0; i < contours.size(); i++)
{
if(hierarchy[i][2] != -1) // means it has child contour
{
// do something with it
}
else // means it doesn't have any child contour
{
// do something with it
}
}
为了比较两个等高线是否太近以过滤掉它们,您可以使用它们之间的距离测量(范数)。这样的事情会有所帮助:
for(int i = 0; i < contours.size(); i++)
{
int prvIndx = hierarchy[i][0]; // coordinates of previous contour
int nxtIndx = hierarchy[i][1]; // coordinates of next contour
std::vector<cv::Point> prvPoint = contours[prvIndx];
std::vector<cv::Point> nxtPoint = contours[nxtIndx];
// calculate norm of these two points
double distance = cv::norm(point1, point2);
// use a threshold value to decide what to do
if(double <= 40.0) // change the value according to your situation
{
// you decide what to do here
}
}
有关轮廓层次的更多信息,请查看以下参考资料:
ref1: Finding contours in your image
希望对您有所帮助!
我有源图片
我已经应用了合适的阈值并得到了这个
现在我使用轮廓来找到内部的黑色斑点。我用绿色表示外边界,用红色表示内边界。这就是我得到的:-
我使用红色提取了斑点。但我想只提取那些内部没有绿色的,或者至少只给那些内部没有其他轮廓的内部边界。还是要做?
EDIT-1:- 我想找到绿色和红色像素的坐标,如果它们彼此非常接近,则将所有读取的像素转换为绿色。但是有人知道如何获取坐标吗?
EDIT-2 我按照 Derman 的方法,得到了 80% 的结果。查看另一张源图片及其遮罩
现在根据 Derman 的输入,我得到了这个
代码清楚地识别标记为 1 和 3(绿色和红色)的轮廓,基于它们有或没有子轮廓的事实。但是轮廓 2 显然与轮廓 1 相同并且具有子轮廓但仍被视为红色。我会和你们分享代码,我知道它可能只需要一个小的修改,但它似乎让我望而却步-
Mat binMask;
Mat lung_src;
vector<std::vector<cv::Point>> contours;
vector<cv::Vec4i> hierarchy;
int count = 0;
findContours(binMask, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, cv::Point(0, 0));
for (int i = 0; i < contours.size(); i++)
{
if (hierarchy[i][2] != -1) // means it has child contour
{
if (count>1)// number of child countors,if its greater than 1 then green else red
{
drawContours(lung_src, contours, i, Scalar(0, 255, 0), 1, 8, hierarchy, 0, Point());
}
else // means it's count is 1 or less
{
drawContours(lung_src, contours, i, Scalar(0, 0, 255), 1, 8, hierarchy, 0, Point());
}
count++;
}
else // means it doesn't have any child contour
{
drawContours(lung_src, contours, i, Scalar(0, 0, 255), 1, 8, hierarchy, 0, Point());
}
}
imshow("lung", lung_src);
imwrite("lung.tiff", lung_src);
lung_src 就是上面显示的 red/green 等高线图像。
为了判断一个轮廓是否在另一个轮廓内,您可以使用轮廓的层次结构特征。例如,在您的情况下,您可能首先使用如下方式检测轮廓:
cv::Mat inputImg = cv::imread("keVZc.png", CV_LOAD_IMAGE_GRAYSCALE);
cv::Mat binMask = cv::Mat::zeros(inputImg.size(), inputImg.type());
cv::threshold(inputImg, binMask, 28, 255, CV_THRESH_BINARY);
cv::Mat cannyOutput = cv::Mat::zeros(binMask.size(), binMask.type());
cv::Canny(binMask, cannyOutput, 28, 28 * 2, 3);
std::vector<std::vector<cv::Point>> contours;
std::vector<cv::Vec4i> hierarchy;
cv::findContours(cannyOutput, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, cv::Point(0, 0));
然后利用hierarchy判断那个轮廓有没有parent、child等。hierarchy的一般结构是这样的:
[next contour, previous contour, child contour, parent contour]
previous
和next
等高线是与输入等高线属于同一级别的等高线。如果输入轮廓有 child,那么它会给你 child 标签,否则,它的值将是 -1
,这与 parents 的情况类似。
因此,您可以像这样检查轮廓是否在另一个轮廓内:
for(int i = 0; i < contours.size(); i++)
{
if(hierarchy[i][2] != -1) // means it has child contour
{
// do something with it
}
else // means it doesn't have any child contour
{
// do something with it
}
}
为了比较两个等高线是否太近以过滤掉它们,您可以使用它们之间的距离测量(范数)。这样的事情会有所帮助:
for(int i = 0; i < contours.size(); i++)
{
int prvIndx = hierarchy[i][0]; // coordinates of previous contour
int nxtIndx = hierarchy[i][1]; // coordinates of next contour
std::vector<cv::Point> prvPoint = contours[prvIndx];
std::vector<cv::Point> nxtPoint = contours[nxtIndx];
// calculate norm of these two points
double distance = cv::norm(point1, point2);
// use a threshold value to decide what to do
if(double <= 40.0) // change the value according to your situation
{
// you decide what to do here
}
}
有关轮廓层次的更多信息,请查看以下参考资料:
ref1: Finding contours in your image
希望对您有所帮助!