3

接続されたコンポーネント (円で塗りつぶされた) のイメージがあります。それらをセグメント化したい場合は、流域アルゴリズムを使用できます。 opencvを使用したオブジェクトの?

4

4 に答える 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;
}
于 2016-06-02T18:36:07.593 に答える
0

それがあなたが望むものであるかどうかはわかりませんが、この投稿への私の答えでは、グレースケール画像(距離変換の結果)で極大値(ピーク)を見つけるためのコードをいくつか与えました。このアプローチは、拡張された画像から元の画像を差し引き、ゼロピクセルを見つけることに依存しています。お役に立てば幸いです

于 2012-06-26T11:07:25.173 に答える
-3

私はしばらく前に同じ問題を抱えていましたが、解決策は OpenCV/Cpp で imregionalmax アルゴリズムを再実装することでした。関数の C++ ソース コードは Matlab ディストリビューションに含まれているため、それほど複雑ではありません。(ツールボックスのどこかに)。あなたがしなければならないことは、そこに記述されているアルゴリズムを注意深く読んで理解することだけです. 次に、それを書き直すか、matlab 固有のチェックを削除すると、それが得られます。

于 2012-06-26T11:27:40.717 に答える