Esempio n. 1
0
/*!
 *  pixBilateral()
 *
 *      Input:  pixs (8 bpp gray or 32 bpp rgb, 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: pixd (bilateral filtered image), or null on error
 *
 *  Notes:
 *      (1) This performs a relatively fast, separable bilateral
 *          filtering operation.  The time is proportional to ncomps
 *          and varies inversely approximately as the cube of the
 *          reduction factor.  See bilateral.h for algorithm details.
 *      (2) We impose minimum values for range_stdev and ncomps to
 *          avoid nasty artifacts when either are too small.  We also
 *          impose a constraint on their product:
 *               ncomps * range_stdev >= 100.
 *          So for values of range_stdev >= 25, ncomps can be as small as 4.
 *          Here is a qualitative, intuitive explanation for this constraint.
 *          Call the difference in k values between the J(k) == 'delta', where
 *              'delta' ~ 200 / ncomps
 *          Then this constraint is roughly equivalent to the condition:
 *              'delta' < 2 * range_stdev
 *          Note that at an intensity difference of (2 * range_stdev), the
 *          range part of the kernel reduces the effect by the factor 0.14.
 *          This constraint requires that we have a sufficient number of
 *          PCBs (i.e, a small enough 'delta'), so that for any value of
 *          image intensity I, there exists a k (and a PCB, J(k), such that
 *              |I - k| < range_stdev
 *          Any fewer PCBs and we don't have enough to support this condition.
 *      (3) The upper limit of 30 on ncomps is imposed because the
 *          gain in accuracy is not worth the extra computation.
 *      (4) The size of the gaussian kernel is twice the spatial_stdev
 *          on each side of the origin.  The minimum value of
 *          spatial_stdev, 0.5, is required to have a finite sized
 *          spatial kernel.  In practice, a much larger value is used.
 *      (5) Computation of the intermediate images goes inversely
 *          as the cube of the reduction factor.  If you can use a
 *          reduction of 2 or 4, it is well-advised.
 *      (6) The range kernel is defined over the absolute value of pixel
 *          grayscale differences, and hence must have size 256 x 1.
 *          Values in the array represent the multiplying weight
 *          depending on the absolute gray value difference between
 *          the source pixel and the neighboring pixel, and should
 *          be monotonically decreasing.
 *      (7) Interesting observation.  Run this on prog/fish24.jpg, with
 *          range_stdev = 60, ncomps = 6, and spatial_dev = {10, 30, 50}.
 *          As spatial_dev gets larger, we get the counter-intuitive
 *          result that the body of the red fish becomes less blurry.
 */
