4

透明な領域と色付きの領域を含むPNG画像から、画像の可能な限り最良のエッジに近いN辺(Nは構成可能)のポリゴンを生成したいと思います。このポリゴンを一連のベクトルで定義したいと思います。

たとえば、次の画像について考えてみましょう。+ プラスへのリンク。ピクセルごとに、その周りの透明なピクセルの数を数えることで、画像のエッジを検出することができます。次の行列が得られます。

0000000000000000
0000053335000000
0000030003000000
0000030003000000
0000020002000000
0533210001233500
0300000000000300
0300000000000300
0300000000000300
0533210001233500
0000020002000000
0000030003000000
0000030003000000
0000053335000000
0000000000000000
0000000000000000

この行列に基づいて、すべてのコーナーの座標を取得できるはずなので、ベクトルを取得できるはずですが、その方法がわかりません。この場合、プログラムを元に戻したいと思います。

[7,2]->[11,2]
[11,2]->[11,6]
[11,6]->[15,6]
... 

それを行うための提案やリンクはありますか?

最終的には、90と0以外のおおよその角度も欲しいのですが、それは本当に第2段階です。

4

3 に答える 3

2

CV ツールキットに含まれる多くのツールが役立つことがわかると思います。独自のソリューションを開発するよりも、これらのリソースを最大限に活用してください。

抽出することに関心があると思われる 2 つの特徴は、エッジとコーナーです。

エッジは、あなたが目指していたものと同様に、形状の輪郭に近づくことができます. あなたが今興味を持っていないのは、エッジ検出技術です。これらは、画像をエッジ/スペースのバイナリ画像に変換します。代わりに、画像内の各線の終点を得ることができるハフ変換を調べる必要があります。見た目のように明確に定義された実線の直線を扱っている場合、これは非常にうまく機能するはずです。質問に Ruby のタグを付けたので、OpenCV を調べることができます (OpenCV は C で記述されていますが、バインドするruby ​​-opencvおよびjavacvプロジェクトがあります)。これは、OpenCV のハフ変換のドキュメントです。. ただし、ハフ変換では、接続する線が得られないことがあります。これは、画像内の実際の線の規則性/不規則性によって異なります。このため、線の終点を構造に手動で接続する必要がある場合があります。

コーナーは、あなたが提供したような画像に対して非常にうまく機能する可能性があります。標準アルゴリズムは、Harris コーナー検出です。ハフ変換と同様に、この手法を使用して、画像内の「最も重要な」特徴を返すことができます。この手法は、同じものの異なる画像であっても、一貫した結果が得られることで知られています。そのため、パターン認識などによく使用されます。ただし、画像が提供されているものと同じくらい単純な場合は、この方法で形状のすべての角を抽出できる可能性があります。画像の形状を取得するには、定義済みの N 辺が与えられた場合に意味のある方法でポイントを接続するだけです。

これらの機能空間の両方を試して、それらがどのように機能するかを確認する必要がありますおそらく両方を同時に使用して、より良い結果を得ることができます。

余談ですが、画像が本当に透明で色/強度である場合は、画像を「バイナリ画像」に変換できます。これは単なるバイナリ データではないことに注意してください。0代わりに、1 つは で表され、もう 1 つは で表される 2 つの色のみを表していることを意味します1。そうすることで、グレースケールおよびバイナリ イメージで機能する一連のツール全体が開かれます。たとえば、上記で手動で計算した数値の行列は距離変換と呼ばれ、OpenCV などのツールを使用して非常に簡単かつ効率的に実行できます。

于 2013-01-06T10:37:44.460 に答える
1

ハフ変換は、一連の点から線、多角形、およびその他の形状を見つけるための標準的な手法です。それはまさにあなたが探しているものかもしれません。ハフ変換を使用して、画像内のすべての可能な線分を見つけてから、近くの線分をグループ化して、画像を近似する多角形のセットを取得できます。

お役に立てれば!

于 2013-01-06T05:24:28.220 に答える
0

このような単純な状況では、次の 3 つの手順を実行できます: 形状の重心を見つける、x 軸と現在の点と重心によって形成される線との間の角度に基づいて対象の点を並べ替える、並べ替えられた点をウォークスルーする.

状況を考えると、重心の x 座標は、関心のある各ポイントの x 座標の合計を、関心のあるポイントの総数で割ったものです (それぞれ、重心の y 座標)。角度を計算するには、ほぼすべての言語で使用できる atan2 を使用するだけです。あなたの関心のあるポイントは、1 または 5 として提示されているポイントです。それ以外の場合はコーナーではありません (入力に基づく)。

Hough があなたの質問を解決すると騙されないでください。費用もかかる方法です。また、マトリックスが与えられた場合、他の方法に勝るものがないほど完全な情報が既にあります(もちろん、問題は、提示したような良い結果を繰り返すことです-そのような場合、ハフが役立つかもしれません)。

私の Ruby は非常に悪いので、次のコードを問題のガイドラインとして使用してください。

include Math

data = ["0000000000000000",
    "0000053335000000",
    "0000030003000000",
    "0000030003000000",
    "0000020002000000",
    "0533210001233500",
    "0300000000000300",
    "0300000000000300",
    "0300000000000300",
    "0533210001233500",
    "0000020002000000",
    "0000030003000000",
    "0000030003000000",
    "0000053335000000",
    "0000000000000000",
    "0000000000000000"]

corner_x = []
corner_y = []
data.each_with_index{|line, i|
    line.split(//).each_with_index{|col, j|
        if col == "1" || col == "5"
            # Cartesian coords.
            corner_x.push(j + 1)
            corner_y.push(data.length - i)
        end
    }
}

centroid_y = corner_y.reduce(:+)/corner_y.length.to_f
centroid_x = corner_x.reduce(:+)/corner_x.length.to_f

corner = []
corner_x.zip(corner_y).each{|c|
    dy = c[1] - centroid_y
    dx = c[0] - centroid_x
    theta = Math.atan2(dy, dx)
    corner.push([theta, c])
}

corner.sort!
corner.each_cons(2) {|c|
    puts "%s->%s" % [c[0][1].inspect, c[1][1].inspect]
}

これにより、次の結果が得られます。

[2, 7]->[6, 7]
[6, 7]->[6, 3]
[6, 3]->[10, 3]
[10, 3]->[10, 7]
[10, 7]->[14, 7]
[14, 7]->[14, 11]
[14, 11]->[10, 11]
[10, 11]->[10, 15]
[10, 15]->[6, 15]
[6, 15]->[6, 11]
[6, 11]->[2, 11]

左下の点から始まる反時計回りの頂点はどれですか(左下の位置で(1、1)から始まるデカルト座標)。

于 2013-01-07T19:13:34.733 に答える