3

私はこれについて長い間頭を悩ませてきました

イメージングを行っています。これまでのところ、画像を 2 値化しました。つまり、グレースケール画像から、特定の値を下回るすべてのピクセルが削除されます。これにより、元の画像からいくつかの領域だけが得られ、それらの領域の周りに多くの「ゼロピクセル」があります。

次に、領域を「ブロブ」にエンコードした長さを実行しました。実行は、データの圧縮方法です。たとえば、正方形を 2 値化したと仮定すると、画像全体を表す数回の実行しかありません。ランは、x、y 座標と長さによって定義されます。

画像を再作成するときは、実行ごとに x、y 座標に移動し、実行の長さの x 軸にピクセルを追加します。

次に、ランを取得して、領域の輪郭を表すチェーンを作成する必要があります。私はそれを行う方法がわかりません。

x、y、長さのランがたくさんあり、チェーンを形成するためにエッジを「ナビゲート」する必要があります。通常、イメージングでは、このプロセスは元の画像で行われますが、ここでは元の画像を使用できないため、ランで計算する必要があります。

これが大きなテキストの壁のように見えることはわかっていますが、この質問をより適切に行う方法がわかりません。

同一の実装に関するヒントやポインタは素晴らしいでしょう。

編集

巻き戻しのおかげで、いくつかの画像をリンクします:

代替テキスト
(出典: tudelft.nl )

この例では、画像 B を輪郭 C に処理します (チェーンと呼びます)。ただし、D、ランレングスから輪郭を生成したいと思います

4

3 に答える 3

0

完全にシンプルで実用的なソリューション (C++) を次に示します。

#include <iostream>
#include <vector>

struct Run { int x, w; };
enum { EAST, NORTHEAST, NORTH, NORTHWEST, WEST, SOUTHWEST, SOUTH, SOUTHEAST };

int main() {

    const Run data[] = {
        { 7, 2 },
        { 5, 6 },
        { 5, 7 },
        { 5, 7 },
        { 6, 6 },
        { 0, 12 },
        { 0, 12 },
        { 0, 11 },
        { 1, 7 },
        { 3, 4 },
        { 3, 4 },
        { 3, 5 },
        { 3, 7 },
        { 3, 7 },
        { 5, 5 }
    };

    std::vector<Run> runs(data, data + 15);
    std::vector<int> before;
    std::vector<int> after;
    unsigned int i;
    int j;

    for (i = 0; i < runs.size() - 1; ++i) {

        if (runs[i].x < runs[i + 1].x) {

            for (j = 0; j < runs[i + 1].x - runs[i].x - 1; ++j)
                before.push_back(WEST);
            before.push_back(NORTHWEST);

        } else if (runs[i].x > runs[i + 1].x) {

            before.push_back(NORTHEAST);
            for (j = 0; j < runs[i].x - runs[i + 1].x - 1; ++j)
                before.push_back(EAST);

        } else {

            before.push_back(NORTH);

        }

        int first_right(runs[i].x + runs[i].w);
        int second_right(runs[i + 1].x + runs[i + 1].w);

        if (first_right < second_right) {

            after.push_back(SOUTHEAST);
            for (j = 0; j < second_right - first_right - 1; ++j)
                after.push_back(EAST);

        } else if (first_right > second_right) {

            for (j = 0; j < first_right - second_right - 1; ++j)
                after.push_back(WEST);
            after.push_back(SOUTHWEST);

        } else {

            after.push_back(SOUTH);

        }

    }

    for (j = 0; j < runs.back().w - 1; ++j)
        after.push_back(WEST);

    std::reverse(before.begin(), before.end());
    after.insert(after.end(), before.begin(), before.end());

    for (j = 0; j < int(after.size()); ++j) {
        switch (after[j]) {
        case EAST:      std::cout << "EAST\n";      break;
        case NORTHEAST: std::cout << "NORTHEAST\n"; break;
        case NORTH:     std::cout << "NORTH\n";     break;
        case NORTHWEST: std::cout << "NORTHWEST\n"; break;
        case WEST:      std::cout << "WEST\n";      break;
        case SOUTHWEST: std::cout << "SOUTHWEST\n"; break;
        case SOUTH:     std::cout << "SOUTH\n";     break;
        case SOUTHEAST: std::cout << "SOUTHEAST\n"; break;
        }
    }

}

これは、実行を反復し、ジャンプ先の方向について左右のエンドポイントをテストし、適切な数のチェーン要素を 2 つのベクトルに追加することによって機能します。 、左用。次に、最後のスキャンラインに適切な数のリンクを追加して 2 つのチェーンを接続し、左側のチェーンを逆にして右側のチェーンに追加して、最終的なチェーンを生成します。

これがあなたが探しているものであることを願っています!

于 2010-02-12T09:15:21.033 に答える
0

私はその契約を失いましたが、答えはFreeman Chain Coding テクニックを使用することでした

ランレングス エンコーディングであるという事実は、私が以前考えていたのとは異なり、アルゴリズムとは何の関係もありません。

于 2010-08-18T18:32:05.003 に答える
0

一見したところ、そのための実用的なアルゴリズムは見当たりません。貧しい人の解決策は、元の画像をエンコードされた長さから拡張することです。したがって、行が次のようになっている場合:

A 3B 10A C 8D
C 4D 3A 6C 9A

ここで、文字は実際のピクセル値を返します (たとえば、A = 0、B = 127、...)。ピクセル値を 2 次元配列 (または選択した別のデータ構造) に書き込むことができます。次のようになります。

ABBBAAAAAAAAAACDDDDDDDD
CDDDDAAACCCCCCAAAAAAAAA

その後、チェーンを生成し、配列を削除してチェーン情報を保持します。確かにこれは高価なので、元の画像の長さをエンコードする前にこれを行うことができます。

于 2010-02-12T08:44:37.347 に答える