zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    [linux] SIGPIPE信号处理
    巧妙使用spring对commons fileUpload的包装
    对commons fileupload组件的简单封装
    利用脚本启动java程序
    [linux] 创建daemon进程
    利用Jakarta commons fileupload组件实现多文件上传
    dedeCms下面 arclist标签无法嵌套图片(img)之解决办法
    编程乱码问题初步探索
    PHP下载文件函数
    Windows7下IIS中以FastCgi安装PHP
  • 原文地址:https://www.cnblogs.com/brother-louie/p/13976546.html
Copyright © 2011-2022 走看看