SeedFill——连通区域分析

Two-Pass方法计算二值图连通域效率比较低,补充下Seed Filling种子填充法,该方法类似于图的深度搜素。

这里还是参考了这篇文章OpenCV_连通区域分析

为了提高效率,做了一点修改。

  1. 针对新标签的第一个像素,其邻域只选取下方和后方未处理的像素;
  2. 针对处理过的像素添加标识符,下次再碰到该像素时,可直接跳过。
  3. 判断邻域坐标,防止越界。

具体代码:

bool seedFill(cv::Mat pBinary, int background, int foreground, 
int border,cv::Mat& pLabel)
{
    // connected component analysis (4- component)  
    if (pBinary.empty() || pBinary.channels() != 1)
        return false;

    int width = pBinary.cols;
    int height = pBinary.rows;

    pLabel.release();
    pBinary.convertTo(pLabel, CV_32SC1);

    int *data = pLabel.ptr<int>(0);
    for (int i = 0; i < width*height; i++)
        if (foreground == data[i]) data[i] = 1;
        else                                    data[i] = 0;

    int label = 1;

    Mat marked = pLabel.clone();
    for (int i = border; i < height - border; i++)
    {
        int* curRow = pLabel.ptr<int>(i);
        for (int j = border; j < width - border; j++)
        {
            int* cur_data = curRow + j;
            int& marked_status = marked.ptr<int>(i)[j];
            if (1 != *cur_data || 0 == marked_status)
                continue;

            *cur_data = ++label;
            marked_status = 0;

            stack<pair<int, int>> neighbor_data;
            if( j < width -1 )
                neighbor_data.push(pair<int, int>(i, j+1)); // right
            if( i < height - 1 )
                neighbor_data.push(pair<int, int>(i + 1, j)); // down

            while (!neighbor_data.empty())
            {
                pair<int, int> position = neighbor_data.top();
                int cur_y = position.first;
                int cur_x = position.second;

                if(cur_x < 0 ||cur_x >= width || cur_y < 0 || cur_y >= height)
                {
                    neighbor_data.pop();  // 注意弹出旧值
                    continue;
                }
                int& label_data = pLabel.ptr<int>(cur_y)[cur_x];
                int& stauts = marked.ptr<int>(cur_y)[cur_x];

                if (1 != label_data || 0 == stauts)
                {
                    neighbor_data.pop();  // 注意弹出旧值
                    continue;
                }
                label_data = label;
                stauts = 0;

                neighbor_data.pop();
                // up
                neighbor_data.push(pair<int,int>(cur_y - 1, cur_x) ); 
                // down
                neighbor_data.push(pair<int, int>(cur_y+1, cur_x)); 
                // left
                neighbor_data.push(pair<int, int>(cur_y, cur_x - 1)); 
                // right
                neighbor_data.push(pair<int, int>(cur_y, cur_x + 1)); 

            }
        }
    }
    return true;
}

结果:
这里写图片描述

完。

Lewis, 2018-06-25

posted @ 2018-06-25 23:55  Louie-Liu  阅读(223)  评论(0编辑  收藏  举报