PIX *
pixBilateral(PIX       *pixs,
             l_float32  spatial_stdev,
             l_float32  range_stdev,
             l_int32    ncomps,
             l_int32    reduction)
{
l_int32       d;
l_float32     sstdev;  /* scaled spatial stdev */
PIX          *pixt, *pixr, *pixg, *pixb, *pixd;

    PROCNAME("pixBilateral");

    if (!pixs || pixGetColormap(pixs))
        return (PIX *)ERROR_PTR("pixs not defined or cmapped", procName, NULL);
    d = pixGetDepth(pixs);
    if (d != 8 && d != 32)
        return (PIX *)ERROR_PTR("pixs not 8 or 32 bpp", procName, NULL);
    if (reduction != 1 && reduction != 2 && reduction != 4)
        return (PIX *)ERROR_PTR("reduction invalid", procName, NULL);
    sstdev = spatial_stdev / (l_float32)reduction;  /* reduced spat. stdev */
    if (sstdev < 0.5)
        return (PIX *)ERROR_PTR("sstdev < 0.5", procName, NULL);
    if (range_stdev <= 5.0)
        return (PIX *)ERROR_PTR("range_stdev <= 5.0", procName, NULL);
    if (ncomps < 4 || ncomps > 30)
        return (PIX *)ERROR_PTR("ncomps not in [4 ... 30]", procName, NULL);
    if (ncomps * range_stdev < 100.0)
        return (PIX *)ERROR_PTR("ncomps * range_stdev < 100.0", procName, NULL);

    if (d == 8)
        return pixBilateralGray(pixs, spatial_stdev, range_stdev,
                                ncomps, reduction);

    pixt = pixGetRGBComponent(pixs, COLOR_RED);
    pixr = pixBilateralGray(pixt, spatial_stdev, range_stdev, ncomps,
                            reduction);
    pixDestroy(&pixt);
    pixt = pixGetRGBComponent(pixs, COLOR_GREEN);
    pixg = pixBilateralGray(pixt, spatial_stdev, range_stdev, ncomps,
                            reduction);
    pixDestroy(&pixt);
    pixt = pixGetRGBComponent(pixs, COLOR_BLUE);
    pixb = pixBilateralGray(pixt, spatial_stdev, range_stdev, ncomps,
                            reduction);
    pixDestroy(&pixt);
    pixd = pixCreateRGBImage(pixr, pixg, pixb);
    pixDestroy(&pixr);
    pixDestroy(&pixg);
    pixDestroy(&pixb);
    return pixd;
}
Esempio n. 2
0
/*!
 *  pixApplyFilter()
 *
 *      Input:  pix (8 or 32 bpp; or 2, 4 or 8 bpp with colormap)
 *              dpix (filter)
 *              outflag (L_CLIP_TO_ZERO, L_TAKE_ABSVAL,
 *                       L_THRESH_NEG_TO_BLACK or L_THRESH_NEG_TO_WHITE)
 *      Return: pixd, or null on error
 *
 *  Notes:
 *      (1) Apply the input filter to pix by multiplying it for the
 *          Fourier transform of pix. The inverse Fourier transform
 *          is then used on the result to return the filtered image.
 *      (2) If pix is 32 bpp RGB, the filter is applied to each color
 *          channel separately.
 *      (3) If colormapped, remove to grayscale.
 */
PIX *
pixApplyFilter(PIX     *pixs,
			   DPIX    *dpix,
			   l_int32  outflag)
{
	l_int32	 w, h, d;
	PIX     *pixt, *pixd, *pixr, *pixrc, *pixg, *pixgc, *pixb, *pixbc;
	
	PROCNAME("pixApplyFilter");
	
    if (!pixs && !dpix)
        return (PIX *)ERROR_PTR("pixs or dpix not defined", procName, NULL);
	
	/* Remove colormap if necessary */
	pixGetDimensions(pixs, &w, &h, &d);
    if ((d == 2 || d == 4 || d == 8) && pixGetColormap(pixs)) {
        L_WARNING("pix has colormap; removing", procName);
        pixt = pixRemoveColormap(pixs, REMOVE_CMAP_BASED_ON_SRC);
        d = pixGetDepth(pixt);
    }
    else
        pixt = pixClone(pixs);
	
    if (d != 8 && d != 32) {
        pixDestroy(&pixt);
        return (PIX *)ERROR_PTR("depth not 8 or 32 bpp", procName, NULL);
    }
	
	if (d == 8) {
		pixd = pixApplyFilterGray(pixt, dpix, outflag);
	}
	else { /* d == 32 */
		pixr = pixGetRGBComponent(pixt, COLOR_RED);
        pixrc = pixApplyFilterGray(pixr, dpix, outflag);
        pixDestroy(&pixr);
        pixg = pixGetRGBComponent(pixt, COLOR_GREEN);
        pixgc = pixApplyFilterGray(pixg, dpix, outflag);
        pixDestroy(&pixg);
        pixb = pixGetRGBComponent(pixt, COLOR_BLUE);
        pixbc = pixApplyFilterGray(pixb, dpix, outflag);
        pixDestroy(&pixb);
        pixd = pixCreateRGBImage(pixrc, pixgc, pixbc);
        pixDestroy(&pixrc);
        pixDestroy(&pixgc);
        pixDestroy(&pixbc);
	}
	
	pixDestroy(&pixt);
	return pixd;
}
Esempio n. 3
0
/*!
 *  pixBilateralExact()
 *
 *      Input:  pixs (8 bpp gray or 32 bpp rgb)
 *              spatial_kel  (gaussian kernel)
 *              range_kel (<optional> 256 x 1, monotonically decreasing)
 *      Return: pixd (8 bpp bilateral filtered image)
 *
 *  Notes:
 *      (1) The spatial_kel is a conventional smoothing kernel, typically a
 *          2-d Gaussian kernel or other block kernel.  It can be either
 *          normalized or not, but must be everywhere positive.
 *      (2) The range_kel is defined over the absolute value of pixel
 *          grayscale differences, and hence must have size 256 x 1.
 *          Values in the array represent the multiplying weight for each
 *          gray value difference between the target pixel and center of the
 *          kernel, and should be monotonically decreasing.
 *      (3) If range_kel == NULL, a constant weight is applied regardless
 *          of the range value difference.  This degenerates to a regular
 *          pixConvolve() with a normalized kernel.
 */
PIX *
pixBilateralExact(PIX       *pixs,
                  L_KERNEL  *spatial_kel,
                  L_KERNEL  *range_kel)
{
l_int32  d;
PIX     *pixt, *pixr, *pixg, *pixb, *pixd;

    PROCNAME("pixBilateralExact");
    if (!pixs)
        return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
    if (pixGetColormap(pixs) != NULL)
        return (PIX *)ERROR_PTR("pixs is cmapped", procName, NULL);
    d = pixGetDepth(pixs);
    if (d != 8 && d != 32)
        return (PIX *)ERROR_PTR("pixs not 8 or 32 bpp", procName, NULL);
    if (!spatial_kel)
        return (PIX *)ERROR_PTR("spatial_ke not defined", procName, NULL);

    if (d == 8) {
        return pixBilateralGrayExact(pixs, spatial_kel, range_kel);
    } else {  /* d == 32 */
        pixt = pixGetRGBComponent(pixs, COLOR_RED);
        pixr = pixBilateralGrayExact(pixt, spatial_kel, range_kel);
        pixDestroy(&pixt);
        pixt = pixGetRGBComponent(pixs, COLOR_GREEN);
        pixg = pixBilateralGrayExact(pixt, spatial_kel, range_kel);
        pixDestroy(&pixt);
        pixt = pixGetRGBComponent(pixs, COLOR_BLUE);
        pixb = pixBilateralGrayExact(pixt, spatial_kel, range_kel);
        pixDestroy(&pixt);
        pixd = pixCreateRGBImage(pixr, pixg, pixb);

        pixDestroy(&pixr);
        pixDestroy(&pixg);
        pixDestroy(&pixb);
        return pixd;
    }
}
Esempio n. 4
0
/*!
 *  pixRankFilterRGB()
 *
 *      Input:  pixs (32 bpp)
 *              wf, hf  (width and height of filter; each is >= 1)
 *              rank (in [0.0 ... 1.0])
 *      Return: pixd (of rank values), or null on error
 *
 *  Notes:
 *      (1) This defines, for each pixel in pixs, a neighborhood of
 *          pixels given by a rectangle "centered" on the pixel.
 *          This set of wf*hf pixels has a distribution of values.
 *          For each component, if the values are sorted in increasing
 *          order, we choose the component such that rank*(wf*hf-1)
 *          pixels have a lower or equal value and
 *          (1-rank)*(wf*hf-1) pixels have an equal or greater value.
 *      (2) Apply gray rank filtering to each component independently.
 *      (3) See notes in pixRankFilterGray() for further details.
 */
