9

画面の周囲を囲む長方形の平均色を返す簡単なPythonスクリプトを作成しました。(ここでの最終目標は、モニターの周囲にRGB LEDストリップを配置して、映画の中で光る効果を出すことです。このように(youtube)ですが、自分で作成しているのでもっと楽しくなります)。

私は現在、画面をビットマップ( "screenshot")として取得し、各ピクセル値を取得し、RGB<->HEX変換を行うためにautopyを使用しています。

簡略化されたバージョン:

step = 1
width = 5
height = 5

b = autopy.bitmap.capture_screen()

for block in border_block(width, height): # for each rectangle around the perimeter of my screen

    R,G,B = 0,0,0
    count = 0

    for x in xrange(block.x_min, block.x_max, step):
        for y in xrange(block.y_min, block.y_max, step):
            r,g,b = autopy.color.hex_to_rgb(image.get_color(x, y))
            R += r; G += g; B += b
            count += 1

   block.colour = "#{:06x}".format(autopy.color.rgb_to_hex(R/count,G/count,B/count))

matplotlib次に、 :(これは5x5ブロックとして構成され、ステップ= 1)を使用してブロックを表示します。

5x5スクリーンショット

問題は、実装の速度です。これは、ブロック内の各ピクセル(2560*1600解像度/5= 320 *512ブロック=163,840ピクセル/ブロック)、および周囲の各ブロック(16 * 163,840 = 2,621,440ループ)でループしているためです。 )。全体として、これは完了するのに2.814秒かかりました。

ステップ値を増やすと、速度は上がりますが、十分ではありません:(これは境界を囲むより現実的な15x10ブロックを使用しています)

Step    Time (s)
1       1.35099983215
2       0.431000232697
5       0.137000083923
10      0.0980000495911
15      0.095999956131
20      0.0839998722076
50      0.0759999752045

これは、スクリーンショット自体に約0.070秒かかるためです。これは、12.8FPSに制限されていることを意味します。

>>> timeit.Timer("autopy.bitmap.capture_screen()", "import autopy").timeit(100)/100
0.06874468830306966

質問:

  • スクリーンショットを撮り、画面の領域を平均化するより速い方法はありますか?

    精度についてはあまり心配していませんが、シリアル伝送のオーバーヘッドを考慮して、これらの値を約30 FPS、理想的にはより高速(20〜30ミリ秒)で返すことができるようにしたいと考えています。私の画面解像度は2560*1600であることを覚えておいてください!

    Python Imaging Library(PIL)について聞いたことがありますが、関数の速度を調べる時間がImageGrabまだありませんが、有望に見えます。

  • GPUから直接ピクセル値を読み取ることはできますか?

  • 別の考え-映画の上端/下端を検出するための最良の方法は何ですか?(アスペクト比がワイドスクリーンの場合、スクリーンショットの上下に黒いバーがあり、一部の長方形は黒いです)。


PILのgrab()の使用

>>> timeit.Timer("ImageGrab.grab()", "from PIL import ImageGrab").timeit(100)/100
0.1099840205312789

PIL-サイズ変更:(ChristopheD)

>>> timeit.Timer("PIL.ImageGrab.grab().resize((15, 10), PIL.Image.NEAREST)", "import PIL").timeit(100)/100
0.1028043677442085

>>> timeit.Timer("PIL.ImageGrab.grab().resize((15, 10), PIL.Image.ANTIALIAS)", "import PIL").timeit(100)/100
0.3267692217886088

注:これは上記で得られた結果よりも改善されていますが、9 FPS、または完全なアンチエイリアシングを使用した3FPSに制限されています。


PIL-最も近く、サイズを変更:(マークランサム)

>>> for step in [1,2,5,10,15,20,50]:
    print step, timeit.Timer("PIL.ImageGrab.grab().resize(("+str(2560/step)+", "+str(1600/step)+"), PIL.Image.NEAREST).resize((15, 10), PIL.Image.ANTIALIAS)", "import PIL.ImageGrab").timeit(100)/100

結果:

Step  Time(s)
1     0.333048412226
2     0.16206895716
5     0.117172371393
10    0.102383282629
15    0.101844097599
20    0.101229094581
50    0.100824552193

手動で上部をループするよりもはるかに高速autopyですが、それでも最大9 FPSに制限されています(「ステップ」10)。

注:これには、必要なRGBからHEXへの変換は含まれていません


誰かがより速い方法を思い付くことができますか?つまり、部分的なスクリーンショットを撮ることができますか?Cで何か書くべきですか?

4

3 に答える 3

3

Python イメージング ライブラリを使用します。ドキュメントから(Imageモジュール内):

色を取得

im.getcolors() => (count, color) タプルのリストまたは None

im.getcolors(maxcolors) => (count, color) タプルのリストまたは None

(1.1.5 の新機能) (count, color) タプルのソートされていないリストを返します。count は、対応する色が画像内に出現する回数です。

Image モジュールには、getcolors() にプラグインする各四角形を取得するために使用できる crop() メソッドも含まれています。そこから簡単に加重平均を取ることができます。

Python でループを手動で実行するよりもはるかに高速です。リアルタイムで使用するのに十分な速度かどうかはわかりませんが、劇的な速度向上が得られます. また、スクリーンショットを 1 秒間に数回撮影することもできます。これは、10 fps に対して 60 fps で LED に信号を送信しても特に目立たない可能性が高いためです。「12.8 FPS に制限されている」と見なさないでください。「5 フレームごとに 1 回しか LED を更新できない」と見なしてください。これは、顕著な違いではないはずです。

編集:ここでさらに最適化することに本当に興味がある場合は、WindowsでPythonを使用してスクリーンショットを撮る最速の方法が非常に役立つと思います。

于 2012-05-18T14:57:45.980 に答える
1

迅速な勝利はresize、領域を平均化する代わりに、5x5 画像に対して (PIL で) 操作を使用することです (速度のために単純な補間を使用できます)。

myimg = ImageGrab.grab()
resized = myimg.resize((5, 5), Image.NEAREST) 

これにより、自分で平均化作業を行うのとほぼ同じ効果が得られるはずです。

ただし、 PIL の ImageGrab の速度 (および との比較autopy) についてはよくわかりませんが、試すのは簡単です。

于 2012-05-18T14:45:03.677 に答える
1

サイズ変更操作を高速化するには、2 つのステップで行うことができます。最初のものに NEAREST を使用して、可能な限り最速の方法でピクセル数を削減し、次に ANTIALIAS を使用してそれらを代表的なサンプルにマージします。これは、前に PIL 関数で実験したステップ サイズと同じです。

PIL.ImageGrab.grab().resize((150, 100), PIL.Image.NEAREST).resize((15, 10), PIL.Image.ANTIALIAS)
于 2012-05-18T16:40:02.577 に答える