2009-07-20 15 views
10

XNAを使用して、液晶プロジェクタとハンドヘルドレーザードットポインタのみを表示するようにフィルタリングされたモノクロカメラを使用して壁に「落書き」を描くプロジェクトを構築しています。レーザーポインターをいくつでも使用したいのですが、現時点では区別する必要はありません。高速サブピクセルレーザードット検出

壁10' ×10' であり、カメラは、ここで概説されるようにのみ640×480は、私はスプライン曲線を使用して、サブピクセル測定を使用しようとしています:(tpub.com

カメラは120FPSで実行8私の質問はすべて、そのサブピクセルレーザードットセンターを見つけるための最速の方法です。現在、私はスプライン補間を行う前に、無理矢理2D検索を使用して画像上の最も明るいピクセル(0〜254)を探しています。その方法はそれほど高速ではなく、各フレームは入って来るよりもコンピュータに時間がかかります。

編集:最終的に、私のカメラデータはピクセルの明るさを示すバイトの2次元配列で表されます。

私がしたいのは、XNAシェーダを使って私のために画像をクランチすることです。それは実用的ですか?私が理解しているところでは、実際にピクセルシェーダに実行中の合計、平均などの永続変数を保持する方法はありません。

しかし、議論のために、スプライン曲線の隣接ピクセルをテクスチャを使用してX個の頂点に格納します。 texcoordsを使ってスプライン曲線を計算するのにHLSLを使用するのが現実的ですか?

私はXNAボックス外の提案にもオープンしています。DX10/DX11、多分FPGAのようなものかもしれません。このようにデータを処理する方法はあまり経験がありません。私はおそらくこれを間違った方法でやっているよりも、2つのAA電池を使ってWii-Moteでこれを行うことができるかどうかを判断します。

アイデア?

+0

スキャンが遅い、またはスプライン補間を行うのは遅いですか? – Nosredna

+0

スプライン補間は、スプラインをどのデルタで評価するかによって、最も遅い成分です。この場合、0.1pxの精度が必要です。 – bufferz

+0

もし私が20のレーザーを持っていれば、スプライン計算は非常に非常に高価なcPUになります。 – bufferz

答えて

3

サブピクセル精度が必要な場合は、かなり複雑な数学を扱っています。私はthis paperが何か考えていると思います。残念ながら、あなたはそのサイトを使ってそれを見るために支払う必要があります。適切な図書館にアクセスすることができれば、あなたのためにそれを保有することができます。

元のポストのリンクは、軸ごとに1000のスプライン計算を行うことを示唆しました。xとyを独立して扱いました。円形のイメージでは問題ありませんが、イメージが歪んだ楕円であればビットオフです。

X C = SUM( nは X .F( N X))/ SUM( nは X F())

:あなたは合理的な見積もりを取得するには、以下を使用することができますC X は、 Nを意味Xはここで、x軸およびF(X N)に沿った点は、x N点における値です。したがって、このために:

  * 
     * * 
     * * 
     * * 
     * * 
     * * 
     * * * 
    * * * * 
    * * * * 
* * * * * * 
------------------ 
2 3 4 5 6 7 

を与える:

和(X N .F(X N))= 1 * 2 + 3 * 3 + 4×9 + 5 * 10 + 6 * 4 + 7 * 1つの

和(F(X N))= 1 + 3 + 9 + 10 + 4 + 1

X C = 28分の128 = 4.57

を入力し、y軸を繰り返します。

+0

これはとてもうまく動作します。これは私のスプライン実装よりもはるかに速く実行されます。それはかなり多くのリアルタイムです!提案していただきありがとうございます。 – bufferz

+0

リンクについて:タイトルを検索するだけです。トップヒット:http://groups.mrl.illinois.edu/granick/Publications/pdf%20files/2009/stephen_2009_image%20analysis%20with%20rapid%20and%20accurate%202d%20gaussian%20fit.pdf – jnm2

5

ブルートフォースは、すべてのピクセルを独立して見ることを意味していれば、それは基本的に唯一の方法です。画像で何をしたいのかに関係なく、すべての画像ピクセルをスキャンする必要があります。最も明るいピクセルを見つける必要はないかもしれませんが、イメージを色でフィルタリングすることができます(例:赤いレーザーを使用している場合)。これは、HSVの色分けされた画像を使用して簡単に実行できます。より高速なアルゴリズムをお探しの場合は、OpenCVを試してみてください。なお、画像処理のために何度も何度も最適化されています、そしてあなたは、ラッパーを経由してC#でそれを使用することができます。

[http://www.codeproject.com/KB/cs/Intel_OpenCV.aspx][1]

OpenCVのはまた、あなたが簡単にポイントセンターを見つけ、それぞれのポイントを追跡することができます。

120fpsカメラを使用する理由はありますか?あなたは人間の目は約30fpsしか見ることができないことを知っていますか?私はそれが非常に速いレーザーの動きに従うことを推測しています... 120fpsのリアルタイム処理が達成するのが非常に難しいので、それを打ち消すことを検討したいかもしれません。

4

最高のバイトを見つけるために640 * 480バイトを実行するのは、ms以内に実行する必要があります。遅いプロセッサでも。シェーダのルートを取る必要はありません。

私はあなたのループを最適化する助言をします。例えば :(それはすべての配列の検索との乗算を行うので)これは本当に遅いです:

byte highest=0; 
foundX=-1, foundY=-1; 
for(y=0; y<480; y++) 
{ 
    for(x=0; x<640; x++) 
    { 
     if(myBytes[x][y] > highest) 
     { 
      highest = myBytes[x][y]; 
      foundX = x; 
      foundY = y; 
     } 
    } 
} 

これははるかに高速です:

byte [] myBytes = new byte[640*480]; 
//fill it with your image 

byte highest=0; 
int found=-1, foundX=-1, foundY=-1; 
int len = 640*480; 
for(i=0; i<len; i++) 
{ 
    if(myBytes[i] > highest) 
    { 
     highest = myBytes[i]; 
     found = i; 
    } 
} 
if(found!=-1) 
{ 
    foundX = i%640; 
    foundY = i/640; 
} 

これは私の頭の上からのためにとても残念ですエラー; ^)

3

実際にはブルートフォースが唯一の方法ですが、シェーダを使用するというあなたの考えは良いです.CPUからのブルートフォースチェックをオフロードすることになります。ピクセルを同時に(コアあたり約1つ)GPUに転送しますピクセルを同時に比較できる100以上のダムコア(パイプライン)を備えています(アルゴリズムを1命令でうまく動作させるには少し修正する必要があります - 多くのコアをGPUで配置する必要があります)。

私が見ている最大の問題は、GPUにそのデータを十分に速く移動できるかどうかということです。

+0

GPUのフレーム上で最高の単一ピクセルをどのように追跡できますか?ダムコアがピクセルを前の最も明るいピクセルと比較する方法でメモリを共有できないという点でこれを正しく理解していますか? – bufferz

+1

GPUは、数学演算に最適化された本当にシンプルなCPUの大きなコレクションと考えることができます。しかし、最大の違いは、命令デコーダが削除されていることです。単一のコントローラが同じ命令を各ダムコアに送信し、そのコアのデータで実行されます。 IF文は、同じコードを2回実行することによって実行されます。分岐する代わりに、条件に一致しないコアは停止します。同じデータが再び送信されますが、比較命令は逆になります。 – David

+1

128個のコアが明るいピクセルを検出した可能性があるため、*直前の最も明るいピクセルと比較することはできません。その代わりに、各コアをそれ自身のラインに集中させてみてください。ライン内で最も明るいピクセルを見つけてください(同時に128ラインを処理します)。画像内の線が効果的にその線の中で最も明るい画素としてまとめられれば、全体的に最も明るい部分を連続的に見つけることができます。 – David

1

カメラを焦点から少し外し、bitbltをニュートラルサンプルに置きます。非0値の行をすばやくスキャンすることができます。また、8ビットで4バイトを一度に取得する場合は、イメージを高速に処理できます。他の人が指摘しているように、フレームレートを下げる可能性があります。結果の画像より忠実度が低い場合は、高いスキャンレートではあまり意味がありません。

(フォーカスカメラのうちわずかだけの最も明るいポイントを得るのを助ける、あなたが忙しいの表面を持っている場合は偽陽性を削減します...もちろん、あなたが滑らか/平らな面を撮影していないと仮定した場合)

2

別の最適化考えてみましょう:あなたが描画している場合は、現在のポインタの位置がおそらくポインタの最後の位置に近いことになります。フレーム間のポインタの最後に記録された位置を覚えて、その位置に近い領域をスキャンするだけです... 1'x1 'の領域。ポインタがその領域に見つからない場合にのみ、表面全体をスキャンする必要があります。

明らかに、プログラムがスキャンする速度と、カメラがポインタを失う前にマウスを動かすことができる速度との間にはトレードオフがあり、ゆっくりとしたフルイメージスキャン。おそらく少しの実験で最適な値が明らかになるでしょう。

クールなプロジェクトです。

+0

なぜちょうど1x1。サイズを1^2増やしてみませんか?したがって、1x1に見つからない場合は、2x2、4x4などをチェックします。ちょっと気をつけて、すでにチェックした領域をまたぐことができます。 –

+0

私もそれについて考えました。しかし、彼は複数のレーザーを持つことができるので、とにかくあらゆるピクセルを見る必要があります。レーザは、予告なしにその領域をオンまたは再投入することができます。 – Nosredna

1

黒の出力バッファで開始してください。今はサブピクセルについては忘れてしまいます。すべてのフレーム、すべてのピクセル、これを行う:

outbuff = max(outbuff、inbuff);

画像が完成したら、3番目の「クリーン」バッファーにサブピクセルフィルター処理を行います。または、一度に画面のチャンクまたはラインをリアルタイムで実行します。利点:あなたが行くにつれてきれいになった、図面のリアルタイムの「粗い」表示。

ラフ出力バッファから「クリーン」第3バッファに変換すると、ラフからブラックにクリアできます。これにより、速度を落とさずに永遠に描画を続けることができます。

「クリーン」を「ラフ」の上に描画すると、わずかに異なる色になる可能性がありますが、両方の世界の中で最も優れたものになります。

これは、ペイントプログラムと同じです。あなたが本当に速く描画すると、荒いバージョンが表示され、ペイントプログラムは時間があるとイメージを「クリーンアップ」します。


アルゴリズムのいくつかのコメント:

私はこの分野での詐欺をたくさん見てきました。私はアップサンプリングしたSega GenesisエミュレータでSonicを演奏しました。それは非常にうまく動作し、非常に速いいくつかの非常に野性的なアルゴリズムを持っています。

ドットの明るさと半径を知ることができるので、実際にはいくつかの利点があります。

各ピクセルとその8近傍を見て、その9ピクセルがサブピクセルのどこにあるかの明るさに応じて「投票」することができます。


その他の考え

あなたは、レーザーポインタを操作するときあなたの手がその正確ではありません。 10フレームごとにすべてのドットを取得して、どのビームがあるかを特定してください(以前のモーションに基づいて、新しいドット、消灯したレーザー、視野を出入りしたドットを考慮して)解像度曲線。入力のサブピクセルを気にする必要はありません。カーブを高解像度の出力に描画するだけです。

すべてのコントロールポイントを通過するCatmull-Romスプラインを使用します。

+0

私はこのアイデアが好きで、完璧な意味を持っています。したがって、5x5ピクセル値を含む構造体として「きれいな」ピクセルを表現し、別のスレッドのキューでそれらを通過させることができます。 しかし、このキューを経由して焼くことは、大規模なCPU処理になります。たぶん私は頂点にこれらの構造体のそれぞれを保存し、ビデオカード上のスプライン曲線を行うことができますか?私はまだ5x5の2Dスプラインを計算するための照明の速い方法を探しています。 この高レベルの提案をありがとうございます! – bufferz

+0

どのくらい遅いかは本当に問題ではありません。後で最適化することができます。あなたは単にタイマーを見て、各フレームでどれくらいの画面を行うことができるかを確認するだけです。 – Nosredna