我有一类函数‘检测器’,它在给定一段视频、一个空间尺度参数和一个时间尺度参数的情况下,检测一些兴趣点.我编写了一个‘MultiscaleDetector’函数,它基本上接受一个空间尺度参数列表和一个‘探测器’函数作为参数,并 for each 尺度执行给定的探测器系数.
下面是它们的外观:
def GaborDetector(v, sigma, tau, threshold, num_points):
"""
Gabor Detector
Keyword arguments:
video -- input video (y_len, x_len, frames)
sigma -- Gaussian kernel space standard deviation
tau -- Gaussian kernel time standard deviation
kappa -- Gabor response threshold
"""
# setup video
video = v.copy()
video = video.astype(float)/video.max()
video = video_smoothen_space(video, sigma)
# first define a linspace of width -2tau to 2tau
time = np.linspace(-2*tau, 2*tau, int(4*tau+1))
omega = 4/tau
# define the gabor filters
h_ev = np.exp(-time**2/(2*tau**2)) * np.cos(2*np.pi*omega*time)
h_od = np.exp(-time**2/(2*tau**2)) * np.sin(2*np.pi*omega*time)
# normalize the L1 norm
h_ev /= np.linalg.norm(h_ev, ord=1)
h_od /= np.linalg.norm(h_od, ord=1)
# compute the response
response = (scp.convolve1d(video, h_ev, axis=2) ** 2) + (scp.convolve1d(video, h_od, axis=2) ** 2)
points = interest_points(response, num=num_points, threshold=threshold, scale=sigma)
return points
def MultiscaleDetector(detector, video, sigmas, tau, num_points):
"""
Multiscale Detector
Executes a detector at multiple scales. Detector has to be a function that
takes a video as input, along with other parameters, and returns a list of interest points.
Keyword arguments:
detector -- function that returns interest points
video -- input video (y_len, x_len, frames)
sigmas -- list of scales
"""
# for every scale, compute the response
points = []
for sigm in sigmas:
found = detector(video, sigm, tau)
points.append(found)
# filter the points, currently irrelevant
正如您可能已经注意到的,在"GborDetector"函数内部进行了一些繁重的计算,这仅取决于时间参数.因此,"MultiscaleDetector"函数在每次调用中都不必要地重新计算这些变量.
为了避免重构代码,我想出了一个我希望是一个很好的技巧,但我认为这将是徒劳的:
def MultiscaleDetector(detector, video, sigmas, tau, num_points):
"""
Multiscale Detector
Executes a detector at multiple scales. Detector has to be a function that
takes a video as input, along with other parameters, and returns a list of interest points.
Keyword arguments:
detector -- function that returns interest points
video -- input video (y_len, x_len, frames)
sigmas -- list of scales
"""
optimization_trick = lambda s_param: detector(video, s_param, tau)
# for every scale, compute the response
points = []
for sigm in sigmas:
found = optimization_trick(sigm)
points.append(found)
# filter the points, currently irrelevant
我希望只依赖tau的变量将以某种方式"存储"在"OPTIMIZATION_TICK"中,从而避免被重新计算.然而,当我对不同的实现进行计时时,差异大约是0.02秒,"优化"函数的速度更快.
编辑:
实际发生的呼叫如下所示:
# read the video
video = read_video(video_name, num_frames, 0)
# get the interest points
detector = lambda v, s, t: GaborDetector(v, s, t, 0.3, 500)
scales = [3*(1.1)**i for i in range(6)]
start = time.time()
points = MultiscaleDetector(detector, video, scales, 1.5, 500)
end = time.time()
print("Time: {}".format(end-start))
我try 将我想要避免的所有变量放在一个不同的函数中,如下所示:
def GaborDetectorTrial(v, sigma, tau, threshold, num_points):
"""
Gabor Detector
Keyword arguments:
video -- input video (y_len, x_len, frames)
sigma -- Gaussian kernel space standard deviation
tau -- Gaussian kernel time standard deviation
kappa -- Gabor response threshold
"""
@lru_cache(maxsize=None)
def time_function(tau):
time = np.linspace(-2*tau, 2*tau, int(4*tau+1))
omega = 4/tau
# define the gabor filters
h_ev = np.exp(-time**2/(2*tau**2)) * np.cos(2*np.pi*omega*time)
h_od = np.exp(-time**2/(2*tau**2)) * np.sin(2*np.pi*omega*time)
# normalize the L1 norm
h_ev /= np.linalg.norm(h_ev, ord=1)
h_od /= np.linalg.norm(h_od, ord=1)
return h_ev, h_od
# setup video
video = v.copy()
video = video.astype(float)/video.max()
video = video_smoothen_space(video, sigma)
# compute the response
h_ev, h_od = time_function(tau)
response = (scp.convolve1d(video, h_ev, axis=2) ** 2) + (scp.convolve1d(video, h_od, axis=2) ** 2)
points = interest_points(response, num=num_points, threshold=threshold, scale=sigma)
return points
我想避免重新计算的变量是h_ev和h_od.执行时间基本相同(实际上慢了一些毫秒).