Leptonica 1.68
C Image Processing Library

pix3.c

Go to the documentation of this file.
00001 /*====================================================================*
00002  -  Copyright (C) 2001 Leptonica.  All rights reserved.
00003  -  This software is distributed in the hope that it will be
00004  -  useful, but with NO WARRANTY OF ANY KIND.
00005  -  No author or distributor accepts responsibility to anyone for the
00006  -  consequences of using this software, or for whether it serves any
00007  -  particular purpose or works at all, unless he or she says so in
00008  -  writing.  Everyone is granted permission to copy, modify and
00009  -  redistribute this source code, for commercial or non-commercial
00010  -  purposes, with the following restrictions: (1) the origin of this
00011  -  source code must not be misrepresented; (2) modified versions must
00012  -  be plainly marked as such; and (3) this notice may not be removed
00013  -  or altered from any source or modified source distribution.
00014  *====================================================================*/
00015 
00016 /*
00017  *  pix3.c
00018  *
00019  *    This file has these operations:
00020  *
00021  *      (1) Mask-directed operations
00022  *      (2) Full-image bit-logical operations
00023  *      (3) Foreground pixel counting operations on 1 bpp images
00024  *      (4) Sum of pixel values
00025  *      (5) Mirrored tiling of a smaller image
00026  *
00027  *
00028  *    Masked operations
00029  *           l_int32     pixSetMasked()
00030  *           l_int32     pixSetMaskedGeneral()
00031  *           l_int32     pixCombineMasked()
00032  *           l_int32     pixCombineMaskedGeneral()
00033  *           l_int32     pixPaintThroughMask()
00034  *           PIX        *pixPaintSelfThroughMask()
00035  *           PIX        *pixMakeMaskFromLUT()
00036  *           PIX        *pixSetUnderTransparency()
00037  *
00038  *    One and two-image boolean operations on arbitrary depth images
00039  *           PIX        *pixInvert()
00040  *           PIX        *pixOr()
00041  *           PIX        *pixAnd()
00042  *           PIX        *pixXor()
00043  *           PIX        *pixSubtract()
00044  *
00045  *    Foreground pixel counting in 1 bpp images
00046  *           l_int32     pixZero()
00047  *           l_int32     pixCountPixels()
00048  *           NUMA       *pixaCountPixels()
00049  *           l_int32     pixCountPixelsInRow()
00050  *           NUMA       *pixCountPixelsByRow()
00051  *           NUMA       *pixCountPixelsByColumn()
00052  *           NUMA       *pixSumPixelsByRow()
00053  *           NUMA       *pixSumPixelsByColumn()
00054  *           l_int32     pixThresholdPixelSum()
00055  *           l_int32    *makePixelSumTab8()
00056  *           l_int32    *makePixelCentroidTab8()
00057  *
00058  *    Sum of pixel values
00059  *           l_int32     pixSumPixelValues()
00060  *
00061  *    Mirrored tiling
00062  *           PIX        *pixMirroredTiling()
00063  *
00064  *    Static helper function
00065  *           static l_int32  findTilePatchCenter()
00066  */
00067 
00068 #include <stdio.h>
00069 #include <stdlib.h>
00070 #include <string.h>
00071 #include "allheaders.h"
00072 
00073 static l_int32 findTilePatchCenter(PIX *pixs, BOX *box, l_int32 dir,
00074                                    l_uint32 targdist, l_uint32 *pdist,
00075                                    l_int32 *pxc, l_int32 *pyc);
00076 
00077 #ifndef  NO_CONSOLE_IO
00078 #define   EQUAL_SIZE_WARNING      0
00079 #endif  /* ~NO_CONSOLE_IO */
00080 
00081 
00082 /*-------------------------------------------------------------*
00083  *                        Masked operations                    *
00084  *-------------------------------------------------------------*/
00085 /*!
00086  *  pixSetMasked()
00087  *
00088  *      Input:  pixd (1, 2, 4, 8, 16 or 32 bpp; or colormapped)
00089  *              pixm (<optional> 1 bpp mask; no operation if NULL)
00090  *              val (value to set at each masked pixel)
00091  *      Return: 0 if OK; 1 on error
00092  *
00093  *  Notes:
00094  *      (1) In-place operation.
00095  *      (2) NOTE: For cmapped images, this calls pixSetMaskedCmap().
00096  *          @val must be the 32-bit color representation of the RGB pixel.
00097  *          It is not the index into the colormap!
00098  *      (2) If pixm == NULL, a warning is given.
00099  *      (3) This is an implicitly aligned operation, where the UL
00100  *          corners of pixd and pixm coincide.  A warning is
00101  *          issued if the two image sizes differ significantly,
00102  *          but the operation proceeds.
00103  *      (4) Each pixel in pixd that co-locates with an ON pixel
00104  *          in pixm is set to the specified input value.
00105  *          Other pixels in pixd are not changed.
00106  *      (5) You can visualize this as painting the color through
00107  *          the mask, as a stencil.
00108  *      (6) If you do not want to have the UL corners aligned,
00109  *          use the function pixSetMaskedGeneral(), which requires
00110  *          you to input the UL corner of pixm relative to pixd.
00111  *      (7) Implementation details: see comments in pixPaintThroughMask()
00112  *          for when we use rasterop to do the painting.
00113  */
00114 l_int32
00115 pixSetMasked(PIX      *pixd,
00116              PIX      *pixm,
00117              l_uint32  val)
00118 {
00119 l_int32    wd, hd, wm, hm, w, h, d, wpld, wplm;
00120 l_int32    i, j, rval, gval, bval;
00121 l_uint32  *datad, *datam, *lined, *linem;
00122 
00123     PROCNAME("pixSetMasked");
00124 
00125     if (!pixd)
00126         return ERROR_INT("pixd not defined", procName, 1);
00127     if (!pixm) {
00128         L_WARNING("no mask; nothing to do", procName);
00129         return 0;
00130     }
00131     if (pixGetColormap(pixd)) {
00132         extractRGBValues(val, &rval, &gval, &bval);
00133         return pixSetMaskedCmap(pixd, pixm, 0, 0, rval, gval, bval);
00134     }
00135 
00136     if (pixGetDepth(pixm) != 1)
00137         return ERROR_INT("pixm not 1 bpp", procName, 1);
00138     d = pixGetDepth(pixd);
00139     if (d == 1)
00140         val &= 1;
00141     else if (d == 2)
00142         val &= 3;
00143     else if (d == 4)
00144         val &= 0x0f;
00145     else if (d == 8)
00146         val &= 0xff;
00147     else if (d == 16)
00148         val &= 0xffff;
00149     else if (d != 32)
00150         return ERROR_INT("pixd not 1, 2, 4, 8, 16 or 32 bpp", procName, 1);
00151     pixGetDimensions(pixm, &wm, &hm, NULL);
00152 
00153         /* If d == 1, use rasterop; it's about 25x faster */
00154     if (d == 1) {
00155         if (val == 0) {
00156             PIX *pixmi = pixInvert(NULL, pixm);
00157             pixRasterop(pixd, 0, 0, wm, hm, PIX_MASK, pixmi, 0, 0);
00158             pixDestroy(&pixmi);
00159         }
00160         else  /* val == 1 */
00161             pixRasterop(pixd, 0, 0, wm, hm, PIX_PAINT, pixm, 0, 0);
00162         return 0;
00163     }
00164     
00165         /* For d < 32, use rasterop for val == 0 (black); ~3x faster. */
00166     if (d < 32 && val == 0) {
00167         PIX *pixmd = pixUnpackBinary(pixm, d, 1);
00168         pixRasterop(pixd, 0, 0, wm, hm, PIX_MASK, pixmd, 0, 0);
00169         pixDestroy(&pixmd);
00170         return 0;
00171     }
00172 
00173         /* For d < 32, use rasterop for val == maxval (white); ~3x faster. */
00174     if (d < 32 && val == ((1 << d) - 1)) {
00175         PIX *pixmd = pixUnpackBinary(pixm, d, 0);
00176         pixRasterop(pixd, 0, 0, wm, hm, PIX_PAINT, pixmd, 0, 0);
00177         pixDestroy(&pixmd);
00178         return 0;
00179     }
00180 
00181     pixGetDimensions(pixd, &wd, &hd, &d);
00182     w = L_MIN(wd, wm);
00183     h = L_MIN(hd, hm);
00184     if (L_ABS(wd - wm) > 7 || L_ABS(hd - hm) > 7)  /* allow a small tolerance */
00185         L_WARNING("pixd and pixm sizes differ", procName);
00186 
00187     datad = pixGetData(pixd);
00188     datam = pixGetData(pixm);
00189     wpld = pixGetWpl(pixd);
00190     wplm = pixGetWpl(pixm);
00191     for (i = 0; i < h; i++) {
00192         lined = datad + i * wpld;
00193         linem = datam + i * wplm;
00194         for (j = 0; j < w; j++) {
00195             if (GET_DATA_BIT(linem, j)) {
00196                 switch(d)
00197                 {
00198                 case 2:
00199                     SET_DATA_DIBIT(lined, j, val);
00200                     break;
00201                 case 4:
00202                     SET_DATA_QBIT(lined, j, val);
00203                     break;
00204                 case 8:
00205                     SET_DATA_BYTE(lined, j, val);
00206                     break;
00207                 case 16:
00208                     SET_DATA_TWO_BYTES(lined, j, val);
00209                     break;
00210                 case 32:
00211                     *(lined + j) = val;
00212                     break;
00213                 default:
00214                     return ERROR_INT("shouldn't get here", procName, 1);
00215                 }
00216             }
00217         }
00218     }
00219 
00220     return 0;
00221 }
00222 
00223 
00224 /*!
00225  *  pixSetMaskedGeneral()
00226  *
00227  *      Input:  pixd (8, 16 or 32 bpp)
00228  *              pixm (<optional> 1 bpp mask; no operation if null)
00229  *              val (value to set at each masked pixel)
00230  *              x, y (location of UL corner of pixm relative to pixd;
00231  *                    can be negative)
00232  *      Return: 0 if OK; 1 on error
00233  *
00234  *  Notes:
00235  *      (1) This is an in-place operation.
00236  *      (2) Alignment is explicit.  If you want the UL corners of
00237  *          the two images to be aligned, use pixSetMasked().
00238  *      (3) A typical use would be painting through the foreground
00239  *          of a small binary mask pixm, located somewhere on a
00240  *          larger pixd.  Other pixels in pixd are not changed.
00241  *      (4) You can visualize this as painting the color through
00242  *          the mask, as a stencil.
00243  *      (5) This uses rasterop to handle clipping and different depths of pixd.
00244  *      (6) If pixd has a colormap, you should call pixPaintThroughMask().
00245  *      (7) Why is this function here, if pixPaintThroughMask() does the
00246  *          same thing, and does it more generally?  I've retained it here
00247  *          to show how one can paint through a mask using only full
00248  *          image rasterops, rather than pixel peeking in pixm and poking
00249  *          in pixd.  It's somewhat baroque, but I found it amusing.
00250  */
00251 l_int32
00252 pixSetMaskedGeneral(PIX      *pixd,
00253                     PIX      *pixm,
00254                     l_uint32  val,
00255                     l_int32   x,
00256                     l_int32   y)
00257 {
00258 l_int32    wm, hm, d;
00259 PIX       *pixmu, *pixc;
00260 
00261     PROCNAME("pixSetMaskedGeneral");
00262 
00263     if (!pixd)
00264         return ERROR_INT("pixd not defined", procName, 1);
00265     if (!pixm)  /* nothing to do */
00266         return 0;
00267 
00268     d = pixGetDepth(pixd);
00269     if (d != 8 && d != 16 && d != 32)
00270         return ERROR_INT("pixd not 8, 16 or 32 bpp", procName, 1);
00271     if (pixGetDepth(pixm) != 1)
00272         return ERROR_INT("pixm not 1 bpp", procName, 1);
00273 
00274         /* Unpack binary to depth d, with inversion:  1 --> 0, 0 --> 0xff... */
00275     if ((pixmu = pixUnpackBinary(pixm, d, 1)) == NULL)
00276         return ERROR_INT("pixmu not made", procName, 1);
00277 
00278         /* Clear stenciled pixels in pixd */
00279     pixGetDimensions(pixm, &wm, &hm, NULL);
00280     pixRasterop(pixd, x, y, wm, hm, PIX_SRC & PIX_DST, pixmu, 0, 0);
00281 
00282         /* Generate image with requisite color */
00283     if ((pixc = pixCreateTemplate(pixmu)) == NULL)
00284         return ERROR_INT("pixc not made", procName, 1);
00285     pixSetAllArbitrary(pixc, val);
00286 
00287         /* Invert stencil mask, and paint color color into stencil */
00288     pixInvert(pixmu, pixmu);
00289     pixAnd(pixmu, pixmu, pixc);
00290 
00291         /* Finally, repaint stenciled pixels, with val, in pixd */
00292     pixRasterop(pixd, x, y, wm, hm, PIX_SRC | PIX_DST, pixmu, 0, 0);
00293 
00294     pixDestroy(&pixmu);
00295     pixDestroy(&pixc);
00296     return 0;
00297 }
00298 
00299 
00300 /*!
00301  *  pixCombineMasked()
00302  *
00303  *      Input:  pixd (1 bpp, 8 bpp gray or 32 bpp rgb; no cmap)
00304  *              pixs (1 bpp, 8 bpp gray or 32 bpp rgb; no cmap)
00305  *              pixm (<optional> 1 bpp mask; no operation if NULL)
00306  *      Return: 0 if OK; 1 on error
00307  *
00308  *  Notes:
00309  *      (1) In-place operation; pixd is changed.
00310  *      (2) This sets each pixel in pixd that co-locates with an ON
00311  *          pixel in pixm to the corresponding value of pixs.
00312  *      (3) pixs and pixd must be the same depth and not colormapped.
00313  *      (4) All three input pix are aligned at the UL corner, and the
00314  *          operation is clipped to the intersection of all three images.
00315  *      (5) If pixm == NULL, it's a no-op.
00316  *      (6) Implementation: see notes in pixCombineMaskedGeneral().
00317  *          For 8 bpp selective masking, you might guess that it
00318  *          would be faster to generate an 8 bpp version of pixm,
00319  *          using pixConvert1To8(pixm, 0, 255), and then use a
00320  *          general combine operation
00321  *               d = (d & ~m) | (s & m)
00322  *          on a word-by-word basis.  Not always.  The word-by-word
00323  *          combine takes a time that is independent of the mask data.
00324  *          If the mask is relatively sparse, the byte-check method
00325  *          is actually faster!
00326  */
00327 l_int32
00328 pixCombineMasked(PIX  *pixd,
00329                  PIX  *pixs,
00330                  PIX  *pixm)
00331 {
00332 l_int32    w, h, d, ws, hs, ds, wm, hm, dm, wmin, hmin;
00333 l_int32    wpl, wpls, wplm, i, j, val;
00334 l_uint32  *data, *datas, *datam, *line, *lines, *linem;
00335 PIX       *pixt;
00336 
00337     PROCNAME("pixCombineMasked");
00338 
00339     if (!pixm)  /* nothing to do */
00340         return 0;
00341     if (!pixd)
00342         return ERROR_INT("pixd not defined", procName, 1);
00343     if (!pixs)
00344         return ERROR_INT("pixs not defined", procName, 1);
00345     pixGetDimensions(pixd, &w, &h, &d);
00346     pixGetDimensions(pixs, &ws, &hs, &ds);
00347     pixGetDimensions(pixm, &wm, &hm, &dm);
00348     if (d != ds)
00349         return ERROR_INT("pixs and pixd depths differ", procName, 1);
00350     if (dm != 1)
00351         return ERROR_INT("pixm not 1 bpp", procName, 1);
00352     if (d != 1 && d != 8 && d != 32)
00353         return ERROR_INT("pixd not 1, 8 or 32 bpp", procName, 1);
00354     if (pixGetColormap(pixd) || pixGetColormap(pixs))
00355         return ERROR_INT("pixs and/or pixd is cmapped", procName, 1);
00356 
00357         /* For d = 1, use rasterop.  pixt is the part from pixs, under
00358          * the fg of pixm, that is to be combined with pixd.  We also
00359          * use pixt to remove all fg of pixd that is under the fg of pixm.
00360          * Then pixt and pixd are combined by ORing. */
00361     wmin = L_MIN(w, L_MIN(ws, wm));
00362     hmin = L_MIN(h, L_MIN(hs, hm));
00363     if (d == 1) {
00364         pixt = pixAnd(NULL, pixs, pixm);
00365         pixRasterop(pixd, 0, 0, wmin, hmin, PIX_DST & PIX_NOT(PIX_SRC),
00366                     pixm, 0, 0);
00367         pixRasterop(pixd, 0, 0, wmin, hmin, PIX_SRC | PIX_DST, pixt, 0, 0);
00368         pixDestroy(&pixt);
00369         return 0;
00370     }
00371 
00372     data = pixGetData(pixd);
00373     datas = pixGetData(pixs);
00374     datam = pixGetData(pixm);
00375     wpl = pixGetWpl(pixd);
00376     wpls = pixGetWpl(pixs);
00377     wplm = pixGetWpl(pixm);
00378     if (d == 8) {
00379         for (i = 0; i < hmin; i++) {
00380             line = data + i * wpl;
00381             lines = datas + i * wpls;
00382             linem = datam + i * wplm;
00383             for (j = 0; j < wmin; j++) {
00384                 if (GET_DATA_BIT(linem, j)) {
00385                    val = GET_DATA_BYTE(lines, j);
00386                    SET_DATA_BYTE(line, j, val);
00387                 }
00388             }
00389         }
00390     }
00391     else {  /* d == 32 */
00392         for (i = 0; i < hmin; i++) {
00393             line = data + i * wpl;
00394             lines = datas + i * wpls;
00395             linem = datam + i * wplm;
00396             for (j = 0; j < wmin; j++) {
00397                 if (GET_DATA_BIT(linem, j))
00398                    line[j] = lines[j];
00399             }
00400         }
00401     }
00402 
00403     return 0;
00404 }
00405 
00406 
00407 /*!
00408  *  pixCombineMaskedGeneral()
00409  *
00410  *      Input:  pixd (1 bpp, 8 bpp gray or 32 bpp rgb)
00411  *              pixs (1 bpp, 8 bpp gray or 32 bpp rgb)
00412  *              pixm (<optional> 1 bpp mask)
00413  *              x, y (origin of pixs and pixm relative to pixd; can be negative)
00414  *      Return: 0 if OK; 1 on error
00415  *
00416  *  Notes:
00417  *      (1) In-place operation; pixd is changed.
00418  *      (2) This is a generalized version of pixCombinedMasked(), where
00419  *          the source and mask can be placed at the same (arbitrary)
00420  *          location relative to pixd.
00421  *      (3) pixs and pixd must be the same depth and not colormapped.
00422  *      (4) The UL corners of both pixs and pixm are aligned with
00423  *          the point (x, y) of pixd, and the operation is clipped to
00424  *          the intersection of all three images.
00425  *      (5) If pixm == NULL, it's a no-op.
00426  *      (6) Implementation.  There are two ways to do these.  In the first,
00427  *          we use rasterop, ORing the part of pixs under the mask
00428  *          with pixd (which has been appropriately cleared there first).
00429  *          In the second, the mask is used one pixel at a time to
00430  *          selectively replace pixels of pixd with those of pixs.
00431  *          Here, we use rasterop for 1 bpp and pixel-wise replacement
00432  *          for 8 and 32 bpp.  To use rasterop for 8 bpp, for example,
00433  *          we must first generate an 8 bpp version of the mask.
00434  *          The code is simple:
00435  *
00436  *             Pix *pixm8 = pixConvert1To8(NULL, pixm, 0, 255);
00437  *             Pix *pixt = pixAnd(NULL, pixs, pixm8);
00438  *             pixRasterop(pixd, x, y, wmin, hmin, PIX_DST & PIX_NOT(PIX_SRC),
00439  *                         pixm8, 0, 0);
00440  *             pixRasterop(pixd, x, y, wmin, hmin, PIX_SRC | PIX_DST,
00441  *                         pixt, 0, 0);
00442  *             pixDestroy(&pixt);
00443  *             pixDestroy(&pixm8);
00444  */
00445 l_int32
00446 pixCombineMaskedGeneral(PIX      *pixd,
00447                         PIX      *pixs,
00448                         PIX      *pixm,
00449                         l_int32   x,
00450                         l_int32   y)
00451 {
00452 l_int32    d, w, h, ws, hs, ds, wm, hm, dm, wmin, hmin;
00453 l_int32    wpl, wpls, wplm, i, j, val;
00454 l_uint32  *data, *datas, *datam, *line, *lines, *linem;
00455 PIX       *pixt;
00456 
00457     PROCNAME("pixCombineMaskedGeneral");
00458 
00459     if (!pixm)  /* nothing to do */
00460         return 0;
00461     if (!pixd)
00462         return ERROR_INT("pixd not defined", procName, 1);
00463     if (!pixs)
00464         return ERROR_INT("pixs not defined", procName, 1);
00465     pixGetDimensions(pixd, &w, &h, &d);
00466     pixGetDimensions(pixs, &ws, &hs, &ds);
00467     pixGetDimensions(pixm, &wm, &hm, &dm);
00468     if (d != ds)
00469         return ERROR_INT("pixs and pixd depths differ", procName, 1);
00470     if (dm != 1)
00471         return ERROR_INT("pixm not 1 bpp", procName, 1);
00472     if (d != 1 && d != 8 && d != 32)
00473         return ERROR_INT("pixd not 1, 8 or 32 bpp", procName, 1);
00474     if (pixGetColormap(pixd) || pixGetColormap(pixs))
00475         return ERROR_INT("pixs and/or pixd is cmapped", procName, 1);
00476 
00477         /* For d = 1, use rasterop.  pixt is the part from pixs, under
00478          * the fg of pixm, that is to be combined with pixd.  We also
00479          * use pixt to remove all fg of pixd that is under the fg of pixm.
00480          * Then pixt and pixd are combined by ORing. */
00481     wmin = L_MIN(ws, wm);
00482     hmin = L_MIN(hs, hm);
00483     if (d == 1) {
00484         pixt = pixAnd(NULL, pixs, pixm);
00485         pixRasterop(pixd, x, y, wmin, hmin, PIX_DST & PIX_NOT(PIX_SRC),
00486                     pixm, 0, 0);
00487         pixRasterop(pixd, x, y, wmin, hmin, PIX_SRC | PIX_DST, pixt, 0, 0);
00488         pixDestroy(&pixt);
00489         return 0;
00490     }
00491 
00492     wpl = pixGetWpl(pixd);
00493     data = pixGetData(pixd);
00494     wpls = pixGetWpl(pixs);
00495     datas = pixGetData(pixs);
00496     wplm = pixGetWpl(pixm);
00497     datam = pixGetData(pixm);
00498 
00499     for (i = 0; i < hmin; i++) {
00500         if (y + i < 0 || y + i >= h) continue;
00501         line = data + (y + i) * wpl;
00502         lines = datas + i * wpls;
00503         linem = datam + i * wplm;
00504         for (j = 0; j < wmin; j++) {
00505             if (x + j < 0 || x + j >= w) continue;
00506             if (GET_DATA_BIT(linem, j)) {
00507                 switch (d)
00508                 {
00509                 case 8:
00510                     val = GET_DATA_BYTE(lines, j);
00511                     SET_DATA_BYTE(line, x + j, val);
00512                     break;
00513                 case 32:
00514                     *(line + x + j) = *(lines + j);
00515                     break;
00516                 default:
00517                     return ERROR_INT("shouldn't get here", procName, 1);
00518                 }
00519             }
00520         }
00521     }
00522 
00523     return 0;
00524 }
00525 
00526 
00527 /*!
00528  *  pixPaintThroughMask()
00529  *
00530  *      Input:  pixd (1, 2, 4, 8, 16 or 32 bpp; or colormapped)
00531  *              pixm (<optional> 1 bpp mask)
00532  *              x, y (origin of pixm relative to pixd; can be negative)
00533  *              val (pixel value to set at each masked pixel)
00534  *      Return: 0 if OK; 1 on error
00535  *
00536  *  Notes:
00537  *      (1) In-place operation.  Calls pixSetMaskedCmap() for colormapped
00538  *          images.
00539  *      (2) For 1, 2, 4, 8 and 16 bpp gray, we take the appropriate
00540  *          number of least significant bits of val.
00541  *      (3) If pixm == NULL, it's a no-op.
00542  *      (4) The mask origin is placed at (x,y) on pixd, and the
00543  *          operation is clipped to the intersection of rectangles.
00544  *      (5) For rgb, the components in val are in the canonical locations,
00545  *          with red in location COLOR_RED, etc.
00546  *      (6) Implementation detail 1:
00547  *          For painting with val == 0 or val == maxval, you can use rasterop.
00548  *          If val == 0, invert the mask so that it's 0 over the region
00549  *          into which you want to write, and use PIX_SRC & PIX_DST to
00550  *          clear those pixels.  To write with val = maxval (all 1's),
00551  *          use PIX_SRC | PIX_DST to set all bits under the mask.
00552  *      (7) Implementation detail 2:
00553  *          The rasterop trick can be used for depth > 1 as well.
00554  *          For val == 0, generate the mask for depth d from the binary
00555  *          mask using
00556  *              pixmd = pixUnpackBinary(pixm, d, 1);
00557  *          and use pixRasterop() with PIX_MASK.  For val == maxval,
00558  *              pixmd = pixUnpackBinary(pixm, d, 0);
00559  *          and use pixRasterop() with PIX_PAINT.
00560  *          But note that if d == 32 bpp, it is about 3x faster to use
00561  *          the general implementation (not pixRasterop()).
00562  *      (8) Implementation detail 3:
00563  *          It might be expected that the switch in the inner loop will
00564  *          cause large branching delays and should be avoided.
00565  *          This is not the case, because the entrance is always the
00566  *          same and the compiler can correctly predict the jump.
00567  */
00568 l_int32
00569 pixPaintThroughMask(PIX      *pixd,
00570                     PIX      *pixm,
00571                     l_int32   x,
00572                     l_int32   y,
00573                     l_uint32  val)
00574 {
00575 l_int32    d, w, h, wm, hm, wpl, wplm, i, j, rval, gval, bval;
00576 l_uint32  *data, *datam, *line, *linem;
00577 
00578     PROCNAME("pixPaintThroughMask");
00579 
00580     if (!pixd)
00581         return ERROR_INT("pixd not defined", procName, 1);
00582     if (!pixm)  /* nothing to do */
00583         return 0;
00584     if (pixGetColormap(pixd)) {
00585         extractRGBValues(val, &rval, &gval, &bval);
00586         return pixSetMaskedCmap(pixd, pixm, x, y, rval, gval, bval);
00587     }
00588 
00589     if (pixGetDepth(pixm) != 1)
00590         return ERROR_INT("pixm not 1 bpp", procName, 1);
00591     d = pixGetDepth(pixd);
00592     if (d == 1)
00593         val &= 1;
00594     else if (d == 2)
00595         val &= 3;
00596     else if (d == 4)
00597         val &= 0x0f;
00598     else if (d == 8)
00599         val &= 0xff;
00600     else if (d == 16)
00601         val &= 0xffff;
00602     else if (d != 32)
00603         return ERROR_INT("pixd not 1, 2, 4, 8, 16 or 32 bpp", procName, 1);
00604     pixGetDimensions(pixm, &wm, &hm, NULL);
00605 
00606         /* If d == 1, use rasterop; it's about 25x faster. */
00607     if (d == 1) {
00608         if (val == 0) {
00609             PIX *pixmi = pixInvert(NULL, pixm);
00610             pixRasterop(pixd, x, y, wm, hm, PIX_MASK, pixmi, 0, 0);
00611             pixDestroy(&pixmi);
00612         }
00613         else  /* val == 1 */
00614             pixRasterop(pixd, x, y, wm, hm, PIX_PAINT, pixm, 0, 0);
00615         return 0;
00616     }
00617     
00618         /* For d < 32, use rasterop if val == 0 (black); ~3x faster. */
00619     if (d < 32 && val == 0) {
00620         PIX *pixmd = pixUnpackBinary(pixm, d, 1);
00621         pixRasterop(pixd, x, y, wm, hm, PIX_MASK, pixmd, 0, 0);
00622         pixDestroy(&pixmd);
00623         return 0;
00624     }
00625 
00626         /* For d < 32, use rasterop if val == maxval (white); ~3x faster. */
00627     if (d < 32 && val == ((1 << d) - 1)) {
00628         PIX *pixmd = pixUnpackBinary(pixm, d, 0);
00629         pixRasterop(pixd, x, y, wm, hm, PIX_PAINT, pixmd, 0, 0);
00630         pixDestroy(&pixmd);
00631         return 0;
00632     }
00633 
00634         /* All other cases */
00635     pixGetDimensions(pixd, &w, &h, NULL);
00636     wpl = pixGetWpl(pixd);
00637     data = pixGetData(pixd);
00638     wplm = pixGetWpl(pixm);
00639     datam = pixGetData(pixm);
00640     for (i = 0; i < hm; i++) {
00641         if (y + i < 0 || y + i >= h) continue;
00642         line = data + (y + i) * wpl;
00643         linem = datam + i * wplm;
00644         for (j = 0; j < wm; j++) {
00645             if (x + j < 0 || x + j >= w) continue;
00646             if (GET_DATA_BIT(linem, j)) {
00647                 switch (d)
00648                 {
00649                 case 2:
00650                     SET_DATA_DIBIT(line, x + j, val);
00651                     break;
00652                 case 4:
00653                     SET_DATA_QBIT(line, x + j, val);
00654                     break;
00655                 case 8:
00656                     SET_DATA_BYTE(line, x + j, val);
00657                     break;
00658                 case 16:
00659                     SET_DATA_TWO_BYTES(line, x + j, val);
00660                     break;
00661                 case 32:
00662                     *(line + x + j) = val;
00663                     break;
00664                 default:
00665                     return ERROR_INT("shouldn't get here", procName, 1);
00666                 }
00667             }
00668         }
00669     }
00670 
00671     return 0;
00672 }
00673     
00674 
00675 /*!
00676  *  pixPaintSelfThroughMask()
00677  *
00678  *      Input:  pixd (8 bpp gray or 32 bpp rgb; not colormapped)
00679  *              pixm (1 bpp mask)
00680  *              x, y (origin of pixm relative to pixd; must not be negative)
00681  *              tilesize (requested size for tiling)
00682  *              searchdir (L_HORIZ, L_VERT)
00683  *      Return: 0 if OK; 1 on error
00684  *
00685  *  Notes:
00686  *      (1) In-place operation; pixd is changed.
00687  *      (2) If pixm == NULL, it's a no-op.
00688  *      (3) The mask origin is placed at (x,y) on pixd, and the
00689  *          operation is clipped to the intersection of pixd and the
00690  *          fg of the mask.
00691  *      (4) The tilesize is the the requested size for tiling.  The
00692  *          actual size for each c.c. will be bounded by the minimum
00693  *          dimension of the c.c. and the distance at which the tile
00694  *          center is located.
00695  *      (5) searchdir is the direction with respect to the b.b. of each
00696  *          mask component, from which the square patch is chosen and
00697  *          tiled onto the image, clipped by the mask component.
00698  *      (6) Specifically, a mirrored tiling, generated from pixd,
00699  *          is used to construct the pixels that are painted onto
00700  *          pixd through pixm.
00701  */
00702 l_int32
00703 pixPaintSelfThroughMask(PIX      *pixd,
00704                         PIX      *pixm,
00705                         l_int32   x,
00706                         l_int32   y,
00707                         l_int32   tilesize,
00708                         l_int32   searchdir)
00709 {
00710 l_int32   w, h, d, wm, hm, dm, i, n, xc, yc, bx, by, bw, bh;
00711 l_int32   depth, cctilesize;
00712 l_uint32  dist, minside, retval;
00713 BOX      *box, *boxt;
00714 BOXA     *boxa;
00715 PIX      *pix, *pixf, *pixdf, *pixt, *pixc;
00716 PIXA     *pixa;
00717 
00718     PROCNAME("pixPaintSelfThroughMask");
00719 
00720     if (!pixm)  /* nothing to do */
00721         return 0;
00722     if (!pixd)
00723         return ERROR_INT("pixd not defined", procName, 1);
00724     if (pixGetColormap(pixd) != NULL)
00725         return ERROR_INT("pixd has colormap", procName, 1);
00726     pixGetDimensions(pixd, &w, &h, &d);
00727     if (d != 8 && d != 32)
00728         return ERROR_INT("pixd not 8 or 32 bpp", procName, 1);
00729     pixGetDimensions(pixm, &wm, &hm, &dm);
00730     if (dm != 1)
00731         return ERROR_INT("pixm not 1 bpp", procName, 1);
00732     if (x < 0 || y < 0)
00733         return ERROR_INT("x and y must be non-negative", procName, 1);
00734     if (tilesize < 1)
00735         return ERROR_INT("tilesize must be >= 1", procName, 1);
00736     if (searchdir != L_HORIZ && searchdir != L_VERT)
00737         return ERROR_INT("searchdir not in {L_HORIZ, L_VERT}", procName, 1);
00738 
00739         /* Embed mask in full sized mask */
00740     if (wm < w || hm < h) {
00741         pixf = pixCreate(w, h, 1);
00742         pixRasterop(pixf, x, y, wm, hm, PIX_SRC, pixm, 0, 0);
00743     }
00744     else
00745         pixf = pixCopy(NULL, pixm);
00746 
00747         /* Get connected components of mask */
00748     boxa = pixConnComp(pixf, &pixa, 8);
00749     if ((n = pixaGetCount(pixa)) == 0) {
00750         L_WARNING("no fg in mask", procName);
00751         pixDestroy(&pixf);
00752         pixaDestroy(&pixa);
00753         boxaDestroy(&boxa);
00754         return 1;
00755     }
00756 
00757         /* Get distance function for the mask */
00758     pixInvert(pixf, pixf);
00759     depth = (tilesize < 256) ? 8 : 16;
00760     pixdf = pixDistanceFunction(pixf, 4, depth, L_BOUNDARY_BG);
00761     pixDestroy(&pixf);
00762 
00763         /* For each c.c., generate a representative tile for texturizing
00764          * and apply it through the mask.  The input 'tilesize' is the
00765          * requested value.  findTilePatchCenter() returns the distance
00766          * at which this patch can safely be found. */
00767     retval = 0;
00768     for (i = 0; i < n; i++) {
00769         pix = pixaGetPix(pixa, i, L_CLONE);
00770         box = pixaGetBox(pixa, i, L_CLONE);
00771         boxGetGeometry(box, &bx, &by, &bw, &bh);
00772         minside = L_MIN(bw, bh);
00773 
00774         findTilePatchCenter(pixdf, box, searchdir, L_MIN(minside, tilesize),
00775                             &dist, &xc, &yc);
00776         cctilesize = L_MIN(tilesize, dist);  /* for this c.c. */
00777         if (cctilesize < 1) {
00778             L_WARNING("region not found!", procName);
00779             pixDestroy(&pix);
00780             boxDestroy(&box);
00781             retval = 1;
00782             continue;
00783         }
00784 
00785             /* Extract the selected square from pixd, and generate 
00786              * an image the size of the b.b. of the c.c., which
00787              * is then painted through the c.c. mask.  */
00788         boxt = boxCreate(L_MAX(0, xc - dist / 2), L_MAX(0, yc - dist / 2),
00789                          cctilesize, cctilesize);
00790         pixt = pixClipRectangle(pixd, boxt, NULL);
00791         pixc = pixMirroredTiling(pixt, bw, bh);
00792         pixCombineMaskedGeneral(pixd, pixc, pix, bx, by);
00793         pixDestroy(&pix);
00794         pixDestroy(&pixt);
00795         pixDestroy(&pixc);
00796         boxDestroy(&box);
00797         boxDestroy(&boxt);
00798     }
00799 
00800     pixDestroy(&pixdf);
00801     pixaDestroy(&pixa);
00802     boxaDestroy(&boxa);
00803     return retval;
00804 }
00805 
00806 
00807 /*!
00808  *  pixMakeMaskFromLUT()
00809  *
00810  *      Input:  pixs (2, 4 or 8 bpp; can be colormapped)
00811  *              tab (256-entry LUT; 1 means to write to mask)
00812  *      Return: pixd (1 bpp mask), or null on error
00813  *
00814  *  Notes:
00815  *      (1) This generates a 1 bpp mask image, where a 1 is written in
00816  *          the mask for each pixel in pixs that has a value corresponding
00817  *          to a 1 in the LUT.
00818  *      (2) The LUT should be of size 256.
00819  */
00820 PIX *
00821 pixMakeMaskFromLUT(PIX      *pixs,
00822                    l_int32  *tab)
00823 {
00824 l_int32    w, h, d, i, j, val, wpls, wpld;
00825 l_uint32  *datas, *datad, *lines, *lined;
00826 PIX       *pixd;
00827 
00828     PROCNAME("pixMakeMaskFromLUT");
00829 
00830     if (!pixs)
00831         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00832     if (!tab)
00833         return (PIX *)ERROR_PTR("tab not defined", procName, NULL);
00834     pixGetDimensions(pixs, &w, &h, &d);
00835     if (d != 2 && d != 4 && d != 8)
00836         return (PIX *)ERROR_PTR("pix not 2, 4 or 8 bpp", procName, NULL);
00837 
00838     pixd = pixCreate(w, h, 1);
00839     datas = pixGetData(pixs);
00840     datad = pixGetData(pixd);
00841     wpls = pixGetWpl(pixs);
00842     wpld = pixGetWpl(pixd);
00843     for (i = 0; i < h; i++) {
00844         lines = datas + i * wpls;
00845         lined = datad + i * wpld;
00846         for (j = 0; j < w; j++) {
00847             if (d == 2)
00848                 val = GET_DATA_DIBIT(lines, j);
00849             else if (d == 4)
00850                 val = GET_DATA_QBIT(lines, j);
00851             else  /* d == 8 */
00852                 val = GET_DATA_BYTE(lines, j);
00853             if (tab[val] == 1)
00854                 SET_DATA_BIT(lined, j);
00855         }
00856     }
00857 
00858     return pixd;
00859 }
00860 
00861 
00862 /*!
00863  *  pixSetUnderTransparency()
00864  *
00865  *      Input:  pixs (32 bpp rgba)
00866  *              val (32 bit unsigned color to use where alpha == 0)
00867  *              debugflag (generates intermediate images)
00868  *      Return: pixd (32 bpp rgba), or null on error
00869  *
00870  *  Notes:
00871  *      (1) This is one of the few operations in leptonica that uses
00872  *          the alpha blending component in rgba images.  It sets
00873  *          the r, g and b components under every fully transparent alpha
00874  *          component to @val.
00875  *      (2) Full transparency is denoted by alpha == 0.  By setting
00876  *          all pixels to @val where alpha == 0, this can improve
00877  *          compressibility by reducing the entropy.
00878  *      (3) The visual result depends on how the image is displayed.
00879  *          (a) For display devices that respect the use of the alpha
00880  *              layer, this will not affect the appearance.
00881  *          (b) For typical leptonica operations, alpha is ignored,
00882  *              so there will be a change in appearance because this
00883  *              resets the rgb values in the fully transparent region.
00884  *      (4) For reading and writing rgba pix in png format, use
00885  *          pixReadRGBAPng() and pixWriteRGBAPng().
00886  *      (5) For example, if you want to rewrite all fully transparent
00887  *          pixels in a png file to white:
00888  *              pixs = pixReadRGBAPng(<infile>);  // special read
00889  *              pixd = pixSetUnderTransparency(pixs, 0xffffff00, 0);
00890  *          Then either use a normal write if you won't be using transparency:
00891  *              pixWrite(<outfile>, pixd, IFF_PNG);
00892  *          or an RGBA write if you want to preserve the transparency layer
00893  *              pixWriteRGBAPng(<outfile>, pixd);  // special write
00894  *      (6) Caution.  Because rgb images in leptonica typically
00895  *          have value 0 in the alpha channel, this function would
00896  *          interpret the entire image as fully transparent, and set
00897  *          every pixel to @val.  Because this is not desirable, instead
00898  *          we issue a warning and return a copy of the input pix.
00899  *          If you really want to set every pixel to the same value,
00900  *          use pixSetAllArbitrary().
00901  */
00902 PIX *
00903 pixSetUnderTransparency(PIX      *pixs,
00904                         l_uint32  val,
00905                         l_int32   debugflag)
00906 {
00907 l_int32   isblack, rval, gval, bval;
00908 PIX      *pixr, *pixg, *pixb, *pixalpha, *pixm, *pixt, *pixd;
00909 PIXA     *pixa;
00910 
00911     PROCNAME("pixSetUnderTransparency");
00912 
00913     if (!pixs || pixGetDepth(pixs) != 32)
00914         return (PIX *)ERROR_PTR("pixs not defined or not 32 bpp",
00915                                 procName, NULL);
00916 
00917     pixalpha = pixGetRGBComponent(pixs, L_ALPHA_CHANNEL);
00918     pixZero(pixalpha, &isblack);
00919     if (isblack) {
00920         L_WARNING(
00921             "alpha channel is fully transparent; likely invalid; ignoring",
00922             procName);
00923         pixDestroy(&pixalpha);
00924         return pixCopy(NULL, pixs);
00925     }
00926     pixr = pixGetRGBComponent(pixs, COLOR_RED);
00927     pixg = pixGetRGBComponent(pixs, COLOR_GREEN);
00928     pixb = pixGetRGBComponent(pixs, COLOR_BLUE);
00929 
00930         /* Make a mask from the alpha component with ON pixels
00931          * wherever the alpha component is fully transparent (0).
00932          * One can do this:
00933          *     l_int32 *lut = (l_int32 *)CALLOC(256, sizeof(l_int32));
00934          *     lut[0] = 1;
00935          *     pixm = pixMakeMaskFromLUT(pixalpha, lut);
00936          *     FREE(lut);
00937          * But there's an easier way to set pixels in a mask where
00938          * the alpha component is 0 ...  */
00939     pixm = pixThresholdToBinary(pixalpha, 1);
00940 
00941     if (debugflag) {
00942         pixa = pixaCreate(0);
00943         pixSaveTiled(pixs, pixa, 1, 1, 20, 32);
00944         pixSaveTiled(pixm, pixa, 1, 0, 20, 0);
00945         pixSaveTiled(pixr, pixa, 1, 1, 20, 0);
00946         pixSaveTiled(pixg, pixa, 1, 0, 20, 0);
00947         pixSaveTiled(pixb, pixa, 1, 0, 20, 0);
00948         pixSaveTiled(pixalpha, pixa, 1, 0, 20, 0);
00949     }
00950 
00951         /* Clean each component and reassemble */
00952     extractRGBValues(val, &rval, &gval, &bval);
00953     pixSetMasked(pixr, pixm, rval);
00954     pixSetMasked(pixg, pixm, gval);
00955     pixSetMasked(pixb, pixm, bval);
00956     pixd = pixCreateRGBImage(pixr, pixg, pixb);
00957     pixSetRGBComponent(pixd, pixalpha, L_ALPHA_CHANNEL);
00958 
00959     if (debugflag) {
00960         pixSaveTiled(pixr, pixa, 1, 1, 20, 0);
00961         pixSaveTiled(pixg, pixa, 1, 0, 20, 0);
00962         pixSaveTiled(pixb, pixa, 1, 0, 20, 0);
00963         pixSaveTiled(pixd, pixa, 1, 1, 20, 0);
00964         pixt = pixaDisplay(pixa, 0, 0);
00965         pixWriteTempfile("/tmp", "rgb.png", pixt, IFF_PNG, NULL);
00966         pixDestroy(&pixt);
00967         pixaDestroy(&pixa);
00968     }
00969 
00970     pixDestroy(&pixr);
00971     pixDestroy(&pixg);
00972     pixDestroy(&pixb);
00973     pixDestroy(&pixm);
00974     pixDestroy(&pixalpha);
00975     return pixd;
00976 }
00977 
00978 
00979 /*-------------------------------------------------------------*
00980  *    One and two-image boolean ops on arbitrary depth images  *
00981  *-------------------------------------------------------------*/
00982 /*!
00983  *  pixInvert()
00984  *
00985  *      Input:  pixd  (<optional>; this can be null, equal to pixs,
00986  *                     or different from pixs)
00987  *              pixs
00988  *      Return: pixd, or null on error
00989  *
00990  *  Notes:
00991  *      (1) This inverts pixs, for all pixel depths.
00992  *      (2) There are 3 cases:
00993  *           (a) pixd == null,   ~src --> new pixd
00994  *           (b) pixd == pixs,   ~src --> src  (in-place)
00995  *           (c) pixd != pixs,   ~src --> input pixd
00996  *      (3) For clarity, if the case is known, use these patterns:
00997  *           (a) pixd = pixInvert(NULL, pixs);
00998  *           (b) pixInvert(pixs, pixs);
00999  *           (c) pixInvert(pixd, pixs);
01000  */
01001 PIX *
01002 pixInvert(PIX  *pixd,
01003           PIX  *pixs)
01004 {
01005     PROCNAME("pixInvert");
01006 
01007     if (!pixs)
01008         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
01009 
01010         /* Prepare pixd for in-place operation */
01011     if ((pixd = pixCopy(pixd, pixs)) == NULL)
01012         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
01013 
01014     pixRasterop(pixd, 0, 0, pixGetWidth(pixd), pixGetHeight(pixd),
01015                 PIX_NOT(PIX_DST), NULL, 0, 0);   /* invert pixd */
01016 
01017     return pixd;
01018 }
01019 
01020 
01021 /*!
01022  *  pixOr()
01023  *
01024  *      Input:  pixd  (<optional>; this can be null, equal to pixs1,
01025  *                     different from pixs1)
01026  *              pixs1 (can be == pixd)
01027  *              pixs2 (must be != pixd)
01028  *      Return: pixd always
01029  *
01030  *  Notes:
01031  *      (1) This gives the union of two images with equal depth,
01032  *          aligning them to the the UL corner.  pixs1 and pixs2
01033  *          need not have the same width and height.
01034  *      (2) There are 3 cases:
01035  *            (a) pixd == null,   (src1 | src2) --> new pixd
01036  *            (b) pixd == pixs1,  (src1 | src2) --> src1  (in-place)
01037  *            (c) pixd != pixs1,  (src1 | src2) --> input pixd
01038  *      (3) For clarity, if the case is known, use these patterns:
01039  *            (a) pixd = pixOr(NULL, pixs1, pixs2);
01040  *            (b) pixOr(pixs1, pixs1, pixs2);
01041  *            (c) pixOr(pixd, pixs1, pixs2);
01042  *      (4) The size of the result is determined by pixs1.
01043  *      (5) The depths of pixs1 and pixs2 must be equal.
01044  *      (6) Note carefully that the order of pixs1 and pixs2 only matters
01045  *          for the in-place case.  For in-place, you must have
01046  *          pixd == pixs1.  Setting pixd == pixs2 gives an incorrect
01047  *          result: the copy puts pixs1 image data in pixs2, and
01048  *          the rasterop is then between pixs2 and pixs2 (a no-op).
01049  */
01050 PIX *
01051 pixOr(PIX  *pixd,
01052       PIX  *pixs1,
01053       PIX  *pixs2)
01054 {
01055     PROCNAME("pixOr");
01056 
01057     if (!pixs1)
01058         return (PIX *)ERROR_PTR("pixs1 not defined", procName, pixd);
01059     if (!pixs2)
01060         return (PIX *)ERROR_PTR("pixs2 not defined", procName, pixd);
01061     if (pixd == pixs2)
01062         return (PIX *)ERROR_PTR("cannot have pixs2 == pixd", procName, pixd);
01063     if (pixGetDepth(pixs1) != pixGetDepth(pixs2))
01064         return (PIX *)ERROR_PTR("depths of pixs* unequal", procName, pixd);
01065 
01066 #if  EQUAL_SIZE_WARNING
01067     if (!pixSizesEqual(pixs1, pixs2))
01068         L_WARNING("pixs1 and pixs2 not equal sizes", procName);
01069 #endif  /* EQUAL_SIZE_WARNING */
01070 
01071         /* Prepare pixd to be a copy of pixs1 */
01072     if ((pixd = pixCopy(pixd, pixs1)) == NULL)
01073         return (PIX *)ERROR_PTR("pixd not made", procName, pixd);
01074 
01075         /* src1 | src2 --> dest */
01076     pixRasterop(pixd, 0, 0, pixGetWidth(pixd), pixGetHeight(pixd),
01077                 PIX_SRC | PIX_DST, pixs2, 0, 0);
01078 
01079     return pixd;
01080 }
01081 
01082 
01083 /*!
01084  *  pixAnd()
01085  *
01086  *      Input:  pixd  (<optional>; this can be null, equal to pixs1,
01087  *                     different from pixs1)
01088  *              pixs1 (can be == pixd)
01089  *              pixs2 (must be != pixd)
01090  *      Return: pixd always
01091  *
01092  *  Notes:
01093  *      (1) This gives the intersection of two images with equal depth,
01094  *          aligning them to the the UL corner.  pixs1 and pixs2 
01095  *          need not have the same width and height.
01096  *      (2) There are 3 cases:
01097  *            (a) pixd == null,   (src1 & src2) --> new pixd
01098  *            (b) pixd == pixs1,  (src1 & src2) --> src1  (in-place)
01099  *            (c) pixd != pixs1,  (src1 & src2) --> input pixd
01100  *      (3) For clarity, if the case is known, use these patterns:
01101  *            (a) pixd = pixAnd(NULL, pixs1, pixs2);
01102  *            (b) pixAnd(pixs1, pixs1, pixs2);
01103  *            (c) pixAnd(pixd, pixs1, pixs2);
01104  *      (4) The size of the result is determined by pixs1.
01105  *      (5) The depths of pixs1 and pixs2 must be equal.
01106  *      (6) Note carefully that the order of pixs1 and pixs2 only matters
01107  *          for the in-place case.  For in-place, you must have
01108  *          pixd == pixs1.  Setting pixd == pixs2 gives an incorrect
01109  *          result: the copy puts pixs1 image data in pixs2, and
01110  *          the rasterop is then between pixs2 and pixs2 (a no-op).
01111  */
01112 PIX *
01113 pixAnd(PIX  *pixd,
01114        PIX  *pixs1,
01115        PIX  *pixs2)
01116 {
01117     PROCNAME("pixAnd");
01118 
01119     if (!pixs1)
01120         return (PIX *)ERROR_PTR("pixs1 not defined", procName, pixd);
01121     if (!pixs2)
01122         return (PIX *)ERROR_PTR("pixs2 not defined", procName, pixd);
01123     if (pixd == pixs2)
01124         return (PIX *)ERROR_PTR("cannot have pixs2 == pixd", procName, pixd);
01125     if (pixGetDepth(pixs1) != pixGetDepth(pixs2))
01126         return (PIX *)ERROR_PTR("depths of pixs* unequal", procName, pixd);
01127 
01128 #if  EQUAL_SIZE_WARNING
01129     if (!pixSizesEqual(pixs1, pixs2))
01130         L_WARNING("pixs1 and pixs2 not equal sizes", procName);
01131 #endif  /* EQUAL_SIZE_WARNING */
01132 
01133         /* Prepare pixd to be a copy of pixs1 */
01134     if ((pixd = pixCopy(pixd, pixs1)) == NULL)
01135         return (PIX *)ERROR_PTR("pixd not made", procName, pixd);
01136 
01137         /* src1 & src2 --> dest */
01138     pixRasterop(pixd, 0, 0, pixGetWidth(pixd), pixGetHeight(pixd),
01139                 PIX_SRC & PIX_DST, pixs2, 0, 0);
01140 
01141     return pixd;
01142 }
01143 
01144 
01145 /*!
01146  *  pixXor()
01147  *
01148  *      Input:  pixd  (<optional>; this can be null, equal to pixs1,
01149  *                     different from pixs1)
01150  *              pixs1 (can be == pixd)
01151  *              pixs2 (must be != pixd)
01152  *      Return: pixd always
01153  *
01154  *  Notes:
01155  *      (1) This gives the XOR of two images with equal depth,
01156  *          aligning them to the the UL corner.  pixs1 and pixs2
01157  *          need not have the same width and height.
01158  *      (2) There are 3 cases:
01159  *            (a) pixd == null,   (src1 ^ src2) --> new pixd
01160  *            (b) pixd == pixs1,  (src1 ^ src2) --> src1  (in-place)
01161  *            (c) pixd != pixs1,  (src1 ^ src2) --> input pixd
01162  *      (3) For clarity, if the case is known, use these patterns:
01163  *            (a) pixd = pixXor(NULL, pixs1, pixs2);
01164  *            (b) pixXor(pixs1, pixs1, pixs2);
01165  *            (c) pixXor(pixd, pixs1, pixs2);
01166  *      (4) The size of the result is determined by pixs1.
01167  *      (5) The depths of pixs1 and pixs2 must be equal.
01168  *      (6) Note carefully that the order of pixs1 and pixs2 only matters
01169  *          for the in-place case.  For in-place, you must have
01170  *          pixd == pixs1.  Setting pixd == pixs2 gives an incorrect
01171  *          result: the copy puts pixs1 image data in pixs2, and
01172  *          the rasterop is then between pixs2 and pixs2 (a no-op).
01173  */
01174 PIX *
01175 pixXor(PIX  *pixd,
01176        PIX  *pixs1,
01177        PIX  *pixs2)
01178 {
01179     PROCNAME("pixXor");
01180 
01181     if (!pixs1)
01182         return (PIX *)ERROR_PTR("pixs1 not defined", procName, pixd);
01183     if (!pixs2)
01184         return (PIX *)ERROR_PTR("pixs2 not defined", procName, pixd);
01185     if (pixd == pixs2)
01186         return (PIX *)ERROR_PTR("cannot have pixs2 == pixd", procName, pixd);
01187     if (pixGetDepth(pixs1) != pixGetDepth(pixs2))
01188         return (PIX *)ERROR_PTR("depths of pixs* unequal", procName, pixd);
01189 
01190 #if  EQUAL_SIZE_WARNING
01191     if (!pixSizesEqual(pixs1, pixs2))
01192         L_WARNING("pixs1 and pixs2 not equal sizes", procName);
01193 #endif  /* EQUAL_SIZE_WARNING */
01194 
01195         /* Prepare pixd to be a copy of pixs1 */
01196     if ((pixd = pixCopy(pixd, pixs1)) == NULL)
01197         return (PIX *)ERROR_PTR("pixd not made", procName, pixd);
01198 
01199         /* src1 ^ src2 --> dest */
01200     pixRasterop(pixd, 0, 0, pixGetWidth(pixd), pixGetHeight(pixd),
01201                 PIX_SRC ^ PIX_DST, pixs2, 0, 0);
01202 
01203     return pixd;
01204 }
01205 
01206 
01207 /*!
01208  *  pixSubtract()
01209  *
01210  *      Input:  pixd  (<optional>; this can be null, equal to pixs1,
01211  *                     equal to pixs2, or different from both pixs1 and pixs2)
01212  *              pixs1 (can be == pixd)
01213  *              pixs2 (can be == pixd)
01214  *      Return: pixd always
01215  *
01216  *  Notes:
01217  *      (1) This gives the set subtraction of two images with equal depth,
01218  *          aligning them to the the UL corner.  pixs1 and pixs2
01219  *          need not have the same width and height.
01220  *      (2) Source pixs2 is always subtracted from source pixs1.
01221  *          The result is
01222  *                  pixs1 \ pixs2 = pixs1 & (~pixs2)
01223  *      (3) There are 4 cases:
01224  *            (a) pixd == null,   (src1 - src2) --> new pixd
01225  *            (b) pixd == pixs1,  (src1 - src2) --> src1  (in-place)
01226  *            (c) pixd == pixs2,  (src1 - src2) --> src2  (in-place)
01227  *            (d) pixd != pixs1 && pixd != pixs2),
01228  *                                 (src1 - src2) --> input pixd
01229  *      (4) For clarity, if the case is known, use these patterns:
01230  *            (a) pixd = pixSubtract(NULL, pixs1, pixs2);
01231  *            (b) pixSubtract(pixs1, pixs1, pixs2);
01232  *            (c) pixSubtract(pixs2, pixs1, pixs2);
01233  *            (d) pixSubtract(pixd, pixs1, pixs2);
01234  *      (5) The size of the result is determined by pixs1.
01235  *      (6) The depths of pixs1 and pixs2 must be equal.
01236  */
01237 PIX *
01238 pixSubtract(PIX  *pixd,
01239             PIX  *pixs1,
01240             PIX  *pixs2)
01241 {
01242 l_int32  w, h;
01243 
01244     PROCNAME("pixSubtract");
01245 
01246     if (!pixs1)
01247         return (PIX *)ERROR_PTR("pixs1 not defined", procName, pixd);
01248     if (!pixs2)
01249         return (PIX *)ERROR_PTR("pixs2 not defined", procName, pixd);
01250     if (pixGetDepth(pixs1) != pixGetDepth(pixs2))
01251         return (PIX *)ERROR_PTR("depths of pixs* unequal", procName, pixd);
01252 
01253 #if  EQUAL_SIZE_WARNING
01254     if (!pixSizesEqual(pixs1, pixs2))
01255         L_WARNING("pixs1 and pixs2 not equal sizes", procName);
01256 #endif  /* EQUAL_SIZE_WARNING */
01257 
01258     pixGetDimensions(pixs1, &w, &h, NULL);
01259     if (!pixd) {
01260         pixd = pixCopy(NULL, pixs1);
01261         pixRasterop(pixd, 0, 0, w, h, PIX_DST & PIX_NOT(PIX_SRC),
01262             pixs2, 0, 0);   /* src1 & (~src2)  */
01263     }
01264     else if (pixd == pixs1) {
01265         pixRasterop(pixd, 0, 0, w, h, PIX_DST & PIX_NOT(PIX_SRC),
01266             pixs2, 0, 0);   /* src1 & (~src2)  */
01267     }
01268     else if (pixd == pixs2) {
01269         pixRasterop(pixd, 0, 0, w, h, PIX_NOT(PIX_DST) & PIX_SRC,
01270             pixs1, 0, 0);   /* src1 & (~src2)  */
01271     }
01272     else  { /* pixd != pixs1 && pixd != pixs2 */
01273         pixCopy(pixd, pixs1);  /* sizes pixd to pixs1 if unequal */
01274         pixRasterop(pixd, 0, 0, w, h, PIX_DST & PIX_NOT(PIX_SRC),
01275             pixs2, 0, 0);   /* src1 & (~src2)  */
01276     }
01277 
01278     return pixd;
01279 }
01280 
01281 
01282 /*-------------------------------------------------------------*
01283  *                         Pixel counting                      *
01284  *-------------------------------------------------------------*/
01285 /*!
01286  *  pixZero()
01287  *
01288  *      Input:  pix (all depths; not colormapped)
01289  *              &empty  (<return> 1 if all bits in image are 0; 0 otherwise)
01290  *      Return: 0 if OK; 1 on error
01291  *
01292  *  Notes:
01293  *      (1) For a binary image, if there are no fg (black) pixels, empty = 1.
01294  *      (2) For a grayscale image, if all pixels are black (0), empty = 1.
01295  *      (3) For an RGB image, if all 4 components in every pixel is 0,
01296  *          empty = 1. 
01297  */
01298 l_int32
01299 pixZero(PIX      *pix,
01300         l_int32  *pempty)
01301 {
01302 l_int32    w, h, wpl, i, j, fullwords, endbits;
01303 l_uint32   endmask;
01304 l_uint32  *data, *line;
01305 
01306     PROCNAME("pixZero");
01307 
01308     if (!pempty)
01309         return ERROR_INT("pempty not defined", procName, 1);
01310     *pempty = 1;
01311     if (!pix)
01312         return ERROR_INT("pix not defined", procName, 1);
01313     if (pixGetColormap(pix) != NULL)
01314         return ERROR_INT("pix is colormapped", procName, 1);
01315 
01316     w = pixGetWidth(pix) * pixGetDepth(pix);
01317     h = pixGetHeight(pix);
01318     wpl = pixGetWpl(pix);
01319     data = pixGetData(pix);
01320     fullwords = w / 32;
01321     endbits = w & 31;
01322     endmask = 0xffffffff << (32 - endbits);
01323 
01324     for (i = 0; i < h; i++) {
01325         line = data + wpl * i;
01326         for (j = 0; j < fullwords; j++)
01327             if (*line++) {
01328                 *pempty = 0;
01329                 return 0;
01330             }
01331         if (endbits) {
01332             if (*line & endmask) {
01333                 *pempty = 0;
01334                 return 0;
01335             }
01336         }
01337     }
01338 
01339     return 0;
01340 }
01341 
01342 
01343 /*!
01344  *  pixCountPixels()
01345  *
01346  *      Input:  pix (1 bpp)
01347  *              &count (<return> count of ON pixels)
01348  *              tab8  (<optional> 8-bit pixel lookup table)
01349  *      Return: 0 if OK; 1 on error
01350  */
01351 l_int32
01352 pixCountPixels(PIX      *pix,
01353                l_int32  *pcount,
01354                l_int32  *tab8)
01355 {
01356 l_uint32   endmask;
01357 l_int32    w, h, wpl, i, j;
01358 l_int32    fullwords, endbits, sum;
01359 l_int32   *tab;
01360 l_uint32  *data;
01361 
01362     PROCNAME("pixCountPixels");
01363 
01364     if (!pcount)
01365         return ERROR_INT("pcount not defined", procName, 1);
01366     *pcount = 0;
01367     if (!pix || pixGetDepth(pix) != 1)
01368         return ERROR_INT("pix not defined or not 1 bpp", procName, 1);
01369 
01370     if (!tab8)
01371         tab = makePixelSumTab8();
01372     else
01373         tab = tab8;
01374 
01375     pixGetDimensions(pix, &w, &h, NULL);
01376     wpl = pixGetWpl(pix);
01377     data = pixGetData(pix);
01378     fullwords = w >> 5;
01379     endbits = w & 31;
01380     endmask = 0xffffffff << (32 - endbits);
01381 
01382     sum = 0;
01383     for (i = 0; i < h; i++, data += wpl) {
01384         for (j = 0; j < fullwords; j++) {
01385             l_uint32 word = data[j];
01386             if (word) {
01387                 sum += tab[word & 0xff] +
01388                        tab[(word >> 8) & 0xff] +
01389                        tab[(word >> 16) & 0xff] +
01390                        tab[(word >> 24) & 0xff];
01391             }
01392         }
01393         if (endbits) {
01394             l_uint32 word = data[j] & endmask;
01395             if (word) {
01396                 sum += tab[word & 0xff] +
01397                        tab[(word >> 8) & 0xff] +
01398                        tab[(word >> 16) & 0xff] +
01399                        tab[(word >> 24) & 0xff];
01400             }
01401         }
01402     }
01403     *pcount = sum;
01404 
01405     if (!tab8)
01406         FREE(tab);
01407     return 0;
01408 }
01409 
01410 
01411 /*!
01412  *  pixaCountPixels()
01413  *
01414  *      Input:  pixa (array of 1 bpp pix)
01415  *      Return: na of ON pixels in each pix, or null on error
01416  */
01417 NUMA *
01418 pixaCountPixels(PIXA  *pixa)
01419 {
01420 l_int32   d, i, n, count;
01421 l_int32  *tab;
01422 NUMA     *na;
01423 PIX      *pix;
01424 
01425     PROCNAME("pixaCountPixels");
01426 
01427     if (!pixa)
01428         return (NUMA *)ERROR_PTR("pix not defined", procName, NULL);
01429 
01430     if ((n = pixaGetCount(pixa)) == 0)
01431         return numaCreate(1);
01432 
01433     pix = pixaGetPix(pixa, 0, L_CLONE);
01434     d = pixGetDepth(pix);
01435     pixDestroy(&pix);
01436     if (d != 1)
01437         return (NUMA *)ERROR_PTR("pixa not 1 bpp", procName, NULL);
01438 
01439     tab = makePixelSumTab8();
01440     if ((na = numaCreate(n)) == NULL)
01441         return (NUMA *)ERROR_PTR("na not made", procName, NULL);
01442     for (i = 0; i < n; i++) {
01443         pix = pixaGetPix(pixa, i, L_CLONE);
01444         pixCountPixels(pix, &count, tab);
01445         numaAddNumber(na, count);
01446         pixDestroy(&pix);
01447     }
01448         
01449     FREE(tab);
01450     return na;
01451 }
01452 
01453 
01454 /*!
01455  *  pixCountPixelsInRow()
01456  *
01457  *      Input:  pix (1 bpp)
01458  *              row number
01459  *              &count (<return> sum of ON pixels in raster line)
01460  *              tab8  (<optional> 8-bit pixel lookup table)
01461  *      Return: 0 if OK; 1 on error
01462  */
01463 l_int32
01464 pixCountPixelsInRow(PIX      *pix,
01465                     l_int32   row,
01466                     l_int32  *pcount,
01467                     l_int32  *tab8)
01468 {
01469 l_uint32   word, endmask;
01470 l_int32    j, w, h, wpl;
01471 l_int32    fullwords, endbits, sum;
01472 l_int32   *tab;
01473 l_uint32  *line;
01474 
01475     PROCNAME("pixCountPixelsInRow");
01476 
01477     if (!pcount)
01478         return ERROR_INT("pcount not defined", procName, 1);
01479     *pcount = 0;
01480     if (!pix || pixGetDepth(pix) != 1)
01481         return ERROR_INT("pix not defined or not 1 bpp", procName, 1);
01482 
01483     pixGetDimensions(pix, &w, &h, NULL);
01484     if (row < 0 || row >= h)
01485         return ERROR_INT("row out of bounds", procName, 1);
01486     wpl = pixGetWpl(pix);
01487     line = pixGetData(pix) + row * wpl;
01488     fullwords = w >> 5;
01489     endbits = w & 31;
01490     endmask = 0xffffffff << (32 - endbits);
01491 
01492     if (!tab8)
01493         tab = makePixelSumTab8();
01494     else
01495         tab = tab8;
01496 
01497     sum = 0;
01498     for (j = 0; j < fullwords; j++) {
01499         word = line[j];
01500         if (word) {
01501             sum += tab[word & 0xff] +
01502                    tab[(word >> 8) & 0xff] +
01503                    tab[(word >> 16) & 0xff] +
01504                    tab[(word >> 24) & 0xff];
01505         }
01506     }
01507     if (endbits) {
01508         word = line[j] & endmask;
01509         if (word) {
01510             sum += tab[word & 0xff] +
01511                    tab[(word >> 8) & 0xff] +
01512                    tab[(word >> 16) & 0xff] +
01513                    tab[(word >> 24) & 0xff];
01514         }
01515     }
01516     *pcount = sum;
01517 
01518     if (!tab8)
01519         FREE(tab);
01520     return 0;
01521 }
01522 
01523 
01524 /*!
01525  *  pixCountPixelsByRow()
01526  *
01527  *      Input:  pix (1 bpp)
01528  *              tab8  (<optional> 8-bit pixel lookup table)
01529  *      Return: na of counts, or null on error
01530  */
01531 NUMA *
01532 pixCountPixelsByRow(PIX      *pix,
01533                     l_int32  *tab8)
01534 {
01535 l_int32   h, i, count;
01536 l_int32  *tab;
01537 NUMA     *na;
01538 
01539     PROCNAME("pixCountPixelsByRow");
01540 
01541     if (!pix || pixGetDepth(pix) != 1)
01542         return (NUMA *)ERROR_PTR("pix undefined or not 1 bpp", procName, NULL);
01543 
01544     if (!tab8)
01545         tab = makePixelSumTab8();
01546     else
01547         tab = tab8;
01548 
01549     h = pixGetHeight(pix);
01550     if ((na = numaCreate(h)) == NULL)
01551         return (NUMA *)ERROR_PTR("na not made", procName, NULL);
01552     for (i = 0; i < h; i++) {
01553         pixCountPixelsInRow(pix, i, &count, tab);
01554         numaAddNumber(na, count);
01555     }
01556 
01557     if (!tab8)
01558         FREE(tab);
01559 
01560     return na;
01561 }
01562 
01563 
01564 /*!
01565  *  pixCountPixelsByColumn()
01566  *
01567  *      Input:  pix (1 bpp)
01568  *      Return: na of counts in each column, or null on error
01569  */
01570 NUMA *
01571 pixCountPixelsByColumn(PIX  *pix)
01572 {
01573 l_int32     i, j, w, h, wpl;
01574 l_uint32   *line, *data;
01575 l_float32  *array;
01576 NUMA       *na;
01577 
01578     PROCNAME("pixCountPixelsByColumn");
01579 
01580     if (!pix || pixGetDepth(pix) != 1)
01581         return (NUMA *)ERROR_PTR("pix undefined or not 1 bpp", procName, NULL);
01582 
01583     pixGetDimensions(pix, &w, &h, NULL);
01584     if ((na = numaCreate(w)) == NULL)
01585         return (NUMA *)ERROR_PTR("na not made", procName, NULL);
01586     numaSetCount(na, w);
01587     array = numaGetFArray(na, L_NOCOPY);
01588     data = pixGetData(pix);
01589     wpl = pixGetWpl(pix);
01590     for (i = 0; i < h; i++) {
01591         line = data + wpl * i;
01592         for (j = 0; j < w; j++) {
01593             if (GET_DATA_BIT(line, j))
01594                 array[j] += 1.0;
01595         }
01596     }
01597 
01598     return na;
01599 }
01600 
01601 
01602 /*!
01603  *  pixSumPixelsByRow()
01604  *
01605  *      Input:  pix (1, 8 or 16 bpp; no colormap)
01606  *              tab8  (<optional> lookup table for 1 bpp; use null for 8 bpp)
01607  *      Return: na of pixel sums by row, or null on error
01608  *
01609  *  Notes:
01610  *      (1) To resample for a bin size different from 1, use
01611  *          numaUniformSampling() on the result of this function.
01612  */
01613 NUMA *
01614 pixSumPixelsByRow(PIX      *pix,
01615                   l_int32  *tab8)
01616 {
01617 l_int32    i, j, w, h, d, wpl;
01618 l_uint32  *line, *data;
01619 l_float32  sum;
01620 NUMA      *na;
01621 
01622     PROCNAME("pixSumPixelsByRow");
01623 
01624     if (!pix)
01625         return (NUMA *)ERROR_PTR("pix not defined", procName, NULL);
01626     pixGetDimensions(pix, &w, &h, &d);
01627     if (d != 1 && d != 8 && d != 16)
01628         return (NUMA *)ERROR_PTR("pix not 1, 8 or 16 bpp", procName, NULL);
01629     if (pixGetColormap(pix) != NULL)
01630         return (NUMA *)ERROR_PTR("pix colormapped", procName, NULL);
01631 
01632     if (d == 1)
01633         return pixCountPixelsByRow(pix, tab8);
01634 
01635     if ((na = numaCreate(h)) == NULL)
01636         return (NUMA *)ERROR_PTR("na not made", procName, NULL);
01637     data = pixGetData(pix);
01638     wpl = pixGetWpl(pix);
01639     for (i = 0; i < h; i++) {
01640         sum = 0.0;
01641         line = data + i * wpl;
01642         if (d == 8) {
01643             sum += w * 255;
01644             for (j = 0; j < w; j++)
01645                 sum -= GET_DATA_BYTE(line, j);
01646         }
01647         else {  /* d == 16 */
01648             sum += w * 0xffff;
01649             for (j = 0; j < w; j++)
01650                 sum -= GET_DATA_TWO_BYTES(line, j);
01651         }
01652         numaAddNumber(na, sum);
01653     }
01654 
01655     return na;
01656 }
01657 
01658 
01659 /*!
01660  *  pixSumPixelsByColumn()
01661  *
01662  *      Input:  pix (1, 8 or 16 bpp; no colormap)
01663  *      Return: na of pixel sums by column, or null on error
01664  *
01665  *  Notes:
01666  *      (1) To resample for a bin size different from 1, use
01667  *          numaUniformSampling() on the result of this function.
01668  */
01669 NUMA *
01670 pixSumPixelsByColumn(PIX  *pix)
01671 {
01672 l_int32     i, j, w, h, d, wpl;
01673 l_uint32   *line, *data;
01674 l_float32  *array;
01675 NUMA       *na;
01676 
01677     PROCNAME("pixSumPixelsByColumn");
01678 
01679     if (!pix)
01680         return (NUMA *)ERROR_PTR("pix not defined", procName, NULL);
01681     pixGetDimensions(pix, &w, &h, &d);
01682     if (d != 1 && d != 8 && d != 16)
01683         return (NUMA *)ERROR_PTR("pix not 1, 8 or 16 bpp", procName, NULL);
01684     if (pixGetColormap(pix) != NULL)
01685         return (NUMA *)ERROR_PTR("pix colormapped", procName, NULL);
01686 
01687     if (d == 1)
01688         return pixCountPixelsByColumn(pix);
01689 
01690     if ((na = numaCreate(w)) == NULL)
01691         return (NUMA *)ERROR_PTR("na not made", procName, NULL);
01692     numaSetCount(na, w);
01693     array = numaGetFArray(na, L_NOCOPY);
01694     data = pixGetData(pix);
01695     wpl = pixGetWpl(pix);
01696     for (i = 0; i < h; i++) {
01697         line = data + wpl * i;
01698         if (d == 8) {
01699             for (j = 0; j < w; j++)
01700                 array[j] += 255 - GET_DATA_BYTE(line, j);
01701         }
01702         else {  /* d == 16 */
01703             for (j = 0; j < w; j++)
01704                 array[j] += 0xffff - GET_DATA_TWO_BYTES(line, j);
01705         }
01706     }
01707 
01708     return na;
01709 }
01710 
01711 
01712 /*!
01713  *  pixThresholdPixelSum()
01714  *
01715  *      Input:  pix (1 bpp)
01716  *              threshold
01717  *              &above (<return> 1 if above threshold;
01718  *                               0 if equal to or less than threshold)
01719  *              tab8  (<optional> 8-bit pixel lookup table)
01720  *      Return: 0 if OK; 1 on error
01721  *
01722  *  Notes:
01723  *      (1) This sums the ON pixels and returns immediately if the count
01724  *          goes above threshold.  It is therefore more efficient
01725  *          for matching images (by running this function on the xor of
01726  *          the 2 images) than using pixCountPixels(), which counts all
01727  *          pixels before returning.
01728  */
01729 l_int32
01730 pixThresholdPixelSum(PIX      *pix,
01731                      l_int32   thresh,
01732                      l_int32  *pabove,
01733                      l_int32  *tab8)
01734 {
01735 l_uint32   word, endmask;
01736 l_int32   *tab;
01737 l_int32    w, h, wpl, i, j;
01738 l_int32    fullwords, endbits, sum;
01739 l_uint32  *line, *data;
01740 
01741     PROCNAME("pixThresholdPixelSum");
01742 
01743     if (!pabove)
01744         return ERROR_INT("pabove not defined", procName, 1);
01745     *pabove = 0;
01746     if (!pix || pixGetDepth(pix) != 1)
01747         return ERROR_INT("pix not defined or not 1 bpp", procName, 1);
01748 
01749     if (!tab8)
01750         tab = makePixelSumTab8();
01751     else
01752         tab = tab8;
01753 
01754     pixGetDimensions(pix, &w, &h, NULL);
01755     wpl = pixGetWpl(pix);
01756     data = pixGetData(pix);
01757     fullwords = w >> 5;
01758     endbits = w & 31;
01759     endmask = 0xffffffff << (32 - endbits);
01760 
01761     sum = 0;
01762     for (i = 0; i < h; i++) {
01763         line = data + wpl * i;
01764         for (j = 0; j < fullwords; j++) {
01765             word = line[j];
01766             if (word) {
01767                 sum += tab[word & 0xff] +
01768                        tab[(word >> 8) & 0xff] +
01769                        tab[(word >> 16) & 0xff] +
01770                        tab[(word >> 24) & 0xff];
01771             }
01772         }
01773         if (endbits) {
01774             word = line[j] & endmask;
01775             if (word) {
01776                 sum += tab[word & 0xff] +
01777                        tab[(word >> 8) & 0xff] +
01778                        tab[(word >> 16) & 0xff] +
01779                        tab[(word >> 24) & 0xff];
01780             }
01781         }
01782         if (sum > thresh) {
01783             *pabove = 1;
01784             if (!tab8)
01785                 FREE(tab);
01786             return 0;
01787         }
01788     }
01789 
01790     if (!tab8)
01791         FREE(tab);
01792     return 0;
01793 }
01794 
01795 
01796 /*!
01797  *  makePixelSumTab8()
01798  *
01799  *      Input:  void
01800  *      Return: table of 256 l_int32, or null on error
01801  *
01802  *  Notes:
01803  *      (1) This table of integers gives the number of 1 bits
01804  *          in the 8 bit index.
01805  */
01806 l_int32 *
01807 makePixelSumTab8(void)
01808 {
01809 l_uint8   byte;
01810 l_int32   i;
01811 l_int32  *tab;
01812 
01813     PROCNAME("makePixelSumTab8");
01814 
01815     if ((tab = (l_int32 *)CALLOC(256, sizeof(l_int32))) == NULL)
01816         return (l_int32 *)ERROR_PTR("tab not made", procName, NULL);
01817 
01818     for (i = 0; i < 256; i++) {
01819         byte = (l_uint8)i;
01820         tab[i] = (byte & 0x1) +
01821                  ((byte >> 1) & 0x1) +
01822                  ((byte >> 2) & 0x1) +
01823                  ((byte >> 3) & 0x1) +
01824                  ((byte >> 4) & 0x1) +
01825                  ((byte >> 5) & 0x1) +
01826                  ((byte >> 6) & 0x1) +
01827                  ((byte >> 7) & 0x1);
01828     }
01829 
01830     return tab;
01831 }
01832 
01833 
01834 /*!
01835  *  makePixelCentroidTab8()
01836  *
01837  *      Input:  void
01838  *      Return: table of 256 l_int32, or null on error
01839  *
01840  *  Notes:
01841  *      (1) This table of integers gives the centroid weight of the 1 bits
01842  *          in the 8 bit index.  In other words, if sumtab is obtained by
01843  *          makePixelSumTab8, and centroidtab is obtained by
01844  *          makePixelCentroidTab8, then, for 1 <= i <= 255,
01845  *          centroidtab[i] / (float)sumtab[i]
01846  *          is the centroid of the 1 bits in the 8-bit index i, where the
01847  *          MSB is considered to have position 0 and the LSB is considered
01848  *          to have position 7.
01849  */
01850 l_int32 *
01851 makePixelCentroidTab8(void)
01852 {
01853 l_int32   i;
01854 l_int32  *tab;
01855 
01856     PROCNAME("makePixelCentroidTab8");
01857 
01858     if ((tab = (l_int32 *)CALLOC(256, sizeof(l_int32))) == NULL)
01859         return (l_int32 *)ERROR_PTR("tab not made", procName, NULL);
01860 
01861     tab[0] = 0;
01862     tab[1] = 7;
01863     for (i = 2; i < 4; i++) {
01864         tab[i] = tab[i - 2] + 6;
01865     }
01866     for (i = 4; i < 8; i++) {
01867         tab[i] = tab[i - 4] + 5;
01868     }
01869     for (i = 8; i < 16; i++) {
01870         tab[i] = tab[i - 8] + 4;
01871     }
01872     for (i = 16; i < 32; i++) {
01873         tab[i] = tab[i - 16] + 3;
01874     }
01875     for (i = 32; i < 64; i++) {
01876         tab[i] = tab[i - 32] + 2;
01877     }
01878     for (i = 64; i < 128; i++) {
01879         tab[i] = tab[i - 64] + 1;
01880     }
01881     for (i = 128; i < 256; i++) {
01882         tab[i] = tab[i - 128];
01883     }
01884 
01885     return tab;
01886 }
01887 
01888 
01889 /*-------------------------------------------------------------*
01890  *                       Sum of pixel values                   *
01891  *-------------------------------------------------------------*/
01892 /*!
01893  *  pixSumPixelValues()
01894  *
01895  *      Input:  pix (1, 2, 4, 8, 16, 32 bpp; not cmapped)
01896  *              box (<optional> if null, use entire image)
01897  *              &sum (<return> sum of pixel values in region)
01898  *      Return: 0 if OK; 1 on error
01899  */
01900 l_int32
01901 pixSumPixelValues(PIX        *pix,
01902                   BOX        *box,
01903                   l_float64  *psum)
01904 {
01905 l_int32    w, h, d, wpl, i, j, xstart, xend, ystart, yend, bw, bh;
01906 l_uint32  *data, *line;
01907 l_float64  sum;
01908 BOX       *boxc;
01909 
01910     PROCNAME("pixSumPixelValues");
01911 
01912     if (!psum)
01913         return ERROR_INT("psum not defined", procName, 1);
01914     *psum = 0;
01915     if (!pix)
01916         return ERROR_INT("pix not defined", procName, 1);
01917     if (pixGetColormap(pix) != NULL)
01918         return ERROR_INT("pix is colormapped", procName, 1);
01919     pixGetDimensions(pix, &w, &h, &d);
01920     if (d != 1 && d != 2 && d != 4 && d != 8 && d != 16 && d != 32)
01921         return ERROR_INT("pix not 1, 2, 4, 8, 16 or 32 bpp", procName, 1);
01922 
01923     wpl = pixGetWpl(pix);
01924     data = pixGetData(pix);
01925     boxc = NULL;
01926     if (box) {
01927         boxc = boxClipToRectangle(box, w, h);
01928         if (!boxc)
01929             return ERROR_INT("box outside image", procName, 1);
01930     }
01931     xstart = ystart = 0;
01932     xend = w;
01933     yend = h;
01934     if (boxc) {
01935         boxGetGeometry(boxc, &xstart, &ystart, &bw, &bh);
01936         xend = xstart + bw;  /* 1 past the end */
01937         yend = ystart + bh;  /* 1 past the end */
01938         boxDestroy(&boxc);
01939     }
01940 
01941     sum = 0;
01942     for (i = ystart; i < yend; i++) {
01943         line = data + i * wpl;
01944         for (j = xstart; j < xend; j++) {
01945             if (d == 1)
01946                 sum += GET_DATA_BIT(line, j);
01947             else if (d == 2)
01948                 sum += GET_DATA_DIBIT(line, j);
01949             else if (d == 4)
01950                 sum += GET_DATA_QBIT(line, j);
01951             else if (d == 8)
01952                 sum += GET_DATA_BYTE(line, j);
01953             else if (d == 16)
01954                 sum += GET_DATA_TWO_BYTES(line, j);
01955             else if (d == 32)
01956                 sum += line[j];
01957         }
01958     }
01959     *psum = sum;
01960 
01961     return 0;
01962 }
01963 
01964 
01965 
01966 /*-------------------------------------------------------------*
01967  *              Mirrored tiling of a smaller image             *
01968  *-------------------------------------------------------------*/
01969 /*!
01970  *  pixMirroredTiling()
01971  *
01972  *      Input:  pixs (8 or 32 bpp, small tile; to be replicated)
01973  *              w, h (dimensions of output pix)
01974  *      Return: pixd (usually larger pix, mirror-tiled with pixs),
01975  *              or null on error
01976  *
01977  *  Notes:
01978  *      (1) This uses mirrored tiling, where each row alternates
01979  *          with LR flips and every column alternates with TB
01980  *          flips, such that the result is a tiling with identical
01981  *          2 x 2 tiles, each of which is composed of these transforms:
01982  *                  -----------------
01983  *                  | 1    |  LR    |
01984  *                  -----------------
01985  *                  | TB   |  LR/TB |
01986  *                  -----------------
01987  */
01988 PIX *
01989 pixMirroredTiling(PIX     *pixs,
01990                   l_int32  w,
01991                   l_int32  h)
01992 {
01993 l_int32   wt, ht, d, i, j, nx, ny;
01994 PIX      *pixd, *pixsfx, *pixsfy, *pixsfxy, *pix;
01995 
01996     PROCNAME("pixMirroredTiling");
01997 
01998     if (!pixs)
01999         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
02000     pixGetDimensions(pixs, &wt, &ht, &d);
02001     if (wt <= 0 || ht <= 0)
02002         return (PIX *)ERROR_PTR("pixs size illegal", procName, NULL);
02003     if (d != 8 && d != 32)
02004         return (PIX *)ERROR_PTR("depth not 32 bpp", procName, NULL);
02005     if ((pixd = pixCreate(w, h, d)) == NULL)
02006         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
02007 
02008     nx = (w + wt - 1) / wt;
02009     ny = (h + ht - 1) / ht;
02010     pixsfx = pixFlipLR(NULL, pixs);
02011     pixsfy = pixFlipTB(NULL, pixs);
02012     pixsfxy = pixFlipTB(NULL, pixsfx);
02013     for (i = 0; i < ny; i++) {
02014         for (j = 0; j < nx; j++) {
02015             pix = pixs;
02016             if ((i & 1) && !(j & 1))
02017                 pix = pixsfy;
02018             else if (!(i & 1) && (j & 1))
02019                 pix = pixsfx;
02020             else if ((i & 1) && (j & 1))
02021                 pix = pixsfxy;
02022             pixRasterop(pixd, j * wt, i * ht, wt, ht, PIX_SRC, pix, 0, 0);
02023         }
02024     }
02025 
02026     pixDestroy(&pixsfx);
02027     pixDestroy(&pixsfy);
02028     pixDestroy(&pixsfxy);
02029     return pixd;
02030 }
02031 
02032 
02033 /*!
02034  *  findTilePatchCenter()
02035  *
02036  *      Input:  pixs (8 or 16 bpp; distance function of a binary mask)
02037  *              box (region of pixs to search around)
02038  *              searchdir (L_HORIZ or L_VERT; direction to search)
02039  *              targdist (desired distance of selected patch center from fg)
02040  *              &dist (<return> actual distance of selected location)
02041  *              &xc, &yc (<return> location of selected patch center)
02042  *      Return: 0 if OK, 1 on error
02043  *
02044  *  Notes:
02045  *      (1) This looks for a patch of non-masked image, that is outside
02046  *          but near the input box.  The input pixs is a distance
02047  *          function giving the distance from the fg in a binary mask.
02048  *      (2) The target distance implicitly specifies a desired size
02049  *          for the patch.  The location of the center of the patch,
02050  *          and the actual distance from fg are returned.
02051  *      (3) If the target distance is larger than 255, a 16-bit distance
02052  *          transform is input.
02053  *      (4) It is assured that a square centered at (xc, yc) and of
02054  *          size 'dist' will not intersect with the fg of the binary
02055  *          mask that was used to generate pixs.
02056  *      (5) We search away from the component, in approximately
02057  *          the center 1/3 of its dimension.  This gives a better chance
02058  *          of finding patches that are close to the component.
02059  */
02060 static l_int32
02061 findTilePatchCenter(PIX       *pixs,
02062                     BOX       *box,
02063                     l_int32    searchdir,
02064                     l_uint32   targdist,
02065                     l_uint32  *pdist,
02066                     l_int32   *pxc,
02067                     l_int32   *pyc)
02068 {
02069 l_int32   w, h, bx, by, bw, bh, left, right, top, bot, i, j;
02070 l_int32   xstart, xend, ystart, yend;
02071 l_uint32  val, maxval;
02072 
02073     PROCNAME("findTilePatchCenter");
02074 
02075     if (!pdist || !pxc || !pyc)
02076         return ERROR_INT("&pdist, &pxc, &pyc not all defined", procName, 1);
02077     *pdist = *pxc = *pyc = 0;
02078     if (!pixs)
02079         return ERROR_INT("pixs not defined", procName, 1);
02080     if (!box)
02081         return ERROR_INT("box not defined", procName, 1);
02082 
02083     pixGetDimensions(pixs, &w, &h, NULL);
02084     boxGetGeometry(box, &bx, &by, &bw, &bh);
02085 
02086     if (searchdir == L_HORIZ) {
02087         left = bx;   /* distance to left of box */
02088         right = w - bx - bw + 1;   /* distance to right of box */
02089         ystart = by + bh / 3;
02090         yend = by + 2 * bh / 3;
02091         maxval = 0;
02092         if (left > right) {  /* search to left */
02093             for (j = bx - 1; j >= 0; j--) {
02094                 for (i = ystart; i <= yend; i++) {
02095                     pixGetPixel(pixs, j, i, &val);
02096                     if (val > maxval) {
02097                         maxval = val;
02098                         *pxc = j;
02099                         *pyc = i;
02100                         *pdist = val;
02101                         if (val >= targdist)
02102                             return 0;
02103                     }
02104                 }
02105             }
02106         }
02107         else {  /* search to right */
02108             for (j = bx + bw; j < w; j++) {
02109                 for (i = ystart; i <= yend; i++) {
02110                     pixGetPixel(pixs, j, i, &val);
02111                     if (val > maxval) {
02112                         maxval = val;
02113                         *pxc = j;
02114                         *pyc = i;
02115                         *pdist = val;
02116                         if (val >= targdist)
02117                             return 0;
02118                     }
02119                 }
02120             }
02121         }
02122     }
02123     else {  /* searchdir == L_VERT */
02124         top = by;    /* distance above box */
02125         bot = h - by - bh + 1;   /* distance below box */
02126         xstart = bx + bw / 3;
02127         xend = bx + 2 * bw / 3;
02128         maxval = 0;
02129         if (top > bot) {  /* search above */
02130             for (i = by - 1; i >= 0; i--) {
02131                 for (j = xstart; j <=xend; j++) {
02132                     pixGetPixel(pixs, j, i, &val);
02133                     if (val > maxval) {
02134                         maxval = val;
02135                         *pxc = j;
02136                         *pyc = i;
02137                         *pdist = val;
02138                         if (val >= targdist)
02139                             return 0;
02140                     }
02141                 }
02142             }
02143         }
02144         else {  /* search below */
02145             for (i = by + bh; i < h; i++) {
02146                 for (j = xstart; j <=xend; j++) {
02147                     pixGetPixel(pixs, j, i, &val);
02148                     if (val > maxval) {
02149                         maxval = val;
02150                         *pxc = j;
02151                         *pyc = i;
02152                         *pdist = val;
02153                         if (val >= targdist)
02154                             return 0;
02155                     }
02156                 }
02157             }
02158         }
02159     }
02160 
02161 
02162     pixGetPixel(pixs, *pxc, *pyc, pdist);
02163     return 0;
02164 }
02165 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines