python中生成定向光流(HOOF)直方图的最有效方法

python中生成定向光流(HOOF)直方图的最有效方法,python,performance,computer-vision,histogram,opticalflow,Python,Performance,Computer Vision,Histogram,Opticalflow,我有一个498帧长的图像序列,我使用cv2.calcOpticalFlowFarneback计算光流。因此,现在我有497个矢量图代表我的运动矢量,这些矢量由大小和方向来描述 我需要做的是生成一个直方图,其中x轴上的角度范围以度为单位。更具体地说,我有12个箱子,其中第一个箱子包含所有方向0

我有一个498帧长的图像序列,我使用cv2.calcOpticalFlowFarneback计算光流。因此,现在我有497个矢量图代表我的运动矢量,这些矢量由大小和方向来描述

我需要做的是生成一个直方图,其中x轴上的角度范围以度为单位。更具体地说,我有12个箱子,其中第一个箱子包含所有方向
0
,第二个箱子
30
,依此类推。相反,在y轴上,我需要得到每个箱子中包含的向量的模和

这里的问题是,使用简单的
for
循环和
if
语句执行所有这些操作需要花费很长时间:

#magnitude and angle are two np.array of shape (497, 506, 1378)

bins = [1,2,3,4,5,6,7,8,9,10,11,12]
sum = np.zeros_like(bins)

for idx in range(np.array(magnitude).shape[0]): # for each flow map, i.e. for each image pair
    for mag, ang in zip(magnitude[idx].reshape(-1), angle[idx].reshape(-1)): 
        if ang >= 0 and ang <= 30:
            sum[0] += mag
        elif ang > 30 and ang <= 60:
            sum[1] += mag
        elif ang > 60 and ang <= 90:
            sum[2] += mag
        elif ang > 90 and ang <= 120:
            sum[3] += mag
        elif ang > 120 and ang <= 150:
            sum[4] += mag
        elif ang > 150 and ang <= 180:
            sum[5] += mag
        elif ang > 180 and ang <= 210:
            sum[6] += mag
        elif ang > 210 and ang <= 240:
            sum[7] += mag
        elif ang > 240 and ang <= 270:
            sum[8] += mag
        elif ang > 270 and ang <= 300:
            sum[9] += mag
        elif ang > 300 and ang <= 330:
            sum[10] += mag
        elif ang > 330 and ang <= 360:
            sum[11] += mag

条件句的速度很慢。你应该尽量避免它们。另外,Numpy矢量化Numba-JIT有助于大大加快此类代码的速度。以下是一个未经测试的示例:

import numba as nb

@nb.jit
def compute(magnitude, angle):
    s = np.zeros(12)
    for idx in range(magnitude.shape[0]):
        for mag, ang in zip(magnitude[idx].reshape(-1), angle[idx].reshape(-1)):
            if ang == 0:
                s[0] += mag
            elif ang > 0 and ang <= 360: # The condition can be removed if always true
                s[(ang-1)//30] += mag
    return s

# Assume both are Numpy array and angle is of type int.
# Note that the first call will be slower unless you precise the types.
compute(magnitude, angle)
将numba作为nb导入
@注意:准时制
def计算(幅值、角度):
s=np.0(12)
对于范围内的idx(幅值形状[0]):
对于mag,zip中的ang(幅值[idx]。重塑(-1),角度[idx]。重塑(-1)):
如果ang==0:
s[0]+=mag

elif ang>0,ang感谢您的回答。角度不是整数,但实际上
s[(ang-1)//30]+=mag
要聪明得多。为什么从
mag
中减去1?如果你减去1,你有非常小的角度,比如
ang=0.3
,那么
(ang-1)//30)=-1
,这是错误的。我想这就是为什么你假设角度是整数。但是,如果没有
-1
,如果
ang=360
,就会出现问题,因为
(360//30)=12
(超出范围)。不管怎样,我使用了一种变通方法(见上面的编辑),现在计算不到10秒:)谢谢!我做了一个减法,因为30、60等都包括在内,而不是排除在外。实际上,
ang[30//30]==ang[1]
。ang=0.3的Yes不起作用,因为我希望值是整数。您可以将
floor
ceil
与float一起使用(可能与加法/减法一起使用,以便间隔与初始代码一样有效)。
import numba as nb

@nb.jit
def compute(magnitude, angle):
    s = np.zeros(12)
    for idx in range(magnitude.shape[0]):
        for mag, ang in zip(magnitude[idx].reshape(-1), angle[idx].reshape(-1)):
            if ang == 0:
                s[0] += mag
            elif ang > 0 and ang <= 360: # The condition can be removed if always true
                s[(ang-1)//30] += mag
    return s

# Assume both are Numpy array and angle is of type int.
# Note that the first call will be slower unless you precise the types.
compute(magnitude, angle)