【发布时间】:2013-02-08 11:33:21
【问题描述】:
我正在编写代码来显示图像之间的特征匹配。目前代码运行速度相当慢。我对如何加快速度有一些想法,但我对 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 中的转换时,我的基本想法是在自己的坐标中绘制每个图像,然后保持几个转换,以便以后可以用它们做一些很酷的事情,但我怀疑它不会很好地缩放。
draw的实际输出是这样的:
当我调整它的大小时,重绘该图形大约需要 4 秒,我想要平移/缩放。
我为每个特征添加了两个补丁,大约(每个图像 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 和一些手动计算非常快速地计算和绘制了椭圆(大约一秒钟,我没有对其进行分析)。 唯一的缺点是我似乎无法将椭圆的填充设置为 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)
【问题讨论】:
-
您也许可以将所有椭圆放入一个补丁集合中,这也可以加快绘图速度。
-
也许可以试试
PathCollection?这是相同的想法,但使用路径而不是补丁。还可以尝试添加 kwargmatch_orginal=True(stackoverflow.com/questions/14492241/…) -
我想出了一个更简单的方法。您可以将补丁集合的 facecolor 设置为字符串:'none'。 (注意,如果你使用 None 则不起作用,那么它只是默认值)
-
是的,
'none'是一个字符串对象,None是None对象。抱歉,我应该更仔细地考虑一下我之前的评论。 -
您能否发表您的最后一条评论作为解决方案,因为您似乎已经解决了自己的问题?
标签: python performance matplotlib