/** * @brief PSF Estimation (Main Function) */ float * psf_estim (float *img, int nx, int ny, float *pattern, int pat_nx, int pat_ny, int s, int psf_nrow, int psf_ncol, int solver, char *detected_ppm) { ImageFloat in, imgW, imgN, imgT, imgEq, xGrid, yGrid, imgC, imgP, imgPf; int i, j; int ncs, nrs; float *psharp, *pblur; float xmin, xmax, ymin, ymax; float fcx, fcy; float *cblur, *csharp; float ps; float *A, *b, *x; int ncol, nrow; ImageFloat imgMask; ThinPlate tp, tpI; /* convert input image to ImageFloat */ in = new_imageFloat (nx, ny); memcpy (in->val, img, nx * ny * sizeof (float)); /* Convert the input random pattern image to a sharp pattern image of UP_RES x UP_RES larger size by replacing each pixel by a block of UP_RES x UP_RES pixels with the same gray value. Also normalize the sharp pattern image to be a FloatImage in [0,1]*/ imgP = pattern_to_pattern_image(pattern, pat_nx, pat_ny); /*---------Detecting the pattern---------*/ printf ("Detecting the pattern...\n"); pblur = detect_pattern (in); /*Check if the detected pattern is required by the user*/ if(detected_ppm) { ImageFloat inR_detected, inG_detected, inB_detected; inR_detected = draw_detected_corners_image_maxval(in, pblur); inG_detected = draw_detected_corners_image_minval(in, pblur); inB_detected = draw_detected_corners_image_minval(in, pblur); write_ppm_normalize_float(detected_ppm, inR_detected->val, inG_detected->val, inB_detected->val, inR_detected->ncol, inR_detected->nrow); free_imageFloat(inR_detected); free_imageFloat(inG_detected); free_imageFloat(inB_detected); } /*---Extract a sub image with the target * and update the checkpoints locations relative to the extracted image */ printf ("Extracting the pattern...\n"); imgT = extract_pattern_region (in, pblur, 12); #ifdef SAVE_INTERMEDIATE_IMGS write_pgm_normalize_float("pattern_region_image.pgm", imgT->val,imgT->ncol, imgT->nrow); #endif /*----Geometric Distortion - Thin Plates----*/ printf ("Calculating thin-plates distortion...\n"); /* Compute checkerboard X points positions in the analytic pattern */ psharp = pattern_Xpoints (); tp = calculate_thinPlate (pblur, psharp, 12, 10);/*lambda = 10 */ tpI = calculate_thinPlate (psharp, pblur, 12, 10);/*lambda = 10 */ /*---Image Ilumination Normalization B&W---*/ printf ("Normalizing image illumination...\n"); imgN = image_normalization (imgT, tpI); #ifdef SAVE_INTERMEDIATE_IMGS write_pgm_normalize_float("illumination_normalized_image.pgm", imgN->val, imgN->ncol, imgN->nrow); #endif /*---CRF Estimation and Correction---*/ printf ("Estimating and correcting CRF...\n"); imgEq = crf_correction (imgN, tpI); #ifdef SAVE_INTERMEDIATE_IMGS write_pgm_normalize_float("crf_corrected_image.pgm", imgEq->val, imgEq->ncol, imgEq->nrow); #endif /*---Extract Noise Region from the observed image*/ printf ("Extracting noise region...\n"); imgW = extract_noise_region (imgEq, tpI, &xmin, &xmax, &ymin, &ymax, &imgMask); #ifdef SAVE_INTERMEDIATE_IMGS write_pgm_normalize_float("noise_region_image.pgm", imgW->val, imgW->ncol, imgW->nrow); write_pgm_normalize_float("mask_image.pgm", imgMask->val, imgMask->ncol, imgMask->nrow); #endif /*--- Pattern Rasterization --- */ /*--------> Cut the spectrum- */ /* * int m = up_res*512; * int n = up_res*512; * double fcx = q*s/(2*n); * double fcy = p*s/(2*m); */ /* fcx = imgW->ncol*s/(2*UP_RES*512); fcy = imgW->nrow*s/(2*UP_RES*512); */ printf ("Filtering and interpolating sharp pattern image...\n"); fcx = roundfi (imgW->ncol * s); fcy = roundfi (imgW->nrow * s); imgPf = lpf_image_dct (imgP, (int) fcx, (int) fcy); /* Pattern sx Interpolation */ ps = 1 / ((float) s); ncs = (xmax - xmin) * s + 1; nrs = (ymax - ymin) * s + 1; cblur = (float *) malloc (nrs * ncs * 2 * sizeof (float)); csharp = (float *) malloc (nrs * ncs * 2 * sizeof (float)); /*Generating the sx-sampling grid */ for (i = 0; i < nrs; i++) for (j = 0; j < ncs; j++) { cblur[2 * i * ncs + 2 * j] = xmin + j * ps; cblur[2 * i * ncs + 2 * j + 1] = ymin + i * ps; } /*Applying TP to the sx-sampling grid and interpolate the Sharp pattern */ evaluate_thinPlate (tp, cblur, csharp, nrs * ncs); xGrid = new_imageFloat (ncs, nrs); yGrid = new_imageFloat (ncs, nrs); /*The Sharp pattern image only contains the noise part * so i need to translate the x,y Grid. Noise regions * starts in (PATTERN_BLOCK_SIZE,PATTERN_BLOCK_SIZE)*UP_RES */ for (i = 0; i < nrs; i++) for (j = 0; j < ncs; j++) { xGrid->val[i * ncs + j] = csharp[2 * i * ncs + 2 * j] - PATTERN_BLOCK_SIZE * UP_RES; yGrid->val[i * ncs + j] = csharp[2 * i * ncs + 2 * j + 1] - PATTERN_BLOCK_SIZE * UP_RES; } /*In version 1.0 the parameter was wrongly set to 0.5 instead of -0.5*/ imgC = bicubic (xGrid, yGrid, imgPf, -0.5); #ifdef SAVE_INTERMEDIATE_IMGS write_pgm_normalize_float("pattern_interpolated_image.pgm", imgC->val, imgC->ncol, imgC->nrow); #endif /*Generating A and b for Ax = b system */ printf ("Generating A,b for Ax = b linear system...\n"); make_Ab (imgC, imgW, imgMask, psf_nrow, psf_ncol, s, &A, &b, &ncol, &nrow); /*There are three different ways of solving * x / Ax = b. * i) least squares * ii) least squares and then projection (x>=th) * iii) non-negative least squares (x>=0) */ printf ("Estimating the PSF: solving Ax = b...\n"); if(solver==0) { x = solve_lsd(A, b, nrow, ncol); } else if (solver==1) { x = solve_lsd_th (A, b, nrow, ncol, 0.001); } else if (solver ==2) { x = solve_nnlsd(A, b, nrow, ncol); } else { error("Solver not recognized. Solver must be 0,1,2"); } printf ("Cleaning the house...\n"); free_imageFloat (imgW); free_imageFloat (imgN); free_imageFloat (imgT); free_imageFloat (imgEq); free_imageFloat (xGrid); free_imageFloat (yGrid); free_imageFloat (imgC); free_imageFloat (imgP); free_imageFloat (imgPf); free_imageFloat (in); free_thinPlate (tp); free_thinPlate (tpI); free ((void *) cblur); free ((void *) csharp); free ((void *) psharp); free ((void *) pblur); free ((void *) A); free((void*) b); return x; }
/** * * Procedure to handle the pyramidal approach. * This procedure relies on the previous functions to calculate * large optical flow fields using a pyramidal scheme. * */ void horn_schunck_pyramidal( const float *I1, // source image const float *I2, // target image float *u, // x component of optical flow float *v, // y component of optical flow const int nx, // image width const int ny, // image height const float alpha, // smoothing weight const int nscales, // number of scales const float zfactor, // zoom factor const int warps, // number of warpings per scale const float TOL, // stopping criterion threshold const int maxiter, // maximum number of iterations const bool verbose // switch on messages ) { if (verbose) fprintf(stderr, "Multiscale Horn-Schunck of a %dx%d pair" "\n\ta=%g ns=%d zf=%g nw=%d eps=%g mi=%d\n", nx, ny, alpha, nscales, zfactor, warps, TOL, maxiter); int size = nx * ny; float *I1s[nscales]; float *I2s[nscales]; float *us[nscales]; float *vs[nscales]; int nxx[nscales]; int nyy[nscales]; I1s[0] = xmalloc(size * sizeof(float)); I2s[0] = xmalloc(size * sizeof(float)); // normalize the finest scale images between 0 and 255 image_normalization(I1, I2, I1s[0], I2s[0], size); // presmoothing the finest scale images gaussian(I1s[0], nx, ny, INPUT_PRESMOOTHING_SIGMA); gaussian(I2s[0], nx, ny, INPUT_PRESMOOTHING_SIGMA); us[0] = u; vs[0] = v; nxx[0] = nx; nyy[0] = ny; // create the scales for(int s = 1; s < nscales; s++) { zoom_size(nxx[s-1], nyy[s-1], nxx+s, nyy+s, zfactor); const int sizes = nxx[s] * nyy[s]; I1s[s] = xmalloc(sizes * sizeof(float)); I2s[s] = xmalloc(sizes * sizeof(float)); us[s] = xmalloc(sizes * sizeof(float)); vs[s] = xmalloc(sizes * sizeof(float)); // compute the zoom from the previous finer scale zoom_out(I1s[s-1], I1s[s], nxx[s-1], nyy[s-1], zfactor); zoom_out(I2s[s-1], I2s[s], nxx[s-1], nyy[s-1], zfactor); } // initialize the flow for (int i = 0; i < nxx[nscales-1] * nyy[nscales-1]; i++) { us[nscales-1][i] = 0; vs[nscales-1][i] = 0; } // pyramidal approximation to the optic flow for(int s = nscales-1; s >= 0; s--) { if(verbose) fprintf(stderr, "Scale: %d %dx%d\n", s, nxx[s], nyy[s]); // compute the optical flow at this scale horn_schunck_optical_flow( I1s[s], I2s[s], us[s], vs[s], nxx[s], nyy[s], alpha, warps, TOL, maxiter, verbose ); // if this was the last scale, finish now if (!s) break; // otherwise, upsample the optical flow // zoom the optic flow for the next finer scale zoom_in(us[s], us[s-1], nxx[s], nyy[s], nxx[s-1], nyy[s-1]); zoom_in(vs[s], vs[s-1], nxx[s], nyy[s], nxx[s-1], nyy[s-1]); // scale the optic flow with the appropriate zoom factor for(int i = 0; i < nxx[s-1] * nyy[s-1]; i++) { us[s-1][i] *= 1.0 / zfactor; vs[s-1][i] *= 1.0 / zfactor; } } // free the allocated memory free(I1s[0]); free(I2s[0]); for(int i = 1; i < nscales; i++) { free(I1s[i]); free(I2s[i]); free(us[i]); free(vs[i]); } }
/** * * Function to compute the optical flow using multiple scales * **/ void Dual_TVL1_optic_flow_multiscale( float *I0, // source image float *I1, // target image float *u1, // x component of the optical flow float *u2, // y component of the optical flow const int nxx, // image width const int nyy, // image height const float tau, // time step const float lambda, // weight parameter for the data term const float theta, // weight parameter for (u - v)² const int nscales, // number of scales const float zfactor, // factor for building the image piramid const int warps, // number of warpings per scale const float epsilon, // tolerance for numerical convergence const bool verbose // enable/disable the verbose mode ) { int size = nxx * nyy; // allocate memory for the pyramid structure float **I0s = xmalloc(nscales * sizeof(float*)); float **I1s = xmalloc(nscales * sizeof(float*)); float **u1s = xmalloc(nscales * sizeof(float*)); float **u2s = xmalloc(nscales * sizeof(float*)); int *nx = xmalloc(nscales * sizeof(int)); int *ny = xmalloc(nscales * sizeof(int)); I0s[0] = xmalloc(size*sizeof(float)); I1s[0] = xmalloc(size*sizeof(float)); u1s[0] = u1; u2s[0] = u2; nx [0] = nxx; ny [0] = nyy; // normalize the images between 0 and 255 image_normalization(I0, I1, I0s[0], I1s[0], size); // pre-smooth the original images gaussian(I0s[0], nx[0], ny[0], PRESMOOTHING_SIGMA); gaussian(I1s[0], nx[0], ny[0], PRESMOOTHING_SIGMA); // create the scales for (int s = 1; s < nscales; s++) { zoom_size(nx[s-1], ny[s-1], &nx[s], &ny[s], zfactor); const int sizes = nx[s] * ny[s]; // allocate memory I0s[s] = xmalloc(sizes*sizeof(float)); I1s[s] = xmalloc(sizes*sizeof(float)); u1s[s] = xmalloc(sizes*sizeof(float)); u2s[s] = xmalloc(sizes*sizeof(float)); // zoom in the images to create the pyramidal structure zoom_out(I0s[s-1], I0s[s], nx[s-1], ny[s-1], zfactor); zoom_out(I1s[s-1], I1s[s], nx[s-1], ny[s-1], zfactor); } // initialize the flow at the coarsest scale for (int i = 0; i < nx[nscales-1] * ny[nscales-1]; i++) u1s[nscales-1][i] = u2s[nscales-1][i] = 0.0; // pyramidal structure for computing the optical flow for (int s = nscales-1; s >= 0; s--) { if (verbose) fprintf(stderr, "Scale %d: %dx%d\n", s, nx[s], ny[s]); // compute the optical flow at the current scale Dual_TVL1_optic_flow( I0s[s], I1s[s], u1s[s], u2s[s], nx[s], ny[s], tau, lambda, theta, warps, epsilon, verbose ); // if this was the last scale, finish now if (!s) break; // otherwise, upsample the optical flow // zoom the optical flow for the next finer scale zoom_in(u1s[s], u1s[s-1], nx[s], ny[s], nx[s-1], ny[s-1]); zoom_in(u2s[s], u2s[s-1], nx[s], ny[s], nx[s-1], ny[s-1]); // scale the optical flow with the appropriate zoom factor for (int i = 0; i < nx[s-1] * ny[s-1]; i++) { u1s[s-1][i] *= (float) 1.0 / zfactor; u2s[s-1][i] *= (float) 1.0 / zfactor; } } // delete allocated memory for (int i = 1; i < nscales; i++) { free(I0s[i]); free(I1s[i]); free(u1s[i]); free(u2s[i]); } free(I0s[0]); free(I1s[0]); free(I0s); free(I1s); free(u1s); free(u2s); free(nx); free(ny); }