imregionalmax在Matlab中的函数,在OpenCV中对应的是什么?

3

我有一副联通组件的图像(填充的圆)。如果我想要对它们进行分割,可以使用分水岭算法。我更喜欢编写自己的分水岭函数,而不是使用OPENCV中的内置函数。我已经成功实现了它。

如何使用opencv找到对象的regionalmax?

4个回答

2
我自己编写了一个函数。我的结果与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;
}

这很有帮助,但意图是找到最大值,而不是最小值。 - rayryeng

1
以下代码段是类似于Matlab的“imregionalmax”的函数。它查找最多nLocMax个本地最大值,这些本地最大值在threshold以上,并且找到的本地最大值至少相距minDistBtwLocMax个像素。它返回实际找到的本地最大值数量。请注意,它使用OpenCV的minMaxLoc来查找全局最大值。除了计算点(r,c)和(row,col)之间(欧几里得)距离的vdist函数(易于实现)外,它是“opencv-self-contained”的。 输入是一个单通道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;
}


0

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


谢谢,但是你似乎没有在你的程序中使用分水岭算法。由于我的图像中的对象形状不规则,我想使用分水岭算法,所以我打算自己编写代码来找到区域最大值。我从下面的回复中得到了一个解决方案! - user14

-3
我之前也遇到过同样的问题,解决方法是在OpenCV/Cpp中重新实现imregionalmax算法。这并不复杂,因为你可以在Matlab发行版中找到该函数的C++源代码(在工具箱中某个地方)。你只需要仔细阅读并理解那里描述的算法,然后重写它或删除Matlab特定的检查即可。

嗨,萨米。正如你所说,我通过选择imregionalmax然后选择_Open Selection_在MATLAB中挖掘了它。找到区域最大值的关键步骤是BW = imregionalmaxmex(I,conn)。除此之外,在MATLAB中再也找不到其他东西了。我找到了一个关于imregionalmaxmexcpp,但是关键步骤compute_reg_max也是未知的。你能告诉我如何实现imregionalmax吗? - WangYudong
正如我所说,算法的核心部分可以在工具箱文件夹中找到。那里有成千上万的文件,请查找图像处理文件夹。 - Sam

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接