int sobel_argb32_3x3_partial(vbx_uword_t *sobel_out, vbx_uword_t *argb_in, const short image_width, const short image_height, const short image_pitch, const short renorm) { VBX::Prefetcher<vbx_uword_t> input(1,image_width,argb_in,argb_in+image_height*image_pitch,image_pitch); VBX::Vector<vbx_uword_t> output(image_width); VBX::Vector<vbx_uhalf_t>* luma[3]; luma[0]=new VBX::Vector<vbx_uhalf_t>(image_width); luma[1]=new VBX::Vector<vbx_uhalf_t>(image_width); luma[2]=new VBX::Vector<vbx_uhalf_t>(image_width); VBX::Vector<vbx_uhalf_t> gradient_x(image_width); VBX::Vector<vbx_uhalf_t> gradient_y(image_width); VBX::Vector<vbx_uhalf_t>* sobel_rows[3]; sobel_rows[0]=new VBX::Vector<vbx_uhalf_t>(image_width); sobel_rows[1]=new VBX::Vector<vbx_uhalf_t>(image_width); sobel_rows[2]=new VBX::Vector<vbx_uhalf_t>(image_width); input.fetch(); int rowmod3=0; for(int row=0;row<image_height;row++){ input.fetch(); VBX::Vector<vbx_uhalf_t>& sobel_top= *sobel_rows[rowmod3]; VBX::Vector<vbx_uhalf_t>& sobel_bot= *sobel_rows[mod3(rowmod3+2)]; VBX::Vector<vbx_uhalf_t>& luma_top= *luma[rowmod3]; VBX::Vector<vbx_uhalf_t>& luma_mid= *luma[mod3(rowmod3+1)]; VBX::Vector<vbx_uhalf_t>& luma_bot= *luma[mod3(rowmod3+2)]; rowmod3=mod3(rowmod3+1); argb_to_luma8(luma_bot,input[0]); sobel_row( sobel_bot ,luma_bot); if(row<2){ continue; } gradient_y=absdiff(sobel_top,sobel_bot); gradient_x=luma_top +luma_bot + luma_mid*2; gradient_x[1 upto image_width-1]=absdiff(gradient_x[0 upto image_width-2],gradient_x[2 upto image_width]); output=((gradient_x + gradient_y) >> renorm); output.cond_move(output>0xFF,0xFF); output*=0x010101; //write to output buffer, skipping first and last elements output[1 upto (image_width -1)].dma_write(sobel_out+(row-1)*image_pitch +1); } output=0; output.dma_write(sobel_out); output.dma_write(sobel_out+ (image_height-1)*image_pitch); delete luma[0]; delete luma[1]; delete luma[2]; delete sobel_rows[0]; delete sobel_rows[1]; delete sobel_rows[2]; return 0; }
int sobel_luma8_3x3(vbx_uword_t *output, unsigned char *input, const short image_width, const short image_height, const short image_pitch, const short renorm) { VBX::Prefetcher<vbx_ubyte_t> luma_in(3,image_width,input,input+image_height*image_pitch,image_pitch); VBX::Vector<vbx_uhalf_t> *sobel[3]; sobel[0]=new VBX::Vector<vbx_uhalf_t>(image_width-2); sobel[1]=new VBX::Vector<vbx_uhalf_t>(image_width-2); sobel[2]=new VBX::Vector<vbx_uhalf_t>(image_width-2); VBX::Vector<vbx_uhalf_t> gradient_x(image_width-2); VBX::Vector<vbx_uhalf_t> gradient_y(image_width-2); VBX::Vector<vbx_uword_t> row_out(image_width); VBX::Vector<vbx_uhalf_t> tmp(image_width); if(!tmp.data){ printf("Out of scratchpad memory\n"); return -1; } luma_in.fetch(); luma_in.fetch(); sobel_row(*sobel[0],luma_in[0]); luma_in.fetch(); sobel_row(*sobel[1],luma_in[1]); //set first row black row_out=0; row_out.dma_write(output); for(int row=0,s_t=0,s_b=2;row<image_height-(3-1);row++,s_t++,s_b++){ luma_in.fetch(); //use reference to refer to vectors without copying VBX::Vector<vbx_ubyte_t>& luma_top=luma_in[0]; VBX::Vector<vbx_ubyte_t>& luma_mid=luma_in[1]; VBX::Vector<vbx_ubyte_t>& luma_bot=luma_in[2]; if(s_t>=3)s_t=0;//mod 3 if(s_b>=3)s_b=0;//mod 3 VBX::Vector<vbx_uhalf_t>& sobel_top=*sobel[s_t]; VBX::Vector<vbx_uhalf_t>& sobel_bot=*sobel[s_b]; sobel_row(sobel_bot,luma_bot); gradient_y=absdiff(sobel_top,sobel_bot); tmp=luma_top+luma_bot+(luma_mid<<1); gradient_x=absdiff(tmp,tmp[2 upto image_width]); //sum the gradients, normalize and saturate at 255 row_out[1 upto image_width-1]=(gradient_x+gradient_y)>>renorm; row_out.cond_move(row_out>255,255); //copy lowest byte into the 2nd and 3rd; row_out*=0x10101; row_out.dma_write(output+(row+1)*image_pitch); } //set last row black row_out=0; row_out.dma_write(output+(image_height-1)*image_width); return 0; }
// Per OpenVX // Implements the Sobel Image Filter k. // This k produces two output planes (one can be omitted) in the x and y plane. // The Sobel Operators Gx,Gy are defined as: // // -1 0 1 -1 -2 -1 // Gx = -2 0 2 Gy = 0 0 0 // 1 0 1 1 2 1 // // https://www.khronos.org/registry/vx/specs/1.0/html/da/d4b/group__group__vision__function__sobel3x3.html // std::pair<Halide::Func, Halide::Func> sobel_3x3(Halide::Func input, bool grayscale) { Halide::Func kx("kx"), ky("ky"); Halide::Func gradient_x("gradient_x"), gradient_y("gradient_y"); Halide::RDom r(-1,3,-1,3); Halide::Var x,y,c; kx(x,y) = 0; kx(-1,-1) = -1; kx(0,-1) = 0; kx(1,-1) = 1; kx(-1, 0) = -2; kx(0, 0) = 0; kx(1, 0) = 2; kx(-1, 1) = -1; kx(0, 1) = 0; kx(1, 1) = 1; if (grayscale) gradient_x(x,y) = sum(input(x+r.x, y+r.y) * kx(r.x, r.y)); else gradient_x(x,y,c) = sum(input(x+r.x, y+r.y, c) * kx(r.x, r.y)); ky(x,y) = 0; ky(-1,-1) = -1; ky(0,-1) = -2; ky(1,-1) = -1; ky(-1, 0) = 0; ky(0, 0) = 0; ky(1, 0) = 0; ky(-1, 1) = 1; ky(0, 1) = 2; ky(1, 1) = 1; if (grayscale) gradient_y(x,y) = sum(input(x+r.x, y+r.y) * ky(r.x, r.y)); else gradient_y(x,y,c) = sum(input(x+r.x, y+r.y, c) * ky(r.x, r.y)); std::pair<Halide::Func, Halide::Func> ret = std::make_pair(gradient_x, gradient_y); return ret; }
// Main int main(int argc, char ** argv) { // Choose the best GPU in case there are multiple available choose_GPU(); // Keep track of the start time of the program long long program_start_time = get_time(); if (argc !=3){ fprintf(stderr, "usage: %s <input file> <number of frames to process>", argv[0]); exit(1); } // Let the user specify the number of frames to process int num_frames = atoi(argv[2]); // Open video file char *video_file_name = argv[1]; avi_t *cell_file = AVI_open_input_file(video_file_name, 1); if (cell_file == NULL) { AVI_print_error("Error with AVI_open_input_file"); return -1; } int i, j, *crow, *ccol, pair_counter = 0, x_result_len = 0, Iter = 20, ns = 4, k_count = 0, n; MAT *cellx, *celly, *A; double *GICOV_spots, *t, *G, *x_result, *y_result, *V, *QAX_CENTERS, *QAY_CENTERS; double threshold = 1.8, radius = 10.0, delta = 3.0, dt = 0.01, b = 5.0; // Extract a cropped version of the first frame from the video file MAT *image_chopped = get_frame(cell_file, 0, 1, 0); printf("Detecting cells in frame 0\n"); // Get gradient matrices in x and y directions MAT *grad_x = gradient_x(image_chopped); MAT *grad_y = gradient_y(image_chopped); // Allocate for gicov_mem and strel gicov_mem = (float*) malloc(sizeof(float) * grad_x->m * grad_y->n); strel = (float*) malloc(sizeof(float) * strel_m * strel_n); m_free(image_chopped); int grad_m = grad_x->m; int grad_n = grad_y->n; #pragma acc data create(sin_angle,cos_angle,theta,tX,tY) \ create(gicov_mem[0:grad_x->m*grad_y->n]) { // Precomputed constants on GPU compute_constants(); // Get GICOV matrices corresponding to image gradients long long GICOV_start_time = get_time(); MAT *gicov = GICOV(grad_x, grad_y); long long GICOV_end_time = get_time(); // Dilate the GICOV matrices long long dilate_start_time = get_time(); MAT *img_dilated = dilate(gicov); long long dilate_end_time = get_time(); } /* end acc data */ // Find possible matches for cell centers based on GICOV and record the rows/columns in which they are found pair_counter = 0; crow = (int *) malloc(gicov->m * gicov->n * sizeof(int)); ccol = (int *) malloc(gicov->m * gicov->n * sizeof(int)); for(i = 0; i < gicov->m; i++) { for(j = 0; j < gicov->n; j++) { if(!double_eq(m_get_val(gicov,i,j), 0.0) && double_eq(m_get_val(img_dilated,i,j), m_get_val(gicov,i,j))) { crow[pair_counter]=i; ccol[pair_counter]=j; pair_counter++; } } } GICOV_spots = (double *) malloc(sizeof(double) * pair_counter); for(i = 0; i < pair_counter; i++) GICOV_spots[i] = sqrt(m_get_val(gicov, crow[i], ccol[i])); G = (double *) calloc(pair_counter, sizeof(double)); x_result = (double *) calloc(pair_counter, sizeof(double)); y_result = (double *) calloc(pair_counter, sizeof(double)); x_result_len = 0; for (i = 0; i < pair_counter; i++) { if ((crow[i] > 29) && (crow[i] < BOTTOM - TOP + 39)) { x_result[x_result_len] = ccol[i]; y_result[x_result_len] = crow[i] - 40; G[x_result_len] = GICOV_spots[i]; x_result_len++; } } // Make an array t which holds each "time step" for the possible cells t = (double *) malloc(sizeof(double) * 36); for (i = 0; i < 36; i++) { t[i] = (double)i * 2.0 * PI / 36.0; } // Store cell boundaries (as simple circles) for all cells cellx = m_get(x_result_len, 36); celly = m_get(x_result_len, 36); for(i = 0; i < x_result_len; i++) { for(j = 0; j < 36; j++) { m_set_val(cellx, i, j, x_result[i] + radius * cos(t[j])); m_set_val(celly, i, j, y_result[i] + radius * sin(t[j])); } } A = TMatrix(9,4); V = (double *) malloc(sizeof(double) * pair_counter); QAX_CENTERS = (double * )malloc(sizeof(double) * pair_counter); QAY_CENTERS = (double *) malloc(sizeof(double) * pair_counter); memset(V, 0, sizeof(double) * pair_counter); memset(QAX_CENTERS, 0, sizeof(double) * pair_counter); memset(QAY_CENTERS, 0, sizeof(double) * pair_counter); // For all possible results, find the ones that are feasibly leukocytes and store their centers k_count = 0; for (n = 0; n < x_result_len; n++) { if ((G[n] < -1 * threshold) || G[n] > threshold) { MAT * x, *y; VEC * x_row, * y_row; x = m_get(1, 36); y = m_get(1, 36); x_row = v_get(36); y_row = v_get(36); // Get current values of possible cells from cellx/celly matrices x_row = get_row(cellx, n, x_row); y_row = get_row(celly, n, y_row); uniformseg(x_row, y_row, x, y); // Make sure that the possible leukocytes are not too close to the edge of the frame if ((m_min(x) > b) && (m_min(y) > b) && (m_max(x) < cell_file->width - b) && (m_max(y) < cell_file->height - b)) { MAT * Cx, * Cy, *Cy_temp, * Ix1, * Iy1; VEC *Xs, *Ys, *W, *Nx, *Ny, *X, *Y; Cx = m_get(1, 36); Cy = m_get(1, 36); Cx = mmtr_mlt(A, x, Cx); Cy = mmtr_mlt(A, y, Cy); Cy_temp = m_get(Cy->m, Cy->n); for (i = 0; i < 9; i++) m_set_val(Cy, i, 0, m_get_val(Cy, i, 0) + 40.0); // Iteratively refine the snake/spline for (i = 0; i < Iter; i++) { int typeofcell; if(G[n] > 0.0) typeofcell = 0; else typeofcell = 1; splineenergyform01(Cx, Cy, grad_x, grad_y, ns, delta, 2.0 * dt, typeofcell); } X = getsampling(Cx, ns); for (i = 0; i < Cy->m; i++) m_set_val(Cy_temp, i, 0, m_get_val(Cy, i, 0) - 40.0); Y = getsampling(Cy_temp, ns); Ix1 = linear_interp2(grad_x, X, Y); Iy1 = linear_interp2(grad_x, X, Y); Xs = getfdriv(Cx, ns); Ys = getfdriv(Cy, ns); Nx = v_get(Ys->dim); for (i = 0; i < Ys->dim; i++) v_set_val(Nx, i, v_get_val(Ys, i) / sqrt(v_get_val(Xs, i)*v_get_val(Xs, i) + v_get_val(Ys, i)*v_get_val(Ys, i))); Ny = v_get(Xs->dim); for (i = 0; i < Xs->dim; i++) v_set_val(Ny, i, -1.0 * v_get_val(Xs, i) / sqrt(v_get_val(Xs, i)*v_get_val(Xs, i) + v_get_val(Ys, i)*v_get_val(Ys, i))); W = v_get(Nx->dim); for (i = 0; i < Nx->dim; i++) v_set_val(W, i, m_get_val(Ix1, 0, i) * v_get_val(Nx, i) + m_get_val(Iy1, 0, i) * v_get_val(Ny, i)); V[n] = mean(W) / std_dev(W); // Find the cell centers by computing the means of X and Y values for all snaxels of the spline contour QAX_CENTERS[k_count] = mean(X); QAY_CENTERS[k_count] = mean(Y) + TOP; k_count++; // Free memory v_free(W); v_free(Ny); v_free(Nx); v_free(Ys); v_free(Xs); m_free(Iy1); m_free(Ix1); v_free(Y); v_free(X); m_free(Cy_temp); m_free(Cy); m_free(Cx); } // Free memory v_free(y_row); v_free(x_row); m_free(y); m_free(x); } } // Free memory free(gicov_mem); free(strel); free(V); free(ccol); free(crow); free(GICOV_spots); free(t); free(G); free(x_result); free(y_result); m_free(A); m_free(celly); m_free(cellx); m_free(img_dilated); m_free(gicov); m_free(grad_y); m_free(grad_x); // Report the total number of cells detected printf("Cells detected: %d\n\n", k_count); // Report the breakdown of the detection runtime printf("Detection runtime\n"); printf("-----------------\n"); printf("GICOV computation: %.5f seconds\n", ((float) (GICOV_end_time - GICOV_start_time)) / (1000*1000)); printf(" GICOV dilation: %.5f seconds\n", ((float) (dilate_end_time - dilate_start_time)) / (1000*1000)); printf(" Total: %.5f seconds\n", ((float) (get_time() - program_start_time)) / (1000*1000)); // Now that the cells have been detected in the first frame, // track the ellipses through subsequent frames if (num_frames > 1) printf("\nTracking cells across %d frames\n", num_frames); else printf("\nTracking cells across 1 frame\n"); long long tracking_start_time = get_time(); int num_snaxels = 20; ellipsetrack(cell_file, QAX_CENTERS, QAY_CENTERS, k_count, radius, num_snaxels, num_frames); printf(" Total: %.5f seconds\n", ((float) (get_time() - tracking_start_time)) / (float) (1000*1000*num_frames)); // Report total program execution time printf("\nTotal application run time: %.5f seconds\n", ((float) (get_time() - program_start_time)) / (1000*1000)); return 0; }
void ellipseevolve(MAT *f, double *xc0, double *yc0, double *r0, double *t, int Np, double Er, double Ey) { /* % ELLIPSEEVOLVE evolves a parametric snake according % to some energy constraints. % % INPUTS: % f............potential surface % xc0,yc0......initial center position % r0,t.........initial radii & angle vectors (with Np elements each) % Np...........number of snaxel points per snake % Er...........expected radius % Ey...........expected y position % % OUTPUTS % xc0,yc0.......final center position % r0...........final radii % % Matlab code written by: DREW GILLIAM (based on work by GANG DONG / % NILANJAN RAY) % Ported to C by: MICHAEL BOYER */ // Constants double deltax = 0.2; double deltay = 0.2; double deltar = 0.2; double converge = 0.1; double lambdaedge = 1; double lambdasize = 0.2; double lambdapath = 0.05; int iterations = 1000; // maximum number of iterations int i, j; // Initialize variables double xc = *xc0; double yc = *yc0; double *r = (double *) malloc(sizeof(double) * Np); for (i = 0; i < Np; i++) r[i] = r0[i]; // Compute the x- and y-gradients of the MGVF matrix MAT *fx = gradient_x(f); MAT *fy = gradient_y(f); // Normalize the gradients int fh = f->m, fw = f->n; for (i = 0; i < fh; i++) { for (j = 0; j < fw; j++) { double temp_x = m_get_val(fx, i, j); double temp_y = m_get_val(fy, i, j); double fmag = sqrt((temp_x * temp_x) + (temp_y * temp_y)); m_set_val(fx, i, j, temp_x / fmag); m_set_val(fy, i, j, temp_y / fmag); } } double *r_old = (double *) malloc(sizeof(double) * Np); VEC *x = v_get(Np); VEC *y = v_get(Np); // Evolve the snake int iter = 0; double snakediff = 1.0; while (iter < iterations && snakediff > converge) { // Save the values from the previous iteration double xc_old = xc, yc_old = yc; for (i = 0; i < Np; i++) { r_old[i] = r[i]; } // Compute the locations of the snaxels for (i = 0; i < Np; i++) { v_set_val(x, i, xc + r[i] * cos(t[i])); v_set_val(y, i, yc + r[i] * sin(t[i])); } // See if any of the points in the snake are off the edge of the image double min_x = v_get_val(x, 0), max_x = v_get_val(x, 0); double min_y = v_get_val(y, 0), max_y = v_get_val(y, 0); for (i = 1; i < Np; i++) { double x_i = v_get_val(x, i); if (x_i < min_x) min_x = x_i; else if (x_i > max_x) max_x = x_i; double y_i = v_get_val(y, i); if (y_i < min_y) min_y = y_i; else if (y_i > max_y) max_y = y_i; } if (min_x < 0.0 || max_x > (double) fw - 1.0 || min_y < 0 || max_y > (double) fh - 1.0) break; // Compute the length of the snake double L = 0.0; for (i = 0; i < Np - 1; i++) { double diff_x = v_get_val(x, i + 1) - v_get_val(x, i); double diff_y = v_get_val(y, i + 1) - v_get_val(y, i); L += sqrt((diff_x * diff_x) + (diff_y * diff_y)); } double diff_x = v_get_val(x, 0) - v_get_val(x, Np - 1); double diff_y = v_get_val(y, 0) - v_get_val(y, Np - 1); L += sqrt((diff_x * diff_x) + (diff_y * diff_y)); // Compute the potential surface at each snaxel MAT *vf = linear_interp2(f, x, y); MAT *vfx = linear_interp2(fx, x, y); MAT *vfy = linear_interp2(fy, x, y); // Compute the average potential surface around the snake double vfmean = sum_m(vf ) / L; double vfxmean = sum_m(vfx) / L; double vfymean = sum_m(vfy) / L; // Compute the radial potential surface int m = vf->m, n = vf->n; MAT *vfr = m_get(m, n); for (i = 0; i < n; i++) { double vf_val = m_get_val(vf, 0, i); double vfx_val = m_get_val(vfx, 0, i); double vfy_val = m_get_val(vfy, 0, i); double x_val = v_get_val(x, i); double y_val = v_get_val(y, i); double new_val = (vf_val + vfx_val * (x_val - xc) + vfy_val * (y_val - yc) - vfmean) / L; m_set_val(vfr, 0, i, new_val); } // Update the snake center and snaxels xc = xc + (deltax * lambdaedge * vfxmean); yc = (yc + (deltay * lambdaedge * vfymean) + (deltay * lambdapath * Ey)) / (1.0 + deltay * lambdapath); double r_diff = 0.0; for (i = 0; i < Np; i++) { r[i] = (r[i] + (deltar * lambdaedge * m_get_val(vfr, 0, i)) + (deltar * lambdasize * Er)) / (1.0 + deltar * lambdasize); r_diff += fabs(r[i] - r_old[i]); } // Test for convergence snakediff = fabs(xc - xc_old) + fabs(yc - yc_old) + r_diff; // Free temporary matrices m_free(vf); m_free(vfx); m_free(vfy); m_free(vfr); iter++; } // Set the return values *xc0 = xc; *yc0 = yc; for (i = 0; i < Np; i++) r0[i] = r[i]; // Free memory free(r); free(r_old); v_free( x); v_free( y); m_free(fx); m_free(fy); }
void ellipsetrack(avi_t *video, double *xc0, double *yc0, int Nc, int R, int Np, int Nf) { /* % ELLIPSETRACK tracks cells in the movie specified by 'video', at % locations 'xc0'/'yc0' with radii R using an ellipse with Np discrete % points, starting at frame number one and stopping at frame number 'Nf'. % % INPUTS: % video.......pointer to avi video object % xc0,yc0.....initial center location (Nc entries) % Nc..........number of cells % R...........initial radius % Np..........nbr of snaxels points per snake % Nf..........nbr of frames in which to track % % Matlab code written by: DREW GILLIAM (based on code by GANG DONG / % NILANJAN RAY) % Ported to C by: MICHAEL BOYER */ int i, j; // Compute angle parameter double *t = (double *) malloc(sizeof(double) * Np); double increment = (2.0 * PI) / (double) Np; for (i = 0; i < Np; i++) { t[i] = increment * (double) i ; } // Allocate space for a snake for each cell in each frame double **xc = alloc_2d_double(Nc, Nf + 1); double **yc = alloc_2d_double(Nc, Nf + 1); double ***r = alloc_3d_double(Nc, Np, Nf + 1); double ***x = alloc_3d_double(Nc, Np, Nf + 1); double ***y = alloc_3d_double(Nc, Np, Nf + 1); // Save the first snake for each cell for (i = 0; i < Nc; i++) { xc[i][0] = xc0[i]; yc[i][0] = yc0[i]; for (j = 0; j < Np; j++) { r[i][j][0] = (double) R; } } // Generate ellipse points for each cell for (i = 0; i < Nc; i++) { for (j = 0; j < Np; j++) { x[i][j][0] = xc[i][0] + (r[i][j][0] * cos(t[j])); y[i][j][0] = yc[i][0] + (r[i][j][0] * sin(t[j])); } } // Keep track of the total time spent on computing // the MGVF matrix and evolving the snakes long long MGVF_time = 0; long long snake_time = 0; // Process each frame int frame_num, cell_num; for (frame_num = 1; frame_num <= Nf; frame_num++) { printf("\rProcessing frame %d / %d", frame_num, Nf); fflush(stdout); // Get the current video frame and its dimensions MAT *I = get_frame(video, frame_num, 0, 1); int Ih = I->m; int Iw = I->n; // Set the current positions equal to the previous positions for (i = 0; i < Nc; i++) { xc[i][frame_num] = xc[i][frame_num - 1]; yc[i][frame_num] = yc[i][frame_num - 1]; for (j = 0; j < Np; j++) { r[i][j][frame_num] = r[i][j][frame_num - 1]; } } // Split the work among multiple threads, if OPEN is defined #ifdef OPEN #pragma omp parallel for num_threads(omp_num_threads) private(i, j) #endif // Track each cell for (cell_num = 0; cell_num < Nc; cell_num++) { // Make copies of the current cell's location double xci = xc[cell_num][frame_num]; double yci = yc[cell_num][frame_num]; double *ri = (double *) malloc(sizeof(double) * Np); for (j = 0; j < Np; j++) { ri[j] = r[cell_num][j][frame_num]; } // Add up the last ten y-values for this cell // (or fewer if there are not yet ten previous frames) double ycavg = 0.0; for (i = (frame_num > 10 ? frame_num - 10 : 0); i < frame_num; i++) { ycavg += yc[cell_num][i]; } // Compute the average of the last ten y-values // (this represents the expected y-location of the cell) ycavg = ycavg / (double) (frame_num > 10 ? 10 : frame_num); // Determine the range of the subimage surrounding the current position int u1 = max(xci - 4.0 * R + 0.5, 0 ); int u2 = min(xci + 4.0 * R + 0.5, Iw - 1); int v1 = max(yci - 2.0 * R + 1.5, 0 ); int v2 = min(yci + 2.0 * R + 1.5, Ih - 1); // Extract the subimage MAT *Isub = m_get(v2 - v1 + 1, u2 - u1 + 1); for (i = v1; i <= v2; i++) { for (j = u1; j <= u2; j++) { m_set_val(Isub, i - v1, j - u1, m_get_val(I, i, j)); } } // Compute the subimage gradient magnitude MAT *Ix = gradient_x(Isub); MAT *Iy = gradient_y(Isub); MAT *IE = m_get(Isub->m, Isub->n); for (i = 0; i < Isub->m; i++) { for (j = 0; j < Isub->n; j++) { double temp_x = m_get_val(Ix, i, j); double temp_y = m_get_val(Iy, i, j); m_set_val(IE, i, j, sqrt((temp_x * temp_x) + (temp_y * temp_y))); } } // Compute the motion gradient vector flow (MGVF) edgemaps long long MGVF_start_time = get_time(); MAT *IMGVF = MGVF(IE, 1, 1); MGVF_time += get_time() - MGVF_start_time; // Determine the position of the cell in the subimage xci = xci - (double) u1; yci = yci - (double) (v1 - 1); ycavg = ycavg - (double) (v1 - 1); // Evolve the snake long long snake_start_time = get_time(); ellipseevolve(IMGVF, &xci, &yci, ri, t, Np, (double) R, ycavg); snake_time += get_time() - snake_start_time; // Compute the cell's new position in the full image xci = xci + u1; yci = yci + (v1 - 1); // Store the new location of the cell and the snake xc[cell_num][frame_num] = xci; yc[cell_num][frame_num] = yci; for (j = 0; j < Np; j++) { r[cell_num][j][frame_num] = ri[j]; x[cell_num][j][frame_num] = xc[cell_num][frame_num] + (ri[j] * cos(t[j])); y[cell_num][j][frame_num] = yc[cell_num][frame_num] + (ri[j] * sin(t[j])); } // Output the updated center of each cell //printf("%d,%f,%f\n", cell_num, xci[cell_num], yci[cell_num]); // Free temporary memory m_free(IMGVF); free(ri); } // Output a new line to visually distinguish the output from different frames //printf("\n"); } // Free temporary memory free(t); free_2d_double(xc); free_2d_double(yc); free_3d_double(r); free_3d_double(x); free_3d_double(y); // Report average processing time per frame printf("\n\nTracking runtime (average per frame):\n"); printf("------------------------------------\n"); printf("MGVF computation: %.5f seconds\n", ((float) (MGVF_time)) / (float) (1000*1000*Nf)); printf(" Snake evolution: %.5f seconds\n", ((float) (snake_time)) / (float) (1000*1000*Nf)); }
template <typename PointInT, typename PointOutT> void pcl::IntegralImageNormalEstimation<PointInT, PointOutT>::computePointNormalMirror ( const int pos_x, const int pos_y, const unsigned point_index, PointOutT &normal) { float bad_point = std::numeric_limits<float>::quiet_NaN (); const int width = input_->width; const int height = input_->height; // ============================================================== if (normal_estimation_method_ == COVARIANCE_MATRIX) { if (!init_covariance_matrix_) initCovarianceMatrixMethod (); const int start_x = pos_x - rect_width_2_; const int start_y = pos_y - rect_height_2_; const int end_x = start_x + rect_width_; const int end_y = start_y + rect_height_; unsigned count = 0; sumArea<unsigned>(start_x, start_y, end_x, end_y, width, height, boost::bind(&IntegralImage2D<float, 3>::getFiniteElementsCountSE, &integral_image_XYZ_, _1, _2, _3, _4), count); // no valid points within the rectangular reagion? if (count == 0) { normal.normal_x = normal.normal_y = normal.normal_z = normal.curvature = bad_point; return; } EIGEN_ALIGN16 Eigen::Matrix3f covariance_matrix; Eigen::Vector3f center; typename IntegralImage2D<float, 3>::SecondOrderType so_elements; typename IntegralImage2D<float, 3>::ElementType tmp_center; typename IntegralImage2D<float, 3>::SecondOrderType tmp_so_elements; center[0] = 0; center[1] = 0; center[2] = 0; tmp_center[0] = 0; tmp_center[1] = 0; tmp_center[2] = 0; so_elements[0] = 0; so_elements[1] = 0; so_elements[2] = 0; so_elements[3] = 0; so_elements[4] = 0; so_elements[5] = 0; sumArea<typename IntegralImage2D<float, 3>::ElementType>(start_x, start_y, end_x, end_y, width, height, boost::bind(&IntegralImage2D<float, 3>::getFirstOrderSumSE, &integral_image_XYZ_, _1, _2, _3, _4), tmp_center); sumArea<typename IntegralImage2D<float, 3>::SecondOrderType>(start_x, start_y, end_x, end_y, width, height, boost::bind(&IntegralImage2D<float, 3>::getSecondOrderSumSE, &integral_image_XYZ_, _1, _2, _3, _4), so_elements); center[0] = float (tmp_center[0]); center[1] = float (tmp_center[1]); center[2] = float (tmp_center[2]); covariance_matrix.coeffRef (0) = static_cast<float> (so_elements [0]); covariance_matrix.coeffRef (1) = covariance_matrix.coeffRef (3) = static_cast<float> (so_elements [1]); covariance_matrix.coeffRef (2) = covariance_matrix.coeffRef (6) = static_cast<float> (so_elements [2]); covariance_matrix.coeffRef (4) = static_cast<float> (so_elements [3]); covariance_matrix.coeffRef (5) = covariance_matrix.coeffRef (7) = static_cast<float> (so_elements [4]); covariance_matrix.coeffRef (8) = static_cast<float> (so_elements [5]); covariance_matrix -= (center * center.transpose ()) / static_cast<float> (count); float eigen_value; Eigen::Vector3f eigen_vector; pcl::eigen33 (covariance_matrix, eigen_value, eigen_vector); flipNormalTowardsViewpoint (input_->points[point_index], vpx_, vpy_, vpz_, eigen_vector[0], eigen_vector[1], eigen_vector[2]); normal.getNormalVector3fMap () = eigen_vector; // Compute the curvature surface change if (eigen_value > 0.0) normal.curvature = fabsf (eigen_value / (covariance_matrix.coeff (0) + covariance_matrix.coeff (4) + covariance_matrix.coeff (8))); else normal.curvature = 0; return; } // ======================================================= else if (normal_estimation_method_ == AVERAGE_3D_GRADIENT) { if (!init_average_3d_gradient_) initAverage3DGradientMethod (); const int start_x = pos_x - rect_width_2_; const int start_y = pos_y - rect_height_2_; const int end_x = start_x + rect_width_; const int end_y = start_y + rect_height_; unsigned count_x = 0; unsigned count_y = 0; sumArea<unsigned>(start_x, start_y, end_x, end_y, width, height, boost::bind(&IntegralImage2D<float, 3>::getFiniteElementsCountSE, &integral_image_DX_, _1, _2, _3, _4), count_x); sumArea<unsigned>(start_x, start_y, end_x, end_y, width, height, boost::bind(&IntegralImage2D<float, 3>::getFiniteElementsCountSE, &integral_image_DY_, _1, _2, _3, _4), count_y); if (count_x == 0 || count_y == 0) { normal.normal_x = normal.normal_y = normal.normal_z = normal.curvature = bad_point; return; } Eigen::Vector3d gradient_x (0, 0, 0); Eigen::Vector3d gradient_y (0, 0, 0); sumArea<typename IntegralImage2D<float, 3>::ElementType>(start_x, start_y, end_x, end_y, width, height, boost::bind(&IntegralImage2D<float, 3>::getFirstOrderSumSE, &integral_image_DX_, _1, _2, _3, _4), gradient_x); sumArea<typename IntegralImage2D<float, 3>::ElementType>(start_x, start_y, end_x, end_y, width, height, boost::bind(&IntegralImage2D<float, 3>::getFirstOrderSumSE, &integral_image_DY_, _1, _2, _3, _4), gradient_y); Eigen::Vector3d normal_vector = gradient_y.cross (gradient_x); double normal_length = normal_vector.squaredNorm (); if (normal_length == 0.0f) { normal.getNormalVector3fMap ().setConstant (bad_point); normal.curvature = bad_point; return; } normal_vector /= sqrt (normal_length); float nx = static_cast<float> (normal_vector [0]); float ny = static_cast<float> (normal_vector [1]); float nz = static_cast<float> (normal_vector [2]); flipNormalTowardsViewpoint (input_->points[point_index], vpx_, vpy_, vpz_, nx, ny, nz); normal.normal_x = nx; normal.normal_y = ny; normal.normal_z = nz; normal.curvature = bad_point; return; } // ====================================================== else if (normal_estimation_method_ == AVERAGE_DEPTH_CHANGE) { if (!init_depth_change_) initAverageDepthChangeMethod (); int point_index_L_x = pos_x - rect_width_4_ - 1; int point_index_L_y = pos_y; int point_index_R_x = pos_x + rect_width_4_ + 1; int point_index_R_y = pos_y; int point_index_U_x = pos_x - 1; int point_index_U_y = pos_y - rect_height_4_; int point_index_D_x = pos_x + 1; int point_index_D_y = pos_y + rect_height_4_; if (point_index_L_x < 0) point_index_L_x = -point_index_L_x; if (point_index_U_x < 0) point_index_U_x = -point_index_U_x; if (point_index_U_y < 0) point_index_U_y = -point_index_U_y; if (point_index_R_x >= width) point_index_R_x = width-(point_index_R_x-(width-1)); if (point_index_D_x >= width) point_index_D_x = width-(point_index_D_x-(width-1)); if (point_index_D_y >= height) point_index_D_y = height-(point_index_D_y-(height-1)); const int start_x_L = pos_x - rect_width_2_; const int start_y_L = pos_y - rect_height_4_; const int end_x_L = start_x_L + rect_width_2_; const int end_y_L = start_y_L + rect_height_2_; const int start_x_R = pos_x + 1; const int start_y_R = pos_y - rect_height_4_; const int end_x_R = start_x_R + rect_width_2_; const int end_y_R = start_y_R + rect_height_2_; const int start_x_U = pos_x - rect_width_4_; const int start_y_U = pos_y - rect_height_2_; const int end_x_U = start_x_U + rect_width_2_; const int end_y_U = start_y_U + rect_height_2_; const int start_x_D = pos_x - rect_width_4_; const int start_y_D = pos_y + 1; const int end_x_D = start_x_D + rect_width_2_; const int end_y_D = start_y_D + rect_height_2_; unsigned count_L_z = 0; unsigned count_R_z = 0; unsigned count_U_z = 0; unsigned count_D_z = 0; sumArea<unsigned>(start_x_L, start_y_L, end_x_L, end_y_L, width, height, boost::bind(&IntegralImage2D<float, 1>::getFiniteElementsCountSE, &integral_image_depth_, _1, _2, _3, _4), count_L_z); sumArea<unsigned>(start_x_R, start_y_R, end_x_R, end_y_R, width, height, boost::bind(&IntegralImage2D<float, 1>::getFiniteElementsCountSE, &integral_image_depth_, _1, _2, _3, _4), count_R_z); sumArea<unsigned>(start_x_U, start_y_U, end_x_U, end_y_U, width, height, boost::bind(&IntegralImage2D<float, 1>::getFiniteElementsCountSE, &integral_image_depth_, _1, _2, _3, _4), count_U_z); sumArea<unsigned>(start_x_D, start_y_D, end_x_D, end_y_D, width, height, boost::bind(&IntegralImage2D<float, 1>::getFiniteElementsCountSE, &integral_image_depth_, _1, _2, _3, _4), count_D_z); if (count_L_z == 0 || count_R_z == 0 || count_U_z == 0 || count_D_z == 0) { normal.normal_x = normal.normal_y = normal.normal_z = normal.curvature = bad_point; return; } float mean_L_z = 0; float mean_R_z = 0; float mean_U_z = 0; float mean_D_z = 0; sumArea<float>(start_x_L, start_y_L, end_x_L, end_y_L, width, height, boost::bind(&IntegralImage2D<float, 1>::getFirstOrderSumSE, &integral_image_depth_, _1, _2, _3, _4), mean_L_z); sumArea<float>(start_x_R, start_y_R, end_x_R, end_y_R, width, height, boost::bind(&IntegralImage2D<float, 1>::getFirstOrderSumSE, &integral_image_depth_, _1, _2, _3, _4), mean_R_z); sumArea<float>(start_x_U, start_y_U, end_x_U, end_y_U, width, height, boost::bind(&IntegralImage2D<float, 1>::getFirstOrderSumSE, &integral_image_depth_, _1, _2, _3, _4), mean_U_z); sumArea<float>(start_x_D, start_y_D, end_x_D, end_y_D, width, height, boost::bind(&IntegralImage2D<float, 1>::getFirstOrderSumSE, &integral_image_depth_, _1, _2, _3, _4), mean_D_z); mean_L_z /= float (count_L_z); mean_R_z /= float (count_R_z); mean_U_z /= float (count_U_z); mean_D_z /= float (count_D_z); PointInT pointL = input_->points[point_index_L_y*width + point_index_L_x]; PointInT pointR = input_->points[point_index_R_y*width + point_index_R_x]; PointInT pointU = input_->points[point_index_U_y*width + point_index_U_x]; PointInT pointD = input_->points[point_index_D_y*width + point_index_D_x]; const float mean_x_z = mean_R_z - mean_L_z; const float mean_y_z = mean_D_z - mean_U_z; const float mean_x_x = pointR.x - pointL.x; const float mean_x_y = pointR.y - pointL.y; const float mean_y_x = pointD.x - pointU.x; const float mean_y_y = pointD.y - pointU.y; float normal_x = mean_x_y * mean_y_z - mean_x_z * mean_y_y; float normal_y = mean_x_z * mean_y_x - mean_x_x * mean_y_z; float normal_z = mean_x_x * mean_y_y - mean_x_y * mean_y_x; const float normal_length = (normal_x * normal_x + normal_y * normal_y + normal_z * normal_z); if (normal_length == 0.0f) { normal.getNormalVector3fMap ().setConstant (bad_point); normal.curvature = bad_point; return; } flipNormalTowardsViewpoint (input_->points[point_index], vpx_, vpy_, vpz_, normal_x, normal_y, normal_z); const float scale = 1.0f / sqrtf (normal_length); normal.normal_x = normal_x * scale; normal.normal_y = normal_y * scale; normal.normal_z = normal_z * scale; normal.curvature = bad_point; return; } // ======================================================== else if (normal_estimation_method_ == SIMPLE_3D_GRADIENT) { PCL_THROW_EXCEPTION (PCLException, "BORDER_POLICY_MIRROR not supported for normal estimation method SIMPLE_3D_GRADIENT"); } normal.getNormalVector3fMap ().setConstant (bad_point); normal.curvature = bad_point; return; }
void ellipsetrack(avi_t *video, double *xc0, double *yc0, int Nc, int R, int Np, int Nf) { /* % ELLIPSETRACK tracks cells in the movie specified by 'video', at % locations 'xc0'/'yc0' with radii R using an ellipse with Np discrete % points, starting at frame number one and stopping at frame number 'Nf'. % % INPUTS: % video.......pointer to avi video object % xc0,yc0.....initial center location (Nc entries) % Nc..........number of cells % R...........initial radius % Np..........number of snaxels points per snake % Nf..........number of frames in which to track % % Matlab code written by: DREW GILLIAM (based on code by GANG DONG / % NILANJAN RAY) % Ported to C by: MICHAEL BOYER */ // Compute angle parameter double *t = (double *) malloc(sizeof(double) * Np); double increment = (2.0 * PI) / (double) Np; int i, j; for (i = 0; i < Np; i++) { t[i] = increment * (double) i ; } // Allocate space for a snake for each cell in each frame double **xc = alloc_2d_double(Nc, Nf + 1); double **yc = alloc_2d_double(Nc, Nf + 1); double ***r = alloc_3d_double(Nc, Np, Nf + 1); double ***x = alloc_3d_double(Nc, Np, Nf + 1); double ***y = alloc_3d_double(Nc, Np, Nf + 1); // Save the first snake for each cell for (i = 0; i < Nc; i++) { xc[i][0] = xc0[i]; yc[i][0] = yc0[i]; for (j = 0; j < Np; j++) { r[i][j][0] = (double) R; } } // Generate ellipse points for each cell for (i = 0; i < Nc; i++) { for (j = 0; j < Np; j++) { x[i][j][0] = xc[i][0] + (r[i][j][0] * cos(t[j])); y[i][j][0] = yc[i][0] + (r[i][j][0] * sin(t[j])); } } // Allocate arrays so we can break up the per-cell for loop below double *xci = (double *) malloc(sizeof(double) * Nc); double *yci = (double *) malloc(sizeof(double) * Nc); double **ri = alloc_2d_double(Nc, Np); double *ycavg = (double *) malloc(sizeof(double) * Nc); int *u1 = (int *) malloc(sizeof(int) * Nc); int *u2 = (int *) malloc(sizeof(int) * Nc); int *v1 = (int *) malloc(sizeof(int) * Nc); int *v2 = (int *) malloc(sizeof(int) * Nc); MAT **Isub = (MAT **) malloc(sizeof(MAT *) * Nc); MAT **Ix = (MAT **) malloc(sizeof(MAT *) * Nc); MAT **Iy = (MAT **) malloc(sizeof(MAT *) * Nc); MAT **IE = (MAT **) malloc(sizeof(MAT *) * Nc); // Keep track of the total time spent on computing // the MGVF matrix and evolving the snakes long long MGVF_time = 0; long long snake_time = 0; // Process each frame sequentially int frame_num; for (frame_num = 1; frame_num <= Nf; frame_num++) { printf("\rProcessing frame %d / %d", frame_num, Nf); fflush(stdout); // Get the current video frame and its dimensions MAT *I = get_frame(video, frame_num, 0, 1); int Ih = I->m; int Iw = I->n; // Initialize the current positions to be equal to the previous positions for (i = 0; i < Nc; i++) { xc[i][frame_num] = xc[i][frame_num - 1]; yc[i][frame_num] = yc[i][frame_num - 1]; for (j = 0; j < Np; j++) { r[i][j][frame_num] = r[i][j][frame_num - 1]; } } // Sequentially extract the subimage near each cell int cell_num; for (cell_num = 0; cell_num < Nc; cell_num++) { // Make copies of the current cell's location xci[cell_num] = xc[cell_num][frame_num]; yci[cell_num] = yc[cell_num][frame_num]; for (j = 0; j < Np; j++) { ri[cell_num][j] = r[cell_num][j][frame_num]; } // Add up the last ten y values for this cell // (or fewer if there are not yet ten previous frames) ycavg[cell_num] = 0.0; for (i = (frame_num > 10 ? frame_num - 10 : 0); i < frame_num; i++) { ycavg[cell_num] += yc[cell_num][i]; } // Compute the average of the last ten values // (this represents the expected location of the cell) ycavg[cell_num] = ycavg[cell_num] / (double) (frame_num > 10 ? 10 : frame_num); // Determine the range of the subimage surrounding the current position u1[cell_num] = max(xci[cell_num] - 4.0 * R + 0.5, 0 ); u2[cell_num] = min(xci[cell_num] + 4.0 * R + 0.5, Iw - 1); v1[cell_num] = max(yci[cell_num] - 2.0 * R + 1.5, 0 ); v2[cell_num] = min(yci[cell_num] + 2.0 * R + 1.5, Ih - 1); // Extract the subimage Isub[cell_num] = m_get(v2[cell_num] - v1[cell_num] + 1, u2[cell_num] - u1[cell_num] + 1); for (i = v1[cell_num]; i <= v2[cell_num]; i++) { for (j = u1[cell_num]; j <= u2[cell_num]; j++) { m_set_val(Isub[cell_num], i - v1[cell_num], j - u1[cell_num], m_get_val(I, i, j)); } } // Compute the subimage gradient magnitude Ix[cell_num] = gradient_x(Isub[cell_num]); Iy[cell_num] = gradient_y(Isub[cell_num]); IE[cell_num] = m_get(Isub[cell_num]->m, Isub[cell_num]->n); for (i = 0; i < Isub[cell_num]->m; i++) { for (j = 0; j < Isub[cell_num]->n; j++) { double temp_x = m_get_val(Ix[cell_num], i, j); double temp_y = m_get_val(Iy[cell_num], i, j); m_set_val(IE[cell_num], i, j, sqrt((temp_x * temp_x) + (temp_y * temp_y))); } } } // Compute the motion gradient vector flow (MGVF) edgemaps for all cells concurrently long long MGVF_start_time = get_time(); MAT **IMGVF = MGVF(IE, 1, 1, Nc); MGVF_time += get_time() - MGVF_start_time; // Sequentially determine the new location of each cell for (cell_num = 0; cell_num < Nc; cell_num++) { // Determine the position of the cell in the subimage xci[cell_num] = xci[cell_num] - (double) u1[cell_num]; yci[cell_num] = yci[cell_num] - (double) (v1[cell_num] - 1); ycavg[cell_num] = ycavg[cell_num] - (double) (v1[cell_num] - 1); // Evolve the snake long long snake_start_time = get_time(); ellipseevolve(IMGVF[cell_num], &(xci[cell_num]), &(yci[cell_num]), ri[cell_num], t, Np, (double) R, ycavg[cell_num]); snake_time += get_time() - snake_start_time; // Compute the cell's new position in the full image xci[cell_num] = xci[cell_num] + u1[cell_num]; yci[cell_num] = yci[cell_num] + (v1[cell_num] - 1); // Store the new location of the cell and the snake xc[cell_num][frame_num] = xci[cell_num]; yc[cell_num][frame_num] = yci[cell_num]; for (j = 0; j < Np; j++) { r[cell_num][j][frame_num] = 0; r[cell_num][j][frame_num] = ri[cell_num][j]; x[cell_num][j][frame_num] = xc[cell_num][frame_num] + (ri[cell_num][j] * cos(t[j])); y[cell_num][j][frame_num] = yc[cell_num][frame_num] + (ri[cell_num][j] * sin(t[j])); } // Output the updated center of each cell // printf("\n%d,%f,%f", cell_num, xci[cell_num], yci[cell_num]); // Free temporary memory m_free(Isub[cell_num]); m_free(Ix[cell_num]); m_free(Iy[cell_num]); m_free(IE[cell_num]); m_free(IMGVF[cell_num]); } #ifdef OUTPUT if (frame_num == Nf) { FILE * pFile; pFile = fopen ("result.txt","w+"); for (cell_num = 0; cell_num < Nc; cell_num++) fprintf(pFile,"\n%d,%f,%f", cell_num, xci[cell_num], yci[cell_num]); fclose (pFile); } #endif free(IMGVF); // Output a new line to visually distinguish the output from different frames //printf("\n"); } // Free temporary memory free_2d_double(xc); free_2d_double(yc); free_3d_double(r); free_3d_double(x); free_3d_double(y); free(t); free(xci); free(yci); free_2d_double(ri); free(ycavg); free(u1); free(u2); free(v1); free(v2); free(Isub); free(Ix); free(Iy); free(IE); // Report average processing time per frame printf("\n\nTracking runtime (average per frame):\n"); printf("------------------------------------\n"); printf("MGVF computation: %.5f seconds\n", ((float) (MGVF_time)) / (float) (1000*1000*Nf)); printf(" Snake evolution: %.5f seconds\n", ((float) (snake_time)) / (float) (1000*1000*Nf)); printf("CAUTION: cpu_offset: %d time: %lf mseconds\n", cpu_offset, ((float) (MGVF_time)) / (float) (1000*1000*Nf)*1000); }
ImageRAII canny( IplImage * image, std::pair< int, int > thresh, double sigma ) { const char * WINDOW_NAME = "Basic Canny Edge Detector"; ImageRAII grayscale( cvCreateImage( cvGetSize( image ), image->depth, 1 ) ); ImageRAII destination( cvCreateImage( cvGetSize( image ), image->depth, grayscale.image->nChannels ) ); ImageRAII gaussian( cvCreateImage( cvGetSize( image ), image->depth, grayscale.image->nChannels ) ); ImageRAII gradient_x( cvCreateImage( cvGetSize( image ), image->depth, grayscale.image->nChannels ) ); ImageRAII gradient_y( cvCreateImage( cvGetSize( image ), image->depth, grayscale.image->nChannels ) ); ImageRAII gradient( cvCreateImage( cvGetSize( image ), image->depth, grayscale.image->nChannels ) ); ImageRAII orientation( cvCreateImage( cvGetSize( image ), image->depth, grayscale.image->nChannels ) ); // convert image to grayscale cvCvtColor( image, grayscale.image, CV_BGR2GRAY ); // gaussian smoothing cvSmooth( grayscale.image, gaussian.image, CV_GAUSSIAN, GAUSSIAN_X, GAUSSIAN_Y, sigma ); // find edge strength cvSobel( gaussian.image, gradient_x.image, 1, 0, 3 ); cvSobel( gaussian.image, gradient_y.image, 0, 1, 3 ); // find edge orientation CvSize image_size = cvGetSize( gaussian.image ); for( int i = 0; i < image_size.width; i++ ) { for( int j = 0; j < image_size.height; j++ ) { double x = cvGet2D( gradient_x.image, j, i ).val[0]; double y = cvGet2D( gradient_y.image, j, i ).val[0]; float angle; if( x == 0 ) { if( y == 0 ) angle = 0; else angle = 90; } else angle = cvFastArctan( y, x ); CvScalar g; CvScalar a; g.val[0] = cvSqrt( pow( x, 2 ) + pow( y, 2 ) ); a.val[0] = find_angle( angle ); cvSet2D( destination.image, j, i, g ); cvSet2D( orientation.image, j, i, a ); } } ImageRAII suppressed_image = nonMaxSup( destination.image, orientation.image ); ImageRAII hysteresis_image = hysteresis( suppressed_image.image, orientation.image, thresh ); cvNamedWindow( WINDOW_NAME ); cvShowImage( WINDOW_NAME, destination.image ); cvMoveWindow( WINDOW_NAME, image_size.width, 0 ); return hysteresis_image; }