I have a category of functions 'detectors', that, given a video, a space scale parameter and a time scale parameter, detect some interest points. I wrote a 'MultiscaleDetector' function, that basically takes a list of space scale parameters and a 'detector' function as parameters and executes the given detector factor for every scale.
This is how they look:
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
As you can maybe already notice, there is some heavy computation done inside the "GaborDetector" function, that depends only on the time parameter. Therefore, the "MultiscaleDetector" function unnecessarily recomputes these variables in each call.
In an attempt to avoid refactoring the code, I came up with what I wished was a nice trick, but believed it would be vain:
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
I hoped that the variables dependent only on tau would remain "stored" somehow in the "optimization_trick" and avoid being recomputed. However, when I timed the different implementations, the difference was around 0.02 seconds, with the "optimized" function being faster.
Aucun commentaire:
Enregistrer un commentaire