QTrk
cpu_tracker.cpp
Go to the documentation of this file.
1 /*
2 
3 CPU only tracker
4 
5 */
6 
7 
8 #include "std_incl.h"
9 #include <exception>
10 #include <cmath>
11 
12 //
13 //#define QI_DBG_EXPORT
14 #define ZLUT_CMPDATA
15 
16 #pragma warning(disable: 4996) // Function call with parameters that may be unsafe
17 
18 #include "QueuedTracker.h"
19 #include "cpu_tracker.h"
20 #include "LsqQuadraticFit.h"
21 #include "random_distr.h"
22 #include "CubicBSpline.h"
23 
24 const float XCorScale = 1.0f; // keep this at 1, because linear oversampling was a bad idea..
25 
26 #include "DebugResultCompare.h"
27 
28 static int round(scalar_t f) { return (int)(f+0.5f); }
29 template<typename T>
30 T conjugate(const T &v) { return T(v.real(),-v.imag()); }
31 
35 
36 static int clamp(int v, int a,int b) { return std::max(a, std::min(b, v)); }
37 
38 
39 CPUTracker::CPUTracker(int w, int h, int xcorwindow, bool testMode)
40  : width(w), height(h), xcorw(xcorwindow), testRun(testMode)
41 {
42  trackerID = 0;
43 
44  xcorBuffer = 0;
45 
46  mean=0.0f;
47  srcImage = new float [w*h];
48  debugImage = new float [w*h];
49  std::fill(srcImage, srcImage+w*h, 0.0f);
50  std::fill(debugImage, debugImage+w*h, 0.0f);
51 
52  zluts = 0;
55 
57 
58  qi_radialsteps = 0;
60 
61  fft2d=0;
62 }
63 
65 {
66  delete[] srcImage;
67  delete[] debugImage;
68  if (zluts && zlut_memoryOwner)
69  delete[] zluts;
70 
71  if (xcorBuffer)
72  delete xcorBuffer;
73 
74  if (qi_fft_forward) {
75  delete qi_fft_forward;
76  delete qi_fft_backward;
77  }
78 
79  if (qa_fft_backward) {
80  delete qa_fft_backward;
81  delete qa_fft_forward;
82  }
83 
84  if (fft2d)
85  delete fft2d;
86 }
87 
88 void CPUTracker::SetImageFloat(float *src)
89 {
90  for (int k=0;k<width*height;k++)
91  srcImage[k]=src[k];
92  mean=0.0f;
93 }
94 
95 void CPUTracker::ApplyOffsetGain(float* offset, float *gain, float offsetFactor, float gainFactor)
96 {
97  if (offset && !gain) {
98  for (int i=0;i<width*height;i++)
99  srcImage[i] = srcImage[i]+offset[i]*offsetFactor;
100  }
101  if (gain && !offset) {
102  for (int i=0;i<width*height;i++)
103  srcImage[i] = srcImage[i]*gain[i]*gainFactor;
104  }
105  if (gain && offset) {
106  for (int i=0;i<width*height;i++)
107  srcImage[i] = (srcImage[i]+offset[i]*offsetFactor)*gain[i]*gainFactor;
108  }
109 }
110 
111 
112 #ifdef _DEBUG
113 
114 inline void markPixel(float* img, int x,int y, int w,int h, float maxv) {
115  if (x>=0 && y>=0 && x < w && y<h)
116  img[y*w+x]+=maxv*0.1f;
117 }
118 
119 inline void _markPixels(float x,float y, float* img, int w, int h, float mv)
120 {
121  int rx=(int)x, ry=(int)y;
122  if (rx >=0 && ry >= 0 && rx+1<w && ry+1<h) {
123  img[ry*w+rx] += mv;
124  img[ry*w+rx+1] += mv;
125  img[(ry+1)*w+rx] += mv;
126  img[(ry+1)*w+rx+1] += mv;
127  }
128 }
129  #define MARKPIXEL(x,y) markPixel(debugImage, (x),(y),width,height,maxImageValue)
130  #define MARKPIXELI(x,y) _markPixels(x,y,debugImage, width, height, maxImageValue*0.1f);
131 #else
132  #define MARKPIXEL(x,y)
133  #define MARKPIXELI(x,y)
134 #endif
135 
136 
137 
139 {
140  complex_t* fft_out = (complex_t*)ALLOCA(sizeof(complex_t)*xcorw);
141  complex_t* fft_out_rev = (complex_t*)ALLOCA(sizeof(complex_t)*xcorw);
142 
143  fft_forward.transform(prof, fft_out);
144  fft_forward.transform(prof_rev, fft_out_rev);
145 
146  // Multiply with conjugate of reverse
147  for (int x=0;x<xcorw;x++) {
148  fft_out[x] *= conjugate(fft_out_rev[x]);
149  }
150 
151  fft_backward.transform(fft_out, fft_out_rev);
152 
153  for (int x=0;x<xcorw;x++)
154  result[x] = fft_out_rev[ (x+xcorw/2) % xcorw ].real();
155 }
156 
157 bool CPUTracker::CheckBoundaries(vector2f center, float radius)
158 {
159  return center.x + radius >= width ||
160  center.x - radius < 0 ||
161  center.y + radius >= height ||
162  center.y - radius < 0;
163 }
164 
165 vector2f CPUTracker::ComputeXCorInterpolated(vector2f initial, int iterations, int profileWidth, bool& boundaryHit)
166 {
167  // extract the image
168  vector2f pos = initial;
169 
170  if (!xcorBuffer)
172 
173  if (xcorw < profileWidth)
174  profileWidth = xcorw;
175 
176 #ifdef _DEBUG
177  std::copy(srcImage, srcImage+width*height, debugImage);
178  maxImageValue = *std::max_element(srcImage,srcImage+width*height);
179 #endif
180 
181  if (xcorw > width || xcorw > height) {
182  boundaryHit = true;
183  return initial;
184  }
185 
186  complex_t* prof = (complex_t*)ALLOCA(sizeof(complex_t)*xcorw);
187  complex_t* prof_rev = (complex_t*)ALLOCA(sizeof(complex_t)*xcorw);
188  scalar_t* prof_autocor = (scalar_t*)ALLOCA(sizeof(scalar_t)*xcorw);
189 
190  boundaryHit = false;
191  for (int k=0;k<iterations;k++) {
192  boundaryHit = CheckBoundaries(pos, XCorScale*xcorw/2);
193 
194  float xmin = pos.x - XCorScale * xcorw/2;
195  float ymin = pos.y - XCorScale * xcorw/2;
196 
197  // generate X position xcor array (summing over y range)
198  for (int x=0;x<xcorw;x++) {
199  scalar_t s = 0.0f;
200  int n=0;
201  for (int y=0;y<profileWidth;y++) {
202  scalar_t xp = x * XCorScale + xmin;
203  scalar_t yp = pos.y + XCorScale * (y - profileWidth/2);
204  bool outside;
205  s += Interpolate(srcImage, width, height, xp, yp, &outside);
206  n += outside?0:1;
207  MARKPIXELI(xp, yp);
208  }
209  if (n >0) s/=n;
210  else s=0;
211  prof [x] = s;
212  prof_rev [xcorw-x-1] = s;
213  }
214 
215  xcorBuffer->XCorFFTHelper(prof, prof_rev, prof_autocor);
216  scalar_t offsetX = ComputeMaxInterp<scalar_t,QI_LSQFIT_NWEIGHTS>::Compute(prof_autocor, xcorw, QIWeights) - (scalar_t)xcorw/2;
217 
218  // generate Y position xcor array (summing over x range)
219  for (int y=0;y<xcorw;y++) {
220  scalar_t s = 0.0f;
221  int n=0;
222  for (int x=0;x<profileWidth;x++) {
223  scalar_t xp = pos.x + XCorScale * (x - profileWidth/2);
224  scalar_t yp = y * XCorScale + ymin;
225  bool outside;
226  s += Interpolate(srcImage,width,height, xp, yp, &outside);
227  n += outside?0:1;
228  MARKPIXELI(xp,yp);
229  }
230  if (n >0) s/=n;
231  else s=0;
232  prof[y] = s;
233  prof_rev [xcorw-y-1] =s;
234  }
235 
236  xcorBuffer->XCorFFTHelper(prof,prof_rev, prof_autocor);
237  //WriteImageAsCSV("xcorautoconv.txt",&xcorBuffer->Y_result[0],xcorBuffer->Y_result.size(),1);
238  scalar_t offsetY = ComputeMaxInterp<scalar_t, QI_LSQFIT_NWEIGHTS>::Compute(prof_autocor, xcorw, QIWeights) - (scalar_t)xcorw/2;
239 
240  pos.x += (offsetX - 1) * XCorScale * 0.5f;
241  pos.y += (offsetY - 1) * XCorScale * 0.5f;
242  }
243 
244  return pos;
245 }
246 
248 {
249  if(!qi_fft_forward || qi_radialsteps != nr) {
250  if(qi_fft_forward) {
251  delete qi_fft_forward;
252  delete qi_fft_backward;
253  }
254  qi_radialsteps = nr;
255  qi_fft_forward = new kissfft<scalar_t>(nr*2,false);
256  qi_fft_backward = new kissfft<scalar_t>(nr*2,true);
257  }
258 }
259 
260 vector2f CPUTracker::ComputeQI(vector2f initial, int iterations, int radialSteps, int angularStepsPerQ,
261  float angStepIterationFactor, float minRadius, float maxRadius, bool& boundaryHit, float* radialWeights)
262 {
263  int nr=radialSteps;
264 #ifdef _DEBUG
265  std::copy(srcImage, srcImage+width*height, debugImage);
266  maxImageValue = *std::max_element(srcImage,srcImage+width*height);
267 #endif
268 
269  if (angularStepsPerQ != quadrantDirs.size()) {
270  quadrantDirs.resize(angularStepsPerQ);
271  for (int j=0;j<angularStepsPerQ;j++) {
272  float ang = 0.5*3.141593f*(j+0.5f)/(float)angularStepsPerQ;
273  quadrantDirs[j] = vector2f( cosf(ang), sinf(ang) );
274  }
275  }
276 
277  AllocateQIFFTs(radialSteps);
278 
279  scalar_t* buf = (scalar_t*)ALLOCA(sizeof(scalar_t)*nr*4);
280  scalar_t* q0=buf, *q1=buf+nr, *q2=buf+nr*2, *q3=buf+nr*3;
281  complex_t* concat0 = (complex_t*)ALLOCA(sizeof(complex_t)*nr*2);
282  complex_t* concat1 = concat0 + nr;
283 
284  vector2f center = initial;
285 
286  float pixelsPerProfLen = (maxRadius-minRadius)/radialSteps;
287  boundaryHit = false;
288 
289  float angsteps = angularStepsPerQ / powf(angStepIterationFactor, iterations);
290 
291  for (int k=0;k<iterations;k++){
292  // check bounds
293  boundaryHit = CheckBoundaries(center, maxRadius);
294 
295  for (int q=0;q<4;q++) {
296  ComputeQuadrantProfile(buf+q*nr, nr, angsteps, q, minRadius, maxRadius, center, radialWeights);
297  //NormalizeRadialProfile(buf+q*nr, nr);
298  }
299 #ifdef QI_DEBUG
300  cmp_cpu_qi_prof.assign (buf,buf+4*nr);
301 #endif
302 
303  // Build Ix = [ qL(-r) qR(r) ]
304  // qL = q1 + q2 (concat0)
305  // qR = q0 + q3 (concat1)
306  for(int r=0;r<nr;r++) {
307  concat0[nr-r-1] = q1[r]+q2[r];
308  concat1[r] = q0[r]+q3[r];
309  }
310 
311  scalar_t offsetX = QI_ComputeOffset(concat0, nr, 0);
312 
313  // Build Iy = [ qB(-r) qT(r) ]
314  // qT = q0 + q1
315  // qB = q2 + q3
316  for(int r=0;r<nr;r++) {
317  concat1[r] = q0[r]+q1[r];
318  concat0[nr-r-1] = q2[r]+q3[r];
319  }
320 
321  scalar_t offsetY = QI_ComputeOffset(concat0, nr, 1);
322 
323 #ifdef QI_DBG_EXPORT
324  std::copy(concat0, concat0+nr*2,tmp.begin()+nr*2);
325  WriteComplexImageAsCSV("cpuprofxy.txt", &tmp[0], nr, 4);
326  dbgprintf("[%d] OffsetX: %f, OffsetY: %f\n", k, offsetX, offsetY);
327 #endif
328 
329  center.x += offsetX * pixelsPerProfLen;
330  center.y += offsetY * pixelsPerProfLen;
331 
332  angsteps *= angStepIterationFactor;
333  }
334 
335  return center;
336 }
337 
338 
339 template<typename T>
340 double sum_diff(T* begin, T* end, T* other)
341 {
342  double sd = 0.0;
343  for (T* i = begin; i != end; i++, other++) {
344  T d = *i - *other;
345  sd += abs(d.real()) + abs(d.imag());
346  }
347  return sd;
348 }
349 
350 // Profile is complex_t[nr*2]
351 scalar_t CPUTracker::QI_ComputeOffset(complex_t* profile, int nr, int axisForDebug)
352 {
353  complex_t* reverse = ALLOCA_ARRAY(complex_t, nr*2);
354  complex_t* fft_out = ALLOCA_ARRAY(complex_t, nr*2);
355  complex_t* fft_out2 = ALLOCA_ARRAY(complex_t, nr*2);
356 
357  for(int x=0;x<nr*2;x++)
358  reverse[x] = profile[nr*2-1-x];
359 
360  qi_fft_forward->transform(profile, fft_out);
361  qi_fft_forward->transform(reverse, fft_out2); // fft_out2 contains fourier-domain version of reverse profile
362 
363  // multiply with conjugate
364  for(int x=0;x<nr*2;x++)
365  fft_out[x] *= conjugate(fft_out2[x]);
366 
367  qi_fft_backward->transform(fft_out, fft_out2);
368 
369 #ifdef QI_DEBUG
370  cmp_cpu_qi_fft_out.assign(fft_out2, fft_out2+nr*2);
371 #endif
372 
373  // fft_out2 now contains the autoconvolution
374  // convert it to float
375  scalar_t* autoconv = ALLOCA_ARRAY(scalar_t, nr*2);
376  for(int x=0;x<nr*2;x++) {
377  autoconv[x] = fft_out2[(x+nr)%(nr*2)].real();
378  }
379 
380  float* profileReal = ALLOCA_ARRAY(float, nr*2);
381  for(int x=0;x<nr*2;x++) {
382  profileReal[x] = profile[x].real();
383  }
384  //WriteArrayAsCSVRow(SPrintf("D:\\TestImages\\AutoconvProf-%d.txt",axisForDebug).c_str() ,profileReal,nr*2,false);
385  //WriteArrayAsCSVRow(SPrintf("D:\\TestImages\\Autoconv-%d.txt",axisForDebug).c_str() ,autoconv,nr*2,false); // */
386 
388  return (maxPos - nr) * (3.14159265359f / 4);
389 }
390 
391 
392 // Profile is complex_t[nr*2]
393 scalar_t CPUTracker::QuadrantAlign_ComputeOffset(complex_t* profile, complex_t* zlut_prof_fft, int nr, int axisForDebug)
394 {
395  complex_t* fft_out = ALLOCA_ARRAY(complex_t, nr*2);
396 
397 // WriteComplexImageAsCSV("qa_profile.txt", profile, nr*2, 1);
398 
399  qa_fft_forward->transform(profile, fft_out);
400 
401  // multiply with conjugate
402  for(int x=0;x<nr*2;x++)
403  fft_out[x] *= conjugate(zlut_prof_fft[x]);
404 
405  qa_fft_backward->transform(fft_out, profile);
406 
407 #ifdef QI_DEBUG
408  cmp_cpu_qi_fft_out.assign(fft_out2, fft_out2+nr*2);
409 #endif
410 
411  // profile now contains the autoconvolution
412  // convert it to float
413  scalar_t* autoconv = ALLOCA_ARRAY(scalar_t, nr*2);
414  for(int x=0;x<nr*2;x++) {
415  autoconv[x] = profile[(x+nr)%(nr*2)].real();
416  }
417 
418 // WriteImageAsCSV("qa_autoconv.txt", autoconv, nr*2, 1);
419 
421  return (maxPos - nr) * (3.14159265359f / 4);
422 
423 }
424 
425 
426 /*
427 
428 - Compute quadrants
429 - Build interpolated profile from ZLUT
430 - Align X & Y against profile with FFT
431 
432 Difference with QI: No mirroring of profile, instead of mirror we use ZLUT profile
433 
434 */
435 vector3f CPUTracker::QuadrantAlign(vector3f pos, int beadIndex, int angularStepsPerQuadrant, bool& boundaryHit)
436 {
437  float* zlut = GetRadialZLUT(beadIndex);
438  int res=zlut_res;
439  complex_t* profile = ALLOCA_ARRAY(complex_t, res*2);
440  complex_t* concat0 = ALLOCA_ARRAY(complex_t, res*2);
441  complex_t* concat1 = concat0 + res;
442 
443  memset(concat0, 0, sizeof(complex_t)*res*2);
444 
445  int zp0 = clamp( (int)pos.z, 0, zlut_planes - 1);
446  int zp1 = clamp( (int)pos.z + 1, 0, zlut_planes - 1);
447 
448  float* zlut0 = &zlut[ res * zp0 ];
449  float* zlut1 = &zlut[ res * zp1 ];
450  float frac = pos.z - (int)pos.z;
451  for (int r=0;r<zlut_res;r++) {
452  // Interpolate plane
453  double zlutValue = Lerp(zlut0[r], zlut1[r], frac);
454  concat0[res-r-1] = concat1[r] = zlutValue;
455  }
456 // WriteComplexImageAsCSV("qa_zlutprof.txt", concat0, res,2);
457  qa_fft_forward->transform(concat0, profile);
458 
459  scalar_t* buf = ALLOCA_ARRAY(scalar_t, res*4);
460  scalar_t* q0=buf, *q1=buf+res, *q2=buf+res*2, *q3=buf+res*3;
461 
462  boundaryHit = CheckBoundaries(vector2f(pos.x,pos.y), zlut_maxradius);
463  for (int q=0;q<4;q++) {
464  scalar_t *quadrantProfile = buf+q*res;
465  ComputeQuadrantProfile(quadrantProfile, res, angularStepsPerQuadrant, q, zlut_minradius, zlut_maxradius, vector2f(pos.x,pos.y));
466  NormalizeRadialProfile(quadrantProfile, res);
467  }
468 
469  //WriteImageAsCSV("qa_qdr.txt" , buf, res,4);
470 
471  float pixelsPerProfLen = (zlut_maxradius-zlut_minradius)/zlut_res;
472  boundaryHit = false;
473 
474  // Build Ix = [ qL(-r) qR(r) ]
475  // qL = q1 + q2 (concat0)
476  // qR = q0 + q3 (concat1)
477  for(int r=0;r<res;r++) {
478  concat0[res-r-1] = q1[r]+q2[r];
479  concat1[r] = q0[r]+q3[r];
480  }
481 
482  scalar_t offsetX = QuadrantAlign_ComputeOffset(concat0, profile, res, 0);
483 
484  // Build Iy = [ qB(-r) qT(r) ]
485  // qT = q0 + q1
486  // qB = q2 + q3
487  for(int r=0;r<res;r++) {
488  concat1[r] = q0[r]+q1[r];
489  concat0[res-r-1] = q2[r]+q3[r];
490  }
491 
492  scalar_t offsetY = QuadrantAlign_ComputeOffset(concat0, profile, res, 1);
493 
494  return vector3f(pos.x + offsetX * pixelsPerProfLen, pos.y + offsetY * pixelsPerProfLen, pos.z);
495 }
496 
498 {
499  vector2f pos = initial;
500  float I0 = mean*0.5f*width*height;
501  float bg = mean*0.5f;
502 
503  const float _1oSq2Sigma = 1.0f / (sqrtf(2) * sigma);
504  const float _1oSq2PiSigma = 1.0f / (sqrtf(2*3.14159265359f) * sigma);
505  const float _1oSq2PiSigma3 = 1.0f / (sqrtf(2*3.14159265359f) * sigma*sigma*sigma);
506 
507  for (int i=0;i<iterations;i++)
508  {
509  double dL_dx = 0.0;
510  double dL_dy = 0.0;
511  double dL_dI0 = 0.0;
512  double dL_dIbg = 0.0;
513  double dL2_dx = 0.0;
514  double dL2_dy = 0.0;
515  double dL2_dI0 = 0.0;
516  double dL2_dIbg = 0.0;
517 
518  double mu_sum = 0.0;
519 
520  for (int y=0;y<height;y++)
521  {
522  for (int x=0;x<width;x++)
523  {
524  float Xexp0 = (x-pos.x + .5f) * _1oSq2Sigma;
525  float Yexp0 = (y-pos.y + .5f) * _1oSq2Sigma;
526 
527  float Xexp1 = (x-pos.x - .5f) * _1oSq2Sigma;
528  float Yexp1 = (y-pos.y - .5f) * _1oSq2Sigma;
529 
530  float DeltaX = 0.5f * erf(Xexp0) - 0.5f * erf(Xexp1);
531  float DeltaY = 0.5f * erf(Yexp0) - 0.5f * erf(Yexp1);
532  float mu = bg + I0 * DeltaX * DeltaY;
533 
534  float dmu_dx = I0*_1oSq2PiSigma * ( expf(-Xexp1*Xexp1) - expf(-Xexp0*Xexp0)) * DeltaY;
535 
536  float dmu_dy = I0*_1oSq2PiSigma * ( expf(-Yexp1*Yexp1) - expf(-Yexp0*Yexp0)) * DeltaX;
537  float dmu_dI0 = DeltaX*DeltaY;
538  float dmu_dIbg = 1;
539 
540  float smp = GetPixel(x,y);
541  float f = smp / mu - 1;
542  dL_dx += dmu_dx * f;
543  dL_dy += dmu_dy * f;
544  dL_dI0 += dmu_dI0 * f;
545  dL_dIbg += dmu_dIbg * f;
546 
547  float d2mu_dx = I0*_1oSq2PiSigma3 * ( (x - pos.x - .5f) * expf (-Xexp1*Xexp1) - (x - pos.x + .5f) * expf(-Xexp0*Xexp0) ) * DeltaY;
548  float d2mu_dy = I0*_1oSq2PiSigma3 * ( (y - pos.y - .5f) * expf (-Yexp1*Yexp1) - (y - pos.y + .5f) * expf(-Yexp0*Yexp0) ) * DeltaX;
549  dL2_dx += d2mu_dx * f - dmu_dx*dmu_dx * smp / (mu*mu);
550  dL2_dy += d2mu_dy * f - dmu_dy*dmu_dy * smp / (mu*mu);
551  dL2_dI0 += -dmu_dI0*dmu_dI0 * smp / (mu*mu);
552  dL2_dIbg += -smp / (mu*mu);
553 
554  mu_sum += mu;
555  }
556  }
557 
558  double mean_mu = mu_sum / (width*height);
559 
560  pos.x -= dL_dx / dL2_dx;
561  pos.y -= dL_dy / dL2_dy;
562  I0 -= dL_dI0 / dL2_dI0;
563  bg -= dL_dIbg / dL2_dIbg;
564  }
565 
566  Gauss2DResult r;
567  r.pos = pos;
568  r.I0 = I0;
569  r.bg = bg;
570 
571  return r;
572 }
573 
574 
575 float CPUTracker::ComputeAsymmetry(vector2f center, int radialSteps, int angularSteps,
576  float minRadius, float maxRadius, float *dstAngProf)
577 {
578  vector2f* radialDirs = (vector2f*)ALLOCA(sizeof(vector2f)*angularSteps);
579  for (int j=0;j<angularSteps;j++) {
580  float ang = 2*3.141593f*j/(float)angularSteps;
581  radialDirs[j] = vector2f (cosf(ang), sinf(ang));
582  }
583 
584  // profile along single radial direction
585  float* rline = (float*)ALLOCA(sizeof(float)*radialSteps);
586 
587  if (!dstAngProf)
588  dstAngProf = (float*)ALLOCA(sizeof(float)*radialSteps);
589 
590  float rstep = (maxRadius-minRadius) / radialSteps;
591 
592  for (int a=0;a<angularSteps;a++) {
593  // fill rline
594  // angularProfile[a] = rline COM
595 
596  float r = minRadius;
597  for (int i=0;i<radialSteps;i++) {
598  float x = center.x + radialDirs[a].x * r;
599  float y = center.y + radialDirs[a].y * r;
600  rline[i] = Interpolate(srcImage,width,height, x,y);
601  r += rstep;
602  }
603 
604  // Compute rline COM
605  dstAngProf[a] = ComputeBgCorrectedCOM1D(rline, radialSteps, 1.0f);
606  }
607 
608  float stdev = ComputeStdDev(dstAngProf, angularSteps);
609  return stdev;
610 }
611 
612 
613 void CPUTracker::ComputeQuadrantProfile(scalar_t* dst, int radialSteps, int angularSteps,
614  int quadrant, float minRadius, float maxRadius, vector2f center ,float* radialWeights)
615 {
616  const int qmat[] = {
617  1, 1,
618  -1, 1,
619  -1, -1,
620  1, -1 };
621  int mx = qmat[2*quadrant+0];
622  int my = qmat[2*quadrant+1];
623 
624  if (angularSteps < MIN_RADPROFILE_SMP_COUNT)
625  angularSteps = MIN_RADPROFILE_SMP_COUNT;
626 
627  for (int i=0;i<radialSteps;i++)
628  dst[i]=0.0f;
629 
630  scalar_t total = 0.0f;
631  scalar_t rstep = (maxRadius - minRadius) / radialSteps;
632  for (int i=0;i<radialSteps; i++) {
633  scalar_t sum = 0.0f;
634  scalar_t r = minRadius + rstep * i;
635 
636  int nPixels = 0;
637  scalar_t angstepf = (scalar_t) quadrantDirs.size() / angularSteps;
638  for (int a=0;a<angularSteps;a++) {
639  int i = (int)angstepf * a;
640  scalar_t x = center.x + mx*quadrantDirs[i].x * r;
641  scalar_t y = center.y + my*quadrantDirs[i].y * r;
642 
643  bool outside;
644  scalar_t v = Interpolate(srcImage,width,height, x,y, &outside);
645  if (!outside) {
646  sum += v;
647  nPixels++;
648  MARKPIXELI(x,y);
649  }
650  }
651 
652  dst[i] = nPixels>=MIN_RADPROFILE_SMP_COUNT ? sum/nPixels : mean;
653  if (radialWeights) dst[i] *= radialWeights[i];
654  total += dst[i];
655  }
656 
657  //WriteImageAsCSV(SPrintf("D:\\TestImages\\qprof%d.txt", quadrant).c_str(), dst, 1, radialSteps);
658  //WriteArrayAsCSVRow("D:\\TestImages\\radialWeights.csv",radialWeights,radialSteps,false);
659 }
660 
662 {
663  double sum=0, sum2=0;
664  double momentX=0;
665  double momentY=0;
666  // Order is important
667  //COM: x:53.959133, y:53.958984
668  //COM: x:53.958984, y:53.959133
669 
670  for (int y=0;y<height;y++) {
671  for (int x=0;x<width;x++) {
672  float v = GetPixel(x,y);
673  sum += v;
674  sum2 += v*v;
675  }
676  }
677 
678  float invN = 1.0f/(width*height);
679  mean = sum * invN;
680  stdev = sqrtf(sum2 * invN - mean * mean);
681  sum = 0.0f;
682 
683  /*float *ymom = ALLOCA_ARRAY(float, width);
684  float *xmom = ALLOCA_ARRAY(float, height);
685 
686  for(int x=0;x<width;x++)
687  ymom[x]=0;
688  for(int y=0;y<height;y++)
689  xmom[y]=0;*/
690 
691  // Comments: Gaussian mask not currently used
692  //vector2f centre = vector2f((float)width/2,(float)height/2);
693  //float sigma = (float)width/4; // Suppress to 5% at edges
694  //float devi = 1/(2*sigma*sigma);
695 
696  for(int x=0;x<width;x++) {
697  for (int y=0;y<height;y++) {
698  float v = GetPixel(x,y);
699 
700  //float xabs = (x-centre.x); float yabs = (y-centre.y);
701  //float gaussfact = 1.0f;//expf(- xabs*xabs*devi - yabs*yabs*devi);
702 
703  v = std::max(0.0f, fabs(v-mean)-bgcorrection*stdev);
704  sum += v;
705  // xmom[y] += x*v;
706  // ymom[x] += y*v;
707  momentX += x*(double)v;
708  momentY += y*(double)v;
709  }
710  }
711 
712  vector2f com;
713  com.x = (float)( momentX / sum );
714  com.y = (float)( momentY / sum );
715  return com;
716 }
717 
718 
719 void CPUTracker::Normalize(float* d)
720 {
721  if (!d) d=srcImage;
722  normalize(d, width, height);
723 }
724 
725 
726 
727 void CPUTracker::ComputeRadialProfile(float* dst, int radialSteps, int angularSteps, float minradius, float maxradius, vector2f center, bool crp, bool* pBoundaryHit, bool normalize)
728 {
729  bool boundaryHit = CheckBoundaries(center, maxradius);
730  if (pBoundaryHit) *pBoundaryHit = boundaryHit;
731 
732  ImageData imgData (srcImage, width,height);
733  if (crp) {
734  ComputeCRP(dst, radialSteps, angularSteps, minradius, maxradius, center, &imgData, mean);
735  }
736  else {
737  ::ComputeRadialProfile(dst, radialSteps, angularSteps, minradius, maxradius, center, &imgData, mean, normalize);
738  }
739 }
740 
741 void CPUTracker::SetRadialZLUT(float* data, int planes, int res, int numLUTs, float minradius, float maxradius, bool copyMemory, bool useCorrelation)
742 {
743  if (zluts && zlut_memoryOwner)
744  delete[] zluts;
745 
746  if (copyMemory) {
747  zluts = new float[planes*res*numLUTs];
748  std::copy(data, data+(planes*res*numLUTs), zluts);
749  } else
750  zluts = data;
751  zlut_memoryOwner = copyMemory;
752  zlut_planes = planes;
753  zlut_res = res;
754  zlut_count = numLUTs;
755  zlut_minradius = minradius;
756  zlut_maxradius = maxradius;
757 
758  if (qa_fft_backward) {
759  delete qa_fft_backward;
760  delete qa_fft_forward;
761  }
762 
763  qa_fft_forward = new kissfft<scalar_t>(res*2,false);
764  qa_fft_backward = new kissfft<scalar_t>(res*2,true);
765 }
766 
767 void CPUTracker::SetRadialWeights(float* radweights)
768 {
769  if (radweights) {
771  std::copy(radweights, radweights+zlut_res, zlut_radialweights.begin());
772  } else
773  zlut_radialweights.clear();
774 }
775 
776 void CPUTracker::CalculateErrorCurve(double* errorcurve_dest, float* profile, float* zlut_sel)
777 {
778 #if 0
779  float* zlut_norm = ALLOCA_ARRAY(float, zlut_res);
780  float* prof_norm = ALLOCA_ARRAY(float, zlut_res);
781  for (int r=0;r<zlut_res;r++)
782  prof_norm[r] = rprof[r] * zlut_radialweights[r];
783  NormalizeRadialProfile(prof_norm, zlut_res);
784 
785  for (int k=0;k<zlut_planes;k++) {
786  double diffsum = 0.0f;
787 
788  if (zlut_radialweights.empty()) {
789  for (int r=0;r<zlut_res;r++) zlut_norm[r]=zlut_sel[k*zlut_res+r];
790  } else {
791  for (int r=0;r<zlut_res;r++) {
792  zlut_norm[r] = zlut_sel[k*zlut_res+r] * zlut_radialweights[r];
793  }
794  }
795  NormalizeRadialProfile(zlut_norm, zlut_res);
796 
797  for (int r = 0; r<zlut_res;r++) {
798  double d = prof_norm[r]-zlut_norm[r];
799  d = -d*d;
800  diffsum += d;
801  }
802  rprof_diff[k] = diffsum;
803  }
804 #else
805  for (int k=0;k<zlut_planes;k++) {
806  double diffsum = 0.0f;
807  for (int r = 0; r<zlut_res;r++) {
808  double d = profile[r]-zlut_sel[k*zlut_res+r];
809  if (!zlut_radialweights.empty())
810  d*=zlut_radialweights[r];
811  d = -d*d;
812  diffsum += d;
813  }
814  errorcurve_dest[k] = diffsum;
815  }
816 #endif
817 }
818 
819 void CPUTracker::CalculateInterpolatedZLUTProfile(float* profile_dest, float z, int zlutIndex)
820 {
821  float* zlut_sel = GetRadialZLUT(zlutIndex);
822  for (int r = 0; r<zlut_res;r++) {
823  if ( z < 0 )
824  profile_dest[r] = 0;
825  else if( ((int)z+1) < zlut_planes ) // Index out of bounds if z > LUT resolution
826  profile_dest[r] = Lerp(zlut_sel[(int)z*zlut_res+r],zlut_sel[((int)z+1)*zlut_res+r],z-(int)z);
827  else
828  profile_dest[r] = zlut_sel[(zlut_planes-1)*zlut_res+r];
829  }
830  NormalizeRadialProfile(profile_dest,zlut_res);
831 }
832 
833 float CPUTracker::CalculateErrorFlag(double* prof1, double* prof2)
834 {
835  // sum(abs(expectedCurve-errorCurve))/size(errorCurve,2)
836  float flag = 0.0f;
837  for(int ii = 0; ii < zlut_res; ii++){
838  flag += std::abs(prof1[ii]-prof2[ii]);
839  }
840  return flag/zlut_res;
841 }
842 
843 float CPUTracker::LUTProfileCompare (float* rprof, int zlutIndex, float* cmpProf, LUTProfileMaxComputeMode maxPosComputeMode, float* fitcurve, int *maxPos, int frameNum)
844 {
845  /* From this function save:
846  - Frame number?
847 
848  - Original image
849  - Profile
850  - LUT
851  - Error curve
852  - Final value
853  */
854 
855  bool freeMem = false;
856  std::string outputName;
857  float zOffset;
858 
859  if(testRun){
860  outputName = SPrintf("%s%05d-%05d",GetCurrentOutputPath().c_str(),zlutIndex,frameNum);
861 
862  if (FILE *file = fopen(SPrintf("%s.jpg",outputName.c_str()).c_str(), "r")) {
863  fclose(file);
864  printf("File exists\n");
865  }
866  SaveImage(SPrintf("%s.jpg",outputName.c_str()).c_str());
867  //FloatToJPEGFile(SPrintf("%s-prof.jpg",outputName.c_str()).c_str(), rprof, zlut_res, 1);
868  WriteArrayAsCSVRow(SPrintf("%s-prof.txt",outputName.c_str()).c_str(), rprof, zlut_res, 0);
869 
870  if(!fitcurve){
871  fitcurve = new float[zlut_planes];
872  freeMem = true;
873  }
874 
875  /*
876  For testing, we want to introduce a fixed height offset of xx nm, regardless of amount of zlut planes
877  Z is in zlut planes here, so calculate back
878 
879  int numImgInStack = 1218;
880  int numPositions = 1001; // ~10nm/frame
881  float range = 10.0f; // total range 25.0 um -> 35.0 um
882  float umPerImg = range/numImgInStack; //
883 
884  int zplanes = 50;
885  int startFrame = 400;
886  */
887  float range = 10.0f; // total range 25.0 um -> 35.0 um
888  int numImgInStack = 1218;
889  float umPerImg = range/numImgInStack;
890  int startFrame = 400;
891  int usedFrames = numImgInStack-startFrame;
892  float rangeInLUT = usedFrames*umPerImg; // Total um of LUT range
893  float umPerPlane = rangeInLUT/zlut_planes;
894 
895  float error = 0.000f; // Forced error in um
896  zOffset = error/umPerPlane; // um * planes / um
897  }
898 
899  if (!zluts)
900  return 0.0f;
901 
902  double* rprof_diff = ALLOCA_ARRAY(double, zlut_planes);
903  //WriteImageAsCSV("zlutradprof-cpu.txt", rprof, zlut_res, 1);
904 
905  // Now compare the radial profile to the profiles stored in Z
906  float* zlut_sel = GetRadialZLUT(zlutIndex);
907 
908  if(testRun){
909  FloatToJPEGFile(SPrintf("%s-zlut.jpg",outputName.c_str()).c_str(),zlut_sel,zlut_res,zlut_planes);
910  }
911 
912  CalculateErrorCurve(rprof_diff, rprof, zlut_sel);
913 
914  if (cmpProf) {
915  //cmpProf->resize(zlut_planes);
916  std::copy(rprof_diff, rprof_diff+zlut_planes, cmpProf);
917  }
918 
919  if (maxPosComputeMode == LUTProfMaxQuadraticFit) {
920  if (maxPos) {
921  *maxPos = std::max_element(rprof_diff, rprof_diff+zlut_planes) - rprof_diff;
922  }
923 
924  if (fitcurve) {
927 
928  int iMax = std::max_element(rprof_diff, rprof_diff+zlut_planes) - rprof_diff;
929  for (int i=0;i<zlut_planes;i++)
930  fitcurve[i] = fit.compute(i-iMax);
931 
932  if(testRun) {
933  z += zOffset; // For testing purposes
934 
935  // Calculate errorcurve of found ZLUT plane
936  float* int_prof = ALLOCA_ARRAY(float, zlut_res);
937  CalculateInterpolatedZLUTProfile(int_prof, z, zlutIndex);
938 
939  double* plane_auto_diff = ALLOCA_ARRAY(double, zlut_planes);
940  CalculateErrorCurve(plane_auto_diff, int_prof, zlut_sel);
941  /*for (int k=0;k<zlut_planes;k++) {
942  double diffsum = 0.0f;
943  for (int r = 0; r<zlut_res;r++) {
944  double d = int_prof[r] - zlut_sel[k*zlut_res+r];
945  if (!zlut_radialweights.empty())
946  d*=zlut_radialweights[r];
947  d = -d*d;
948  diffsum += d;
949  }
950  plane_auto_diff[k] = diffsum;
951  }*/
952 
953  //float errorFlag = CalculateErrorFlag(rprof_diff, plane_auto_diff);
954 
955  WriteArrayAsCSVRow(SPrintf("%s-int-prof.txt",outputName.c_str()).c_str(), int_prof, zlut_res, 0);
956 
957  FILE* f = fopen(SPrintf("%s-out.txt",outputName.c_str()).c_str(),"w+");
958  fprintf_s(f,"z: %f\n",z);
959  for (int i=0;i<zlut_planes;i++)
960  fprintf_s(f,"%f\t%f\t%f\t%f\t%f\n",rprof_diff[i],fitcurve[i],plane_auto_diff[i],fit.a,fit.vertexForm());
961  fclose(f);
962 
963  if(freeMem)
964  delete[] fitcurve;
965  }
966 
967  return z;
968  } else {
970  }
971  }
972  else if (maxPosComputeMode == LUTProfMaxSimpleInterp) {
973  assert(0);
974  return 0;
975  } else
976  return ComputeSplineFitMaxPos(rprof_diff, zlut_planes);
977 }
978 
979 float CPUTracker::LUTProfileCompareAdjustedWeights(float* rprof, int zlutIndex, float z_estim)
980 {
981  if (!zluts)
982  return 0.0f;
983 
984  double* rprof_diff = ALLOCA_ARRAY(double, zlut_planes);
985 
986  // Now compare the radial profile to the profiles stored in Z
987  float* zlut_sel = GetRadialZLUT(zlutIndex);
988 
989  int zi = (int)z_estim;
990  if (zi > zlut_planes-2) zi = zlut_planes-2;
991  float* z0 = &zlut_sel[zi*zlut_res];
992  float* z1 = &zlut_sel[(zi+1)*zlut_res];
993  double* zlut_weights = ALLOCA_ARRAY(double, zlut_res);
994  for (int i=0;i<zlut_res;i++)
995  zlut_weights[i] = fabs((double)z1[i]-(double)z0[i]) * ( zlut_minradius + (zlut_maxradius - zlut_minradius) * i/(float)zlut_res );
996 
997  for (int k=0;k<zlut_planes;k++) {
998  double diffsum = 0.0f;
999  for (int r = 0; r<zlut_res;r++) {
1000  double d = (double)rprof[r]-(double)zlut_sel[k*zlut_res+r];
1001  d = -d*d;
1002  d *= zlut_weights[r];
1003  diffsum += d;
1004  }
1005  rprof_diff[k] = diffsum;
1006  }
1007  //return ComputeSplineFitMaxPos(rprof_diff,zlut_planes);
1009 }
1010 
1011 void CPUTracker::SaveImage(const char *filename)
1012 {
1013  FloatToJPEGFile(filename, srcImage, width, height);
1014 }
1015 
1017 {
1018  //kissfft<float> yfft(h, inverse);
1019  if (!fft2d){
1020  fft2d = new FFT2D(width, height);
1021  }
1022 
1023  fft2d->Apply(srcImage);
1024 }
1025 
1027 {
1028  int w = xfft.nfft();
1029  int h = yfft.nfft();
1030 
1031  std::complex<float>* tmpsrc = ALLOCA_ARRAY(std::complex<float>, h);
1032  std::complex<float>* tmpdst = ALLOCA_ARRAY(std::complex<float>, h);
1033 
1034  for(int y=0;y<h;y++) {
1035  for (int x=0;x<w;x++)
1036  tmpsrc[x]=d[y*w+x];
1037  xfft.transform(tmpsrc, &cbuf[y*w]);
1038  }
1039  for (int x=0;x<w;x++) {
1040  for (int y=0;y<h;y++)
1041  tmpsrc[y]=cbuf[y*w+x];
1042  yfft.transform(tmpsrc, tmpdst);
1043  for (int y=0;y<h;y++)
1044  cbuf[y*w+x]=tmpdst[y];
1045  }
1046  // copy and shift
1047  for (int y=0;y<h;y++) {
1048  for (int x=0;x<w;x++) {
1049  int dx=(x+w/2)%w;
1050  int dy=(y+h/2)%h;
1051  auto v=cbuf[x+y*w];
1052  d[dx+dy*w] = v.real()*v.real() + v.imag()*v.imag();
1053  }
1054  }
1055 
1056 // delete[] tmpsrc;
1057 // delete[] tmpdst;
1058 }
1059 
1060 void CPUTracker::FourierRadialProfile(float* dst, int radialSteps, int angularSteps, float minradius, float maxradius)
1061 {
1064  ::ComputeRadialProfile(dst, radialSteps, angularSteps, 1, width*0.3f, vector2f(width/2,height/2), &img, 0, false);
1065  for (int i=0;i<radialSteps;i++) {
1066  dst[i]=logf(dst[i]);
1067  }
1068  //NormalizeRadialProfile(dst, radialSteps);
1069 }
1070 
void WriteArrayAsCSVRow(const char *file, float *d, int len, bool append)
Definition: utils.cpp:537
CUDA_SUPPORTED_FUNC T compute(T pos)
float ComputeBgCorrectedCOM1D(float *data, int len, float cf)
Definition: utils.cpp:231
Gauss2DResult Compute2DGaussianMLE(vector2f initial, int iterations, float sigma)
Calculate a 2D Gaussian fit on the image.
void SaveImage(const char *filename)
Save the tracker&#39;s image to a jpg file.
void ComputeRadialProfile(float *dst, int radialSteps, int angularSteps, float minradius, float maxradius, vector2f center, bool crp, bool *boundaryHit=0, bool normalize=true)
Wrapper to compute a radial profile.
kissfft< scalar_t > * qa_fft_backward
Handle to backward FFT kissfft instance for quadrant align.
Definition: cpu_tracker.h:70
kissfft< scalar_t > * qi_fft_forward
Handle to forward FFT kissfft instance for QI.
Definition: cpu_tracker.h:95
float zlut_maxradius
Maximum radius in pixels of the ZLUT profile sampling circle.
Definition: cpu_tracker.h:67
const scalar_t QIWeights[QI_LSQFIT_NWEIGHTS]
Definition: cpu_tracker.cpp:32
std::vector< float > cmp_cpu_qi_prof
Definition: test.cu:668
#define MARKPIXELI(x, y)
void Normalize(float *image=0)
Normalize an image.
float zlut_minradius
Minimum radius in pixels to start sampling for a ZLUT profile.
Definition: cpu_tracker.h:66
int zlut_planes
Number of planes per ZLUT.
Definition: cpu_tracker.h:63
int zlut_res
ZLUT resolution = number of radial steps in a plane.
Definition: cpu_tracker.h:64
bool testRun
Flag to enable running a test run.
Definition: cpu_tracker.h:82
std::vector< float > zlut_radialweights
Vector with the radialweights used by the error curve calculation.
Definition: cpu_tracker.h:68
CUDA_SUPPORTED_FUNC T vertexForm()
int zlut_count
Number of ZLUTs (= # beads) available.
Definition: cpu_tracker.h:65
Structure to group results from the 2D Gaussian fit.
Definition: cpu_tracker.h:180
FFT2D * fft2d
Instance of FFT2D to perform 2D FFTs.
Definition: cpu_tracker.h:120
T erf(T x)
Definition: utils.h:373
std::vector< std::complex< float > > cmp_cpu_qi_fft_out
Definition: test.cu:671
void normalize(TPixel *d, uint w, uint h)
Definition: utils.h:27
void NormalizeRadialProfile(scalar_t *prof, int rsteps)
Definition: utils.cpp:257
scalar_t QI_ComputeOffset(complex_t *qi_profile, int nr, int axisForDebug)
QI helper function to calculate the offset from concatenated profiles.
int height
ROI height.
Definition: cpu_tracker.h:42
vector2f pos
Found position.
Definition: cpu_tracker.h:181
vector2< float > vector2f
Definition: std_incl.h:39
float LUTProfileCompare(float *profile, int zlutIndex, float *cmpProf, LUTProfileMaxComputeMode maxPosMethod, float *fitcurve=0, int *maxPos=0, int frameNum=0)
Compare a profile to a LUT and calculate the optimum Z value for it.
#define QI_LSQFIT_WEIGHTS
float stdev
Standard deviation of values in the ROI. Calculated in ComputeMeanAndCOM.
Definition: cpu_tracker.h:49
T ComputeStdDev(T *data, int len)
Definition: utils.h:221
float & GetPixel(int x, int y)
Get the image pixel greyscale value at point (x,y).
Definition: cpu_tracker.h:122
T Lerp(T a, T b, float x)
Definition: utils.h:40
float * GetRadialZLUT(int index)
Get the start of the ZLUT of a specific bead.
Definition: cpu_tracker.h:90
vector2f ComputeMeanAndCOM(float bgcorrection=0.0f)
Calculate the center of mass of the image.
void CalculateErrorCurve(double *errorcurve_dest, float *profile, float *zlut_sel)
Calculate the error curve from a specific profile and LUT.
void AllocateQIFFTs(int nsteps)
Initializes the fft handles.
void FourierTransform2D()
Calculate a 2D fourier transform of the tracker&#39;s image.
float * srcImage
Memory region that holds the image on which tracking is to be performed.
Definition: cpu_tracker.h:46
CPUTracker(int w, int h, int xcorwindow=128, bool testRun=false)
Create an instance of CPUTracker.
Definition: cpu_tracker.cpp:39
void ApplyOffsetGain(float *offset, float *gain, float offsetFactor, float gainFactor)
Scale the input image with the background calibration values.
Definition: cpu_tracker.cpp:95
int xcorw
Cross correlation profile length.
Definition: cpu_tracker.h:43
bool CheckBoundaries(vector2f center, float radius)
Test to see if a circle extends outside of image boundaries.
float scalar_t
Definition: scalar_types.h:9
#define MIN_RADPROFILE_SMP_COUNT
Minimum number of samples for a profile radial bin. Below this the image mean will be used...
Definition: QueuedTracker.h:74
const double ZLUTWeights_d[ZLUT_LSQFIT_NWEIGHTS]
Definition: cpu_tracker.cpp:34
float mean
Mean intensity of the ROI. Calculated in ComputeMeanAndCOM.
Definition: cpu_tracker.h:48
std::string GetCurrentOutputPath(bool ext)
Definition: utils.cpp:19
void CalculateInterpolatedZLUTProfile(float *profile_dest, float z, int zlutIndex)
Calculates an intermediate ZLUT profile between two planes.
#define QI_LSQFIT_NWEIGHTS
float CalculateErrorFlag(double *prof1, double *prof2)
WIP. Calculate the error flag between two profiles.
double sum_diff(T *begin, T *end, T *other)
kissfft< scalar_t > * qa_fft_forward
Handle to forward FFT kissfft instance for quadrant align.
Definition: cpu_tracker.h:69
const float XCorScale
Definition: cpu_tracker.cpp:24
XCor1DBuffer * xcorBuffer
The handle from which to perform cross correlation calculations.
Definition: cpu_tracker.h:92
void WriteComplexImageAsCSV(const char *file, std::complex< float > *d, int w, int h, const char *labels[])
Definition: utils.cpp:579
vector2f ComputeXCorInterpolated(vector2f initial, int iterations, int profileWidth, bool &boundaryHit)
Compute the cross correlation offsets and resulting position.
float bg
Found fit parameter.
Definition: cpu_tracker.h:183
void SetRadialZLUT(float *data, int planes, int res, int num_zluts, float minradius, float maxradius, bool copyMemory, bool useCorrelation)
Tell the tracker where in memory the LUT is located.
float * debugImage
Memory in which an intermediate image can optionally be place and retrieved.
Definition: cpu_tracker.h:47
#define ALLOCA_ARRAY(T, N)
Definition: std_incl.h:153
void SetRadialWeights(float *radweights)
Set the radial weights to be used for profile comparisons.
static CUDA_SUPPORTED_FUNC T Compute(T *data, int len, const T *weights, LsqSqQuadFit< T > *fit=0)
Default. Use a 7-point quadratic fit around the error curve&#39;s maximum.
Definition: cpu_tracker.h:379
void Apply(float *d)
Apply the 2D FFT.
vector3< float > vector3f
Definition: std_incl.h:114
void XCorFFTHelper(complex_t *prof, complex_t *prof_rev, scalar_t *result)
Calculates a cross correlation much like https://en.wikipedia.org/wiki/Autocorrelation#Efficient_comp...
static int round(scalar_t f)
Definition: cpu_tracker.cpp:28
void dbgprintf(const char *fmt,...)
Definition: utils.cpp:149
float CUDA_SUPPORTED_FUNC ComputeSplineFitMaxPos(T *data, int len)
Definition: CubicBSpline.h:55
T Interpolate(T *image, int width, int height, float x, float y, bool *outside=0)
Definition: utils.h:43
LUTProfileMaxComputeMode
Settings to compute the Z coordinate from the error curve.
Definition: cpu_tracker.h:378
Class to facilitate 1D cross correlation calculations.
Definition: cpu_tracker.h:9
void ComputeCRP(float *dst, int radialSteps, int angularSteps, float minradius, float maxradius, vector2f center, ImageData *img, float paddingValue, float *crpmap)
Definition: utils.cpp:181
float LUTProfileCompareAdjustedWeights(float *rprof, int zlutIndex, float z_estim)
Compare a profile to a LUT and calculate the optimum Z value for it using an initial estimate...
std::vector< vector2f > quadrantDirs
Vector with the sampling points for a single quadrant (cos & sin pairs).
Definition: cpu_tracker.h:93
void FloatToJPEGFile(const char *name, const float *d, int w, int h)
Definition: fastjpg.cpp:189
T conjugate(const T &v)
Definition: cpu_tracker.cpp:30
int qi_radialsteps
Number of radialsteps in the QI calculations.
Definition: cpu_tracker.h:94
scalar_t QuadrantAlign_ComputeOffset(complex_t *profile, complex_t *zlut_prof_fft, int nr, int axisForDebug)
QA helper function to calculate the offset from concatenated profiles.
static int clamp(int v, int a, int b)
Definition: cpu_tracker.cpp:36
#define ALLOCA(size)
Definition: std_incl.h:151
#define ZLUT_LSQFIT_NWEIGHTS
~CPUTracker()
Destroy a CPUTracker instance.
Definition: cpu_tracker.cpp:64
float I0
Found fit parameter.
Definition: cpu_tracker.h:182
int trackerID
ID of this tracker (= ID of thread it runs in).
Definition: cpu_tracker.h:44
float abs(std::complex< float > x)
Definition: BeadFinder.cpp:19
void FourierRadialProfile(float *dst, int radialSteps, int angularSteps, float minradius, float maxradius)
Calculate the radial profile based on the fourier transform.
#define ZLUT_LSQFIT_WEIGHTS
vector3f QuadrantAlign(vector3f initial, int beadIndex, int angularStepsPerQuadrant, bool &boundaryHit)
Perform the quadrant align algorithm.
kissfft< scalar_t > * qi_fft_backward
Handle to backward FFT kissfft instance for QI.
Definition: cpu_tracker.h:96
std::complex< scalar_t > complex_t
Definition: scalar_types.h:12
vector2f ComputeQI(vector2f initial, int iterations, int radialSteps, int angularStepsPerQuadrant, float angStepIterationFactor, float minRadius, float maxRadius, bool &boundaryHit, float *radialweights=0)
Execute the quadrant interpolation algorithm.
float ComputeAsymmetry(vector2f center, int radialSteps, int angularSteps, float minRadius, float maxRadius, float *dstAngProf=0)
Find a measure for the asymmetry of the ROI.
float * zluts
Pointer to the first data in the ZLUTs.
Definition: cpu_tracker.h:61
void SetImageFloat(float *srcImage)
Set an image with float type.
Definition: cpu_tracker.cpp:88
std::string SPrintf(const char *fmt,...)
Definition: utils.cpp:132
void FFT2D(std::complex< float > *d, int w, int h, bool inverse)
Definition: BeadFinder.cpp:44
bool zlut_memoryOwner
Flag indicating if this instance is the owner of the zluts memory, or is it external. False in all normal operation.
Definition: cpu_tracker.h:62
void ComputeQuadrantProfile(scalar_t *dst, int radialSteps, int angularSteps, int quadrant, float minRadius, float maxRadius, vector2f center, float *radialWeights=0)
Wrapper to compute a radial profile.
const float ZLUTWeights[ZLUT_LSQFIT_NWEIGHTS]
Definition: cpu_tracker.cpp:33
int width
ROI width.
Definition: cpu_tracker.h:41