ndarrayとPySideのQImageとの相互変換

魚類はあまり変態しない(生まれた姿のまま大きくなる)ことが一般的で、カレイなどのように左右対称形から非対称になる…など、昆虫や両生類のそれに比べると控えめな程度にとどまるようです。

さてnumpyと愉快な仲間たちにおいて画像はndarrayとして表現されていて、それを表示するのに使うmatplotlibはちょっとしたGUI機能(widgetsモジュール)をもっています。
ただこれコード的にも絵的にもクセが強くごく単純なデモ以上のことは難しいので、何かしたいときはQtのPythonラッパーであるPySideを使っています。

んで、そのPySideで画像はQImageで扱われるので、裏っかわでndarrayで処理をしているならそれをQImageとの間で相互変換できる必要があります。

そのやり方はこちら。

(参考: python – QImage to Numpy Array using PySide – Stack Overflow

画素毎にループしてコピーするとかイケてないことしなくて済むから簡単だね!
QImageに持ってきてしまえばQPixmapにしてQLabelに突っ込んで表示するなりQPainterでお絵かきするなり、自由です。

2行N列のndarrayを一発で(1行目≦2行目)にするnumpy芸

各国における国民1人当たりの魚の年間消費量をランク付けすると、1位はモルディブなんだそうです。土地柄を考えると妥当な結果と言えそうで、6位の日本の2倍以上です。

Numpyにて、行同士の大小関係を強制したい、つまり「2行N列のndarrayがあるんだけど、各列ごとに、常に1行目の値が2行目よりも小さい値を取る必要がある」「そうでない列の値を強制的に上下交換させたい」という状況に遭遇しました。
生ループ回してひとつひとつチェックしては…とやってもいいんですが、それをPython側でやっていてはパフォーマンス上どうかなということで、Numpyのインデクス芸・スライス芸・ブロードキャスト芸あたりを駆使してやってみました。

もちろん、N行2列のndarrayの列間の大小関係を統一するのも同様に可能。

インデクシングなどの詳細の説明はここではしません。
日本語であればこのあたりがわかりやすそう(まだ見てない)。

性能やいかに?

Benchmarker.pyを使って、実行時間を比べてみました。
比較対象は、まぁ何も考えずに書くとそうなりますわな、というような雰囲気のコード(だとおもう)。
#ところで標準の時間計測モジュールtimeitが最高に嫌いなんだけどあれなんであんなふうになってしまったのかな。。。

こちらが実行結果。
proposedが本記事で紹介した黒魔術、conventionalがシンプルな方法。

##                             real    (total    = user    + sys)
col-proposed                 3.6327    3.6200    2.8100    0.8100
row-proposed                 3.6977    3.6900    2.8700    0.8200
col-conventional            49.9127   49.8600   49.7600    0.1000
row-conventional            51.3075   51.2600   51.1600    0.1000

だいたい14倍高速ですね。
メモリ上では行オーダーで格納される都合上、row-*とcol-*の間で速度差が出るのかなと思いましたが、たかだか2行/2列なので、関係ない模様(σが未知なのでなんともいえませんが。。)。

Pythonの高速化の鉄則は『生Python書くな』に尽きますが、それが改めて示された形になりましたとさ。

ただこのようなコード、後から読んだり他人に読ませたりするのはとても困難なので、あまり多用しないようにしましょう。