Leptonica 1.68
C Image Processing Library

boxfunc3.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  *   boxfunc3.c
00018  *
00019  *      Boxa/Boxaa painting into pix
00020  *           PIX             *pixMaskConnComp()
00021  *           PIX             *pixMaskBoxa()
00022  *           PIX             *pixPaintBoxa()
00023  *           PIX             *pixSetWhiteOrBlackBoxa()
00024  *           PIX             *pixPaintBoxaRandom()
00025  *           PIX             *pixBlendBoxaRandom()
00026  *           PIX             *pixDrawBoxa()
00027  *           PIX             *pixDrawBoxaRandom()
00028  *           PIX             *boxaaDisplay() 
00029  *
00030  *      Split mask components into Boxa
00031  *           BOXA            *pixSplitIntoBoxa()
00032  *           BOXA            *pixSplitComponentIntoBoxa()
00033  *           static l_int32   pixSearchForRectangle()
00034  *
00035  *  See summary in pixPaintBoxa() of various ways to paint and draw
00036  *  boxes on images.
00037  */
00038 
00039 #include "allheaders.h"
00040 
00041 static l_int32 pixSearchForRectangle(PIX *pixs, BOX *boxs, l_int32 minsum,
00042                                      l_int32 skipdist, l_int32 delta,
00043                                      l_int32 maxbg, l_int32 sideflag,
00044                                      BOXA *boxat, NUMA *nascore);
00045 
00046 #ifndef NO_CONSOLE_IO
00047 #define  DEBUG_SPLIT     0
00048 #endif  /* ~NO_CONSOLE_IO */
00049 
00050 
00051 /*---------------------------------------------------------------------*
00052  *                     Boxa/Boxaa painting into Pix                    *
00053  *---------------------------------------------------------------------*/
00054 /*!
00055  *  pixMaskConnComp()
00056  *
00057  *      Input:  pixs (1 bpp)
00058  *              connectivity (4 or 8)
00059  *              &boxa (<optional return> bounding boxes of c.c.)
00060  *      Return: pixd (1 bpp mask over the c.c.), or null on error
00061  *
00062  *  Notes:
00063  *      (1) This generates a mask image with ON pixels over the
00064  *          b.b. of the c.c. in pixs.  If there are no ON pixels in pixs,
00065  *          pixd will also have no ON pixels.
00066  */
00067 PIX *
00068 pixMaskConnComp(PIX     *pixs,
00069                 l_int32  connectivity,
00070                 BOXA   **pboxa)
00071 {
00072 BOXA  *boxa;
00073 PIX   *pixd;
00074 
00075     PROCNAME("pixMaskConnComp");
00076 
00077     if (!pixs || pixGetDepth(pixs) != 1)
00078         return (PIX *)ERROR_PTR("pixs undefined or not 1 bpp", procName, NULL);
00079     if (connectivity != 4 && connectivity != 8)
00080         return (PIX *)ERROR_PTR("connectivity not 4 or 8", procName, NULL);
00081 
00082     boxa = pixConnComp(pixs, NULL, connectivity);
00083     pixd = pixCreateTemplate(pixs);
00084     if (boxaGetCount(boxa) != 0)
00085         pixMaskBoxa(pixd, pixd, boxa, L_SET_PIXELS);
00086     if (pboxa)
00087         *pboxa = boxa;
00088     else
00089         boxaDestroy(&boxa);
00090     return pixd;
00091 }
00092 
00093 
00094 /*!
00095  *  pixMaskBoxa()
00096  *
00097  *      Input:  pixd (<optional> may be null)
00098  *              pixs (any depth; not cmapped)
00099  *              boxa (of boxes, to paint)
00100  *              op (L_SET_PIXELS, L_CLEAR_PIXELS, L_FLIP_PIXELS)
00101  *      Return: pixd (with masking op over the boxes), or null on error
00102  *
00103  *  Notes:
00104  *      (1) This can be used with:
00105  *              pixd = NULL  (makes a new pixd)
00106  *              pixd = pixs  (in-place)
00107  *      (2) If pixd == NULL, this first makes a copy of pixs, and then
00108  *          bit-twiddles over the boxes.  Otherwise, it operates directly
00109  *          on pixs.
00110  *      (3) This simple function is typically used with 1 bpp images.
00111  *          It uses the 1-image rasterop function, rasteropUniLow(),
00112  *          to set, clear or flip the pixels in pixd.  
00113  *      (4) If you want to generate a 1 bpp mask of ON pixels from the boxes
00114  *          in a Boxa, in a pix of size (w,h):
00115  *              pix = pixCreate(w, h, 1);
00116  *              pixMaskBoxa(pix, pix, boxa, L_SET_PIXELS);
00117  */
00118 PIX *
00119 pixMaskBoxa(PIX     *pixd,
00120             PIX     *pixs,
00121             BOXA    *boxa,
00122             l_int32  op)
00123 {
00124 l_int32  i, n, x, y, w, h;
00125 BOX     *box;
00126 
00127     PROCNAME("pixMaskBoxa");
00128 
00129     if (!pixs)
00130         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00131     if (pixGetColormap(pixs))
00132         return (PIX *)ERROR_PTR("pixs is cmapped", procName, NULL);
00133     if (pixd && (pixd != pixs))
00134         return (PIX *)ERROR_PTR("if pixd, must be in-place", procName, NULL);
00135     if (!boxa)
00136         return (PIX *)ERROR_PTR("boxa not defined", procName, NULL);
00137     if (op != L_SET_PIXELS && op != L_CLEAR_PIXELS && op != L_FLIP_PIXELS)
00138         return (PIX *)ERROR_PTR("invalid op", procName, NULL);
00139 
00140     pixd = pixCopy(pixd, pixs);
00141     if ((n = boxaGetCount(boxa)) == 0) {
00142         L_WARNING("no boxes to mask", procName);
00143         return pixd;
00144     }
00145 
00146     for (i = 0; i < n; i++) {
00147         box = boxaGetBox(boxa, i, L_CLONE);
00148         boxGetGeometry(box, &x, &y, &w, &h);
00149         if (op == L_SET_PIXELS)
00150             pixRasterop(pixd, x, y, w, h, PIX_SET, NULL, 0, 0);
00151         else if (op == L_CLEAR_PIXELS)
00152             pixRasterop(pixd, x, y, w, h, PIX_CLR, NULL, 0, 0);
00153         else  /* op == L_FLIP_PIXELS */
00154             pixRasterop(pixd, x, y, w, h, PIX_NOT(PIX_DST), NULL, 0, 0);
00155         boxDestroy(&box);
00156     }
00157 
00158     return pixd;
00159 }
00160 
00161 
00162 /*!
00163  *  pixPaintBoxa()
00164  *
00165  *      Input:  pixs (any depth, can be cmapped)
00166  *              boxa (of boxes, to paint)
00167  *              val (rgba color to paint)
00168  *      Return: pixd (with painted boxes), or null on error
00169  *
00170  *  Notes:
00171  *      (1) If pixs is 1 bpp or is colormapped, it is converted to 8 bpp
00172  *          and the boxa is painted using a colormap; otherwise,
00173  *          it is converted to 32 bpp rgb.
00174  *      (2) There are several ways to display a box on an image:
00175  *            * Paint it as a solid color
00176  *            * Draw the outline
00177  *            * Blend the outline or region with the existing image
00178  *          We provide painting and drawing here; blending is in blend.c.
00179  *          When painting or drawing, the result can be either a 
00180  *          cmapped image or an rgb image.  The dest will be cmapped
00181  *          if the src is either 1 bpp or has a cmap that is not full.
00182  *          To force RGB output, use pixConvertTo8(pixs, FALSE)
00183  *          before calling any of these paint and draw functions.
00184  */
00185 PIX *
00186 pixPaintBoxa(PIX      *pixs,
00187              BOXA     *boxa,
00188              l_uint32  val)
00189 {
00190 l_int32   i, n, d, rval, gval, bval, newindex;
00191 l_int32   mapvacancy;   /* true only if cmap and not full */
00192 BOX      *box;
00193 PIX      *pixd;
00194 PIXCMAP  *cmap;
00195 
00196     PROCNAME("pixPaintBoxa");
00197 
00198     if (!pixs)
00199         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00200     if (!boxa)
00201         return (PIX *)ERROR_PTR("boxa not defined", procName, NULL);
00202 
00203     if ((n = boxaGetCount(boxa)) == 0) {
00204         L_WARNING("no boxes to paint; returning a copy", procName);
00205         return pixCopy(NULL, pixs);
00206     }
00207 
00208     mapvacancy = FALSE;
00209     if ((cmap = pixGetColormap(pixs)) != NULL) {
00210         if (pixcmapGetCount(cmap) < 256)
00211             mapvacancy = TRUE;
00212     }
00213     if (pixGetDepth(pixs) == 1 || mapvacancy)
00214         pixd = pixConvertTo8(pixs, TRUE);
00215     else
00216         pixd = pixConvertTo32(pixs);
00217     if (!pixd)
00218         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
00219 
00220     d = pixGetDepth(pixd);
00221     if (d == 8) {  /* colormapped */
00222         cmap = pixGetColormap(pixd);
00223         extractRGBValues(val, &rval, &gval, &bval);
00224         if (pixcmapAddNewColor(cmap, rval, gval, bval, &newindex))
00225             return (PIX *)ERROR_PTR("cmap full; can't add", procName, NULL);
00226     }
00227 
00228     for (i = 0; i < n; i++) {
00229         box = boxaGetBox(boxa, i, L_CLONE);
00230         if (d == 8)
00231             pixSetInRectArbitrary(pixd, box, newindex);
00232         else
00233             pixSetInRectArbitrary(pixd, box, val);
00234         boxDestroy(&box);
00235     }
00236 
00237     return pixd;
00238 }
00239 
00240 
00241 /*!
00242  *  pixSetBlackOrWhiteBoxa()
00243  *
00244  *      Input:  pixs (any depth, can be cmapped)
00245  *              boxa (<optional> of boxes, to clear or set)
00246  *              op (L_SET_BLACK, L_SET_WHITE)
00247  *      Return: pixd (with boxes filled with white or black), or null on error
00248  */
00249 PIX *
00250 pixSetBlackOrWhiteBoxa(PIX     *pixs,
00251                        BOXA    *boxa,
00252                        l_int32  op)
00253 {
00254 l_int32   i, n, d, index;
00255 l_uint32  color;
00256 BOX      *box;
00257 PIX      *pixd;
00258 PIXCMAP  *cmap;
00259 
00260     PROCNAME("pixSetBlackOrWhiteBoxa");
00261 
00262     if (!pixs)
00263         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00264     if (!boxa)
00265         return pixCopy(NULL, pixs);
00266     if ((n = boxaGetCount(boxa)) == 0)
00267         return pixCopy(NULL, pixs);
00268 
00269     pixd = pixCopy(NULL, pixs);
00270     d = pixGetDepth(pixd);
00271     if (d == 1) {
00272         for (i = 0; i < n; i++) {
00273             box = boxaGetBox(boxa, i, L_CLONE);
00274             if (op == L_SET_WHITE)
00275                 pixClearInRect(pixd, box);
00276             else
00277                 pixSetInRect(pixd, box);
00278             boxDestroy(&box);
00279         }
00280         return pixd;
00281     }
00282 
00283     cmap = pixGetColormap(pixs);
00284     if (cmap) {
00285         color = (op == L_SET_WHITE) ? 1 : 0;
00286         pixcmapAddBlackOrWhite(cmap, color, &index);
00287     }
00288     else if (d == 8)
00289         color = (op == L_SET_WHITE) ? 0xff : 0x0;
00290     else if (d == 32)
00291         color = (op == L_SET_WHITE) ? 0xffffff00 : 0x0;
00292     else if (d == 2)
00293         color = (op == L_SET_WHITE) ? 0x3 : 0x0;
00294     else if (d == 4)
00295         color = (op == L_SET_WHITE) ? 0xf : 0x0;
00296     else if (d == 16)
00297         color = (op == L_SET_WHITE) ? 0xffff : 0x0;
00298     else {
00299         pixDestroy(&pixd);
00300         return (PIX *)ERROR_PTR("invalid depth", procName, NULL);
00301     }
00302 
00303     for (i = 0; i < n; i++) {
00304         box = boxaGetBox(boxa, i, L_CLONE);
00305         if (cmap)
00306             pixSetInRectArbitrary(pixd, box, index);
00307         else
00308             pixSetInRectArbitrary(pixd, box, color);
00309         boxDestroy(&box);
00310     }
00311 
00312     return pixd;
00313 }
00314 
00315 
00316 /*!
00317  *  pixPaintBoxaRandom()
00318  *
00319  *      Input:  pixs (any depth, can be cmapped)
00320  *              boxa (of boxes, to paint)
00321  *      Return: pixd (with painted boxes), or null on error
00322  *
00323  *  Notes:
00324  *      (1) If pixs is 1 bpp, we paint the boxa using a colormap;
00325  *          otherwise, we convert to 32 bpp.
00326  *      (2) We use up to 254 different colors for painting the regions.
00327  *      (3) If boxes overlap, the later ones paint over earlier ones.
00328  */
00329 PIX *
00330 pixPaintBoxaRandom(PIX   *pixs,
00331                    BOXA  *boxa)
00332 {
00333 l_int32   i, n, d, rval, gval, bval, index;
00334 l_uint32  val;
00335 BOX      *box;
00336 PIX      *pixd;
00337 PIXCMAP  *cmap;
00338 
00339     PROCNAME("pixPaintBoxaRandom");
00340 
00341     if (!pixs)
00342         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00343     if (!boxa)
00344         return (PIX *)ERROR_PTR("boxa not defined", procName, NULL);
00345 
00346     if ((n = boxaGetCount(boxa)) == 0) {
00347         L_WARNING("no boxes to paint; returning a copy", procName);
00348         return pixCopy(NULL, pixs);
00349     }
00350 
00351     if (pixGetDepth(pixs) == 1)
00352         pixd = pixConvert1To8(NULL, pixs, 255, 0);
00353     else
00354         pixd = pixConvertTo32(pixs);
00355     if (!pixd)
00356         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
00357 
00358     cmap = pixcmapCreateRandom(8, 1, 1);
00359     d = pixGetDepth(pixd);
00360     if (d == 8)  /* colormapped */
00361         pixSetColormap(pixd, cmap);
00362 
00363     for (i = 0; i < n; i++) {
00364         box = boxaGetBox(boxa, i, L_CLONE);
00365         index = 1 + (i % 254);
00366         if (d == 8)
00367             pixSetInRectArbitrary(pixd, box, index);
00368         else {  /* d == 32 */
00369             pixcmapGetColor(cmap, index, &rval, &gval, &bval);
00370             composeRGBPixel(rval, gval, bval, &val);
00371             pixSetInRectArbitrary(pixd, box, val);
00372         }
00373         boxDestroy(&box);
00374     }
00375 
00376     if (d == 32)
00377         pixcmapDestroy(&cmap);
00378     return pixd;
00379 }
00380 
00381 
00382 /*!
00383  *  pixBlendBoxaRandom()
00384  *
00385  *      Input:  pixs (any depth; can be cmapped)
00386  *              boxa (of boxes, to blend/paint)
00387  *              fract (of box color to use)
00388  *      Return: pixd (32 bpp, with blend/painted boxes), or null on error
00389  *
00390  *  Notes:
00391  *      (1) pixs is converted to 32 bpp.
00392  *      (2) This differs from pixPaintBoxaRandom(), in that the
00393  *          colors here are blended with the color of pixs.
00394  *      (3) We use up to 254 different colors for painting the regions.
00395  *      (4) If boxes overlap, the final color depends only on the last
00396  *          rect that is used.
00397  */
00398 PIX *
00399 pixBlendBoxaRandom(PIX       *pixs,
00400                    BOXA      *boxa,
00401                    l_float32  fract)
00402 {
00403 l_int32   i, n, rval, gval, bval, index;
00404 l_uint32  val;
00405 BOX      *box;
00406 PIX      *pixd;
00407 PIXCMAP  *cmap;
00408 
00409     PROCNAME("pixBlendBoxaRandom");
00410 
00411     if (!pixs)
00412         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00413     if (!boxa)
00414         return (PIX *)ERROR_PTR("boxa not defined", procName, NULL);
00415     if (fract < 0.0 || fract > 1.0) {
00416         L_WARNING("fract must be in [0.0, 1.0]; setting to 0.5", procName);
00417         fract = 0.5;
00418     }
00419 
00420     if ((n = boxaGetCount(boxa)) == 0) {
00421         L_WARNING("no boxes to paint; returning a copy", procName);
00422         return pixCopy(NULL, pixs);
00423     }
00424 
00425     if ((pixd = pixConvertTo32(pixs)) == NULL)
00426         return (PIX *)ERROR_PTR("pixd not defined", procName, NULL);
00427 
00428     cmap = pixcmapCreateRandom(8, 1, 1);
00429     for (i = 0; i < n; i++) {
00430         box = boxaGetBox(boxa, i, L_CLONE);
00431         index = 1 + (i % 254);
00432         pixcmapGetColor(cmap, index, &rval, &gval, &bval);
00433         composeRGBPixel(rval, gval, bval, &val);
00434         pixBlendInRect(pixd, box, val, fract);
00435         boxDestroy(&box);
00436     }
00437 
00438     pixcmapDestroy(&cmap);
00439     return pixd;
00440 }
00441 
00442 
00443 /*!
00444  *  pixDrawBoxa()
00445  *
00446  *      Input:  pixs (any depth; can be cmapped)
00447  *              boxa (of boxes, to draw)
00448  *              width (of lines)
00449  *              val (rgba color to draw)
00450  *      Return: pixd (with outlines of boxes added), or null on error
00451  *
00452  *  Notes:
00453  *      (1) If pixs is 1 bpp or is colormapped, it is converted to 8 bpp
00454  *          and the boxa is drawn using a colormap; otherwise,
00455  *          it is converted to 32 bpp rgb.
00456  */
00457 PIX *
00458 pixDrawBoxa(PIX      *pixs,
00459             BOXA     *boxa,
00460             l_int32   width,
00461             l_uint32  val)
00462 {
00463 l_int32   rval, gval, bval, newindex;
00464 l_int32   mapvacancy;   /* true only if cmap and not full */
00465 PIX      *pixd;
00466 PIXCMAP  *cmap;
00467 
00468     PROCNAME("pixDrawBoxa");
00469 
00470     if (!pixs)
00471         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00472     if (!boxa)
00473         return (PIX *)ERROR_PTR("boxa not defined", procName, NULL);
00474     if (width < 1)
00475         return (PIX *)ERROR_PTR("width must be >= 1", procName, NULL);
00476 
00477     if (boxaGetCount(boxa) == 0) {
00478         L_WARNING("no boxes to draw; returning a copy", procName);
00479         return pixCopy(NULL, pixs);
00480     }
00481 
00482     mapvacancy = FALSE;
00483     if ((cmap = pixGetColormap(pixs)) != NULL) {
00484         if (pixcmapGetCount(cmap) < 256)
00485             mapvacancy = TRUE;
00486     }
00487     if (pixGetDepth(pixs) == 1 || mapvacancy)
00488         pixd = pixConvertTo8(pixs, TRUE);
00489     else
00490         pixd = pixConvertTo32(pixs);
00491     if (!pixd)
00492         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
00493 
00494     extractRGBValues(val, &rval, &gval, &bval);
00495     if (pixGetDepth(pixd) == 8) {  /* colormapped */
00496         cmap = pixGetColormap(pixd);
00497         pixcmapAddNewColor(cmap, rval, gval, bval, &newindex);
00498     }
00499 
00500     pixRenderBoxaArb(pixd, boxa, width, rval, gval, bval);
00501     return pixd;
00502 }
00503 
00504 
00505 /*!
00506  *  pixDrawBoxaRandom()
00507  *
00508  *      Input:  pixs (any depth, can be cmapped)
00509  *              boxa (of boxes, to draw)
00510  *              width (thickness of line)
00511  *      Return: pixd (with box outlines drawn), or null on error
00512  *
00513  *  Notes:
00514  *      (1) If pixs is 1 bpp, we draw the boxa using a colormap;
00515  *          otherwise, we convert to 32 bpp.
00516  *      (2) We use up to 254 different colors for drawing the boxes.
00517  *      (3) If boxes overlap, the later ones draw over earlier ones.
00518  */
00519 PIX *
00520 pixDrawBoxaRandom(PIX     *pixs,
00521                   BOXA    *boxa,
00522                   l_int32  width)
00523 {
00524 l_int32   i, n, rval, gval, bval, index;
00525 BOX      *box;
00526 PIX      *pixd;
00527 PIXCMAP  *cmap;
00528 PTAA     *ptaa;
00529 
00530     PROCNAME("pixDrawBoxaRandom");
00531 
00532     if (!pixs)
00533         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00534     if (!boxa)
00535         return (PIX *)ERROR_PTR("boxa not defined", procName, NULL);
00536     if (width < 1)
00537         return (PIX *)ERROR_PTR("width must be >= 1", procName, NULL);
00538 
00539     if ((n = boxaGetCount(boxa)) == 0) {
00540         L_WARNING("no boxes to draw; returning a copy", procName);
00541         return pixCopy(NULL, pixs);
00542     }
00543 
00544         /* Input depth = 1 bpp; generate cmapped output */
00545     if (pixGetDepth(pixs) == 1) {
00546         ptaa = generatePtaaBoxa(boxa);
00547         pixd = pixRenderRandomCmapPtaa(pixs, ptaa, 1, width, 1);
00548         ptaaDestroy(&ptaa);
00549         return pixd;
00550     }
00551 
00552         /* Generate rgb output */
00553     pixd = pixConvertTo32(pixs);
00554     cmap = pixcmapCreateRandom(8, 1, 1);
00555     for (i = 0; i < n; i++) {
00556         box = boxaGetBox(boxa, i, L_CLONE);
00557         index = 1 + (i % 254);
00558         pixcmapGetColor(cmap, index, &rval, &gval, &bval);
00559         pixRenderBoxArb(pixd, box, width, rval, gval, bval);
00560         boxDestroy(&box);
00561     }
00562     pixcmapDestroy(&cmap);
00563     return pixd;
00564 }
00565 
00566 
00567 /*!
00568  *  boxaaDisplay()
00569  *
00570  *      Input:  boxaa
00571  *              linewba (line width to display boxa)
00572  *              linewb (line width to display box)
00573  *              colorba (color to display boxa)
00574  *              colorb (color to display box)
00575  *              w (of pix; use 0 if determined by boxaa)
00576  *              h (of pix; use 0 if determined by boxaa)
00577  *      Return: 0 if OK, 1 on error
00578  */
00579 PIX *
00580 boxaaDisplay(BOXAA    *boxaa,
00581              l_int32   linewba,
00582              l_int32   linewb,
00583              l_uint32  colorba,
00584              l_uint32  colorb,
00585              l_int32   w,
00586              l_int32   h)
00587 {
00588 l_int32   i, j, n, m, rbox, gbox, bbox, rboxa, gboxa, bboxa;
00589 BOX      *box;
00590 BOXA     *boxa;
00591 PIX      *pix;
00592 PIXCMAP  *cmap;
00593 
00594     PROCNAME("boxaaDisplay");
00595 
00596     if (!boxaa)
00597         return (PIX *)ERROR_PTR("boxaa not defined", procName, NULL);
00598     if (w == 0 || h == 0) 
00599         boxaaGetExtent(boxaa, &w, &h, NULL);
00600 
00601     pix = pixCreate(w, h, 8);
00602     cmap = pixcmapCreate(8);
00603     pixSetColormap(pix, cmap);
00604     extractRGBValues(colorb, &rbox, &gbox, &bbox);
00605     extractRGBValues(colorba, &rboxa, &gboxa, &bboxa);
00606     pixcmapAddColor(cmap, 255, 255, 255);
00607     pixcmapAddColor(cmap, rbox, gbox, bbox);
00608     pixcmapAddColor(cmap, rboxa, gboxa, bboxa);
00609     
00610     n = boxaaGetCount(boxaa);
00611     for (i = 0; i < n; i++) {
00612         boxa = boxaaGetBoxa(boxaa, i, L_CLONE);   
00613         boxaGetExtent(boxa, NULL, NULL, &box);
00614         pixRenderBoxArb(pix, box, linewba, rboxa, gboxa, bboxa);
00615         boxDestroy(&box);
00616         m = boxaGetCount(boxa);
00617         for (j = 0; j < m; j++) {
00618             box = boxaGetBox(boxa, j, L_CLONE);
00619             pixRenderBoxArb(pix, box, linewb, rbox, gbox, bbox);
00620             boxDestroy(&box);
00621         }
00622         boxaDestroy(&boxa);
00623     }
00624 
00625     return pix;
00626 }
00627 
00628 
00629 /*---------------------------------------------------------------------*
00630  *                   Split mask components into Boxa                   *
00631  *---------------------------------------------------------------------*/
00632 /*!
00633  *  pixSplitIntoBoxa()
00634  *
00635  *      Input:  pixs (1 bpp)
00636  *              minsum  (minimum pixels to trigger propagation)
00637  *              skipdist (distance before computing sum for propagation)
00638  *              delta (difference required to stop propagation)
00639  *              maxbg (maximum number of allowed bg pixels in ref scan)
00640  *              maxcomps (use 0 for unlimited number of subdivided components)
00641  *              remainder (set to 1 to get b.b. of remaining stuff)
00642  *      Return: boxa (of rectangles covering the fg of pixs), or null on error
00643  *
00644  *  Notes:
00645  *      (1) This generates a boxa of rectangles that covers
00646  *          the fg of a mask.  For each 8-connected component in pixs,
00647  *          it does a greedy partitioning, choosing the largest
00648  *          rectangle found from each of the four directions at each iter.
00649  *          See pixSplitComponentsIntoBoxa() for details.
00650  *      (2) The input parameters give some flexibility for boundary
00651  *          noise.  The resulting set of rectangles may cover some
00652  *          bg pixels.
00653  *      (3) This should be used when there are a small number of
00654  *          mask components, each of which has sides that are close
00655  *          to horizontal and vertical.  The input parameters @delta
00656  *          and @maxbg determine whether or not holes in the mask are covered.
00657  *      (4) The parameter @maxcomps gives the maximum number of allowed
00658  *          rectangles extracted from any single connected component.
00659  *          Use 0 if no limit is to be applied.
00660  *      (5) The flag @remainder specifies whether we take a final bounding
00661  *          box for anything left after the maximum number of allowed
00662  *          rectangle is extracted.
00663  */
00664 BOXA *
00665 pixSplitIntoBoxa(PIX     *pixs,
00666                  l_int32  minsum,
00667                  l_int32  skipdist,
00668                  l_int32  delta,
00669                  l_int32  maxbg,
00670                  l_int32  maxcomps,
00671                  l_int32  remainder)
00672 {
00673 l_int32  i, n;
00674 BOX     *box;
00675 BOXA    *boxa, *boxas, *boxad;
00676 PIX     *pix;
00677 PIXA    *pixas;
00678 
00679     PROCNAME("pixSplitIntoBoxa");
00680 
00681     if (!pixs || pixGetDepth(pixs) != 1)
00682         return (BOXA *)ERROR_PTR("pixs undefined or not 1 bpp", procName, NULL);
00683 
00684     boxas = pixConnComp(pixs, &pixas, 8);
00685     n = boxaGetCount(boxas);
00686     boxad = boxaCreate(0);
00687     for (i = 0; i < n; i++) {
00688         pix = pixaGetPix(pixas, i, L_CLONE);
00689         box = boxaGetBox(boxas, i, L_CLONE);
00690         boxa = pixSplitComponentIntoBoxa(pix, box, minsum, skipdist,
00691                                          delta, maxbg, maxcomps, remainder);
00692         boxaJoin(boxad, boxa, 0, 0);
00693         pixDestroy(&pix);
00694         boxDestroy(&box);
00695         boxaDestroy(&boxa);
00696     }
00697 
00698     pixaDestroy(&pixas);
00699     boxaDestroy(&boxas);
00700     return boxad;
00701 }
00702 
00703 
00704 /*!
00705  *  pixSplitComponentIntoBoxa()
00706  *
00707  *      Input:  pixs (1 bpp)
00708  *              box (<optional> location of pixs w/rt an origin)
00709  *              minsum  (minimum pixels to trigger propagation)
00710  *              skipdist (distance before computing sum for propagation)
00711  *              delta (difference required to stop propagation)
00712  *              maxbg (maximum number of allowed bg pixels in ref scan)
00713  *              maxcomps (use 0 for unlimited number of subdivided components)
00714  *              remainder (set to 1 to get b.b. of remaining stuff)
00715  *      Return: boxa (of rectangles covering the fg of pixs), or null on error
00716  *
00717  *  Notes:
00718  *      (1) This generates a boxa of rectangles that covers
00719  *          the fg of a mask.  It does so by a greedy partitioning of
00720  *          the mask, choosing the largest rectangle found from
00721  *          each of the four directions at each step.
00722  *      (2) The input parameters give some flexibility for boundary
00723  *          noise.  The resulting set of rectangles must cover all
00724  *          the fg pixels and, in addition, may cover some bg pixels.
00725  *          Using small input parameters on a noiseless mask (i.e., one
00726  *          that has only large vertical and horizontal edges) will
00727  *          result in a proper covering of only the fg pixels of the mask.
00728  *      (3) The input is assumed to be a single connected component, that
00729  *          may have holes.  From each side, sweep inward, counting
00730  *          the pixels.  If the count becomes greater than @minsum,
00731  *          and we have moved forward a further amount @skipdist,
00732  *          record that count ('countref'), but don't accept if the scan
00733  *          contains more than @maxbg bg pixels.  Continue the scan
00734  *          until we reach a count that differs from countref by at
00735  *          least @delta, at which point the propagation stops.  The box
00736  *          swept out gets a score, which is the sum of fg pixels
00737  *          minus a penalty.  The penalty is the number of bg pixels
00738  *          in the box.  This is done from all four sides, and the
00739  *          side with the largest score is saved as a rectangle.
00740  *          The process repeats until there is either no rectangle
00741  *          left, or there is one that can't be captured from any 
00742  *          direction.  For the latter case, we simply accept the
00743  *          last rectangle.
00744  *      (4) The input box is only used to specify the location of
00745  *          the UL corner of pixs, with respect to an origin that
00746  *          typically represents the UL corner of an underlying image,
00747  *          of which pixs is one component.  If @box is null,
00748  *          the UL corner is taken to be (0, 0).
00749  *      (5) The parameter @maxcomps gives the maximum number of allowed
00750  *          rectangles extracted from any single connected component.
00751  *          Use 0 if no limit is to be applied.
00752  *      (6) The flag @remainder specifies whether we take a final bounding
00753  *          box for anything left after the maximum number of allowed
00754  *          rectangle is extracted.
00755  *      (7) So if @maxcomps > 0, it specifies that we want no more than
00756  *          the first @maxcomps rectangles that satisfy the input
00757  *          criteria.  After this, we can get a final rectangle that
00758  *          bounds everything left over by setting @remainder == 1.
00759  *          If @remainder == 0, we only get rectangles that satisfy
00760  *          the input criteria.
00761  *      (8) It should be noted that the removal of rectangles can
00762  *          break the original c.c. into several c.c.
00763  *      (9) Summing up:
00764  *            * If @maxcomp == 0, the splitting proceeds as far as possible.
00765  *            * If @maxcomp > 0, the splitting stops when @maxcomps are
00766  *                found, or earlier if no more components can be selected.
00767  *            * If @remainder == 1 and components remain that cannot be
00768  *                selected, they are returned as a single final rectangle;
00769  *                otherwise, they are ignored.
00770  */
00771 BOXA *
00772 pixSplitComponentIntoBoxa(PIX     *pix,
00773                           BOX     *box,
00774                           l_int32  minsum,
00775                           l_int32  skipdist,
00776                           l_int32  delta,
00777                           l_int32  maxbg,
00778                           l_int32  maxcomps,
00779                           l_int32  remainder)
00780 {
00781 l_int32  i, w, h, boxx, boxy, bx, by, bw, bh, maxdir, maxscore;
00782 l_int32  iter;
00783 BOX     *boxs;  /* shrinks as rectangular regions are removed */
00784 BOX     *boxt1, *boxt2, *boxt3;
00785 BOXA    *boxat;  /* stores rectangle data for each side in an iteration */
00786 BOXA    *boxad;
00787 NUMA    *nascore, *nas;
00788 PIX     *pixs;
00789 
00790     PROCNAME("pixSplitComponentIntoBoxa");
00791 
00792     if (!pix || pixGetDepth(pix) != 1)
00793         return (BOXA *)ERROR_PTR("pix undefined or not 1 bpp", procName, NULL);
00794 
00795     pixs = pixCopy(NULL, pix);
00796     pixGetDimensions(pixs, &w, &h, NULL);
00797     if (box)
00798         boxGetGeometry(box, &boxx, &boxy, NULL, NULL);
00799     else
00800         boxx = boxy = 0;
00801     boxs = boxCreate(0, 0, w, h);
00802     boxad = boxaCreate(0);
00803 
00804     iter = 0;
00805     while (boxs != NULL) {
00806         boxGetGeometry(boxs, &bx, &by, &bw, &bh);
00807         boxat = boxaCreate(4);  /* potential rectangular regions */
00808         nascore = numaCreate(4);
00809         for (i = 0; i < 4; i++) {
00810             pixSearchForRectangle(pixs, boxs, minsum, skipdist, delta, maxbg,
00811                                   i, boxat, nascore);
00812         }
00813         nas = numaGetSortIndex(nascore, L_SORT_DECREASING);
00814         numaGetIValue(nas, 0, &maxdir);
00815         numaGetIValue(nascore, maxdir, &maxscore);
00816 #if  DEBUG_SPLIT
00817         fprintf(stderr, "Iteration: %d\n", iter);
00818         boxPrintStreamInfo(stderr, boxs);
00819         boxaWriteStream(stderr, boxat);
00820         fprintf(stderr, "\nmaxdir = %d, maxscore = %d\n\n", maxdir, maxscore);
00821 #endif  /* DEBUG_SPLIT */
00822         if (maxscore > 0) {  /* accept this */
00823             boxt1 = boxaGetBox(boxat, maxdir, L_CLONE);
00824             boxt2 = boxTransform(boxt1, boxx, boxy, 1.0, 1.0);
00825             boxaAddBox(boxad, boxt2, L_INSERT);
00826             pixClearInRect(pixs, boxt1);
00827             boxDestroy(&boxt1);
00828             pixClipBoxToForeground(pixs, boxs, NULL, &boxt3);
00829             boxDestroy(&boxs);
00830             boxs = boxt3;
00831             if (boxs) {
00832                 boxGetGeometry(boxs, NULL, NULL, &bw, &bh);
00833                 if (bw < 2 || bh < 2)
00834                     boxDestroy(&boxs);  /* we're done */
00835             }
00836         }
00837         else {  /* no more valid rectangles can be found */
00838             if (remainder == 1) {  /* save the last box */
00839                 boxt1 = boxTransform(boxs, boxx, boxy, 1.0, 1.0);
00840                 boxaAddBox(boxad, boxt1, L_INSERT);
00841             }
00842             boxDestroy(&boxs);  /* we're done */
00843         }
00844         boxaDestroy(&boxat);
00845         numaDestroy(&nascore);
00846         numaDestroy(&nas);
00847 
00848         iter++;
00849         if ((iter == maxcomps) && boxs) {
00850             if (remainder == 1) {  /* save the last box */
00851                 boxt1 = boxTransform(boxs, boxx, boxy, 1.0, 1.0);
00852                 boxaAddBox(boxad, boxt1, L_INSERT);
00853             }
00854             boxDestroy(&boxs);  /* we're done */
00855         }
00856     }
00857 
00858     pixDestroy(&pixs);
00859     return boxad;
00860 }
00861         
00862 
00863 /*!
00864  *  pixSearchForRectangle()
00865  *
00866  *      Input:  pixs (1 bpp)
00867  *              boxs (current region to investigate)
00868  *              minsum  (minimum pixels to trigger propagation)
00869  *              skipdist (distance before computing sum for propagation)
00870  *              delta (difference required to stop propagation)
00871  *              maxbg (maximum number of allowed bg pixels in ref scan)
00872  *              sideflag (side to search from)
00873  *              boxat (add result of rectangular region found here)
00874  *              nascore (add score for this rectangle here)
00875  *      Return: 0 if OK, 1 on error
00876  *
00877  *  Notes:
00878  *      (1) See pixSplitByRectangles() for an explanation of the algorithm.
00879  *          This does the sweep from a single side.  For each iteration
00880  *          in pixSplitByRectangles(), this will be called 4 times,
00881  *          for @sideflag = {0, 1, 2, 3}.
00882  *      (2) If a valid rectangle is not found, add a score of 0 and
00883  *          input a minimum box.
00884  */
00885 static l_int32
00886 pixSearchForRectangle(PIX     *pixs,
00887                       BOX     *boxs,
00888                       l_int32  minsum,
00889                       l_int32  skipdist,
00890                       l_int32  delta,
00891                       l_int32  maxbg,
00892                       l_int32  sideflag,
00893                       BOXA    *boxat,
00894                       NUMA    *nascore)
00895 {
00896 l_int32  bx, by, bw, bh, width, height, setref, atref;
00897 l_int32  minincol, maxincol, mininrow, maxinrow, minval, maxval, bgref;
00898 l_int32  x, y, x0, y0, xref, yref, colsum, rowsum, score, countref, diff;
00899 void   **lines1;
00900 BOX     *boxr;
00901 
00902     PROCNAME("pixSearchForRectangle");
00903 
00904     if (!pixs || pixGetDepth(pixs) != 1)
00905         return ERROR_INT("pixs undefined or not 1 bpp", procName, 1);
00906     if (!boxs)
00907         return ERROR_INT("boxs not defined", procName, 1);
00908     if (!boxat)
00909         return ERROR_INT("boxat not defined", procName, 1);
00910     if (!nascore)
00911         return ERROR_INT("nascore not defined", procName, 1);
00912 
00913     lines1 = pixGetLinePtrs(pixs, NULL);
00914     boxGetGeometry(boxs, &bx, &by, &bw, &bh);
00915     boxr = NULL;
00916     setref = 0;
00917     atref = 0;
00918     maxval = 0;
00919     minval = 100000;
00920     score = 0;  /* sum of all (fg - bg) pixels seen in the scan */
00921     xref = yref = 100000;  /* init to impossibly big number */
00922     if (sideflag == L_FROM_LEFT) {
00923         for (x = bx; x < bx + bw; x++) {
00924             colsum = 0;
00925             maxincol = 0;
00926             minincol = 100000;
00927             for (y = by; y < by + bh; y++) {
00928                 if (GET_DATA_BIT(lines1[y], x)) {
00929                     colsum++;
00930                     if (y > maxincol) maxincol = y;
00931                     if (y < minincol) minincol = y;
00932                 }
00933             }
00934             score += colsum;
00935 
00936                 /* Enough fg to sweep out a rectangle? */
00937             if (!setref && colsum >= minsum) {
00938                 setref = 1;
00939                 xref = x + 10;
00940                 if (xref >= bx + bw)
00941                     goto failure;
00942             }
00943 
00944                 /* Reached the reference line; save the count;
00945                  * if there is too much bg, the rectangle is invalid. */
00946             if (setref && x == xref) {
00947                 atref = 1;
00948                 countref = colsum;
00949                 bgref = maxincol - minincol + 1 - countref;
00950                 if (bgref > maxbg)
00951                     goto failure;
00952             }
00953 
00954                 /* Have we left the rectangle?  If so, save it along
00955                  * with the score. */
00956             if (atref) {
00957                 diff = L_ABS(colsum - countref);
00958                 if (diff >= delta || x == bx + bw - 1) {
00959                     height = maxval - minval + 1;
00960                     width = x - bx;
00961                     if (x == bx + bw - 1) width = x - bx + 1;
00962                     boxr = boxCreate(bx, minval, width, height);
00963                     score = 2 * score - width * height;
00964                     goto success;
00965                 }
00966             }
00967             maxval = L_MAX(maxval, maxincol);
00968             minval = L_MIN(minval, minincol);
00969         }
00970         goto failure;
00971     }
00972     else if (sideflag == L_FROM_RIGHT) {
00973         for (x = bx + bw - 1; x >= bx; x--) {
00974             colsum = 0;
00975             maxincol = 0;
00976             minincol = 100000;
00977             for (y = by; y < by + bh; y++) {
00978                 if (GET_DATA_BIT(lines1[y], x)) {
00979                     colsum++;
00980                     if (y > maxincol) maxincol = y;
00981                     if (y < minincol) minincol = y;
00982                 }
00983             }
00984             score += colsum;
00985             if (!setref && colsum >= minsum) {
00986                 setref = 1;
00987                 xref = x - 10;
00988                 if (xref < bx)
00989                     goto failure;
00990             }
00991             if (setref && x == xref) {
00992                 atref = 1;
00993                 countref = colsum;
00994                 bgref = maxincol - minincol + 1 - countref;
00995                 if (bgref > maxbg)
00996                     goto failure;
00997             }
00998             if (atref) {
00999                 diff = L_ABS(colsum - countref);
01000                 if (diff >= delta || x == bx) {
01001                     height = maxval - minval + 1;
01002                     x0 = x + 1;
01003                     if (x == bx) x0 = x;
01004                     width = bx + bw - x0;
01005                     boxr = boxCreate(x0, minval, width, height);
01006                     score = 2 * score - width * height;
01007                     goto success;
01008                 }
01009             }
01010             maxval = L_MAX(maxval, maxincol);
01011             minval = L_MIN(minval, minincol);
01012         }
01013         goto failure;
01014     }
01015     else if (sideflag == L_FROM_TOP) {
01016         for (y = by; y < by + bh; y++) {
01017             rowsum = 0;
01018             maxinrow = 0;
01019             mininrow = 100000;
01020             for (x = bx; x < bx + bw; x++) {
01021                 if (GET_DATA_BIT(lines1[y], x)) {
01022                     rowsum++;
01023                     if (x > maxinrow) maxinrow = x;
01024                     if (x < mininrow) mininrow = x;
01025                 }
01026             }
01027             score += rowsum;
01028             if (!setref && rowsum >= minsum) {
01029                 setref = 1;
01030                 yref = y + 10;
01031                 if (yref >= by + bh)
01032                     goto failure;
01033             }
01034             if (setref && y == yref) {
01035                 atref = 1;
01036                 countref = rowsum;
01037                 bgref = maxinrow - mininrow + 1 - countref;
01038                 if (bgref > maxbg)
01039                     goto failure;
01040             }
01041             if (atref) {
01042                 diff = L_ABS(rowsum - countref);
01043                 if (diff >= delta || y == by + bh - 1) {
01044                     width = maxval - minval + 1;
01045                     height = y - by;
01046                     if (y == by + bh - 1) height = y - by + 1;
01047                     boxr = boxCreate(minval, by, width, height);
01048                     score = 2 * score - width * height;
01049                     goto success;
01050                 }
01051             }
01052             maxval = L_MAX(maxval, maxinrow);
01053             minval = L_MIN(minval, mininrow);
01054         }
01055         goto failure;
01056     } else if (sideflag == L_FROM_BOTTOM) {
01057         for (y = by + bh - 1; y >= by; y--) {
01058             rowsum = 0;
01059             maxinrow = 0;
01060             mininrow = 100000;
01061             for (x = bx; x < bx + bw; x++) {
01062                 if (GET_DATA_BIT(lines1[y], x)) {
01063                     rowsum++;
01064                     if (x > maxinrow) maxinrow = x;
01065                     if (x < mininrow) mininrow = x;
01066                 }
01067             }
01068             score += rowsum;
01069             if (!setref && rowsum >= minsum) {
01070                 setref = 1;
01071                 yref = y - 10;
01072                 if (yref < by)
01073                     goto failure;
01074             }
01075             if (setref && y == yref) {
01076                 atref = 1;
01077                 countref = rowsum;
01078                 bgref = maxinrow - mininrow + 1 - countref;
01079                 if (bgref > maxbg)
01080                     goto failure;
01081             }
01082             if (atref) {
01083                 diff = L_ABS(rowsum - countref);
01084                 if (diff >= delta || y == by) {
01085                     width = maxval - minval + 1;
01086                     y0 = y + 1;
01087                     if (y == by) y0 = y;
01088                     height = by + bh - y0;
01089                     boxr = boxCreate(minval, y0, width, height);
01090                     score = 2 * score - width * height;
01091                     goto success;
01092                 }
01093             }
01094             maxval = L_MAX(maxval, maxinrow);
01095             minval = L_MIN(minval, mininrow);
01096         }
01097         goto failure;
01098     }
01099 
01100 failure:
01101     numaAddNumber(nascore, 0);
01102     boxaAddBox(boxat, boxCreate(0, 0, 1, 1), L_INSERT);  /* min box */
01103     FREE(lines1);
01104     return 0;
01105 
01106 success:
01107     numaAddNumber(nascore, score);
01108     boxaAddBox(boxat, boxr, L_INSERT);
01109     FREE(lines1);
01110     return 0;
01111 }
01112 
01113 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines