VP10.1.21


速度

使用PC
OS:windows 7(64bit)
CPU:Intel U2300 1.2GHz*2
ノートなのでそれほど速いわけではないと思うけど、多少余裕をもって動作するくらいを目標に。

ループを10回やった平均を記録
  • 空ループ1000回:0ms
repeat 1000
loop

  • cvgetcapture10回:307.9ms
1回あたり約31ms。WEBカメラの最大FPSが30FPSのため?
cvgetcapture自体の処理時間をどうやってはかればよいのだろう。
repeat 10
 cvgetcapture
loop

  • cvgetimg1000回
    • フルカラーscreenへ:1708.6ms
    • フルカラーbufferへ:1236.8ms
    • グレースケールscreenへ:703.6ms
    • グレースケールbufferへ:254.4ms
repeat 1000
 cvgetimg 0,0
loop

  • cvflip1000回
    • 上下左右反転:472.7ms
    • 上下反転:124.8ms
    • 左右反転:336.7ms
上下左右反転は上下反転と左右反転をやってるだけ?
repeat 1000
 ;cvflip -1 // 上下左右
 ;cvflip 0  // 上下
 ;cvflip 1  // 左右
loop

  • cvcopy 1000回
    • 上書き63.0ms
    • 加算:861.2ms
    • 減算:846.8ms
    • 乗算:800.3ms
    • 差分:739.3ms
    • 論理積:160.7ms
上書き、論理積は速い。
repeat 1000
 ;cvcopy 0,0,0,1,CVCOPY_SET  // 上書き
 ;cvcopy 0,0,0,1,CVCOPY_ADD  // 加算
 ;cvcopy 0,0,0,1,CVCOPY_SUB  // 減算
 ;cvcopy 0,0,0,1,CVCOPY_MUL  // 乗算
 ;cvcopy 0,0,0,1,CVCOPY_DIF  // 差分
 ;cvcopy 0,0,0,1,CVCOPY_AND  // 論理積
loop

  • cvthreshold1000回
    • CV_THRESH_BINARY(2値化):464.9ms
    • CV_THRESH_BINARY_INV(2値化反転):475.5ms
    • CV_THRESH_TRUNC(上限?):464.9ms
    • CV_THRESH_TOZERO(上切り出し?):464.9ms
    • CV_THRESH_TOZERO_INV(下切り出し?):460.2ms
どれもほぼ同じ。
repeat 1000
 cvthreshold CV_THRESH_BINARY,127,255,0  // 2値化
loop

  • cvconvert*2 1000回:906.3ms
repeat 1000
 cvconvert 0,0  // フルカラー→グレースケール
 cvconvert 1,0  // グレースケール→フルカラー
loop

  • cvxors1000回:107.5ms
repeat 1000
 cvxors 255,255,255,0
loop

memo

処理時間がかかると思われるところ
1.画像取り込み
2.指の検出(HSPの処理になる辺り)


対応策
1.cvgetimgする前にグレースケールにするのとそのままなのとどっちが速いのだろう。
cvconvertのグレースケール化とフルカラー化が同じ速度だったと仮定すると、cvconvert1回あたりの速度は約0.45ms。
cvgetimgのフルカラーとグレースケールの時の差は約1msなので、グレースケールで画像処理するなら0.55msほど速そう。
cvbuffer側で必要な色を抜き出してグレースケール化、転送とかすればOK?
2.指ではなく、背景が変化したところを検出?青いラインを背景に用意→青くなくなったところを押したと判断とか。
できるだけHSPでの計算を頼らない方向で考えたい。

色抜き出し
  1. cvcopyでコピーを作っておく
  2. cvxorsで必要な色以外を反転
  3. cvcopyで論理積コピー?
これでできるかな?
(63+108+161=332μs)

↑の方法じゃグレースケール化したときに0~255/3の値になってしまうのではなかろうか。
まあ、多少精度が落ちるかもしれないが、明るいか暗いかくらいは分かるか。

