本来想偷懒直接在网上找源码,找到了发现都一样,但是有bug,因此参考了https://blog.csdn.net/icvpr/article/details/10259577的介绍与代码,对错误的地方进行了修改,然后将四邻域改为八邻域
原理就不介绍了,可以直接看上面的链接,里面介绍的挺清楚地
上面那个链接有执行出问题的地方其实就是没有判断边界,加上去就好了(加粗标红的地方)
void icvprCcaBySeedFill(const cv::Mat& _binImg, cv::Mat& _lableImg)
{
// connected component analysis (4-component)
// use seed filling algorithm
// 1. begin with a foreground pixel and push its foreground neighbors into a stack;
// 2. pop the top pixel on the stack and label it with the same label until the stack is empty
//
// foreground pixel: _binImg(x,y) = 1
// background pixel: _binImg(x,y) = 0
if (_binImg.empty() ||
_binImg.type() != CV_8UC1)
{
return;
}
_lableImg.release();
_binImg.convertTo(_lableImg, CV_32SC1);
int label = 1; // start by 2
int rows = _binImg.rows - 1;
int cols = _binImg.cols - 1;
for (int i = 1; i < rows - 1; i++)
{
int* data = _lableImg.ptr<int>(i);
for (int j = 1; j < cols - 1; j++)
{
if (data[j] == 1)
{
std::stack<std::pair<int, int>> neighborPixels;
neighborPixels.push(std::pair<int, int>(i, j)); // pixel position: <i,j>
++label; // begin with a new label
while (!neighborPixels.empty())
{
// get the top pixel on the stack and label it with the same label
std::pair<int, int> curPixel = neighborPixels.top();
int curX = curPixel.first;
int curY = curPixel.second;
_lableImg.at<int>(curX, curY) = label;
// pop the top pixel
neighborPixels.pop();
if (curX >= 1 && curX <= rows - 1 && curY >= 1 && curY <= cols - 1)
{
// push the 8-neighbors (foreground pixels)
if (_lableImg.at<int>(curX, curY - 1) == 1)
{// left pixel
neighborPixels.push(std::pair<int, int>(curX, curY - 1));
}
if (_lableImg.at<int>(curX, curY + 1) == 1)
{// right pixel
neighborPixels.push(std::pair<int, int>(curX, curY + 1));
}
if (_lableImg.at<int>(curX - 1, curY) == 1)
{// up pixel
neighborPixels.push(std::pair<int, int>(curX - 1, curY));
}
if (_lableImg.at<int>(curX + 1, curY) == 1)
{// down pixel
neighborPixels.push(std::pair<int, int>(curX + 1, curY));
}
//四邻域分析的话就不需要下面绿色的部分了
if (_lableImg.at<int>(curX - 1, curY - 1) == 1)
{// left up pixel
neighborPixels.push(std::pair<int, int>(curX - 1, curY - 1));
}
if (_lableImg.at<int>(curX - 1, curY + 1) == 1)
{// left down pixel
neighborPixels.push(std::pair<int, int>(curX - 1, curY + 1));
}
if (_lableImg.at<int>(curX + 1, curY - 1) == 1)
{// right up pixel
neighborPixels.push(std::pair<int, int>(curX + 1, curY - 1));
}
if (_lableImg.at<int>(curX + 1, curY + 1) == 1)
{// roght down pixel
neighborPixels.push(std::pair<int, int>(curX + 1, curY + 1));
}
}
}
}
}
}
}
然后需要注意的是, 输入的背景需要是白色的,目标是黑色的, 颜色标记的代码直接参照上面链接的就行。
PS:后期实验发现,建议图像什么的都转为png格式