/*! * bilateralCreate() * * Input: pixs (8 bpp gray, no colormap) * spatial_stdev (of gaussian kernel; in pixels, > 0.5) * range_stdev (of gaussian range kernel; > 5.0; typ. 50.0) * ncomps (number of intermediate sums J(k,x); in [4 ... 30]) * reduction (1, 2 or 4) * Return: bil, or null on error * * Notes: * (1) This initializes a bilateral filtering operation, generating all * the data required. It takes most of the time in the bilateral * filtering operation. * (2) See bilateral.h for details of the algorithm. * (3) See pixBilateral() for constraints on input parameters, which * are not checked here. */ static L_BILATERAL * bilateralCreate(PIX *pixs, l_float32 spatial_stdev, l_float32 range_stdev, l_int32 ncomps, l_int32 reduction) { l_int32 w, ws, wd, h, hs, hd, i, j, k, index; l_int32 border, minval, maxval, spatial_size; l_int32 halfwidth, wpls, wplt, wpld, kval, nval, dval; l_float32 sstdev, fval1, fval2, denom, sum, norm, kern; l_int32 *nc, *kindex; l_float32 *kfract, *range, *spatial; l_uint32 *datas, *datat, *datad, *lines, *linet, *lined; L_BILATERAL *bil; PIX *pixt, *pixt2, *pixsc, *pixd; PIXA *pixac; PROCNAME("bilateralCreate"); sstdev = spatial_stdev / (l_float32) reduction; /* reduced spat. stdev */ if ((bil = (L_BILATERAL *) CALLOC(1, sizeof(L_BILATERAL))) == NULL) return (L_BILATERAL *) ERROR_PTR("bil not made", procName, NULL); bil->spatial_stdev = sstdev; bil->range_stdev = range_stdev; bil->reduction = reduction; bil->ncomps = ncomps; if (reduction == 1) { pixt = pixClone(pixs); } else if (reduction == 2) { pixt = pixScaleAreaMap2(pixs); } else { /* reduction == 4) */ pixt2 = pixScaleAreaMap2(pixs); pixt = pixScaleAreaMap2(pixt2); pixDestroy(&pixt2); } pixGetExtremeValue(pixt, 1, L_SELECT_MIN, NULL, NULL, NULL, &minval); pixGetExtremeValue(pixt, 1, L_SELECT_MAX, NULL, NULL, NULL, &maxval); bil->minval = minval; bil->maxval = maxval; border = (l_int32)(2 * sstdev + 1); pixsc = pixAddMirroredBorder(pixt, border, border, border, border); bil->pixsc = pixsc; pixDestroy(&pixt); bil->pixs = pixClone(pixs); /* -------------------------------------------------------------------- * * Generate arrays for interpolation of J(k,x): * (1.0 - kfract[.]) * J(kindex[.], x) + kfract[.] * J(kindex[.] + 1, x), * where I(x) is the index into kfract[] and kindex[], * and x is an index into the 2D image array. * -------------------------------------------------------------------- */ /* nc is the set of k values to be used in J(k,x) */ nc = (l_int32 *) CALLOC(ncomps, sizeof(l_int32)); for (i = 0; i < ncomps; i++) nc[i] = minval + i * (maxval - minval) / (ncomps - 1); bil->nc = nc; /* kindex maps from intensity I(x) to the lower k index for J(k,x) */ kindex = (l_int32 *) CALLOC(256, sizeof(l_int32)); for (i = minval, k = 0; i <= maxval && k < ncomps - 1; k++) { fval2 = nc[k + 1]; while (i < fval2) { kindex[i] = k; i++; } } kindex[maxval] = ncomps - 2; bil->kindex = kindex; /* kfract maps from intensity I(x) to the fraction of J(k+1,x) used */ kfract = (l_float32 *) CALLOC(256, sizeof(l_float32)); /* from lower */ for (i = minval, k = 0; i <= maxval && k < ncomps - 1; k++) { fval1 = nc[k]; fval2 = nc[k + 1]; while (i < fval2) { kfract[i] = (l_float32)(i - fval1) / (l_float32)(fval2 - fval1); i++; } } kfract[maxval] = 1.0; bil->kfract = kfract; #if DEBUG_BILATERAL for (i = minval; i <= maxval; i++) fprintf(stderr, "kindex[%d] = %d; kfract[%d] = %5.3f\n", i, kindex[i], i, kfract[i]); for (i = 0; i < ncomps; i++) fprintf(stderr, "nc[%d] = %d\n", i, nc[i]); #endif /* DEBUG_BILATERAL */ /* -------------------------------------------------------------------- * * Generate 1-D kernel arrays (spatial and range) * * -------------------------------------------------------------------- */ spatial_size = 2 * sstdev + 1; spatial = (l_float32 *) CALLOC(spatial_size, sizeof(l_float32)); denom = 2. * sstdev * sstdev; for (i = 0; i < spatial_size; i++) spatial[i] = expf(-(l_float32)(i * i) / denom); bil->spatial = spatial; range = (l_float32 *) CALLOC(256, sizeof(l_float32)); denom = 2. * range_stdev * range_stdev; for (i = 0; i < 256; i++) range[i] = expf(-(l_float32)(i * i) / denom); bil->range = range; /* -------------------------------------------------------------------- * * Generate principal bilateral component images * * -------------------------------------------------------------------- */ pixac = pixaCreate(ncomps); pixGetDimensions(pixsc, &ws, &hs, NULL); datas = pixGetData(pixsc); wpls = pixGetWpl(pixsc); pixGetDimensions(pixs, &w, &h, NULL); wd = (w + reduction - 1) / reduction; hd = (h + reduction - 1) / reduction; halfwidth = (l_int32)(2.0 * sstdev); for (index = 0; index < ncomps; index++) { pixt = pixCopy(NULL, pixsc); datat = pixGetData(pixt); wplt = pixGetWpl(pixt); kval = nc[index]; /* Separable convolutions: horizontal first */ for (i = 0; i < hd; i++) { lines = datas + (border + i) * wpls; linet = datat + (border + i) * wplt; for (j = 0; j < wd; j++) { sum = 0.0; norm = 0.0; for (k = -halfwidth; k <= halfwidth; k++) { nval = GET_DATA_BYTE(lines, border + j + k); kern = spatial[L_ABS(k)] * range[L_ABS(kval - nval)]; sum += kern * nval; norm += kern; } dval = (l_int32)((sum / norm) + 0.5); SET_DATA_BYTE(linet, border + j, dval); } } /* Vertical convolution */ pixd = pixCreate(wd, hd, 8); datad = pixGetData(pixd); wpld = pixGetWpl(pixd); for (i = 0; i < hd; i++) { linet = datat + (border + i) * wplt; lined = datad + i * wpld; for (j = 0; j < wd; j++) { sum = 0.0; norm = 0.0; for (k = -halfwidth; k <= halfwidth; k++) { nval = GET_DATA_BYTE(linet + k * wplt, border + j); kern = spatial[L_ABS(k)] * range[L_ABS(kval - nval)]; sum += kern * nval; norm += kern; } dval = (l_int32)((sum / norm) + 0.5); SET_DATA_BYTE(lined, j, dval); } } pixDestroy(&pixt); pixaAddPix(pixac, pixd, L_INSERT); } bil->pixac = pixac; bil->lineset = (l_uint32 ***) pixaGetLinePtrs(pixac, NULL); return bil; }
Pix* reduce2(Pix* pix){ return pixScaleAreaMap2(pix); }