Opencv 分水岭算法
void watershed( InputArray image, InputOutputArray markers );
官方文档中这样表述分水岭算法种子的选取
/*
Before passing the image to the function, you have to roughly outline the desired regions in the
image markers with positive (\>0) indices. So, every region is represented as one or more connected
components with the pixel values 1, 2, 3, and so on. Such markers can be retrieved from a binary
mask using #findContours and #drawContours (see the watershed.cpp demo). The markers are "seeds" of
the future image regions. All the other pixels in markers , whose relation to the outlined regions
is not known and should be defined by the algorithm, should be set to 0's. In the function output,
each pixel in markers is set to a value of the "seed" components or to -1 at boundaries between the
regions.
*/
//寻找种子点
vector<vector<Point>>contours;
findContours(binaryImg, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point(0, 0));
Mat markers = Mat::zeros(srcImg.size(), CV_32S);
for (int i = 0; i < contours.size(); i++)
{
drawContours(markers, contours, i, Scalar(i + 1), -1); // i 标记markers
}
简单说就是在在进行要先用findcontours和drawcontours将markers(种子点,注水口)找出来。
这里就要提一下为什么在进行findcontours之前都要先进行距离变换或者腐蚀呢?
因为原始图像经过二值化后,如果直接用该二值图像调用findcontours,那么最后用drawcontours画出来的markers填充的大小就是我们需要寻找的原图轮廓大小,意思就是注水口markers太大了,水刚注进去就漫了,所以最后分水岭算法得出的图像为四不像,如下图所示:有种水漫金山的感觉。
但是当我们在进行findcontours之前都要先进行距离变换或者腐蚀后会发现,二值图像中前景的轮廓变小了 ,此时再用这个图像寻找注水口,注水口的大小(这个轮廓大小)比我们需要寻找的原图轮廓小那么一些些,进行分水岭算法,这下灌水便会得到较好的结果了,如下图所示:(腐蚀核越大,越不容易出现水漫出去,效果越好)