Performance of the getOrientationAndMagnitude()Published 10 February 2014
I normally don’t do premature performance optimizations, and I was planning on optimizing the whole eye tracker later, when I felt I had all of the functionality I wanted, but from time to time, you still want to check your code, particularly when it’s suspiciously slow. So I did examine the code I had written so far using line_profiler (Abysmal documentation btw.) like so:
I have found that the most time is being spent in one function,
getOrientationAndMagnitude, you’ll recall it
looked like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 def getOrientationAndMagnitude(image, show=False): sobelHorizontal = cv2.Sobel(image, cv2.CV_32F, 1, 0) sobelVertical = cv2.Sobel(image, cv2.CV_32F, 0, 1) h = sobelHorizontal v = sobelVertical orientation = np.empty(image.shape) magnitude = np.empty(image.shape) height, width = h.shape for y in range(height): for x in range(width): orientation[y][x] = cv2.fastAtan2(h[y][x], v[y][x]) magnitude = cv2.magnitude(h, v) return orientation, magnitude
I wrote this code some time ago, when I was less familiar with OpenCV than I am now, and you can quickly see
the hotspot. Yes, the line
14. I probably did it like this because I hadn’t noticed the
phase() function OpenCV has.
But this will serve the purpose of showing how such a small oversight can have a dramatic effect on performance.
Armed with the
we can do the following:
1 2 3 4 5 6 7 8 def getOrientationAndMagnitude(image, show=False): h = cv2.Sobel(image, cv2.CV_32F, 1, 0) v = cv2.Sobel(image, cv2.CV_32F, 0, 1) orientation = cv2.phase(h, v, angleInDegrees=True) magnitude = cv2.magnitude(h, v) return orientation, magnitude
Now this much shorter and simpler function will also run much faster, thanks to OpenCV. And here’s how I tested it:
1 2 3 4 5 6 7 8 import cProfile image = cv2.imread('eye.png') image = cv2.cvtColor(image, cv2.cv.CV_BGR2GRAY) image2 = np.copy(image) cProfile.runctx("refGetOrientationAndMagnitude(image)", globals=globals(), locals=locals()) cProfile.runctx("newGetOrientationAndMagnitude(image)", globals=globals(), locals=locals())
Which yielded the following results:
So 1.022s to 0.004, 255× faster with just replacing a double
for loop with an OpenCV call.