PIX  *
pixRankFilterRGB(PIX       *pixs,
                 l_int32    wf,
                 l_int32    hf,
                 l_float32  rank)
{
PIX  *pixr, *pixg, *pixb, *pixrf, *pixgf, *pixbf, *pixd;

    PROCNAME("pixRankFilterRGB");

    if (!pixs)
        return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
    if (pixGetDepth(pixs) != 32)
        return (PIX *)ERROR_PTR("pixs not 32 bpp", procName, NULL);
    if (wf < 1 || hf < 1)
        return (PIX *)ERROR_PTR("wf < 1 || hf < 1", procName, NULL);
    if (rank < 0.0 || rank > 1.0)
        return (PIX *)ERROR_PTR("rank must be in [0.0, 1.0]", procName, NULL);
    if (wf == 1 && hf == 1)   /* no-op */
        return pixCopy(NULL, pixs);

    pixr = pixGetRGBComponent(pixs, COLOR_RED);
    pixg = pixGetRGBComponent(pixs, COLOR_GREEN);
    pixb = pixGetRGBComponent(pixs, COLOR_BLUE);

    pixrf = pixRankFilterGray(pixr, wf, hf, rank);
    pixgf = pixRankFilterGray(pixg, wf, hf, rank);
    pixbf = pixRankFilterGray(pixb, wf, hf, rank);

    pixd = pixCreateRGBImage(pixrf, pixgf, pixbf);
    pixDestroy(&pixr);
    pixDestroy(&pixg);
    pixDestroy(&pixb);
    pixDestroy(&pixrf);
    pixDestroy(&pixgf);
    pixDestroy(&pixbf);
    return pixd;
}
Esempio n. 5
0
/*!
 *  pixColorMorph()
 *
 *      Input:  pixs
 *              type  (L_MORPH_DILATE, L_MORPH_ERODE, L_MORPH_OPEN,
 *                     or L_MORPH_CLOSE)
 *              hsize  (of Sel; must be odd; origin implicitly in center)
 *              vsize  (ditto)
 *      Return: pixd
 *
 *  Notes:
 *      (1) This does the morph operation on each component separately,
 *          and recombines the result.
 *      (2) Sel is a brick with all elements being hits.
 *      (3) If hsize = vsize = 1, just returns a copy.
 */
PIX *
pixColorMorph(PIX     *pixs,
              l_int32  type,
              l_int32  hsize,
              l_int32  vsize)
{
PIX  *pixr, *pixg, *pixb, *pixrm, *pixgm, *pixbm, *pixd;

    PROCNAME("pixColorMorph");

    if (!pixs)
        return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
    if (pixGetDepth(pixs) != 32)
        return (PIX *)ERROR_PTR("pixs not 32 bpp", procName, NULL);
    if (type != L_MORPH_DILATE && type != L_MORPH_ERODE &&
        type != L_MORPH_OPEN && type != L_MORPH_CLOSE)
        return (PIX *)ERROR_PTR("invalid morph type", procName, NULL);
    if (hsize < 1 || vsize < 1)
        return (PIX *)ERROR_PTR("hsize or vsize < 1", procName, NULL);
    if ((hsize & 1) == 0 ) {
        L_WARNING("horiz sel size must be odd; increasing by 1", procName);
        hsize++;
    }
    if ((vsize & 1) == 0 ) {
        L_WARNING("vert sel size must be odd; increasing by 1", procName);
        vsize++;
    }

    if (hsize == 1 && vsize == 1)
        return pixCopy(NULL, pixs);

    pixr = pixGetRGBComponent(pixs, COLOR_RED);
    pixg = pixGetRGBComponent(pixs, COLOR_GREEN);
    pixb = pixGetRGBComponent(pixs, COLOR_BLUE);
    if (type == L_MORPH_DILATE) {
        pixrm = pixDilateGray(pixr, hsize, vsize);
        pixgm = pixDilateGray(pixg, hsize, vsize);
        pixbm = pixDilateGray(pixb, hsize, vsize);
    }
    else if (type == L_MORPH_ERODE) {
        pixrm = pixErodeGray(pixr, hsize, vsize);
        pixgm = pixErodeGray(pixg, hsize, vsize);
        pixbm = pixErodeGray(pixb, hsize, vsize);
    }
    else if (type == L_MORPH_OPEN) {
        pixrm = pixOpenGray(pixr, hsize, vsize);
        pixgm = pixOpenGray(pixg, hsize, vsize);
        pixbm = pixOpenGray(pixb, hsize, vsize);
    }
    else {   /* type == L_MORPH_CLOSE */
        pixrm = pixCloseGray(pixr, hsize, vsize);
        pixgm = pixCloseGray(pixg, hsize, vsize);
        pixbm = pixCloseGray(pixb, hsize, vsize);
    }
    pixd = pixCreateRGBImage(pixrm, pixgm, pixbm);
    pixDestroy(&pixr);
    pixDestroy(&pixrm);
    pixDestroy(&pixg);
    pixDestroy(&pixgm);
    pixDestroy(&pixb);
    pixDestroy(&pixbm);

    return pixd;
}
Esempio n. 6
0
/*!
 *  pixLocToColorTransform()
 *
 *      Input:   pixs (1 bpp)
 *      Return:  pixd (32 bpp rgb), or null on error
 *
 *  Notes:
 *      (1) This generates an RGB image where each component value
 *          is coded depending on the (x.y) location and the size
 *          of the fg connected component that the pixel in pixs belongs to.
 *          It is independent of the 4-fold orthogonal orientation, and
 *          only weakly depends on translations and small angle rotations.
 *          Background pixels are black.
 *      (2) Such encodings can be compared between two 1 bpp images
 *          by performing this transform and calculating the
 *          "earth-mover" distance on the resulting R,G,B histograms.
 */
