mpi*_*arz 10 python numpy opticalflow
我正在使用Lucas Kanade方法研究光流程脚本,作为大学项目.虽然它运作良好,但有些东西我无法弄清楚.它在启动时使用几MB的内存,但这个数量每秒都在迅速增加.当它为480帧电影的1帧计算OF时,它使用大约1GB.当它达到1.9GB时,即使停留了几个小时,它也会突然停止并停留在那里.
我尝试在另一台PC上运行脚本,它只"使用1GB".
这是非常奇怪的行为,因为根据我的计算,它应该使用少于100MB.
对我来说最令人惊讶的是,在脚本计算了一帧之后,我打印了垃圾收集器正在观看的对象数量,大约是200万,然后在强制收集后再次打印它,它完全相同.我等待第二帧计算(同时内存使用量增加~1GB)并且脚本打印了GC正在监视的对象数 - 完全相同的数字接近200万.那是什么意思呢?numpy是用C语言编写的,有内存泄漏吗?
我真的很想了解这种行为.
Jai*_*ime 19
虽然它没有解释你的记忆问题,但你的实施是温和的,不是最理想的.你不仅没有充分利用numpy的功能,而且你的算法流程也不能很好地避免重复计算.我认为你只是在资源上运行你的系统,不是因为python或numpy中出了问题,而是因为你创建了太多不必要的列表列表列表......
在看了维基百科在Lucas-Kanade算法上的条目之后,我重写了你的主要功能如下:
def lucas_kanade_np(im1, im2, win=2):
assert im1.shape == im2.shape
I_x = np.zeros(im1.shape)
I_y = np.zeros(im1.shape)
I_t = np.zeros(im1.shape)
I_x[1:-1, 1:-1] = (im1[1:-1, 2:] - im1[1:-1, :-2]) / 2
I_y[1:-1, 1:-1] = (im1[2:, 1:-1] - im1[:-2, 1:-1]) / 2
I_t[1:-1, 1:-1] = im1[1:-1, 1:-1] - im2[1:-1, 1:-1]
params = np.zeros(im1.shape + (5,)) #Ix2, Iy2, Ixy, Ixt, Iyt
params[..., 0] = I_x * I_x # I_x2
params[..., 1] = I_y * I_y # I_y2
params[..., 2] = I_x * I_y # I_xy
params[..., 3] = I_x * I_t # I_xt
params[..., 4] = I_y * I_t # I_yt
del I_x, I_y, I_t
cum_params = np.cumsum(np.cumsum(params, axis=0), axis=1)
del params
win_params = (cum_params[2 * win + 1:, 2 * win + 1:] -
cum_params[2 * win + 1:, :-1 - 2 * win] -
cum_params[:-1 - 2 * win, 2 * win + 1:] +
cum_params[:-1 - 2 * win, :-1 - 2 * win])
del cum_params
op_flow = np.zeros(im1.shape + (2,))
det = win_params[...,0] * win_params[..., 1] - win_params[..., 2] **2
op_flow_x = np.where(det != 0,
(win_params[..., 1] * win_params[..., 3] -
win_params[..., 2] * win_params[..., 4]) / det,
0)
op_flow_y = np.where(det != 0,
(win_params[..., 0] * win_params[..., 4] -
win_params[..., 2] * win_params[..., 3]) / det,
0)
op_flow[win + 1: -1 - win, win + 1: -1 - win, 0] = op_flow_x[:-1, :-1]
op_flow[win + 1: -1 - win, win + 1: -1 - win, 1] = op_flow_y[:-1, :-1]
return op_flow
Run Code Online (Sandbox Code Playgroud)
它使用两个嵌套调用np.cumsum和排除包含原则来计算窗口参数.由于在每个点处求解的方程组仅为2x2,因此它使用Cramer的规则来对求解进行矢量化.
为了比较,我将您的lucas_kanade函数重命名lucas_kanade_op为对最后一个语句的单个更改,以便它返回一个numpy数组:
def lucas_kanade_op(im1, im2, win=2) :
...
return np.array(opfl)
Run Code Online (Sandbox Code Playgroud)
我计算了两种方法,(并检查它们都输出相同)并且没有任何意外,利用numpy提供了巨大的推动:
rows, cols = 100, 100
im1 = np.random.rand(rows, cols)
im2 = np.random.rand(rows, cols)
ans1 = lucas_kanade_op(im1, im2)
ans2 = lucas_kanade_np(im1, im2)
np.testing.assert_almost_equal(ans1,ans2)
import timeit
print 'op\'s time:', timeit.timeit('lucas_kanade_op(im1, im2)',
'from __main__ import lucas_kanade_op, im1, im2',
number=1)
print 'np\'s time:', timeit.timeit('lucas_kanade_np(im1, im2)',
'from __main__ import lucas_kanade_np, im1, im2',
number=1)
Run Code Online (Sandbox Code Playgroud)
打印出:
op's time: 5.7419579567
np's time: 0.00256002154425
Run Code Online (Sandbox Code Playgroud)
这是一个x2000的速度增加,对于一个小的100x100图像.我不敢测试你的全尺寸480p图像的方法,但上面的函数可以在每秒随机854x480阵列上处理大约5次计算,没有任何问题.
我建议你以类似于上面提出的方式重写你的代码,充分利用numpy.将完整代码发布到Code Review将是一个很好的起点.但是当你的代码开始时代码效率低下时,寻找对象的杂散引用真的没有意义!
| 归档时间: |
|
| 查看次数: |
6287 次 |
| 最近记录: |