【问题标题】:imregionalmax matlab function's equivalent in opencvimregionalmax matlab函数在opencv中的等价物
【发布时间】:2012-06-26 10:08:37
【问题描述】:

我有一个连接组件的图像(圆圈填充)。如果我想对它们进行分割,我可以使用分水岭算法。我更喜欢为分水岭编写自己的函数,而不是使用 OPENCV 中的内置函数。我成功了 我该怎么做使用opencv找到对象的区域最大值?

【问题讨论】:

    标签: matlab opencv


    【解决方案1】:

    我自己写了一个函数。我的结果与 MATLAB 非常相似,尽管不准确。此函数是为CV_32F 实现的,但它可以很容易地修改为其他类型。

    1. 我通过检查所有相邻点来标记所有不属于最小区域的点。其余区域是最小值、最大值或拐点区域。
    2. 我使用连通分量来标记每个区域。
    3. 我检查每个区域是否有属于最大值的任何点,如果是,那么我将该标签推入向量中。
    4. 最后我对坏标签进行排序,删除所有重复项,然后将输出中的所有点标记为非最小值。
    5. 剩下的就是最小值区域。

    代码如下:

    //  output is a binary image
    //  1: not a min region
    //  0: part of a min region
    //  2: not sure if min or not
    //  3: uninitialized
    void imregionalmin(cv::Mat& img, cv::Mat& out_img)
    {
        // pad the border of img with 1 and copy to img_pad
        cv::Mat img_pad;
        cv::copyMakeBorder(img, img_pad, 1, 1, 1, 1, IPL_BORDER_CONSTANT, 1);
    
        //  initialize binary output to 2, unknown if min
        out_img = cv::Mat::ones(img.rows, img.cols, CV_8U)+2;
    
        //  initialize pointers to matrices
        float* in = (float *)(img_pad.data);
        uchar* out = (uchar *)(out_img.data);
    
        //  size of matrix
        int in_size = img_pad.cols*img_pad.rows;
        int out_size = img.cols*img.rows;
    
        int x, y;
        for (int i = 0; i < out_size; i++) {
            //  find x, y indexes
            y = i % img.cols;
            x = i / img.cols;
    
            neighborCheck(in, out, i, x, y, img_pad.cols);  //  all regions are either min or max
        }
    
        cv::Mat label;
        cv::connectedComponents(out_img, label);
    
        int* lab = (int *)(label.data);
    
        in = (float *)(img.data);
        in_size = img.cols*img.rows;
    
        std::vector<int> bad_labels;
    
        for (int i = 0; i < out_size; i++) {
            //  find x, y indexes
            y = i % img.cols;
            x = i / img.cols;
    
            if (lab[i] != 0) {
                if (neighborCleanup(in, out, i, x, y, img.rows, img.cols) == 1) {
                    bad_labels.push_back(lab[i]);
                }
            }
        }
    
        std::sort(bad_labels.begin(), bad_labels.end());
        bad_labels.erase(std::unique(bad_labels.begin(), bad_labels.end()), bad_labels.end());
    
        for (int i = 0; i < out_size; ++i) {
            if (lab[i] != 0) {
                if (std::find(bad_labels.begin(), bad_labels.end(), lab[i]) != bad_labels.end()) {
                    out[i] = 0;
                }
            }
        }
    }
    
    int inline neighborCleanup(float* in, uchar* out, int i, int x, int y, int x_lim, int y_lim)
    {
        int index;
        for (int xx = x - 1; xx < x + 2; ++xx) {
            for (int yy = y - 1; yy < y + 2; ++yy) {
                if (((xx == x) && (yy==y)) || xx < 0 || yy < 0 || xx >= x_lim || yy >= y_lim)
                    continue;
                index = xx*y_lim + yy;
                if ((in[i] == in[index]) && (out[index] == 0))
                    return 1;
            }
        }
    
        return 0;
    }
    
    void inline neighborCheck(float* in, uchar* out, int i, int x, int y, int x_lim)
    {   
        int indexes[8], cur_index;
        indexes[0] = x*x_lim + y;
        indexes[1] = x*x_lim + y+1;
        indexes[2] = x*x_lim + y+2;
        indexes[3] = (x+1)*x_lim + y+2;
        indexes[4] = (x + 2)*x_lim + y+2;
        indexes[5] = (x + 2)*x_lim + y + 1;
        indexes[6] = (x + 2)*x_lim + y;
        indexes[7] = (x + 1)*x_lim + y;
        cur_index = (x + 1)*x_lim + y+1;
    
        for (int t = 0; t < 8; t++) {
            if (in[indexes[t]] < in[cur_index]) {
                out[i] = 0;
                break;
            }
        }
    
        if (out[i] == 3)
            out[i] = 1;
    }
    

    【讨论】:

    • 这很有帮助,但目的是找到最大值,而不是最小值。
    【解决方案2】:

    下面的清单是一个类似于 Matlab 的“imregionalmax”的函数。它最多在 threshold 之上寻找 nLocMax 个局部最大值,其中找到的局部最大值相距至少 minDistBtwLocMax 个像素。它返回找到的局部最大值的实际数量。请注意,它使用 OpenCV 的 minMaxLoc 来查找全局最大值。它是“opencv-self-contained”的,除了(易于实现)函数vdist,它计算点(r,c)和(row,col)之间的(欧几里德)距离。

    input 是单通道 CV_32F 矩阵,locations 是 nLocMax(行)乘 2(列)CV_32S 矩阵。

    int imregionalmax(Mat input, int nLocMax, float threshold, float minDistBtwLocMax, Mat locations)
    {
        Mat scratch = input.clone();
        int nFoundLocMax = 0;
        for (int i = 0; i < nLocMax; i++) {
            Point location;
            double maxVal;
            minMaxLoc(scratch, NULL, &maxVal, NULL, &location);
            if (maxVal > threshold) {
                nFoundLocMax += 1;
                int row = location.y;
                int col = location.x;
                locations.at<int>(i,0) = row;
                locations.at<int>(i,1) = col;
                int r0 = (row-minDistBtwLocMax > -1 ? row-minDistBtwLocMax : 0);
                int r1 = (row+minDistBtwLocMax < scratch.rows ? row+minDistBtwLocMax : scratch.rows-1);
                int c0 = (col-minDistBtwLocMax > -1 ? col-minDistBtwLocMax : 0);
                int c1 = (col+minDistBtwLocMax < scratch.cols ? col+minDistBtwLocMax : scratch.cols-1);
                for (int r = r0; r <= r1; r++) {
                    for (int c = c0; c <= c1; c++) {
                        if (vdist(Point2DMake(r, c),Point2DMake(row, col)) <= minDistBtwLocMax) {
                            scratch.at<float>(r,c) = 0.0;
                        }
                    }
                }
            } else {
                break;
            }
        }
        return nFoundLocMax;
    }

    【讨论】:

      【解决方案3】:

      我不知道这是否是您想要的,但在我对this post 的回答中,我给出了一些代码来在灰度图像中找到局部最大值(峰值)(由距离变换产生)。 该方法依赖于从膨胀图像中减去原始图像并找到零像素)。 我希望它有帮助, 祝你好运

      【讨论】:

      • 谢谢你,但你似乎没有在你的程序中使用分水岭。由于我图像中的对象形状不规则,我想使用分水岭,为此我将编写自己的代码来查找 regionmax。我从下面发布的回复中得到了解决方案!
      【解决方案4】:

      前段时间我也遇到过同样的问题,解决方法是在OpenCV/Cpp中重新实现imregionalmax算法。它并不复杂,因为您可以在 Matlab 发行版中找到该函数的 C++ 源代码。 (工具箱中的某处)。您所要做的就是仔细阅读并理解那里描述的算法。然后重写它或删除特定于 matlab 的检查,你就会拥有它。

      【讨论】:

      • 嗨,萨米。正如你所说,我通过选择imregionalmax,然后选择打开选择,在MATLAB 中挖掘imregionalmax。找出区域最大值的关键步骤是BW = imregionalmaxmex(I,conn)。除此之外,在 MATLAB 中再也找不到任何东西了。关于imregionalmaxmex有一个cpp,但是关键步骤compute_reg_max也是未知的。你能告诉我你是如何实现imregionalmax的吗?
      • 如我所说,该算法的核心aprt可以在工具箱文件夹中找到。里面有几万个文件,找图片处理文件夹
      猜你喜欢
      • 1970-01-01
      • 2019-11-30
      • 1970-01-01
      • 2013-11-28
      • 1970-01-01
      • 2018-12-17
      • 2019-12-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多