PIX *
pixLocToColorTransform(PIX  *pixs)
{
l_int32    w, h, w2, h2, wpls, wplr, wplg, wplb, wplcc, i, j, rval, gval, bval;
l_float32  invw2, invh2;
l_uint32  *datas, *datar, *datag, *datab, *datacc;
l_uint32  *lines, *liner, *lineg, *lineb, *linecc;
PIX       *pix1, *pixcc, *pixr, *pixg, *pixb, *pixd;

    PROCNAME("pixLocToColorTransform");

    if (!pixs || pixGetDepth(pixs) != 1)
        return (PIX *)ERROR_PTR("pixs undefined or not 1 bpp", procName, NULL);

        /* Label each pixel with the area of the c.c. to which it belongs.
         * Clip the result to 255 in an 8 bpp pix. This is used for
         * the blue component of pixd.  */
    pixGetDimensions(pixs, &w, &h, NULL);
    w2 = w / 2;
    h2 = h / 2;
    invw2 = 255.0 / (l_float32)w2;
    invh2 = 255.0 / (l_float32)h2;
    pix1 = pixConnCompAreaTransform(pixs, 8);
    pixcc = pixConvert16To8(pix1, L_CLIP_TO_255);
    pixDestroy(&pix1);

        /* Label the red and green components depending on the location
         * of the fg pixels, in a way that is 4-fold rotationally invariant. */
    pixr = pixCreate(w, h, 8);
    pixg = pixCreate(w, h, 8);
    pixb = pixCreate(w, h, 8);
    wpls = pixGetWpl(pixs);
    wplr = pixGetWpl(pixr);
    wplg = pixGetWpl(pixg);
    wplb = pixGetWpl(pixb);
    wplcc = pixGetWpl(pixcc);
    datas = pixGetData(pixs);
    datar = pixGetData(pixr);
    datag = pixGetData(pixg);
    datab = pixGetData(pixb);
    datacc = pixGetData(pixcc);
    for (i = 0; i < h; i++) {
        lines = datas + i * wpls;
        liner = datar + i * wplr;
        lineg = datag + i * wplg;
        lineb = datab + i * wplb;
        linecc = datacc+ i * wplcc;
        for (j = 0; j < w; j++) {
            if (GET_DATA_BIT(lines, j) == 0) continue;
            if (w < h) {
                rval = invh2 * L_ABS((l_float32)(i - h2));
                gval = invw2 * L_ABS((l_float32)(j - w2));
            } else {
                rval = invw2 * L_ABS((l_float32)(j - w2));
                gval = invh2 * L_ABS((l_float32)(i - h2));
            }
            bval = GET_DATA_BYTE(linecc, j);
            SET_DATA_BYTE(liner, j, rval);
            SET_DATA_BYTE(lineg, j, gval);
            SET_DATA_BYTE(lineb, j, bval);
        }
    }
    pixd = pixCreateRGBImage(pixr, pixg, pixb);

    pixDestroy(&pixcc);
    pixDestroy(&pixr);
    pixDestroy(&pixg);
    pixDestroy(&pixb);
    return pixd;
}