I am writing an algorithm that finds the center of 500 x 500 pixels images coming from a live feed from a camera at 50 Hz. So it has to be quick! The images are images of an optical field which looks like a "flower" (example below) which is somehow circular, so it does have a true center, but since it jiggles and it rotates, I have to calculate the true center for every frame.
Here is an example of the field:
What I did so far:
Prior to the beginning of frame capture, I prepare in advance 10 matrices $M_i$ of size 600 x 600 like this:
linepoints[a_] := {{Cos[a], Sin[a]}, {Cos[a + Pi], Sin[a + Pi]}}
img[l_, k_] := Graphics[{Table[Line[linepoints[a + k*Pi/(10l)]], {a, 0, 2Pi, Pi/l}],
White, Disk[{0, 0}, .2]}, ImageSize -> {600, 600}]
M[l_, k_] := ImageData[ColorConvert[img[l, k], "Grayscale"], "Bit"]
masks = mask[l, Range[10]];
The matrices in masks
have all $2l$ lines going out from the center, and they are rotated of $\frac{2\pi}{10l}k$ from one another, so that $M(l,1)=M(l,11)$. Here's one for $l=30$ (so 60 rays):
It is important that the number of "rays" in the $M_k$ matrices matches the number of "petals" in the true image from the camera, which is not a problem, as that number is fixed from the beginning. The algorithm calculates the discrete convolution of all 10 matrices $M_k$ with a kernel $K$ (the actual frame coming from the camera, cropped at 500 x 500 around a "guessed" center), so that I end up with a tensor $T$ made of 10 matrices of size 100 x 100.
array = ImageData[image, "Real32"][[All, All, 2]] (*10 msec*)
T=ListCorrelate[array, 1 - #] & /@ masks (*about 250 msec*)
(Here image
is the image in 1, not yet a frame from the video feed.)
With Transpose[]
I turn $T$ into a 100 x 100 matrix convol
of lists of length 10, on which I run a simple visibility test:
visibility[list_]:=(Max[list]-Min[list])/(Max[list]+Min[list])
m = Map[visibility,convol,{2}]; (*10 msec*)
{x,y}=Position[m,Max[m]]; (*0.1 msec*)
Here m
is nothing else than an map of where the visibility is highest, which corresponds to the true center of the pattern. Below, the corresponding ArrayPlot[m]
and ArrayPlot[Log[m]]
for the optical field in Fig. 1.
All this is fine, except that if I use ListConvolve[]
it takes 300 milliseconds per frame, while if I use the convolution theorem with FFT it takes 150 milliseconds on my 8-core machine, and to run in real-time it should take no more than 20 milliseconds. As of now, the algorithm is an order of magnitude slower than I would like it to be.
My question is the following: I have GTX 660 Ti, with 1344 CUDA cores. Is there a way I can use it to speedup the above algorithm (or a better version of it) and have it run in real-time? Or, is there a more clever version than the algorithm above? (I'm pretty sure that I am being a very naive programmer...)
EDIT
It is very important to find the center with high precision, because then by addressing the visibility curve (the plot of the 10 points calculated at the true center) I can detect rotations of the pattern with a precision even below $\pi/10l$.
I tried CUDAImageConvolve[]
, but it gives error messages for a too large kernel... Unfortunately a kernel is too large already around 60 x 60.
Other test images:
40 petals: https://i.sstatic.net/ktps4.png
80 petals: https://i.sstatic.net/MUAAo.png
100 petals: https://i.sstatic.net/WBiZD.png
120 petals: https://i.sstatic.net/uFlBH.png
140 petals: https://i.sstatic.net/1B3P2.png
160 petals: https://i.sstatic.net/ZKyxa.png