16 #pragma warning(disable: 4996) // Function call with parameters that may be unsafe 30 T
conjugate(
const T &v) {
return T(v.real(),-v.imag()); }
36 static int clamp(
int v,
int a,
int b) {
return std::max(a, std::min(b, v)); }
40 : width(w), height(h), xcorw(xcorwindow), testRun(testMode)
97 if (offset && !gain) {
101 if (gain && !offset) {
105 if (gain && offset) {
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;
119 inline void _markPixels(
float x,
float y,
float* img,
int w,
int h,
float mv)
121 int rx=(int)x, ry=(
int)y;
122 if (rx >=0 && ry >= 0 && rx+1<w && ry+1<h) {
124 img[ry*w+rx+1] += mv;
125 img[(ry+1)*w+rx] += mv;
126 img[(ry+1)*w+rx+1] += mv;
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); 132 #define MARKPIXEL(x,y) 133 #define MARKPIXELI(x,y) 143 fft_forward.transform(prof, fft_out);
144 fft_forward.transform(prof_rev, fft_out_rev);
147 for (
int x=0;x<
xcorw;x++) {
151 fft_backward.transform(fft_out, fft_out_rev);
153 for (
int x=0;x<
xcorw;x++)
154 result[x] = fft_out_rev[ (x+xcorw/2) %
xcorw ].real();
159 return center.
x + radius >=
width ||
160 center.
x - radius < 0 ||
162 center.
y - radius < 0;
173 if (
xcorw < profileWidth)
174 profileWidth =
xcorw;
191 for (
int k=0;k<iterations;k++) {
198 for (
int x=0;x<
xcorw;x++) {
201 for (
int y=0;y<profileWidth;y++) {
212 prof_rev [xcorw-x-1] = s;
219 for (
int y=0;y<
xcorw;y++) {
222 for (
int x=0;x<profileWidth;x++) {
233 prof_rev [xcorw-y-1] =s;
261 float angStepIterationFactor,
float minRadius,
float maxRadius,
bool& boundaryHit,
float* radialWeights)
271 for (
int j=0;j<angularStepsPerQ;j++) {
272 float ang = 0.5*3.141593f*(j+0.5f)/(
float)angularStepsPerQ;
280 scalar_t* q0=buf, *q1=buf+nr, *q2=buf+nr*2, *q3=buf+nr*3;
286 float pixelsPerProfLen = (maxRadius-minRadius)/radialSteps;
289 float angsteps = angularStepsPerQ / powf(angStepIterationFactor, iterations);
291 for (
int k=0;k<iterations;k++){
295 for (
int q=0;q<4;q++) {
306 for(
int r=0;r<nr;r++) {
307 concat0[nr-r-1] = q1[r]+q2[r];
308 concat1[r] = q0[r]+q3[r];
316 for(
int r=0;r<nr;r++) {
317 concat1[r] = q0[r]+q1[r];
318 concat0[nr-r-1] = q2[r]+q3[r];
324 std::copy(concat0, concat0+nr*2,tmp.begin()+nr*2);
326 dbgprintf(
"[%d] OffsetX: %f, OffsetY: %f\n", k, offsetX, offsetY);
329 center.
x += offsetX * pixelsPerProfLen;
330 center.
y += offsetY * pixelsPerProfLen;
332 angsteps *= angStepIterationFactor;
343 for (T* i = begin; i != end; i++, other++) {
345 sd +=
abs(d.real()) +
abs(d.imag());
357 for(
int x=0;x<nr*2;x++)
358 reverse[x] = profile[nr*2-1-x];
364 for(
int x=0;x<nr*2;x++)
376 for(
int x=0;x<nr*2;x++) {
377 autoconv[x] = fft_out2[(x+nr)%(nr*2)].real();
381 for(
int x=0;x<nr*2;x++) {
382 profileReal[x] = profile[x].real();
388 return (maxPos - nr) * (3.14159265359f / 4);
402 for(
int x=0;x<nr*2;x++)
403 fft_out[x] *=
conjugate(zlut_prof_fft[x]);
414 for(
int x=0;x<nr*2;x++) {
415 autoconv[x] = profile[(x+nr)%(nr*2)].real();
421 return (maxPos - nr) * (3.14159265359f / 4);
443 memset(concat0, 0,
sizeof(
complex_t)*res*2);
448 float* zlut0 = &zlut[ res * zp0 ];
449 float* zlut1 = &zlut[ res * zp1 ];
450 float frac = pos.
z - (int)pos.
z;
453 double zlutValue =
Lerp(zlut0[r], zlut1[r], frac);
454 concat0[res-r-1] = concat1[r] = zlutValue;
460 scalar_t* q0=buf, *q1=buf+res, *q2=buf+res*2, *q3=buf+res*3;
463 for (
int q=0;q<4;q++) {
464 scalar_t *quadrantProfile = buf+q*res;
477 for(
int r=0;r<res;r++) {
478 concat0[res-r-1] = q1[r]+q2[r];
479 concat1[r] = q0[r]+q3[r];
487 for(
int r=0;r<res;r++) {
488 concat1[r] = q0[r]+q1[r];
489 concat0[res-r-1] = q2[r]+q3[r];
494 return vector3f(pos.
x + offsetX * pixelsPerProfLen, pos.
y + offsetY * pixelsPerProfLen, pos.
z);
501 float bg =
mean*0.5f;
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);
507 for (
int i=0;i<iterations;i++)
512 double dL_dIbg = 0.0;
515 double dL2_dI0 = 0.0;
516 double dL2_dIbg = 0.0;
520 for (
int y=0;y<
height;y++)
522 for (
int x=0;x<
width;x++)
524 float Xexp0 = (x-pos.
x + .5f) * _1oSq2Sigma;
525 float Yexp0 = (y-pos.
y + .5f) * _1oSq2Sigma;
527 float Xexp1 = (x-pos.
x - .5f) * _1oSq2Sigma;
528 float Yexp1 = (y-pos.
y - .5f) * _1oSq2Sigma;
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;
534 float dmu_dx = I0*_1oSq2PiSigma * ( expf(-Xexp1*Xexp1) - expf(-Xexp0*Xexp0)) * DeltaY;
536 float dmu_dy = I0*_1oSq2PiSigma * ( expf(-Yexp1*Yexp1) - expf(-Yexp0*Yexp0)) * DeltaX;
537 float dmu_dI0 = DeltaX*DeltaY;
541 float f = smp / mu - 1;
544 dL_dI0 += dmu_dI0 * f;
545 dL_dIbg += dmu_dIbg * f;
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);
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;
576 float minRadius,
float maxRadius,
float *dstAngProf)
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));
585 float* rline = (
float*)
ALLOCA(
sizeof(
float)*radialSteps);
588 dstAngProf = (
float*)
ALLOCA(
sizeof(
float)*radialSteps);
590 float rstep = (maxRadius-minRadius) / radialSteps;
592 for (
int a=0;a<angularSteps;a++) {
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;
614 int quadrant,
float minRadius,
float maxRadius,
vector2f center ,
float* radialWeights)
621 int mx = qmat[2*quadrant+0];
622 int my = qmat[2*quadrant+1];
627 for (
int i=0;i<radialSteps;i++)
631 scalar_t rstep = (maxRadius - minRadius) / radialSteps;
632 for (
int i=0;i<radialSteps; i++) {
638 for (
int a=0;a<angularSteps;a++) {
639 int i = (int)angstepf * a;
653 if (radialWeights) dst[i] *= radialWeights[i];
663 double sum=0, sum2=0;
670 for (
int y=0;y<
height;y++) {
671 for (
int x=0;x<
width;x++) {
696 for(
int x=0;x<
width;x++) {
697 for (
int y=0;y<
height;y++) {
703 v = std::max(0.0f, fabs(v-mean)-bgcorrection*
stdev);
707 momentX += x*(double)v;
708 momentY += y*(double)v;
713 com.
x = (float)( momentX / sum );
714 com.y = (float)( momentY / sum );
730 if (pBoundaryHit) *pBoundaryHit = boundaryHit;
734 ComputeCRP(dst, radialSteps, angularSteps, minradius, maxradius, center, &imgData,
mean);
741 void CPUTracker::SetRadialZLUT(
float* data,
int planes,
int res,
int numLUTs,
float minradius,
float maxradius,
bool copyMemory,
bool useCorrelation)
747 zluts =
new float[planes*res*numLUTs];
748 std::copy(data, data+(planes*res*numLUTs),
zluts);
786 double diffsum = 0.0f;
789 for (
int r=0;r<
zlut_res;r++) zlut_norm[r]=zlut_sel[k*zlut_res+r];
798 double d = prof_norm[r]-zlut_norm[r];
802 rprof_diff[k] = diffsum;
806 double diffsum = 0.0f;
808 double d = profile[r]-zlut_sel[k*zlut_res+r];
814 errorcurve_dest[k] = diffsum;
826 profile_dest[r] =
Lerp(zlut_sel[(
int)z*zlut_res+r],zlut_sel[((
int)z+1)*zlut_res+r],z-(
int)z);
828 profile_dest[r] = zlut_sel[(
zlut_planes-1)*zlut_res+r];
837 for(
int ii = 0; ii <
zlut_res; ii++){
838 flag +=
std::abs(prof1[ii]-prof2[ii]);
855 bool freeMem =
false;
856 std::string outputName;
862 if (FILE *file = fopen(
SPrintf(
"%s.jpg",outputName.c_str()).c_str(),
"r")) {
864 printf(
"File exists\n");
888 int numImgInStack = 1218;
889 float umPerImg = range/numImgInStack;
890 int startFrame = 400;
891 int usedFrames = numImgInStack-startFrame;
892 float rangeInLUT = usedFrames*umPerImg;
895 float error = 0.000f;
896 zOffset = error/umPerPlane;
916 std::copy(rprof_diff, rprof_diff+
zlut_planes, cmpProf);
921 *maxPos = std::max_element(rprof_diff, rprof_diff+
zlut_planes) - rprof_diff;
928 int iMax = std::max_element(rprof_diff, rprof_diff+
zlut_planes) - rprof_diff;
930 fitcurve[i] = fit.
compute(i-iMax);
939 double* plane_auto_diff =
ALLOCA_ARRAY(
double, zlut_planes);
957 FILE* f = fopen(
SPrintf(
"%s-out.txt",outputName.c_str()).c_str(),
"w+");
958 fprintf_s(f,
"z: %f\n",z);
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());
989 int zi = (int)z_estim;
992 float* z1 = &zlut_sel[(zi+1)*
zlut_res];
998 double diffsum = 0.0f;
1000 double d = (double)rprof[r]-(
double)zlut_sel[k*zlut_res+r];
1002 d *= zlut_weights[r];
1005 rprof_diff[k] = diffsum;
1028 int w = xfft.nfft();
1029 int h = yfft.nfft();
1031 std::complex<float>* tmpsrc =
ALLOCA_ARRAY(std::complex<float>, h);
1032 std::complex<float>* tmpdst =
ALLOCA_ARRAY(std::complex<float>, h);
1034 for(
int y=0;y<h;y++) {
1035 for (
int x=0;x<w;x++)
1037 xfft.transform(tmpsrc, &cbuf[y*w]);
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];
1047 for (
int y=0;y<h;y++) {
1048 for (
int x=0;x<w;x++) {
1052 d[dx+dy*w] = v.real()*v.real() + v.imag()*v.imag();
1065 for (
int i=0;i<radialSteps;i++) {
1066 dst[i]=logf(dst[i]);
void WriteArrayAsCSVRow(const char *file, float *d, int len, bool append)
CUDA_SUPPORTED_FUNC T compute(T pos)
float ComputeBgCorrectedCOM1D(float *data, int len, float cf)
Gauss2DResult Compute2DGaussianMLE(vector2f initial, int iterations, float sigma)
Calculate a 2D Gaussian fit on the image.
void SaveImage(const char *filename)
Save the tracker'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.
kissfft< scalar_t > * qi_fft_forward
Handle to forward FFT kissfft instance for QI.
float zlut_maxradius
Maximum radius in pixels of the ZLUT profile sampling circle.
const scalar_t QIWeights[QI_LSQFIT_NWEIGHTS]
std::vector< float > cmp_cpu_qi_prof
void Normalize(float *image=0)
Normalize an image.
float zlut_minradius
Minimum radius in pixels to start sampling for a ZLUT profile.
int zlut_planes
Number of planes per ZLUT.
int zlut_res
ZLUT resolution = number of radial steps in a plane.
bool testRun
Flag to enable running a test run.
std::vector< float > zlut_radialweights
Vector with the radialweights used by the error curve calculation.
CUDA_SUPPORTED_FUNC T vertexForm()
int zlut_count
Number of ZLUTs (= # beads) available.
Structure to group results from the 2D Gaussian fit.
FFT2D * fft2d
Instance of FFT2D to perform 2D FFTs.
std::vector< std::complex< float > > cmp_cpu_qi_fft_out
void normalize(TPixel *d, uint w, uint h)
void NormalizeRadialProfile(scalar_t *prof, int rsteps)
scalar_t QI_ComputeOffset(complex_t *qi_profile, int nr, int axisForDebug)
QI helper function to calculate the offset from concatenated profiles.
vector2f pos
Found position.
vector2< float > vector2f
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.
T ComputeStdDev(T *data, int len)
float & GetPixel(int x, int y)
Get the image pixel greyscale value at point (x,y).
T Lerp(T a, T b, float x)
float * GetRadialZLUT(int index)
Get the start of the ZLUT of a specific bead.
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's image.
float * srcImage
Memory region that holds the image on which tracking is to be performed.
CPUTracker(int w, int h, int xcorwindow=128, bool testRun=false)
Create an instance of CPUTracker.
void ApplyOffsetGain(float *offset, float *gain, float offsetFactor, float gainFactor)
Scale the input image with the background calibration values.
int xcorw
Cross correlation profile length.
bool CheckBoundaries(vector2f center, float radius)
Test to see if a circle extends outside of image boundaries.
#define MIN_RADPROFILE_SMP_COUNT
Minimum number of samples for a profile radial bin. Below this the image mean will be used...
const double ZLUTWeights_d[ZLUT_LSQFIT_NWEIGHTS]
float mean
Mean intensity of the ROI. Calculated in ComputeMeanAndCOM.
std::string GetCurrentOutputPath(bool ext)
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.
XCor1DBuffer * xcorBuffer
The handle from which to perform cross correlation calculations.
void WriteComplexImageAsCSV(const char *file, std::complex< float > *d, int w, int h, const char *labels[])
vector2f ComputeXCorInterpolated(vector2f initial, int iterations, int profileWidth, bool &boundaryHit)
Compute the cross correlation offsets and resulting position.
float bg
Found fit parameter.
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.
#define ALLOCA_ARRAY(T, N)
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's maximum.
void Apply(float *d)
Apply the 2D FFT.
vector3< float > vector3f
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)
void dbgprintf(const char *fmt,...)
float CUDA_SUPPORTED_FUNC ComputeSplineFitMaxPos(T *data, int len)
T Interpolate(T *image, int width, int height, float x, float y, bool *outside=0)
LUTProfileMaxComputeMode
Settings to compute the Z coordinate from the error curve.
Class to facilitate 1D cross correlation calculations.
void ComputeCRP(float *dst, int radialSteps, int angularSteps, float minradius, float maxradius, vector2f center, ImageData *img, float paddingValue, float *crpmap)
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).
void FloatToJPEGFile(const char *name, const float *d, int w, int h)
int qi_radialsteps
Number of radialsteps in the QI calculations.
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)
#define ZLUT_LSQFIT_NWEIGHTS
~CPUTracker()
Destroy a CPUTracker instance.
float I0
Found fit parameter.
int trackerID
ID of this tracker (= ID of thread it runs in).
float abs(std::complex< float > x)
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.
std::complex< scalar_t > complex_t
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.
void SetImageFloat(float *srcImage)
Set an image with float type.
std::string SPrintf(const char *fmt,...)
void FFT2D(std::complex< float > *d, int w, int h, bool inverse)
bool zlut_memoryOwner
Flag indicating if this instance is the owner of the zluts memory, or is it external. False in all normal operation.
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]