画像間の特徴の一致を表示するコードを書いています。現在、コードの実行速度はかなり遅くなっています。私はそれをスピードアップする方法についていくつかのアイデアを持っていますが、私はまだmatplotlibに100%快適ではありません。
コードの基本構造は次のとおりです:(読みやすくするために省略しています)
from matplotlib.patches import Rectangle, Circle, Ellipse
import matplotlib.gridspec as gridspec
from matplotlib.transforms import Affine2D
from scipy.linalg import inv, sqrtm
import matplotlib.pyplot as plt
import numpy as np
リスト画像を追加します。各画像は独自の軸(ax)を取得し、ax.transDataを記憶します
gs = gridspec.GridSpec( nr, nc ) for i in range(num_images): dm.ax_list[i] = plt.subplot(gs[i]) dm.ax_list[i].imshow( img_list[i]) transData_list[i] = dm.ax_list[i].transData
特徴表現を省略記号として視覚化します
for i in range(num_chips): axi = chips[i].axi ax = dm.ax_list[axi] transData = dm.transData_list[axi] chip_feats = chips[i].features for feat in chip_feats: (x,y,a,c,d) = feat A = numpy.array( [ ( a, 0, 0 ) , ( c, d, 0 ) , ( 0, 0, 1 ) ] , dtype=np.float64) EllShape = Affine2D( numpy.array(sqrtm( inv(A) ), dtype=np.float64) ) transEll = EllShape.translate(x,y) unitCirc = Circle((0,0),1,transform=transEll+transData) ax.add_patch(unitCirc)
私はRunSnakeRunを使用してコードのプロファイルを作成しましたが、そこから実際に収集するのは、すべてを描画するのに長い時間がかかることだけです。matplotlibでの変換について学んだときの基本的な考え方は、各画像を独自の座標で描画し、後でそれらを使ってクールなことができるようにいくつかの変換を維持することでしたが、うまくスケーリングされないのではないかと思います。
ドローの実際の出力は次のようになります。
サイズを変更すると、図の再描画に約4秒かかります。これで、パン/ズームしたいと思います。
機能ごとに2つのパッチを追加し、アウトラインと透明度を確認できるように約(画像あたり300の機能)を追加しました。したがって、そのためのオーバーヘッドは明らかにあります。ただし、楕円がなくても比較的低速です。
また、一致する機能の間に行を挿入するコードを作成する必要がありますが、特にこれが比較的小さなデータセットである場合は、複数の軸を使用することが非常に良いアイデアかどうかはわかりません。
したがって、より具体的な質問については、次のようになります。
- 楕円と変換された円をプロットする方が効率的でしょうか?matplotlib変換を使用するオーバーヘッドは何ですか?
- パッチのグループを組み合わせて、一緒に、またはより効率的に変換する方法はありますか?
- すべてを単一の軸にパックする方が効率的でしょうか?それを行った場合でも、変換のパラダイムを使用できますか?それとも、ここでの主な犯人は変身ですか?
- 行列Aのリストに対してsqrtm(inv(A))を実行する簡単な方法はありますか?それとも、forループにそれらを持っているのも同様ですか?
- pyqtgraphのようなものに切り替える必要がありますか?パンとズーム以外のアニメーションになる予定はありません。(将来的には、これらをインタラクティブなグラフに埋め込みたいと思うかもしれません)
編集:
平方根逆行列の形を手作業で計算することで、描画効率を上げることができました。そのかなり大きなスピードアップも。
上記のコードでは:
A = numpy.array( [ ( a, 0, 0 ) ,
( c, d, 0 ) ,
( 0, 0, 1 ) ] , dtype=np.float64)
EllShape = Affine2D( numpy.array(sqrtm( inv(A) ), dtype=np.float64) )
に置き換えられます
EllShape = Affine2D([\
( 1/sqrt(a), 0, 0),\
((c/sqrt(a) - c/sqrt(d))/(a - d), 1/sqrt(d), 0),\
( 0, 0, 1)])
私もいくつかの興味深いタイミング結果を見つけました:
num_to_run = 100000
all_setup = ''' import numpy as np ; from scipy.linalg import sqrtm ; from numpy.linalg import inv ; from numpy import sqrt
a=.1 ; c=43.2 ; d=32.343'''
timeit( \
'sqrtm(inv(np.array([ ( a, 0, 0 ) , ( c, d, 0 ) , ( 0, 0, 1 ) ])))',\
setup=all_setup, number=num_to_run)
>> 22.2588094075 #(Matlab reports 8 seconds for this run)
timeit(\
'[ (1/sqrt(a), 0, 0), ((c/sqrt(a) - c/sqrt(d))/(a - d), 1/sqrt(d), 0), (0, 0, 1) ]',\
setup=all_setup, number=num_to_run)
>> 1.10265190941 #(Matlab reports .1 seconds for this run)
編集2
PatchCollectionといくつかの手動計算を使用して、楕円を非常に迅速に計算および描画できるようになりました(約1秒で、プロファイルを作成しませんでした)。唯一の欠点は、楕円の塗りつぶしをfalseに設定できないことです。
from matplotlib.collections import PatchCollection
ell_list = []
for i in range(num_chips):
axi = chips[i].axi
ax = dm.ax_list[axi]
transData = dm.transData_list[axi]
chip_feats = chips[i].features
for feat in chip_feats:
(x,y,a,c,d) = feat
EllShape = Affine2D([\
( 1/sqrt(a), 0, x),\
((c/sqrt(a) - c/sqrt(d))/(a - d), 1/sqrt(d), y),\
( 0, 0, 1)])
unitCirc = Circle((0,0),1,transform=EllShape)
ell_list = [unitCirc] + ell_list
ellipses = PatchCollection(ell_list)
ellipses.set_color([1,1,1])
ellipses.face_color('none') #'none' gives no fill, while None will default to [0,0,1]
ellipses.set_alpha(.05)
ellipses.set_transformation(transData)
ax.add_collection(ellipses)