/*----------------------------------------------------------------- * Core routine for msskl_filter * - suffix "np" stands for "no padding" * - assumes image is properly padded! * - does not trimm result * - assume shp already allocated * - useful inside loops *-----------------------------------------------------------------*/ AnimalExport int msskl_filter_np(Img *shp, Img *sklimg, annotated_skl *skl, int thresh) { int i,j,k; int maxrad, r, c, *pt; SEDR *sedr; unsigned d; unsigned p, pf; r = skl->skl->rows; c = skl->skl->cols; maxrad = skl->maxradius; if (thresh > 0) { sklimg = new_img(r, c); for (i=0; i < r * c; i++) sklimg->data[i] = (skl->skl->data[i] >= (puint32) thresh); } sedr = grow_sedr(maxrad); if (!sedr) return false; pt = sedr->pt; for (i=maxrad; i<shp->rows-maxrad; i++) for (j=maxrad; j<shp->cols-maxrad; j++) if ( RC(sklimg, i-maxrad, j-maxrad) == 1 ) { // found skeleton /* Paints digital circle around the skeleton with radius equal to the distance-transform value at each point. There should be a more efficient way to do this without using SEDR. */ d = RC(skl->dt, i-maxrad, j-maxrad); /* distance 0 */ RC(shp,i,j) = FG; p = 2; for (k=1; k < (int)sedr->length && sedr->sqrd_dist[k] <= d; k++) { pf = sedr->npts[k]; do { RC(shp,i + pt[p], j + pt[p+1]) = FG; p+=2; // unrolling RC(shp,i + pt[p], j + pt[p+1]) = FG; p+=2; RC(shp,i + pt[p], j + pt[p+1]) = FG; p+=2; RC(shp,i + pt[p], j + pt[p+1]) = FG; p+=2; } while (p < pf); } } return true; }
AnimalExport nhood * circular_nhood(double rad) { SEDR *s; int *dx, *dy; unsigned k, p, n, *pt; nhood *nhood; s = grow_sedr(rad); if (!s) return NULL; pt = s->pt; nhood = new_nhood( (2*ceil(rad)+1)*(2*ceil(rad)+1) ); dx = nhood->dx; dy = nhood->dy; /* -- distance 0 -- */ dy[0] = 0; dx[0] = 0; n=1; p=2; /* -- remaining distances -- */ for (k=1; k < s->length && non_negative_dbl(rad - s->distance[k]); k++) { do { dy[n] = pt[p]; dx[n++] = pt[++p]; ++p; // unrolling dy[n] = pt[p]; dx[n++] = pt[++p]; ++p; dy[n] = pt[p]; dx[n++] = pt[++p]; ++p; dy[n] = pt[p]; dx[n++] = pt[++p]; ++p; } while (p < s->npts[k]); } realloc_nhood(nhood, n); /* @@@ seria eficiente ordenar pontos na ordem "raster" */ return nhood; }
AnimalExport ann_img * exact_propagation(Img *image, ImgPUInt32 *label, list *seed, char side) { char *fname="exact_propagation"; SEDR *sedr; int maxrad, r, c, prev_col, n, rw, cl, i, j, x, y, *pt, *pi, *pf, *lut, d, cp; unsigned maxdist, k, pos; int *p; /* @@@ perhaps a register variable is faster */ ImgPUInt32 *lbl_img, *dist, *pred; puint32 *lbl_data, *dist_data, *pred_data; pixval *img_data; Img *img; list_ptr ptr; ann_img *aimg; r = image->rows; c = image->cols; /* estimate the maximum distance to grow */ if (side != INTERIOR) maxrad = ceil(hypot(r,c)); else { maxrad = (int) (ceil((float)MIN(r,c)/2)); for (n=0,i=0; i<r*c; i++) n += (image->data[i] == FG); maxrad = MIN(maxrad,(int) ceil(sqrt((double)n) / 2)); } sedr = grow_sedr(maxrad); if (!sedr) { animal_err_register (fname, ANIMAL_ERROR_FAILURE,""); return NULL; } img = impad(image, maxrad, maxrad, 0); img_data = img->data; prev_col = c; r = img->rows; c = img->cols; n=r*c; dist = new_img_puint32(r,c); dist_data = dist->data; lut = dist->lut; /* table for (r,c) indexing */ lbl_img = impad_puint32(label, maxrad, maxrad, 0); lbl_data = lbl_img->data; pred = new_img_puint32(r,c); pred_data = pred->data; /* We must mark as INVALID_DIST only those pixels that _will_ be processed by the propagation. */ switch (side) { case INTERIOR: for (i=0; i<n; i++) { pred_data[i] = prev_col*(i/c-maxrad) + i%c - maxrad; if (img_data[i] == FG && lbl_data[i] == 0) /* (**) */ dist_data[i] = INVALID_DIST; } /* OBS: condition (**) tests for lbl_data[i] == 0 because the * seed pixels don't need processing. In fact, the for loop * for the propagation starts at i=1 (distance =1), not i=0 * (distance == 0). */ break; case EXTERIOR: for (i=0; i<n; i++) { pred_data[i] = prev_col*(i/c-maxrad) + i%c - maxrad; if (img_data[i] == BG) dist_data[i] = INVALID_DIST; } break; case BOTH: for (i=0; i<n; i++) { pred_data[i] = prev_col*(i/c-maxrad) + i%c - maxrad; if (lbl_data[i] == 0) dist_data[i] = INVALID_DIST; } break; default: ANIMAL_ERR_FIRST("exact_propagation", ANIMAL_ERROR_FAILURE, "Invalid side parameter", NULL); } maxdist = (unsigned) maxrad*maxrad; /* -- distances >= 1 -- */ pt = sedr->pt; p = pt+2; for (i=1; i < (int)sedr->length && maxdist >= sedr->sqrd_dist[i]; i++) { d = (int)sedr->sqrd_dist[i]; k=1; ptr = get_list_head(seed); pi = p; pf = pt + sedr->npts[i]; do { /* loop the contour */ cp = get_list_point(ptr); x = cp % prev_col + maxrad; y = cp / prev_col + maxrad; p = pi; do { /* loop displacements with distance d */ rw = y + *p; cl = x + *(p+1); p+=2; pos = cl + lut[rw]; if (dist_data[pos] == INVALID_DIST) { dist_data[pos] = d; lbl_data[pos] = k; pred_data[pos] = cp; } /* Four-fold unroll: # of pts at any distance is a multiple of 4 */ rw = y + *p; cl = x + *(p+1); p+=2; pos = cl + lut[rw]; if (dist_data[pos] == INVALID_DIST) { dist_data[pos] = d; lbl_data[pos] = k; pred_data[pos] = cp; } rw = y + *p; cl = x + *(p+1); p+=2; pos = cl + lut[rw]; if (dist_data[pos] == INVALID_DIST) { dist_data[pos] = d; lbl_data[pos] = k; pred_data[pos] = cp; } rw = y + *p; cl = x + *(p+1); p+=2; pos = cl + lut[rw]; if (dist_data[pos] == INVALID_DIST) { dist_data[pos] = d; lbl_data[pos] = k; pred_data[pos] = cp; } } while (p < pf); k++; ptr = next_list_node(ptr); } while (not_nil(ptr)); } aimg = new_ann_img(image); for (i=maxrad; i<r-maxrad; i++) for (j=maxrad; j<c-maxrad; j++) { RC(aimg->label,i-maxrad, j-maxrad) = RC(lbl_img, i, j); RC(aimg->cost, i-maxrad, j-maxrad) = RC(dist, i, j); RC(aimg->pred, i-maxrad, j-maxrad) = RC(pred, i, j); } /* Liberate memory */ imfree(&img); imfree_puint32(&lbl_img); imfree_puint32(&dist); imfree_puint32(&pred); return aimg; }