↑opencvのcvCvtColorを調べてみると、
RGB[A]->Gray: Y<-0.299*R + 0.587*G + 0.114*B
とあるから、青とかほとんど検出できない。
単色をグレースケール化したときの値の範囲は
R:0~76
G:0~149
B:0~29
できれば緑成分を使いたい。
都合のいいことに手が緑色の人はあまりいないだろうし、黒背景に緑の線でやろうか。

↑線の見え隠れが分かれば良いなら、cvcopyの差分コピーが使えそう。
おそらく減算した結果の絶対値が得られるわけだから、線の所の差分の緑成分は
通常:小さい値
指で隠れる:大きい値
になるはず。
差分が一定以上の所をcvthresholdで抜き出して、あとはhsp側でドット数を数えればいい感じ?
グレースケールより2値化画像のほうが転送が速そうな気がしないでもない。
フルカラー3ch、グレースケール1chの差が転送速度の差なら、2値化画像もグレースケールと同じかな?
そういえば、何で減算コピーより差分コピーのほうがちょっと速いのだろう。負の値の扱いの関係だろうか?


鍵盤の幅

hspcvは確か320*240の画像しか扱えなかったはず。
もし3オクターブのePiano使用の鍵盤を想定するなら、
白鍵の数=3*7+1=22
黒鍵の数=3*5=15
全体の数=22+15=37
画像の横幅いっぱい使うとすると、
320/37≒8.65
8ドットで押したか離したか判断するのか…

↑緑の線2本を使って、白鍵と黒鍵を分けるとすると
320/22≒14.54
14ドットに増える。
ただ、2本にすると線の幅も狭くする必要性から、検査する面積はそう変わらないかもしれない。
ついでに、線を2本にすると黒鍵を押したときにその隣の白鍵を押したかどうかが分からなるという問題も。
2本にしたほうが手も大きく映せるし、検知精度あがりそう。でも、白鍵と黒鍵の同時押しができない。どうしたものか。

↑線が隠れたかどうかをみるためにドット数を数えるとすると、押して離したときの差分のドット数は以下のようになる。
小さい→増える→大きい→減る→小さい
一定以上に増えたときにフラグを立てて、一定以上に減ったときにフラグを下ろす感じで。
フラグを下ろすときの一定値は、増えたときの一定値よりも小さくする必要あり。こんな感じで。
小さい―+――――――――+――大きい
   ←|       |→
  離したよ閾値  押したよ閾値
でないと、微妙なときは押したり離したりになってしまう。
ここらへんに問題がある。2本線のとき、黒鍵の線をおすために白鍵の線を隠してしまう。
白鍵で押したよ閾値を超えても黒鍵が押されるかどうかを少し待つ必要がある。
だからといって、黒鍵の分を待つとラグがががが。
やっぱ1本線でないと難しいかな…
でも演奏するときは黒鍵と白鍵の位置が違ったほうがやりやすそうだな…
いっそこうするかな
 ■ ■  ■ ■ ■   ←黒鍵
■■■■■■■■■■■■■ ←白鍵+黒鍵
黒鍵のために位置を変えてもてもいいけど、変えなくても黒鍵。
処理自体は手前の直線だけで、ユーザの演奏のしやすさのために印を加える感じ。

↑白鍵が等幅でないから少し修正
 ■ ■   ■ ■ ■    ←黒鍵
□■□■□■□■□■□■□■□ ←白鍵+黒鍵
上が黒鍵でないところの下の黒鍵は隣の白鍵で半分ずつかな。
こうすると、鍵の数は
14*3+1=43
鍵の幅は
320/43≒7.44
1ドットくらい減ってもいいか…


↑ピアノの鍵の幅
白鍵=2.4cm
黒鍵=0.95cm
1オクターブ=16.8cm
3オクターブ=16.8*3+2.4=52.8cm
使用するカメラの画角をA°とすると、カメラと線の距離は
52.8/2*tan(2*pi*(90-A/2)/360) cm
画角72°のカメラなら約36cm離して撮ればいいくらい。
画角50°で約57cm、画角90°で約26cm



名前:
コメント:
最終更新:2011年02月04日 17:03