// compute angle in most accurate manner that handles 360 degrees using 32-bit floats // compute the number of wraps that would make us closeset to the last value float FindAngle(float x, float y) { int wraps; float theta; if (fast_fabsf(x) < fast_fabsf(y)) theta = atan2f(y,x); else theta = PI_2F-atan2f(x,y); // Diff between expected position and position with no wraps // Diff nearest zero, offset by 1024 wraps to avoid requiring floor() wraps = (int)(((LastAngle-theta)+(1024.0f*TWO_PI_F+PI_F))*(1.0f/TWO_PI_F))-1024; // factor in wraparounds LastAngle=theta + wraps*TWO_PI_F; return LastAngle; }
void imlib_edge_canny(image_t *src, rectangle_t *roi, int low_thresh, int high_thresh) { int w = src->w; gvec_t *gm = fb_alloc0(roi->w*roi->h*sizeof*gm); //1. Noise Reduction with a Gaussian filter imlib_sepconv3(src, kernel_gauss_3, 1.0f/16.0f, 0.0f); //2. Finding Image Gradients for (int gy=1, y=roi->y+1; y<roi->y+roi->h-1; y++, gy++) { for (int gx=1, x=roi->x+1; x<roi->x+roi->w-1; x++, gx++) { int vx=0, vy=0; // sobel kernel in the horizontal direction vx = src->data [(y-1)*w+x-1] - src->data [(y-1)*w+x+1] + (src->data[(y+0)*w+x-1]<<1) - (src->data[(y+0)*w+x+1]<<1) + src->data [(y+1)*w+x-1] - src->data [(y+1)*w+x+1]; // sobel kernel in the vertical direction vy = src->data [(y-1)*w+x-1] + (src->data[(y-1)*w+x+0]<<1) + src->data [(y-1)*w+x+1] - src->data [(y+1)*w+x-1] - (src->data[(y+1)*w+x+0]<<1) - src->data [(y+1)*w+x+1]; // Find magnitude int g = (int) fast_sqrtf(vx*vx + vy*vy); // Find the direction and round angle to 0, 45, 90 or 135 int t = (int) fast_fabsf((atan2f(vy, vx)*180.0f/M_PI)); if (t < 22) { t = 0; } else if (t < 67) { t = 45; } else if (t < 112) { t = 90; } else if (t < 160) { t = 135; } else if (t <= 180) { t = 0; } gm[gy*roi->w+gx].t = t; gm[gy*roi->w+gx].g = g; } } // 3. Hysteresis Thresholding // 4. Non-maximum Suppression and output for (int gy=0, y=roi->y; y<roi->y+roi->h; y++, gy++) { for (int gx=0, x=roi->x; x<roi->x+roi->w; x++, gx++) { int i = y*w+x; gvec_t *va=NULL, *vb=NULL, *vc = &gm[gy*roi->w+gx]; // Clear the borders if (y == (roi->y) || y == (roi->y+roi->h-1) || x == (roi->x) || x == (roi->x+roi->w-1)) { src->data[i] = 0; continue; } if (vc->g < low_thresh) { // Not an edge src->data[i] = 0; continue; // Check if strong or weak edge } else if (vc->g >= high_thresh || gm[(gy-1)*roi->w+(gx-1)].g >= high_thresh || gm[(gy-1)*roi->w+(gx+0)].g >= high_thresh || gm[(gy-1)*roi->w+(gx+1)].g >= high_thresh || gm[(gy+0)*roi->w+(gx-1)].g >= high_thresh || gm[(gy+0)*roi->w+(gx+1)].g >= high_thresh || gm[(gy+1)*roi->w+(gx-1)].g >= high_thresh || gm[(gy+1)*roi->w+(gx+0)].g >= high_thresh || gm[(gy+1)*roi->w+(gx+1)].g >= high_thresh) { vc->g = vc->g; } else { // Not an edge src->data[i] = 0; continue; } switch (vc->t) { case 0: { va = &gm[(gy+0)*roi->w+(gx-1)]; vb = &gm[(gy+0)*roi->w+(gx+1)]; break; } case 45: { va = &gm[(gy+1)*roi->w+(gx-1)]; vb = &gm[(gy-1)*roi->w+(gx+1)]; break; } case 90: { va = &gm[(gy+1)*roi->w+(gx+0)]; vb = &gm[(gy-1)*roi->w+(gx+0)]; break; } case 135: { va = &gm[(gy+1)*roi->w+(gx+1)]; vb = &gm[(gy-1)*roi->w+(gx-1)]; break; } } if (!(vc->g > va->g && vc->g > vb->g)) { src->data[i] = 0; } else { src->data[i] = 255; } } } fb_free(); }