联通区分析常用算法有
1)Two-Pass法;2)Seed-Filling种子填充法
这两类算法详细描述在 http://blog.csdn.net/icvpr/article/details/10259577
本文使用Seed-Filling种子填充算法,实现人脖子肤色调整,为了便于查看,将脖子处颜色调成蓝色
void icvprCcaBySeedFill(const cv::Mat& RGBAImg, const int i, const int j, 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
std::stack<std::pair<int,int>> neighborPixels ;
neighborPixels.push(std::pair<int,int>(i,j)) ; // pixel position: <i,j>
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<uchar>(curX, curY) = 1;
// pop the top pixel
neighborPixels.pop() ;
// push the 4-neighbors (foreground pixels)
// left pixel
{
cv::Vec4b px = RGBAImg.at<cv::Vec4b>(curX,curY-1);
if (_lableImg.at<uchar>(curX, curY-1) == 0 && isSkin(Scalar(px[0],px[1],px[2])))
{
neighborPixels.push(std::pair<int,int>(curX, curY-1)) ;
}
}
// right pixel
{
cv::Vec4b px = RGBAImg.at<cv::Vec4b>(curX,curY+1);
if (_lableImg.at<uchar>(curX, curY+1) == 0 && isSkin(Scalar(px[0],px[1],px[2])))
{
neighborPixels.push(std::pair<int,int>(curX, curY+1)) ;
}
}
// up pixel
{
cv::Vec4b px = RGBAImg.at<cv::Vec4b>(curX-1,curY);
if (_lableImg.at<uchar>(curX-1, curY) == 0 && isSkin(Scalar(px[0],px[1],px[2])))
{
neighborPixels.push(std::pair<int,int>(curX-1, curY)) ;
}
}
// down pixel
{
cv::Vec4b px = RGBAImg.at<cv::Vec4b>(curX+1,curY);
if (_lableImg.at<uchar>(curX+1, curY) == 0 && isSkin(Scalar(px[0],px[1],px[2])))
{
neighborPixels.push(std::pair<int,int>(curX+1, curY)) ;
}
}
}
}