Leptonica 1.68
C Image Processing Library

pix4.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  *  pix4.c
00018  *
00019  *    This file has these operations:
00020  *
00021  *      (1) Pixel histograms
00022  *      (2) Pixel row/column statistics
00023  *      (3) Foreground/background estimation
00024  *
00025  *    Pixel histogram, rank val, averaging and min/max
00026  *           NUMA       *pixGetGrayHistogram()
00027  *           NUMA       *pixGetGrayHistogramMasked()
00028  *           l_int32     pixGetColorHistogram()
00029  *           l_int32     pixGetColorHistogramMasked()
00030  *           NUMA       *pixGetCmapHistogram()
00031  *           NUMA       *pixGetCmapHistogramMasked()
00032  *           l_int32     pixGetRankValueMaskedRGB()
00033  *           l_int32     pixGetRankValueMasked()
00034  *           l_int32     pixGetAverageMaskedRGB()
00035  *           l_int32     pixGetAverageMasked()
00036  *           l_int32     pixGetAverageTiledRGB()
00037  *           PIX        *pixGetAverageTiled()
00038  *           NUMA       *pixRowStats()
00039  *           NUMA       *pixColumnStats()
00040  *           l_int32     pixGetComponentRange()
00041  *           l_int32     pixGetExtremeValue()
00042  *           l_int32     pixGetMaxValueInRect()
00043  *           l_int32     pixGetBinnedComponentRange()
00044  *           l_int32     pixGetRankColorArray()
00045  *           l_int32     pixGetBinnedColor()
00046  *           PIX        *pixDisplayColorArray()
00047  *
00048  *    Pixelwise aligned statistics
00049  *           PIX        *pixaGetAlignedStats()
00050  *           l_int32     pixaExtractColumnFromEachPix()
00051  *           l_int32     pixGetRowStats()
00052  *           l_int32     pixGetColumnStats()
00053  *           l_int32     pixSetPixelColumn()
00054  *
00055  *    Foreground/background estimation
00056  *           l_int32     pixThresholdForFgBg()
00057  *           l_int32     pixSplitDistributionFgBg()
00058  */
00059 
00060 #include <string.h>
00061 #include <math.h>
00062 #include "allheaders.h"
00063 
00064 
00065 /*------------------------------------------------------------------*
00066  *                  Pixel histogram and averaging                   *
00067  *------------------------------------------------------------------*/
00068 /*!
00069  *  pixGetGrayHistogram()
00070  *
00071  *      Input:  pixs (1, 2, 4, 8, 16 bpp; can be colormapped)
00072  *              factor (subsampling factor; integer >= 1)
00073  *      Return: na (histogram), or null on error
00074  *
00075  *  Notes:
00076  *      (1) If pixs has a colormap, it is converted to 8 bpp gray.
00077  *          If you want a histogram of the colormap indices, use
00078  *          pixGetCmapHistogram().
00079  *      (2) If pixs does not have a colormap, the output histogram is
00080  *          of size 2^d, where d is the depth of pixs.
00081  *      (3) This always returns a 256-value histogram of pixel values.
00082  *      (4) Set the subsampling factor > 1 to reduce the amount of computation.
00083  */
00084 NUMA *
00085 pixGetGrayHistogram(PIX     *pixs,
00086                     l_int32  factor)
00087 {
00088 l_int32     i, j, w, h, d, wpl, val, size, count;
00089 l_uint32   *data, *line;
00090 l_float32  *array;
00091 NUMA       *na;
00092 PIX        *pixg;
00093 
00094     PROCNAME("pixGetGrayHistogram");
00095 
00096     if (!pixs)
00097         return (NUMA *)ERROR_PTR("pixs not defined", procName, NULL);
00098     d = pixGetDepth(pixs);
00099     if (d > 16)
00100         return (NUMA *)ERROR_PTR("depth not in {1,2,4,8,16}", procName, NULL);
00101     if (factor < 1)
00102         return (NUMA *)ERROR_PTR("sampling factor < 1", procName, NULL);
00103 
00104     if (pixGetColormap(pixs))
00105         pixg = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
00106     else
00107         pixg = pixClone(pixs);
00108 
00109     pixGetDimensions(pixg, &w, &h, &d);
00110     size = 1 << d;
00111     if ((na = numaCreate(size)) == NULL)
00112         return (NUMA *)ERROR_PTR("na not made", procName, NULL);
00113     numaSetCount(na, size);  /* all initialized to 0.0 */
00114     array = numaGetFArray(na, L_NOCOPY);
00115 
00116     if (d == 1) {  /* special case */
00117         pixCountPixels(pixg, &count, NULL);
00118         array[0] = w * h - count;
00119         array[1] = count;
00120         pixDestroy(&pixg);
00121         return na;
00122     }
00123 
00124     wpl = pixGetWpl(pixg);
00125     data = pixGetData(pixg);
00126     for (i = 0; i < h; i += factor) {
00127         line = data + i * wpl;
00128         switch (d)
00129         {
00130         case 2:
00131             for (j = 0; j < w; j += factor) {
00132                 val = GET_DATA_DIBIT(line, j);
00133                 array[val] += 1.0;
00134             }
00135             break;
00136         case 4:
00137             for (j = 0; j < w; j += factor) {
00138                 val = GET_DATA_QBIT(line, j);
00139                 array[val] += 1.0;
00140             }
00141             break;
00142         case 8:
00143             for (j = 0; j < w; j += factor) {
00144                 val = GET_DATA_BYTE(line, j);
00145                 array[val] += 1.0;
00146             }
00147             break;
00148         case 16:
00149             for (j = 0; j < w; j += factor) {
00150                 val = GET_DATA_TWO_BYTES(line, j);
00151                 array[val] += 1.0;
00152             }
00153             break;
00154         default:
00155             numaDestroy(&na);
00156             return (NUMA *)ERROR_PTR("illegal depth", procName, NULL);
00157         }
00158     }
00159 
00160     pixDestroy(&pixg);
00161     return na;
00162 }
00163 
00164 
00165 /*!
00166  *  pixGetGrayHistogramMasked()
00167  *
00168  *      Input:  pixs (8 bpp, or colormapped)
00169  *              pixm (<optional> 1 bpp mask over which histogram is
00170  *                    to be computed; use all pixels if null)
00171  *              x, y (UL corner of pixm relative to the UL corner of pixs;
00172  *                    can be < 0; these values are ignored if pixm is null)
00173  *              factor (subsampling factor; integer >= 1)
00174  *      Return: na (histogram), or null on error
00175  *
00176  *  Notes:
00177  *      (1) If pixs is cmapped, it is converted to 8 bpp gray.
00178  *          If you want a histogram of the colormap indices, use
00179  *          pixGetCmapHistogramMasked().
00180  *      (2) This always returns a 256-value histogram of pixel values.
00181  *      (3) Set the subsampling factor > 1 to reduce the amount of computation.
00182  *      (4) Clipping of pixm (if it exists) to pixs is done in the inner loop.
00183  *      (5) Input x,y are ignored unless pixm exists.
00184  */
00185 NUMA *
00186 pixGetGrayHistogramMasked(PIX        *pixs,
00187                           PIX        *pixm,
00188                           l_int32     x,
00189                           l_int32     y,
00190                           l_int32     factor)
00191 {
00192 l_int32     i, j, w, h, wm, hm, dm, wplg, wplm, val;
00193 l_uint32   *datag, *datam, *lineg, *linem;
00194 l_float32  *array;
00195 NUMA       *na;
00196 PIX        *pixg;
00197 
00198     PROCNAME("pixGetGrayHistogramMasked");
00199 
00200     if (!pixm)
00201         return pixGetGrayHistogram(pixs, factor);
00202 
00203     if (!pixs)
00204         return (NUMA *)ERROR_PTR("pixs not defined", procName, NULL);
00205     if (pixGetDepth(pixs) != 8 && !pixGetColormap(pixs))
00206         return (NUMA *)ERROR_PTR("pixs neither 8 bpp nor colormapped",
00207                                  procName, NULL);
00208     pixGetDimensions(pixm, &wm, &hm, &dm);
00209     if (dm != 1)
00210         return (NUMA *)ERROR_PTR("pixm not 1 bpp", procName, NULL);
00211     if (factor < 1)
00212         return (NUMA *)ERROR_PTR("sampling factor < 1", procName, NULL);
00213 
00214     if ((na = numaCreate(256)) == NULL)
00215         return (NUMA *)ERROR_PTR("na not made", procName, NULL);
00216     numaSetCount(na, 256);  /* all initialized to 0.0 */
00217     array = numaGetFArray(na, L_NOCOPY);
00218 
00219     if (pixGetColormap(pixs))
00220         pixg = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
00221     else
00222         pixg = pixClone(pixs);
00223     pixGetDimensions(pixg, &w, &h, NULL);
00224     datag = pixGetData(pixg);
00225     wplg = pixGetWpl(pixg);
00226     datam = pixGetData(pixm);
00227     wplm = pixGetWpl(pixm);
00228 
00229         /* Generate the histogram */
00230     for (i = 0; i < hm; i += factor) {
00231         if (y + i < 0 || y + i >= h) continue;
00232         lineg = datag + (y + i) * wplg;
00233         linem = datam + i * wplm;
00234         for (j = 0; j < wm; j += factor) {
00235             if (x + j < 0 || x + j >= w) continue;
00236             if (GET_DATA_BIT(linem, j)) {
00237                 val = GET_DATA_BYTE(lineg, x + j);
00238                 array[val] += 1.0;
00239             }
00240         }
00241     }
00242 
00243     pixDestroy(&pixg);
00244     return na;
00245 }
00246 
00247 
00248 /*!
00249  *  pixGetColorHistogram()
00250  *
00251  *      Input:  pixs (rgb or colormapped)
00252  *              factor (subsampling factor; integer >= 1)
00253  *              &nar (<return> red histogram)
00254  *              &nag (<return> green histogram)
00255  *              &nab (<return> blue histogram)
00256  *      Return: 0 if OK, 1 on error
00257  *
00258  *  Notes:
00259  *      (1) This generates a set of three 256 entry histograms,
00260  *          one for each color component (r,g,b).
00261  *      (2) Set the subsampling factor > 1 to reduce the amount of computation.
00262  */
00263 l_int32
00264 pixGetColorHistogram(PIX     *pixs,
00265                      l_int32  factor,
00266                      NUMA   **pnar,
00267                      NUMA   **pnag,
00268                      NUMA   **pnab)
00269 {
00270 l_int32     i, j, w, h, d, wpl, index, rval, gval, bval;
00271 l_uint32   *data, *line;
00272 l_float32  *rarray, *garray, *barray;
00273 NUMA       *nar, *nag, *nab;
00274 PIXCMAP    *cmap;
00275 
00276     PROCNAME("pixGetColorHistogram");
00277 
00278     if (!pnar || !pnag || !pnab)
00279         return ERROR_INT("&nar, &nag, &nab not all defined", procName, 1);
00280     *pnar = *pnag = *pnab = NULL;
00281     if (!pixs)
00282         return ERROR_INT("pixs not defined", procName, 1);
00283     pixGetDimensions(pixs, &w, &h, &d);
00284     cmap = pixGetColormap(pixs);
00285     if (cmap && (d != 2 && d != 4 && d != 8))
00286         return ERROR_INT("colormap and not 2, 4, or 8 bpp", procName, 1);
00287     if (!cmap && d != 32)
00288         return ERROR_INT("no colormap and not rgb", procName, 1);
00289     if (factor < 1)
00290         return ERROR_INT("sampling factor < 1", procName, 1);
00291 
00292         /* Set up the histogram arrays */
00293     nar = numaCreate(256);
00294     nag = numaCreate(256);
00295     nab = numaCreate(256);
00296     numaSetCount(nar, 256);
00297     numaSetCount(nag, 256);
00298     numaSetCount(nab, 256);
00299     rarray = numaGetFArray(nar, L_NOCOPY);
00300     garray = numaGetFArray(nag, L_NOCOPY);
00301     barray = numaGetFArray(nab, L_NOCOPY);
00302     *pnar = nar;
00303     *pnag = nag;
00304     *pnab = nab;
00305 
00306         /* Generate the color histograms */
00307     data = pixGetData(pixs);
00308     wpl = pixGetWpl(pixs);
00309     if (cmap) {
00310         for (i = 0; i < h; i += factor) {
00311             line = data + i * wpl;
00312             for (j = 0; j < w; j += factor) {
00313                 if (d == 8)
00314                     index = GET_DATA_BYTE(line, j);
00315                 else if (d == 4)
00316                     index = GET_DATA_QBIT(line, j);
00317                 else   /* 2 bpp */
00318                     index = GET_DATA_DIBIT(line, j);
00319                 pixcmapGetColor(cmap, index, &rval, &gval, &bval);
00320                 rarray[rval] += 1.0;
00321                 garray[gval] += 1.0;
00322                 barray[bval] += 1.0;
00323             }
00324         }
00325     }
00326     else {  /* 32 bpp rgb */
00327         for (i = 0; i < h; i += factor) {
00328             line = data + i * wpl;
00329             for (j = 0; j < w; j += factor) {
00330                 extractRGBValues(line[j], &rval, &gval, &bval);
00331                 rarray[rval] += 1.0;
00332                 garray[gval] += 1.0;
00333                 barray[bval] += 1.0;
00334             }
00335         }
00336     }
00337 
00338     return 0;
00339 }
00340 
00341 
00342 /*!
00343  *  pixGetColorHistogramMasked()
00344  *
00345  *      Input:  pixs (32 bpp rgb, or colormapped)
00346  *              pixm (<optional> 1 bpp mask over which histogram is
00347  *                    to be computed; use all pixels if null)
00348  *              x, y (UL corner of pixm relative to the UL corner of pixs;
00349  *                    can be < 0; these values are ignored if pixm is null)
00350  *              factor (subsampling factor; integer >= 1)
00351  *              &nar (<return> red histogram)
00352  *              &nag (<return> green histogram)
00353  *              &nab (<return> blue histogram)
00354  *      Return: 0 if OK, 1 on error
00355  *
00356  *  Notes:
00357  *      (1) This generates a set of three 256 entry histograms,
00358  *      (2) Set the subsampling factor > 1 to reduce the amount of computation.
00359  *      (3) Clipping of pixm (if it exists) to pixs is done in the inner loop.
00360  *      (4) Input x,y are ignored unless pixm exists.
00361  */
00362 l_int32
00363 pixGetColorHistogramMasked(PIX        *pixs,
00364                            PIX        *pixm,
00365                            l_int32     x,
00366                            l_int32     y,
00367                            l_int32     factor,
00368                            NUMA      **pnar,
00369                            NUMA      **pnag,
00370                            NUMA      **pnab)
00371 {
00372 l_int32     i, j, w, h, d, wm, hm, dm, wpls, wplm, index, rval, gval, bval;
00373 l_uint32   *datas, *datam, *lines, *linem;
00374 l_float32  *rarray, *garray, *barray;
00375 NUMA       *nar, *nag, *nab;
00376 PIXCMAP    *cmap;
00377 
00378     PROCNAME("pixGetColorHistogramMasked");
00379 
00380     if (!pixm)
00381         return pixGetColorHistogram(pixs, factor, pnar, pnag, pnab);
00382 
00383     if (!pnar || !pnag || !pnab)
00384         return ERROR_INT("&nar, &nag, &nab not all defined", procName, 1);
00385     *pnar = *pnag = *pnab = NULL;
00386     if (!pixs)
00387         return ERROR_INT("pixs not defined", procName, 1);
00388     pixGetDimensions(pixs, &w, &h, &d);
00389     cmap = pixGetColormap(pixs);
00390     if (cmap && (d != 2 && d != 4 && d != 8))
00391         return ERROR_INT("colormap and not 2, 4, or 8 bpp", procName, 1);
00392     if (!cmap && d != 32)
00393         return ERROR_INT("no colormap and not rgb", procName, 1);
00394     pixGetDimensions(pixm, &wm, &hm, &dm);
00395     if (dm != 1)
00396         return ERROR_INT("pixm not 1 bpp", procName, 1);
00397     if (factor < 1)
00398         return ERROR_INT("sampling factor < 1", procName, 1);
00399 
00400         /* Set up the histogram arrays */
00401     nar = numaCreate(256);
00402     nag = numaCreate(256);
00403     nab = numaCreate(256);
00404     numaSetCount(nar, 256);
00405     numaSetCount(nag, 256);
00406     numaSetCount(nab, 256);
00407     rarray = numaGetFArray(nar, L_NOCOPY);
00408     garray = numaGetFArray(nag, L_NOCOPY);
00409     barray = numaGetFArray(nab, L_NOCOPY);
00410     *pnar = nar;
00411     *pnag = nag;
00412     *pnab = nab;
00413 
00414         /* Generate the color histograms */
00415     datas = pixGetData(pixs);
00416     wpls = pixGetWpl(pixs);
00417     datam = pixGetData(pixm);
00418     wplm = pixGetWpl(pixm);
00419     if (cmap) {
00420         for (i = 0; i < hm; i += factor) {
00421             if (y + i < 0 || y + i >= h) continue;
00422             lines = datas + (y + i) * wpls;
00423             linem = datam + i * wplm;
00424             for (j = 0; j < wm; j += factor) {
00425                 if (x + j < 0 || x + j >= w) continue;
00426                 if (GET_DATA_BIT(linem, j)) {
00427                     if (d == 8)
00428                         index = GET_DATA_BYTE(lines, x + j);
00429                     else if (d == 4)
00430                         index = GET_DATA_QBIT(lines, x + j);
00431                     else   /* 2 bpp */
00432                         index = GET_DATA_DIBIT(lines, x + j);
00433                     pixcmapGetColor(cmap, index, &rval, &gval, &bval);
00434                     rarray[rval] += 1.0;
00435                     garray[gval] += 1.0;
00436                     barray[bval] += 1.0;
00437                 }
00438             }
00439         }
00440     }
00441     else {  /* 32 bpp rgb */
00442         for (i = 0; i < hm; i += factor) {
00443             if (y + i < 0 || y + i >= h) continue;
00444             lines = datas + (y + i) * wpls;
00445             linem = datam + i * wplm;
00446             for (j = 0; j < wm; j += factor) {
00447                 if (x + j < 0 || x + j >= w) continue;
00448                 if (GET_DATA_BIT(linem, j)) {
00449                     extractRGBValues(lines[x + j], &rval, &gval, &bval);
00450                     rarray[rval] += 1.0;
00451                     garray[gval] += 1.0;
00452                     barray[bval] += 1.0;
00453                 }
00454             }
00455         }
00456     }
00457 
00458     return 0;
00459 }
00460 
00461 
00462 /*!
00463  *  pixGetCmapHistogram()
00464  *
00465  *      Input:  pixs (colormapped: d = 2, 4 or 8)
00466  *              factor (subsampling factor; integer >= 1)
00467  *      Return: na (histogram of cmap indices), or null on error
00468  *
00469  *  Notes:
00470  *      (1) This generates a histogram of colormap pixel indices,
00471  *          and is of size 2^d.
00472  *      (2) Set the subsampling factor > 1 to reduce the amount of computation.
00473  */
00474 NUMA *
00475 pixGetCmapHistogram(PIX     *pixs,
00476                     l_int32  factor)
00477 {
00478 l_int32     i, j, w, h, d, wpl, val, size;
00479 l_uint32   *data, *line;
00480 l_float32  *array;
00481 NUMA       *na;
00482 
00483     PROCNAME("pixGetCmapHistogram");
00484 
00485     if (!pixs)
00486         return (NUMA *)ERROR_PTR("pixs not defined", procName, NULL);
00487     if (pixGetColormap(pixs) == NULL)
00488         return (NUMA *)ERROR_PTR("pixs not cmapped", procName, NULL);
00489     if (factor < 1)
00490         return (NUMA *)ERROR_PTR("sampling factor < 1", procName, NULL);
00491     pixGetDimensions(pixs, &w, &h, &d);
00492     if (d != 2 && d != 4 && d != 8)
00493         return (NUMA *)ERROR_PTR("d not 2, 4 or 8", procName, NULL);
00494 
00495     size = 1 << d;
00496     if ((na = numaCreate(size)) == NULL)
00497         return (NUMA *)ERROR_PTR("na not made", procName, NULL);
00498     numaSetCount(na, size);  /* all initialized to 0.0 */
00499     array = numaGetFArray(na, L_NOCOPY);
00500 
00501     wpl = pixGetWpl(pixs);
00502     data = pixGetData(pixs);
00503     for (i = 0; i < h; i += factor) {
00504         line = data + i * wpl;
00505         for (j = 0; j < w; j += factor) {
00506             if (d == 8)
00507                 val = GET_DATA_BYTE(line, j);
00508             else if (d == 4)
00509                 val = GET_DATA_QBIT(line, j);
00510             else  /* d == 2 */
00511                 val = GET_DATA_DIBIT(line, j);
00512             array[val] += 1.0;
00513         }
00514     }
00515 
00516     return na;
00517 }
00518 
00519 
00520 /*!
00521  *  pixGetCmapHistogramMasked()
00522  *
00523  *      Input:  pixs (colormapped: d = 2, 4 or 8)
00524  *              pixm (<optional> 1 bpp mask over which histogram is
00525  *                    to be computed; use all pixels if null)
00526  *              x, y (UL corner of pixm relative to the UL corner of pixs;
00527  *                    can be < 0; these values are ignored if pixm is null)
00528  *              factor (subsampling factor; integer >= 1)
00529  *      Return: na (histogram), or null on error
00530  *
00531  *  Notes:
00532  *      (1) This generates a histogram of colormap pixel indices,
00533  *          and is of size 2^d.
00534  *      (2) Set the subsampling factor > 1 to reduce the amount of computation.
00535  *      (3) Clipping of pixm to pixs is done in the inner loop.
00536  */
00537 NUMA *
00538 pixGetCmapHistogramMasked(PIX     *pixs,
00539                           PIX     *pixm,
00540                           l_int32  x,
00541                           l_int32  y,
00542                           l_int32  factor)
00543 {
00544 l_int32     i, j, w, h, d, wm, hm, dm, wpls, wplm, val, size;
00545 l_uint32   *datas, *datam, *lines, *linem;
00546 l_float32  *array;
00547 NUMA       *na;
00548 
00549     PROCNAME("pixGetCmapHistogramMasked");
00550 
00551     if (!pixm)
00552         return pixGetCmapHistogram(pixs, factor);
00553 
00554     if (!pixs)
00555         return (NUMA *)ERROR_PTR("pixs not defined", procName, NULL);
00556     if (pixGetColormap(pixs) == NULL)
00557         return (NUMA *)ERROR_PTR("pixs not cmapped", procName, NULL);
00558     pixGetDimensions(pixm, &wm, &hm, &dm);
00559     if (dm != 1)
00560         return (NUMA *)ERROR_PTR("pixm not 1 bpp", procName, NULL);
00561     if (factor < 1)
00562         return (NUMA *)ERROR_PTR("sampling factor < 1", procName, NULL);
00563     pixGetDimensions(pixs, &w, &h, &d);
00564     if (d != 2 && d != 4 && d != 8)
00565         return (NUMA *)ERROR_PTR("d not 2, 4 or 8", procName, NULL);
00566 
00567     size = 1 << d;
00568     if ((na = numaCreate(size)) == NULL)
00569         return (NUMA *)ERROR_PTR("na not made", procName, NULL);
00570     numaSetCount(na, size);  /* all initialized to 0.0 */
00571     array = numaGetFArray(na, L_NOCOPY);
00572 
00573     datas = pixGetData(pixs);
00574     wpls = pixGetWpl(pixs);
00575     datam = pixGetData(pixm);
00576     wplm = pixGetWpl(pixm);
00577 
00578     for (i = 0; i < hm; i += factor) {
00579         if (y + i < 0 || y + i >= h) continue;
00580         lines = datas + (y + i) * wpls;
00581         linem = datam + i * wplm;
00582         for (j = 0; j < wm; j += factor) {
00583             if (x + j < 0 || x + j >= w) continue;
00584             if (GET_DATA_BIT(linem, j)) {
00585                 if (d == 8)
00586                     val = GET_DATA_BYTE(lines, x + j);
00587                 else if (d == 4)
00588                     val = GET_DATA_QBIT(lines, x + j);
00589                 else  /* d == 2 */
00590                     val = GET_DATA_DIBIT(lines, x + j);
00591                 array[val] += 1.0;
00592             }
00593         }
00594     }
00595 
00596     return na;
00597 }
00598 
00599 
00600 /*!
00601  *  pixGetRankValueMaskedRGB()
00602  *
00603  *      Input:  pixs (32 bpp)
00604  *              pixm (<optional> 1 bpp mask over which rank val is to be taken;
00605  *                    use all pixels if null)
00606  *              x, y (UL corner of pixm relative to the UL corner of pixs;
00607  *                    can be < 0; these values are ignored if pixm is null)
00608  *              factor (subsampling factor; integer >= 1)
00609  *              rank (between 0.0 and 1.0; 1.0 is brightest, 0.0 is darkest)
00610  *              &rval (<optional return> red component val for to input rank)
00611  *              &gval (<optional return> green component val for to input rank)
00612  *              &bval (<optional return> blue component val for to input rank)
00613  *      Return: 0 if OK, 1 on error
00614  *
00615  *  Notes:
00616  *      (1) Computes the rank component values of pixels in pixs that
00617  *          are under the fg of the optional mask.  If the mask is null, it
00618  *          computes the average of the pixels in pixs.
00619  *      (2) Set the subsampling factor > 1 to reduce the amount of
00620  *          computation.
00621  *      (4) Input x,y are ignored unless pixm exists.
00622  *      (5) The rank must be in [0.0 ... 1.0], where the brightest pixel
00623  *          has rank 1.0.  For the median pixel value, use 0.5.
00624  */
00625 l_int32
00626 pixGetRankValueMaskedRGB(PIX        *pixs,
00627                          PIX        *pixm,
00628                          l_int32     x,
00629                          l_int32     y,
00630                          l_int32     factor,
00631                          l_float32   rank,
00632                          l_float32  *prval,
00633                          l_float32  *pgval,
00634                          l_float32  *pbval)
00635 {
00636 l_float32  scale;
00637 PIX       *pixmt, *pixt;
00638 
00639     PROCNAME("pixGetRankValueMaskedRGB");
00640 
00641     if (!pixs)
00642         return ERROR_INT("pixs not defined", procName, 1);
00643     if (pixGetDepth(pixs) != 32)
00644         return ERROR_INT("pixs not 32 bpp", procName, 1);
00645     if (pixm && pixGetDepth(pixm) != 1)
00646         return ERROR_INT("pixm not 1 bpp", procName, 1);
00647     if (factor < 1)
00648         return ERROR_INT("sampling factor < 1", procName, 1);
00649     if (rank < 0.0 || rank > 1.0)
00650         return ERROR_INT("rank not in [0.0 ... 1.0]", procName, 1);
00651     if (!prval && !pgval && !pbval)
00652         return ERROR_INT("no results requested", procName, 1);
00653 
00654     pixmt = NULL;
00655     if (pixm) {
00656         scale = 1.0 / (l_float32)factor;
00657         pixmt = pixScale(pixm, scale, scale);
00658     }
00659     if (prval) {
00660         pixt = pixScaleRGBToGrayFast(pixs, factor, COLOR_RED);
00661         pixGetRankValueMasked(pixt, pixmt, x / factor, y / factor,
00662                               factor, rank, prval, NULL);
00663         pixDestroy(&pixt);
00664     }
00665     if (pgval) {
00666         pixt = pixScaleRGBToGrayFast(pixs, factor, COLOR_GREEN);
00667         pixGetRankValueMasked(pixt, pixmt, x / factor, y / factor,
00668                               factor, rank, pgval, NULL);
00669         pixDestroy(&pixt);
00670     }
00671     if (pbval) {
00672         pixt = pixScaleRGBToGrayFast(pixs, factor, COLOR_BLUE);
00673         pixGetRankValueMasked(pixt, pixmt, x / factor, y / factor,
00674                               factor, rank, pbval, NULL);
00675         pixDestroy(&pixt);
00676     }
00677     pixDestroy(&pixmt);
00678     return 0;
00679 }
00680 
00681 
00682 /*!
00683  *  pixGetRankValueMasked()
00684  *
00685  *      Input:  pixs (8 bpp, or colormapped)
00686  *              pixm (<optional> 1 bpp mask over which rank val is to be taken;
00687  *                    use all pixels if null)
00688  *              x, y (UL corner of pixm relative to the UL corner of pixs;
00689  *                    can be < 0; these values are ignored if pixm is null)
00690  *              factor (subsampling factor; integer >= 1)
00691  *              rank (between 0.0 and 1.0; 1.0 is brightest, 0.0 is darkest)
00692  *              &val (<return> pixel value corresponding to input rank)
00693  *              &na (<optional return> of histogram)
00694  *      Return: 0 if OK, 1 on error
00695  *
00696  *  Notes:
00697  *      (1) Computes the rank value of pixels in pixs that are under
00698  *          the fg of the optional mask.  If the mask is null, it
00699  *          computes the average of the pixels in pixs.
00700  *      (2) Set the subsampling factor > 1 to reduce the amount of
00701  *          computation.
00702  *      (3) Clipping of pixm (if it exists) to pixs is done in the inner loop.
00703  *      (4) Input x,y are ignored unless pixm exists.
00704  *      (5) The rank must be in [0.0 ... 1.0], where the brightest pixel
00705  *          has rank 1.0.  For the median pixel value, use 0.5.
00706  *      (6) The histogram can optionally be returned, so that other rank
00707  *          values can be extracted without recomputing the histogram.
00708  *          In that case, just use
00709  *              numaHistogramGetValFromRank(na, rank, &val);
00710  *          on the returned Numa for additional rank values.
00711  */
00712 l_int32
00713 pixGetRankValueMasked(PIX        *pixs,
00714                       PIX        *pixm,
00715                       l_int32     x,
00716                       l_int32     y,
00717                       l_int32     factor,
00718                       l_float32   rank,
00719                       l_float32  *pval,
00720                       NUMA      **pna)
00721 {
00722 NUMA  *na;
00723 
00724     PROCNAME("pixGetRankValueMasked");
00725 
00726     if (pna)
00727         *pna = NULL;
00728     if (!pixs)
00729         return ERROR_INT("pixs not defined", procName, 1);
00730     if (pixGetDepth(pixs) != 8 && !pixGetColormap(pixs))
00731         return ERROR_INT("pixs neither 8 bpp nor colormapped", procName, 1);
00732     if (pixm && pixGetDepth(pixm) != 1)
00733         return ERROR_INT("pixm not 1 bpp", procName, 1);
00734     if (factor < 1)
00735         return ERROR_INT("sampling factor < 1", procName, 1);
00736     if (rank < 0.0 || rank > 1.0)
00737         return ERROR_INT("rank not in [0.0 ... 1.0]", procName, 1);
00738     if (!pval)
00739         return ERROR_INT("&val not defined", procName, 1);
00740     *pval = 0.0;  /* init */
00741 
00742     if ((na = pixGetGrayHistogramMasked(pixs, pixm, x, y, factor)) == NULL)
00743         return ERROR_INT("na not made", procName, 1);
00744     numaHistogramGetValFromRank(na, rank, pval);
00745     if (pna)
00746         *pna = na;
00747     else
00748         numaDestroy(&na);
00749 
00750     return 0;
00751 }
00752 
00753 
00754 /*!
00755  *  pixGetAverageMaskedRGB()
00756  *
00757  *      Input:  pixs (32 bpp, or colormapped)
00758  *              pixm (<optional> 1 bpp mask over which average is to be taken;
00759  *                    use all pixels if null)
00760  *              x, y (UL corner of pixm relative to the UL corner of pixs;
00761  *                    can be < 0)
00762  *              factor (subsampling factor; >= 1)
00763  *              type (L_MEAN_ABSVAL, L_ROOT_MEAN_SQUARE,
00764  *                    L_STANDARD_DEVIATION, L_VARIANCE)
00765  *              &rval (<return optional> measured red value of given 'type')
00766  *              &gval (<return optional> measured green value of given 'type')
00767  *              &bval (<return optional> measured blue value of given 'type')
00768  *      Return: 0 if OK, 1 on error
00769  *
00770  *  Notes:
00771  *      (1) For usage, see pixGetAverageMasked().
00772  *      (2) If there is a colormap, it is removed before the 8 bpp
00773  *          component images are extracted.
00774  */
00775 l_int32
00776 pixGetAverageMaskedRGB(PIX        *pixs,
00777                        PIX        *pixm,
00778                        l_int32     x,
00779                        l_int32     y,
00780                        l_int32     factor,
00781                        l_int32     type,
00782                        l_float32  *prval,
00783                        l_float32  *pgval,
00784                        l_float32  *pbval)
00785 {
00786 l_int32   color;
00787 PIX      *pixt;
00788 PIXCMAP  *cmap;
00789 
00790     PROCNAME("pixGetAverageMaskedRGB");
00791 
00792     if (!pixs)
00793         return ERROR_INT("pixs not defined", procName, 1);
00794     color = 0;
00795     cmap = pixGetColormap(pixs);
00796     if (pixGetDepth(pixs) != 32 && !cmap)
00797         return ERROR_INT("pixs neither 32 bpp nor colormapped", procName, 1);
00798     if (pixm && pixGetDepth(pixm) != 1)
00799         return ERROR_INT("pixm not 1 bpp", procName, 1);
00800     if (factor < 1)
00801         return ERROR_INT("subsampling factor < 1", procName, 1);
00802     if (type != L_MEAN_ABSVAL && type != L_ROOT_MEAN_SQUARE &&
00803         type != L_STANDARD_DEVIATION && type != L_VARIANCE)
00804         return ERROR_INT("invalid measure type", procName, 1);
00805     if (!prval && !pgval && !pbval)
00806         return ERROR_INT("no values requested", procName, 1);
00807 
00808     if (prval) {
00809         if (cmap)
00810             pixt = pixGetRGBComponentCmap(pixs, COLOR_RED);
00811         else
00812             pixt = pixGetRGBComponent(pixs, COLOR_RED);
00813         pixGetAverageMasked(pixt, pixm, x, y, factor, type, prval);
00814         pixDestroy(&pixt);
00815     }
00816     if (pgval) {
00817         if (cmap)
00818             pixt = pixGetRGBComponentCmap(pixs, COLOR_GREEN);
00819         else
00820             pixt = pixGetRGBComponent(pixs, COLOR_GREEN);
00821         pixGetAverageMasked(pixt, pixm, x, y, factor, type, pgval);
00822         pixDestroy(&pixt);
00823     }
00824     if (pbval) {
00825         if (cmap)
00826             pixt = pixGetRGBComponentCmap(pixs, COLOR_BLUE);
00827         else
00828             pixt = pixGetRGBComponent(pixs, COLOR_BLUE);
00829         pixGetAverageMasked(pixt, pixm, x, y, factor, type, pbval);
00830         pixDestroy(&pixt);
00831     }
00832 
00833     return 0;
00834 }
00835 
00836 
00837 /*!
00838  *  pixGetAverageMasked()
00839  *
00840  *      Input:  pixs (8 or 16 bpp, or colormapped)
00841  *              pixm (<optional> 1 bpp mask over which average is to be taken;
00842  *                    use all pixels if null)
00843  *              x, y (UL corner of pixm relative to the UL corner of pixs;
00844  *                    can be < 0)
00845  *              factor (subsampling factor; >= 1)
00846  *              type (L_MEAN_ABSVAL, L_ROOT_MEAN_SQUARE,
00847  *                    L_STANDARD_DEVIATION, L_VARIANCE)
00848  *              &val (<return> measured value of given 'type')
00849  *      Return: 0 if OK, 1 on error
00850  *
00851  *  Notes:
00852  *      (1) Use L_MEAN_ABSVAL to get the average value of pixels in pixs
00853  *          that are under the fg of the optional mask.  If the mask
00854  *          is null, it finds the average of the pixels in pixs.
00855  *      (2) Likewise, use L_ROOT_MEAN_SQUARE to get the rms value of
00856  *          pixels in pixs, either masked or not; L_STANDARD_DEVIATION
00857  *          to get the standard deviation from the mean of the pixels;
00858  *          L_VARIANCE to get the average squared difference from the
00859  *          expected value.  The variance is the square of the stdev.
00860  *          For the standard deviation, we use
00861  *              sqrt(<(<x> - x)>^2) = sqrt(<x^2> - <x>^2)
00862  *      (3) Set the subsampling factor > 1 to reduce the amount of
00863  *          computation.
00864  *      (4) Clipping of pixm (if it exists) to pixs is done in the inner loop.
00865  *      (5) Input x,y are ignored unless pixm exists.
00866  */
00867 l_int32
00868 pixGetAverageMasked(PIX        *pixs,
00869                     PIX        *pixm,
00870                     l_int32     x,
00871                     l_int32     y,
00872                     l_int32     factor,
00873                     l_int32     type,
00874                     l_float32  *pval)
00875 {
00876 l_int32    i, j, w, h, d, wm, hm, wplg, wplm, val, count;
00877 l_uint32  *datag, *datam, *lineg, *linem;
00878 l_float64  sumave, summs, ave, meansq, var;
00879 PIX       *pixg;
00880 
00881     PROCNAME("pixGetAverageMasked");
00882 
00883     if (!pixs)
00884         return ERROR_INT("pixs not defined", procName, 1);
00885     d = pixGetDepth(pixs);
00886     if (d != 8 && d != 16 && !pixGetColormap(pixs))
00887         return ERROR_INT("pixs not 8 or 16 bpp or colormapped", procName, 1);
00888     if (pixm && pixGetDepth(pixm) != 1)
00889         return ERROR_INT("pixm not 1 bpp", procName, 1);
00890     if (factor < 1)
00891         return ERROR_INT("subsampling factor < 1", procName, 1);
00892     if (type != L_MEAN_ABSVAL && type != L_ROOT_MEAN_SQUARE &&
00893         type != L_STANDARD_DEVIATION && type != L_VARIANCE)
00894         return ERROR_INT("invalid measure type", procName, 1);
00895     if (!pval)
00896         return ERROR_INT("&val not defined", procName, 1);
00897     *pval = 0.0;  /* init */
00898 
00899     if (pixGetColormap(pixs))
00900         pixg = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
00901     else
00902         pixg = pixClone(pixs);
00903     pixGetDimensions(pixg, &w, &h, &d);
00904     datag = pixGetData(pixg);
00905     wplg = pixGetWpl(pixg);
00906 
00907     sumave = summs = 0.0;
00908     count = 0;
00909     if (!pixm) {
00910         for (i = 0; i < h; i += factor) {
00911             lineg = datag + i * wplg;
00912             for (j = 0; j < w; j += factor) {
00913                 if (d == 8)
00914                     val = GET_DATA_BYTE(lineg, j);
00915                 else  /* d == 16 */
00916                     val = GET_DATA_TWO_BYTES(lineg, j);
00917                 if (type != L_ROOT_MEAN_SQUARE)
00918                     sumave += val;
00919                 if (type != L_MEAN_ABSVAL)
00920                     summs += val * val;
00921                 count++;
00922             }
00923         }
00924     }
00925     else {
00926         pixGetDimensions(pixm, &wm, &hm, NULL);
00927         datam = pixGetData(pixm);
00928         wplm = pixGetWpl(pixm);
00929         for (i = 0; i < hm; i += factor) {
00930             if (y + i < 0 || y + i >= h) continue;
00931             lineg = datag + (y + i) * wplg;
00932             linem = datam + i * wplm;
00933             for (j = 0; j < wm; j += factor) {
00934                 if (x + j < 0 || x + j >= w) continue;
00935                 if (GET_DATA_BIT(linem, j)) {
00936                     if (d == 8)
00937                         val = GET_DATA_BYTE(lineg, x + j);
00938                     else  /* d == 16 */
00939                         val = GET_DATA_TWO_BYTES(lineg, x + j);
00940                     if (type != L_ROOT_MEAN_SQUARE)
00941                         sumave += val;
00942                     if (type != L_MEAN_ABSVAL)
00943                         summs += val * val;
00944                     count++;
00945                 }
00946             }
00947         }
00948     }
00949 
00950     pixDestroy(&pixg);
00951     if (count == 0)
00952         return ERROR_INT("no pixels sampled", procName, 1);
00953     ave = sumave / (l_float64)count;
00954     meansq = summs / (l_float64)count;
00955     var = meansq - ave * ave;
00956     if (type == L_MEAN_ABSVAL)
00957         *pval = (l_float32)ave;
00958     else if (type == L_ROOT_MEAN_SQUARE)
00959         *pval = (l_float32)sqrt(meansq);
00960     else if (type == L_STANDARD_DEVIATION)
00961         *pval = (l_float32)sqrt(var);
00962     else  /* type == L_VARIANCE */
00963         *pval = (l_float32)var;
00964 
00965     return 0;
00966 }
00967 
00968 
00969 /*!
00970  *  pixGetAverageTiledRGB()
00971  *
00972  *      Input:  pixs (32 bpp, or colormapped)
00973  *              sx, sy (tile size; must be at least 2 x 2)
00974  *              type (L_MEAN_ABSVAL, L_ROOT_MEAN_SQUARE, L_STANDARD_DEVIATION)
00975  *              &pixr (<optional return> tiled 'average' of red component)
00976  *              &pixg (<optional return> tiled 'average' of green component)
00977  *              &pixb (<optional return> tiled 'average' of blue component)
00978  *      Return: 0 if OK, 1 on error
00979  *
00980  *  Notes:
00981  *      (1) For usage, see pixGetAverageTiled().
00982  *      (2) If there is a colormap, it is removed before the 8 bpp
00983  *          component images are extracted.
00984  */
00985 l_int32
00986 pixGetAverageTiledRGB(PIX     *pixs,
00987                       l_int32  sx,
00988                       l_int32  sy,
00989                       l_int32  type,
00990                       PIX    **ppixr,
00991                       PIX    **ppixg,
00992                       PIX    **ppixb)
00993 {
00994 PIX      *pixt;
00995 PIXCMAP  *cmap;
00996 
00997     PROCNAME("pixGetAverageTiledRGB");
00998 
00999     if (!pixs)
01000         return ERROR_INT("pixs not defined", procName, 1);
01001     cmap = pixGetColormap(pixs);
01002     if (pixGetDepth(pixs) != 32 && !cmap)
01003         return ERROR_INT("pixs neither 32 bpp nor colormapped", procName, 1);
01004     if (sx < 2 || sy < 2)
01005         return ERROR_INT("sx and sy not both > 1", procName, 1);
01006     if (type != L_MEAN_ABSVAL && type != L_ROOT_MEAN_SQUARE &&
01007         type != L_STANDARD_DEVIATION)
01008         return ERROR_INT("invalid measure type", procName, 1);
01009     if (!ppixr && !ppixg && !ppixb)
01010         return ERROR_INT("no returned data requested", procName, 1);
01011 
01012     if (ppixr) {
01013         if (cmap)
01014             pixt = pixGetRGBComponentCmap(pixs, COLOR_RED);
01015         else
01016             pixt = pixGetRGBComponent(pixs, COLOR_RED);
01017         *ppixr = pixGetAverageTiled(pixt, sx, sy, type);
01018         pixDestroy(&pixt);
01019     }
01020     if (ppixg) {
01021         if (cmap)
01022             pixt = pixGetRGBComponentCmap(pixs, COLOR_GREEN);
01023         else
01024             pixt = pixGetRGBComponent(pixs, COLOR_GREEN);
01025         *ppixg = pixGetAverageTiled(pixt, sx, sy, type);
01026         pixDestroy(&pixt);
01027     }
01028     if (ppixb) {
01029         if (cmap)
01030             pixt = pixGetRGBComponentCmap(pixs, COLOR_BLUE);
01031         else
01032             pixt = pixGetRGBComponent(pixs, COLOR_BLUE);
01033         *ppixb = pixGetAverageTiled(pixt, sx, sy, type);
01034         pixDestroy(&pixt);
01035     }
01036 
01037     return 0;
01038 }
01039 
01040 
01041 /*!
01042  *  pixGetAverageTiled()
01043  *
01044  *      Input:  pixs (8 bpp, or colormapped)
01045  *              sx, sy (tile size; must be at least 2 x 2)
01046  *              type (L_MEAN_ABSVAL, L_ROOT_MEAN_SQUARE, L_STANDARD_DEVIATION)
01047  *      Return: pixd (average values in each tile), or null on error
01048  *
01049  *  Notes:
01050  *      (1) Only computes for tiles that are entirely contained in pixs.
01051  *      (2) Use L_MEAN_ABSVAL to get the average abs value within the tile;
01052  *          L_ROOT_MEAN_SQUARE to get the rms value within each tile;
01053  *          L_STANDARD_DEVIATION to get the standard dev. from the average
01054  *          within each tile.
01055  *      (3) If colormapped, converts to 8 bpp gray.
01056  */
01057 PIX *
01058 pixGetAverageTiled(PIX     *pixs,
01059                    l_int32  sx,
01060                    l_int32  sy,
01061                    l_int32  type)
01062 {
01063 l_int32    i, j, k, m, w, h, wd, hd, d, pos, wplt, wpld, valt;
01064 l_uint32  *datat, *datad, *linet, *lined, *startt;
01065 l_float64  sumave, summs, ave, meansq, normfact;
01066 PIX       *pixt, *pixd;
01067 
01068     PROCNAME("pixGetAverageTiled");
01069 
01070     if (!pixs)
01071         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
01072     pixGetDimensions(pixs, &w, &h, &d);
01073     if (d != 8 && !pixGetColormap(pixs))
01074         return (PIX *)ERROR_PTR("pixs not 8 bpp or cmapped", procName, NULL);
01075     if (sx < 2 || sy < 2)
01076         return (PIX *)ERROR_PTR("sx and sy not both > 1", procName, NULL);
01077     wd = w / sx;
01078     hd = h / sy;
01079     if (wd < 1 || hd < 1)
01080         return (PIX *)ERROR_PTR("wd or hd == 0", procName, NULL);
01081     if (type != L_MEAN_ABSVAL && type != L_ROOT_MEAN_SQUARE &&
01082         type != L_STANDARD_DEVIATION)
01083         return (PIX *)ERROR_PTR("invalid measure type", procName, NULL);
01084 
01085     pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
01086     pixd = pixCreate(wd, hd, 8);
01087     datat = pixGetData(pixt);
01088     wplt = pixGetWpl(pixt);
01089     datad = pixGetData(pixd);
01090     wpld = pixGetWpl(pixd);
01091     normfact = 1. / (l_float64)(sx * sy);
01092     for (i = 0; i < hd; i++) {
01093         lined = datad + i * wpld;
01094         linet = datat + i * sy * wplt;
01095         for (j = 0; j < wd; j++) {
01096             if (type == L_MEAN_ABSVAL || type == L_STANDARD_DEVIATION) {
01097                 sumave = 0.0;
01098                 for (k = 0; k < sy; k++) {
01099                     startt = linet + k * wplt;
01100                     for (m = 0; m < sx; m++) {
01101                         pos = j * sx + m;
01102                         valt = GET_DATA_BYTE(startt, pos);
01103                         sumave += valt;
01104                     }
01105                 }
01106                 ave = normfact * sumave;
01107             }
01108             if (type == L_ROOT_MEAN_SQUARE || type == L_STANDARD_DEVIATION) {
01109                 summs = 0.0;
01110                 for (k = 0; k < sy; k++) {
01111                     startt = linet + k * wplt;
01112                     for (m = 0; m < sx; m++) {
01113                         pos = j * sx + m;
01114                         valt = GET_DATA_BYTE(startt, pos);
01115                         summs += valt * valt;
01116                     }
01117                 }
01118                 meansq = normfact * summs;
01119             }
01120             if (type == L_MEAN_ABSVAL)
01121                 valt = (l_int32)(ave + 0.5);
01122             else if (type == L_ROOT_MEAN_SQUARE)
01123                 valt = (l_int32)(sqrt(meansq) + 0.5);
01124             else  /* type == L_STANDARD_DEVIATION */
01125                 valt = (l_int32)(sqrt(meansq - ave * ave) + 0.5);
01126             SET_DATA_BYTE(lined, j, valt);
01127         }
01128     }
01129 
01130     pixDestroy(&pixt);
01131     return pixd;
01132 }
01133 
01134 
01135 /*!
01136  *  pixRowStats()
01137  *
01138  *      Input:  pixs (8 bpp; not cmapped)
01139  *              &namean (<optional return> numa of mean values)
01140  *              &namedian (<optional return> numa of median values)
01141  *              &namode (<optional return> numa of mode intensity values)
01142  *              &namodecount (<optional return> numa of mode counts)
01143  *              &navar (<optional return> numa of variance)
01144  *              &narootvar (<optional return> numa of square root of variance)
01145  *      Return: na (numa of requested statistic for each row), or null on error
01146  *
01147  *  Notes:
01148  *      (1) This computes numas that represent column vectors of statistics,
01149  *          with each of its values derived from the corresponding row of a Pix.
01150  *      (2) Use NULL on input to prevent computation of any of the 5 numas.
01151  *      (3) Other functions that compute pixel row statistics are:
01152  *             pixCountPixelsByRow()
01153  *             pixSumPixelsByRow()
01154  *             pixGetRowStats()
01155  */
01156 l_int32
01157 pixRowStats(PIX    *pixs,
01158             NUMA  **pnamean,
01159             NUMA  **pnamedian,
01160             NUMA  **pnamode,
01161             NUMA  **pnamodecount,
01162             NUMA  **pnavar,
01163             NUMA  **pnarootvar)
01164 {
01165 l_int32     i, j, k, w, h, val, wpls, sum, sumsq, target, max, modeval;
01166 l_int32    *histo;
01167 l_uint32   *lines, *datas;
01168 l_float32   norm;
01169 l_float32  *famean, *fameansq, *favar, *farootvar;
01170 l_float32  *famedian, *famode, *famodecount;
01171 
01172     PROCNAME("pixRowStats");
01173 
01174     if (pnamean) *pnamean = NULL;
01175     if (pnamedian) *pnamedian = NULL;
01176     if (pnamode) *pnamode = NULL;
01177     if (pnamodecount) *pnamodecount = NULL;
01178     if (pnavar) *pnavar = NULL;
01179     if (pnarootvar) *pnarootvar = NULL;
01180     if (!pixs || pixGetDepth(pixs) != 8)
01181         return ERROR_INT("pixs undefined or not 8 bpp", procName, 1);
01182 
01183     pixGetDimensions(pixs, &w, &h, NULL);
01184     datas = pixGetData(pixs);
01185     wpls = pixGetWpl(pixs);
01186 
01187         /* We need the mean for variance and root variance */
01188     if (pnamean || pnavar || pnarootvar) {
01189         norm = 1. / (l_float32)w;
01190         famean = (l_float32 *)CALLOC(h, sizeof(l_float32));
01191         fameansq = (l_float32 *)CALLOC(h, sizeof(l_float32));
01192         if (pnavar || pnarootvar) {
01193             favar = (l_float32 *)CALLOC(h, sizeof(l_float32));
01194             if (pnarootvar)
01195                 farootvar = (l_float32 *)CALLOC(h, sizeof(l_float32));
01196         }
01197         for (i = 0; i < h; i++) {
01198             sum = sumsq = 0;
01199             lines = datas + i * wpls;
01200             for (j = 0; j < w; j++) {
01201                 val = GET_DATA_BYTE(lines, j);
01202                 sum += val;
01203                 sumsq += val * val;
01204             }
01205             famean[i] = norm * sum;
01206             fameansq[i] = norm * sumsq;
01207             if (pnavar || pnarootvar) {
01208                 favar[i] = fameansq[i] - famean[i] * famean[i];
01209                 if (pnarootvar)
01210                     farootvar[i] = sqrt(favar[i]);
01211             }
01212         }
01213         FREE(fameansq);
01214         if (pnamean)
01215             *pnamean = numaCreateFromFArray(famean, h, L_INSERT);
01216         else
01217             FREE(famean);
01218         if (pnavar)
01219             *pnavar = numaCreateFromFArray(favar, h, L_INSERT);
01220         else
01221             FREE(favar);
01222         if (pnarootvar)
01223             *pnarootvar = numaCreateFromFArray(farootvar, h, L_INSERT);
01224     }
01225 
01226         /* We need a histogram to find the median and/or mode values */
01227     if (pnamedian || pnamode || pnamodecount) {
01228         histo = (l_int32 *)CALLOC(256, sizeof(l_int32));
01229         if (pnamedian) {
01230             *pnamedian = numaMakeConstant(0, h);
01231             famedian = numaGetFArray(*pnamedian, L_NOCOPY);
01232         }
01233         if (pnamode) {
01234             *pnamode = numaMakeConstant(0, h);
01235             famode = numaGetFArray(*pnamode, L_NOCOPY);
01236         }
01237         if (pnamodecount) {
01238             *pnamodecount = numaMakeConstant(0, h);
01239             famodecount = numaGetFArray(*pnamodecount, L_NOCOPY);
01240         }
01241         for (i = 0; i < h; i++) {
01242             lines = datas + i * wpls;
01243             memset(histo, 0, 1024);
01244             for (j = 0; j < w; j++) {
01245                 val = GET_DATA_BYTE(lines, j);
01246                 histo[val]++;
01247             }
01248 
01249             if (pnamedian) {
01250                 sum = 0;
01251                 target = (w + 1) / 2;
01252                 for (k = 0; k < 256; k++) {
01253                     sum += histo[k];
01254                     if (sum >= target) {
01255                         famedian[i] = k;
01256                         break;
01257                     }
01258                 }
01259             }
01260 
01261             if (pnamode || pnamodecount) {
01262                 max = 0;
01263                 modeval = 0;
01264                 for (k = 0; k < 256; k++) {
01265                     if (histo[k] > max) {
01266                         max = histo[k];
01267                         modeval = k;
01268                     }
01269                 }
01270                 if (pnamode)
01271                     famode[i] = modeval;
01272                 if (pnamodecount)
01273                     famodecount[i] = max;
01274             }
01275         }
01276         FREE(histo);
01277     }
01278 
01279     return 0;
01280 }
01281 
01282 
01283 /*!
01284  *  pixColumnStats()
01285  *
01286  *      Input:  pixs (8 bpp; not cmapped)
01287  *              &namean (<optional return> numa of mean values)
01288  *              &namedian (<optional return> numa of median values)
01289  *              &namode (<optional return> numa of mode intensity values)
01290  *              &namodecount (<optional return> numa of mode counts)
01291  *              &navar (<optional return> numa of variance)
01292  *              &narootvar (<optional return> numa of square root of variance)
01293  *      Return: na (numa of requested statistic for each column),
01294  *                  or null on error
01295  *
01296  *  Notes:
01297  *      (1) This computes numas that represent row vectors of statistics,
01298  *          with each of its values derived from the corresponding col of a Pix.
01299  *      (2) Use NULL on input to prevent computation of any of the 5 numas.
01300  *      (3) Other functions that compute pixel column statistics are:
01301  *             pixCountPixelsByColumn()
01302  *             pixSumPixelsByColumn()
01303  *             pixGetColumnStats()
01304  */
01305 l_int32
01306 pixColumnStats(PIX    *pixs,
01307                NUMA  **pnamean,
01308                NUMA  **pnamedian,
01309                NUMA  **pnamode,
01310                NUMA  **pnamodecount,
01311                NUMA  **pnavar,
01312                NUMA  **pnarootvar)
01313 {
01314 l_int32     i, j, k, w, h, val, wpls, sum, sumsq, target, max, modeval;
01315 l_int32    *histo;
01316 l_uint32   *lines, *datas;
01317 l_float32   norm;
01318 l_float32  *famean, *fameansq, *favar, *farootvar;
01319 l_float32  *famedian, *famode, *famodecount;
01320 
01321     PROCNAME("pixColumnStats");
01322 
01323     if (pnamean) *pnamean = NULL;
01324     if (pnamedian) *pnamedian = NULL;
01325     if (pnamode) *pnamode = NULL;
01326     if (pnamodecount) *pnamodecount = NULL;
01327     if (pnavar) *pnavar = NULL;
01328     if (pnarootvar) *pnarootvar = NULL;
01329     if (!pixs || pixGetDepth(pixs) != 8)
01330         return ERROR_INT("pixs undefined or not 8 bpp", procName, 1);
01331 
01332     pixGetDimensions(pixs, &w, &h, NULL);
01333     datas = pixGetData(pixs);
01334     wpls = pixGetWpl(pixs);
01335 
01336         /* We need the mean for variance and root variance */
01337     if (pnamean || pnavar || pnarootvar) {
01338         norm = 1. / (l_float32)h;
01339         famean = (l_float32 *)CALLOC(w, sizeof(l_float32));
01340         fameansq = (l_float32 *)CALLOC(w, sizeof(l_float32));
01341         if (pnavar || pnarootvar) {
01342             favar = (l_float32 *)CALLOC(w, sizeof(l_float32));
01343             if (pnarootvar)
01344                 farootvar = (l_float32 *)CALLOC(w, sizeof(l_float32));
01345         }
01346         for (j = 0; j < w; j++) {
01347             sum = sumsq = 0;
01348             for (i = 0, lines = datas; i < h; lines += wpls, i++) {
01349                 val = GET_DATA_BYTE(lines, j);
01350                 sum += val;
01351                 sumsq += val * val;
01352             }
01353             famean[j] = norm * sum;
01354             fameansq[j] = norm * sumsq;
01355             if (pnavar || pnarootvar) {
01356                 favar[j] = fameansq[j] - famean[j] * famean[j];
01357                 if (pnarootvar)
01358                     farootvar[j] = sqrt(favar[j]);
01359             }
01360         }
01361         FREE(fameansq);
01362         if (pnamean)
01363             *pnamean = numaCreateFromFArray(famean, w, L_INSERT);
01364         else
01365             FREE(famean);
01366         if (pnavar)
01367             *pnavar = numaCreateFromFArray(favar, w, L_INSERT);
01368         else
01369             FREE(favar);
01370         if (pnarootvar)
01371             *pnarootvar = numaCreateFromFArray(farootvar, w, L_INSERT);
01372     }
01373 
01374         /* We need a histogram to find the median and/or mode values */
01375     if (pnamedian || pnamode || pnamodecount) {
01376         histo = (l_int32 *)CALLOC(256, sizeof(l_int32));
01377         if (pnamedian) {
01378             *pnamedian = numaMakeConstant(0, w);
01379             famedian = numaGetFArray(*pnamedian, L_NOCOPY);
01380         }
01381         if (pnamode) {
01382             *pnamode = numaMakeConstant(0, w);
01383             famode = numaGetFArray(*pnamode, L_NOCOPY);
01384         }
01385         if (pnamodecount) {
01386             *pnamodecount = numaMakeConstant(0, w);
01387             famodecount = numaGetFArray(*pnamodecount, L_NOCOPY);
01388         }
01389         for (j = 0; j < w; j++) {
01390             memset(histo, 0, 1024);
01391             for (i = 0, lines = datas; i < h; lines += wpls, i++) {
01392                 val = GET_DATA_BYTE(lines, j);
01393                 histo[val]++;
01394             }
01395 
01396             if (pnamedian) {
01397                 sum = 0;
01398                 target = (h + 1) / 2;
01399                 for (k = 0; k < 256; k++) {
01400                     sum += histo[k];
01401                     if (sum >= target) {
01402                         famedian[j] = k;
01403                         break;
01404                     }
01405                 }
01406             }
01407 
01408             if (pnamode || pnamodecount) {
01409                 max = 0;
01410                 modeval = 0;
01411                 for (k = 0; k < 256; k++) {
01412                     if (histo[k] > max) {
01413                         max = histo[k];
01414                         modeval = k;
01415                     }
01416                 }
01417                 if (pnamode)
01418                     famode[j] = modeval;
01419                 if (pnamodecount)
01420                     famodecount[j] = max;
01421             }
01422         }
01423         FREE(histo);
01424     }
01425 
01426     return 0;
01427 }
01428 
01429 
01430 /*!
01431  *  pixGetComponentRange()
01432  *
01433  *      Input:  pixs (8 bpp grayscale, 32 bpp rgb, or colormapped)
01434  *              factor (subsampling factor; >= 1; ignored if colormapped)
01435  *              color (L_SELECT_RED, L_SELECT_GREEN or L_SELECT_BLUE)
01436  *              &minval (<optional return> minimum value of component)
01437  *              &maxval (<optional return> maximum value of component)
01438  *      Return: 0 if OK, 1 on error
01439  *
01440  *  Notes:
01441  *      (1) If pixs is 8 bpp grayscale, the color selection type is ignored.
01442  */
01443 l_int32
01444 pixGetComponentRange(PIX      *pixs,
01445                      l_int32   factor,
01446                      l_int32   color,
01447                      l_int32  *pminval,
01448                      l_int32  *pmaxval)
01449 {
01450 l_int32   d;
01451 PIXCMAP  *cmap;
01452 
01453     PROCNAME("pixGetComponentRange");
01454 
01455     if (pminval) *pminval = 0;
01456     if (pmaxval) *pmaxval = 0;
01457     if (!pminval && !pmaxval)
01458         return ERROR_INT("no result requested", procName, 1);
01459     if (!pixs)
01460         return ERROR_INT("pixs not defined", procName, 1);
01461 
01462     cmap = pixGetColormap(pixs);
01463     if (cmap)
01464         return pixcmapGetComponentRange(cmap, color, pminval, pmaxval);
01465 
01466     if (factor < 1)
01467         return ERROR_INT("subsampling factor < 1", procName, 1);
01468     d = pixGetDepth(pixs);
01469     if (d != 8 && d != 32)
01470         return ERROR_INT("pixs not 8 or 32 bpp", procName, 1);
01471 
01472     if (d == 8) {
01473         pixGetExtremeValue(pixs, factor, L_SELECT_MIN,
01474                            NULL, NULL, NULL, pminval);
01475         pixGetExtremeValue(pixs, factor, L_SELECT_MAX,
01476                            NULL, NULL, NULL, pmaxval);
01477     } else if (color == L_SELECT_RED) {
01478         pixGetExtremeValue(pixs, factor, L_SELECT_MIN,
01479                            pminval, NULL, NULL, NULL);
01480         pixGetExtremeValue(pixs, factor, L_SELECT_MAX,
01481                            pmaxval, NULL, NULL, NULL);
01482     }
01483     else if (color == L_SELECT_GREEN) {
01484         pixGetExtremeValue(pixs, factor, L_SELECT_MIN,
01485                            NULL, pminval, NULL, NULL);
01486         pixGetExtremeValue(pixs, factor, L_SELECT_MAX,
01487                            NULL, pmaxval, NULL, NULL);
01488     }
01489     else if (color == L_SELECT_BLUE) {
01490         pixGetExtremeValue(pixs, factor, L_SELECT_MIN,
01491                            NULL, NULL, pminval, NULL);
01492         pixGetExtremeValue(pixs, factor, L_SELECT_MAX,
01493                            NULL, NULL, pmaxval, NULL);
01494     }
01495     else
01496         return ERROR_INT("invalid color", procName, 1);
01497 
01498     return 0;
01499 }
01500 
01501 
01502 /*!
01503  *  pixGetExtremeValue()
01504  *
01505  *      Input:  pixs (8 bpp grayscale, 32 bpp rgb, or colormapped)
01506  *              factor (subsampling factor; >= 1; ignored if colormapped)
01507  *              type (L_SELECT_MIN or L_SELECT_MAX)
01508  *              &rval (<optional return> red component)
01509  *              &gval (<optional return> green component)
01510  *              &bval (<optional return> blue component)
01511  *              &grayval (<optional return> min gray value)
01512  *      Return: 0 if OK, 1 on error
01513  *
01514  *  Notes:
01515  *      (1) If pixs is grayscale, the result is returned in &grayval.
01516  *          Otherwise, if there is a colormap or d == 32,
01517  *          each requested color component is returned.  At least
01518  *          one color component (address) must be input.
01519  */
01520 l_int32
01521 pixGetExtremeValue(PIX      *pixs,
01522                    l_int32   factor,
01523                    l_int32   type,
01524                    l_int32  *prval,
01525                    l_int32  *pgval,
01526                    l_int32  *pbval,
01527                    l_int32  *pgrayval)
01528 {
01529 l_int32    i, j, w, h, d, wpl;
01530 l_int32    val, extval, rval, gval, bval, extrval, extgval, extbval;
01531 l_uint32   pixel;
01532 l_uint32  *data, *line;
01533 PIXCMAP   *cmap;
01534 
01535     PROCNAME("pixGetExtremeValue");
01536 
01537     if (!pixs)
01538         return ERROR_INT("pixs not defined", procName, 1);
01539 
01540     cmap = pixGetColormap(pixs);
01541     if (cmap)
01542         return pixcmapGetExtremeValue(cmap, type, prval, pgval, pbval);
01543 
01544     pixGetDimensions(pixs, &w, &h, &d);
01545     if (type != L_SELECT_MIN && type != L_SELECT_MAX)
01546         return ERROR_INT("invalid type", procName, 1);
01547     if (factor < 1)
01548         return ERROR_INT("subsampling factor < 1", procName, 1);
01549     if (d != 8 && d != 32)
01550         return ERROR_INT("pixs not 8 or 32 bpp", procName, 1);
01551     if (d == 8 && !pgrayval)
01552         return ERROR_INT("can't return result in grayval", procName, 1);
01553     if (d == 32 && !prval && !pgval && !pbval)
01554         return ERROR_INT("can't return result in r/g/b-val", procName, 1);
01555 
01556     data = pixGetData(pixs);
01557     wpl = pixGetWpl(pixs);
01558     if (d == 8) {
01559         if (type == L_SELECT_MIN)
01560             extval = 100000;
01561         else  /* get max */
01562             extval = 0;
01563 
01564         for (i = 0; i < h; i += factor) {
01565             line = data + i * wpl;
01566             for (j = 0; j < w; j += factor) {
01567                 val = GET_DATA_BYTE(line, j);
01568                 if ((type == L_SELECT_MIN && val < extval) ||
01569                     (type == L_SELECT_MAX && val > extval))
01570                     extval = val;
01571             }
01572         }
01573         *pgrayval = extval;
01574         return 0;
01575     }
01576 
01577         /* 32 bpp rgb */
01578     if (type == L_SELECT_MIN) {
01579         extrval = 100000;
01580         extgval = 100000;
01581         extbval = 100000;
01582     }
01583     else {
01584         extrval = 0;
01585         extgval = 0;
01586         extbval = 0;
01587     }
01588     for (i = 0; i < h; i += factor) {
01589         line = data + i * wpl;
01590         for (j = 0; j < w; j += factor) {
01591             pixel = line[j];
01592             if (prval) {
01593                 rval = (pixel >> L_RED_SHIFT) & 0xff;
01594                 if ((type == L_SELECT_MIN && rval < extrval) ||
01595                     (type == L_SELECT_MAX && rval > extrval))
01596                     extrval = rval;
01597             }
01598             if (pgval) {
01599                 gval = (pixel >> L_GREEN_SHIFT) & 0xff;
01600                 if ((type == L_SELECT_MIN && gval < extgval) ||
01601                     (type == L_SELECT_MAX && gval > extgval))
01602                     extgval = gval;
01603             }
01604             if (pbval) {
01605                 bval = (pixel >> L_BLUE_SHIFT) & 0xff;
01606                 if ((type == L_SELECT_MIN && bval < extbval) ||
01607                     (type == L_SELECT_MAX && bval > extbval))
01608                     extbval = bval;
01609             }
01610         }
01611     }
01612     if (prval) *prval = extrval;
01613     if (pgval) *pgval = extgval;
01614     if (pbval) *pbval = extbval;
01615     return 0;
01616 }
01617 
01618 
01619 /*!
01620  *  pixGetMaxValueInRect()
01621  *
01622  *      Input:  pixs (8 bpp or 32 bpp grayscale; no color space components)
01623  *              box (<optional> region; set box = NULL to use entire pixs)
01624  *              &maxval (<optional return> max value in region)
01625  *              &xmax (<optional return> x location of max value)
01626  *              &ymax (<optional return> y location of max value)
01627  *      Return: 0 if OK, 1 on error
01628  *
01629  *  Notes:
01630  *      (1) This can be used to find the maximum and its location
01631  *          in a 2-dimensional histogram, where the x and y directions
01632  *          represent two color components (e.g., saturation and hue).
01633  *      (2) Note that here a 32 bpp pixs has pixel values that are simply
01634  *          numbers.  They are not 8 bpp components in a colorspace.
01635  */
01636 l_int32
01637 pixGetMaxValueInRect(PIX       *pixs,
01638                      BOX       *box,
01639                      l_uint32  *pmaxval,
01640                      l_int32   *pxmax,
01641                      l_int32   *pymax)
01642 {
01643 l_int32    i, j, w, h, d, wpl, bw, bh;
01644 l_int32    xstart, ystart, xend, yend, xmax, ymax;
01645 l_uint32   val, maxval;
01646 l_uint32  *data, *line;
01647 
01648     PROCNAME("pixGetMaxValueInRect");
01649 
01650     if (!pmaxval && !pxmax && !pymax)
01651         return ERROR_INT("nothing to do", procName, 1);
01652     if (pmaxval) *pmaxval = 0;
01653     if (pxmax) *pxmax = 0;
01654     if (pymax) *pymax = 0;
01655     if (!pixs)
01656         return ERROR_INT("pixs not defined", procName, 1);
01657     if (pixGetColormap(pixs) != NULL)
01658         return ERROR_INT("pixs has colormap", procName, 1);
01659     pixGetDimensions(pixs, &w, &h, &d);
01660     if (d != 8 && d != 32)
01661         return ERROR_INT("pixs not 8 or 32 bpp", procName, 1);
01662 
01663     xstart = ystart = 0;
01664     xend = w - 1;
01665     yend = h - 1;
01666     if (box) {
01667         boxGetGeometry(box, &xstart, &ystart, &bw, &bh);
01668         xend = xstart + bw - 1;
01669         yend = ystart + bh - 1;
01670     }
01671 
01672     data = pixGetData(pixs);
01673     wpl = pixGetWpl(pixs);
01674     maxval = 0;
01675     xmax = ymax = 0;
01676     for (i = ystart; i <= yend; i++) {
01677         line = data + i * wpl;
01678         for (j = xstart; j <= xend; j++) {
01679             if (d == 8)
01680                 val = GET_DATA_BYTE(line, j);
01681             else  /* d == 32 */
01682                 val = line[j];
01683             if (val > maxval) {
01684                 maxval = val;
01685                 xmax = j;
01686                 ymax = i;
01687             }
01688         }
01689     }
01690     if (maxval == 0) {  /* no counts; pick the center of the rectangle */
01691         xmax = (xstart + xend) / 2;
01692         ymax = (ystart + yend) / 2;
01693     }
01694 
01695     if (pmaxval) *pmaxval = maxval;
01696     if (pxmax) *pxmax = xmax;
01697     if (pymax) *pymax = ymax;
01698     return 0;
01699 }
01700 
01701 
01702 /*!
01703  *  pixGetBinnedComponentRange()
01704  *
01705  *      Input:  pixs (32 bpp rgb)
01706  *              nbins (number of equal population bins; must be > 1)
01707  *              factor (subsampling factor; >= 1)
01708  *              color (L_SELECT_RED, L_SELECT_GREEN or L_SELECT_BLUE)
01709  *              &minval (<optional return> minimum value of component)
01710  *              &maxval (<optional return> maximum value of component)
01711  *              &carray (<optional return> color array of bins)
01712  *              debugflag (1 for debug output)
01713  *      Return: 0 if OK, 1 on error
01714  *
01715  *  Notes:
01716  *      (1) This returns the min and max average values of the
01717  *          selected color component in the set of rank bins,
01718  *          where the ranking is done using the specified component.
01719  */
01720 l_int32
01721 pixGetBinnedComponentRange(PIX        *pixs,
01722                            l_int32     nbins,
01723                            l_int32     factor,
01724                            l_int32     color,
01725                            l_int32    *pminval,
01726                            l_int32    *pmaxval,
01727                            l_uint32  **pcarray,
01728                            l_int32     debugflag)
01729 {
01730 l_int32    i, minval, maxval, rval, gval, bval;
01731 l_uint32  *carray;
01732 PIX       *pixt;
01733 
01734     PROCNAME("pixGetBinnedComponentRange");
01735 
01736     if (pminval) *pminval = 0;
01737     if (pmaxval) *pmaxval = 0;
01738     if (pcarray) *pcarray = NULL;
01739     if (!pminval && !pmaxval)
01740         return ERROR_INT("no result requested", procName, 1);
01741     if (!pixs || pixGetDepth(pixs) != 32)
01742         return ERROR_INT("pixs not defined or not 32 bpp", procName, 1);
01743     if (factor < 1)
01744         return ERROR_INT("subsampling factor < 1", procName, 1);
01745     if (color != L_SELECT_RED && color != L_SELECT_GREEN &&
01746         color != L_SELECT_BLUE)
01747         return ERROR_INT("invalid color", procName, 1);
01748 
01749     pixGetRankColorArray(pixs, nbins, color, factor, &carray, 0);
01750     if (debugflag) {
01751         for (i = 0; i < nbins; i++)
01752             fprintf(stderr, "c[%d] = %x\n", i, carray[i]);
01753         pixt = pixDisplayColorArray(carray, nbins, 200, 5, 1);
01754         pixDisplay(pixt, 100, 100);
01755         pixDestroy(&pixt);
01756     }
01757 
01758     extractRGBValues(carray[0], &rval, &gval, &bval);
01759     minval = rval;
01760     if (color == L_SELECT_GREEN)
01761         minval = gval;
01762     else if (color == L_SELECT_BLUE)
01763         minval = bval;
01764     extractRGBValues(carray[nbins - 1], &rval, &gval, &bval);
01765     maxval = rval;
01766     if (color == L_SELECT_GREEN)
01767         maxval = gval;
01768     else if (color == L_SELECT_BLUE)
01769         maxval = bval;
01770 
01771     if (pminval) *pminval = minval;
01772     if (pmaxval) *pmaxval = maxval;
01773     if (pcarray)
01774         *pcarray = carray;
01775     else
01776         FREE(carray);
01777     return 0;
01778 }
01779 
01780 
01781 /*!
01782  *  pixGetRankColorArray()
01783  *
01784  *      Input:  pixs (32 bpp or cmapped)
01785  *              nbins (number of equal population bins; must be > 1)
01786  *              type (color selection flag)
01787  *              factor (subsampling factor; integer >= 1)
01788  *              &carray (<return> array of colors, ranked by intensity)
01789  *              debugflag (1 to display color squares and plots of color
01790  *                         components; 2 to write them as png to file)
01791  *      Return: 0 if OK, 1 on error
01792  *
01793  *  Notes:
01794  *      (1) The color selection flag is one of: L_SELECT_RED, L_SELECT_GREEN,
01795  *          L_SELECT_BLUE, L_SELECT_MIN, L_SELECT_MAX.
01796  *      (2) Then it finds the histogram of the selected component in each
01797  *          RGB pixel.  For each of the @nbins sets of pixels,
01798  *          ordered by this component value, find the average color,
01799  *          and return this as a "rank color" array.  The output array
01800  *          has @nbins colors.
01801  *      (3) Set the subsampling factor > 1 to reduce the amount of
01802  *          computation.  Typically you want at least 10,000 pixels
01803  *          for reasonable statistics.
01804  *      (4) The rank color as a function of rank can then be found from
01805  *             rankint = (l_int32)(rank * (nbins - 1) + 0.5);
01806  *             extractRGBValues(array[rankint], &rval, &gval, &bval);
01807  *          where the rank is in [0.0 ... 1.0].
01808  *          This function is meant to be simple and approximate.
01809  *      (5) Compare this with pixGetBinnedColor(), which generates equal
01810  *          width intensity bins and finds the average color in each bin.
01811  */
01812 l_int32
01813 pixGetRankColorArray(PIX         *pixs,
01814                      l_int32      nbins,
01815                      l_int32      type,
01816                      l_int32      factor,
01817                      l_uint32   **pcarray,
01818                      l_int32      debugflag)
01819 {
01820 l_int32    ret;
01821 l_uint32  *array;
01822 NUMA      *na, *nan, *narbin;
01823 PIX       *pixt, *pixc, *pixg, *pixd;
01824 PIXCMAP   *cmap;
01825 
01826     PROCNAME("pixGetRankColorArray");
01827 
01828     if (!pcarray)
01829         return ERROR_INT("&carray not defined", procName, 1);
01830     *pcarray = NULL;
01831     if (factor < 1)
01832         return ERROR_INT("sampling factor < 1", procName, 1);
01833     if (nbins < 2)
01834         return ERROR_INT("nbins must be at least 2", procName, 1);
01835     if (!pixs)
01836         return ERROR_INT("pixs not defined", procName, 1);
01837     cmap = pixGetColormap(pixs);
01838     if (pixGetDepth(pixs) != 32 && !cmap)
01839         return ERROR_INT("pixs neither 32 bpp nor cmapped", procName, 1);
01840     if (type != L_SELECT_RED && type != L_SELECT_GREEN &&
01841         type != L_SELECT_BLUE && type != L_SELECT_MIN &&
01842         type != L_SELECT_MAX)
01843         return ERROR_INT("invalid type", procName, 1);
01844 
01845         /* Downscale by factor and remove colormap if it exists */
01846     pixt = pixScaleByIntSubsampling(pixs, factor);
01847     if (cmap)
01848         pixc = pixRemoveColormap(pixt, REMOVE_CMAP_TO_FULL_COLOR);
01849     else
01850         pixc = pixClone(pixt);
01851     pixDestroy(&pixt);
01852 
01853         /* Get normalized histogram of the selected component */
01854     if (type == L_SELECT_RED)
01855         pixg = pixGetRGBComponent(pixc, COLOR_RED);
01856     else if (type == L_SELECT_GREEN)
01857         pixg = pixGetRGBComponent(pixc, COLOR_GREEN);
01858     else if (type == L_SELECT_BLUE)
01859         pixg = pixGetRGBComponent(pixc, COLOR_BLUE);
01860     else if (type == L_SELECT_MIN)
01861         pixg = pixConvertRGBToGrayMinMax(pixc, L_CHOOSE_MIN);
01862     else  /* type == L_SELECT_MAX */
01863         pixg = pixConvertRGBToGrayMinMax(pixc, L_CHOOSE_MAX);
01864     if ((na = pixGetGrayHistogram(pixg, 1)) == NULL)
01865         return ERROR_INT("na not made", procName, 1);
01866     nan = numaNormalizeHistogram(na, 1.0);
01867 
01868         /* Get the following arrays:
01869          * (1) nar: cumulative normalized histogram (rank vs intensity value).
01870          *     With 256 intensity values, we have 257 rank values.
01871          * (2) nai: "average" intensity as function of rank bin, for
01872          *     @nbins equally spaced in rank between 0.0 and 1.0.
01873          * (3) narbin: bin number of discretized rank as a function of
01874          *     intensity.  This is the 'inverse' of nai.
01875          * (4) nabb: intensity value of the right bin boundary, for each
01876          *     of the @nbins descretized rank bins. */
01877     if (!debugflag)
01878         numaDiscretizeRankAndIntensity(nan, nbins, &narbin, NULL, NULL, NULL);
01879     else {
01880         l_int32  type;
01881         NUMA    *nai, *nar, *nabb;
01882         numaDiscretizeRankAndIntensity(nan, nbins, &narbin, &nai, &nar, &nabb);
01883         type = (debugflag == 1) ? GPLOT_X11 : GPLOT_PNG;
01884         gplotSimple1(nan, type, "/tmp/rtnan", "Normalized Histogram");
01885         gplotSimple1(nar, type, "/tmp/rtnar", "Cumulative Histogram");
01886         gplotSimple1(nai, type, "/tmp/rtnai", "Intensity vs. rank bin");
01887         gplotSimple1(narbin, type, "/tmp/rtnarbin",
01888                      "LUT: rank bin vs. Intensity");
01889         gplotSimple1(nabb, type, "/tmp/rtnabb",
01890                      "Intensity of right edge vs. rank bin");
01891         numaDestroy(&nai);
01892         numaDestroy(&nar);
01893         numaDestroy(&nabb);
01894     }
01895 
01896         /* Get the average color in each bin for pixels whose grayscale
01897          * values fall in the bin range.  @narbin is the LUT that
01898          * determines the bin number from the grayscale version of
01899          * the image.  Because this mapping may not be unique,
01900          * some bins may not be represented in the LUT. In use, to get fair
01901          * allocation into all the bins, bin population is monitored
01902          * as pixels are accumulated, and when bins fill up,
01903          * pixels are required to overflow into succeeding bins. */
01904     pixGetBinnedColor(pixc, pixg, 1, nbins, narbin, pcarray, debugflag);
01905     ret = 0;
01906     if ((array = *pcarray) == NULL) {
01907         L_ERROR("color array not returned", procName);
01908         ret = 1;
01909         debugflag = 0;  /* make sure to skip the following */
01910     }
01911     if (debugflag) {
01912         pixd = pixDisplayColorArray(array, nbins, 200, 5, 1);
01913         if (debugflag == 1)
01914             pixDisplayWithTitle(pixd, 0, 500, "binned colors", 1);
01915         else  /* debugflag == 2 */
01916             pixWriteTempfile("/tmp", "rankhisto.png", pixd, IFF_PNG, NULL);
01917         pixDestroy(&pixd);
01918     }
01919 
01920     pixDestroy(&pixc);
01921     pixDestroy(&pixg);
01922     numaDestroy(&na);
01923     numaDestroy(&nan);
01924     numaDestroy(&narbin);
01925     return 0;
01926 }
01927 
01928 
01929 /*!
01930  *  pixGetBinnedColor()
01931  *
01932  *      Input:  pixs (32 bpp)
01933  *              pixg (8 bpp grayscale version of pixs)
01934  *              factor (sampling factor along pixel counting direction)
01935  *              nbins (number of intensity bins)
01936  *              nalut (LUT for mapping from intensity to bin number)
01937  *              &carray (<return> array of average color values in each bin)
01938  *              debugflag (1 to display output debug plots of color
01939  *                         components; 2 to write them as png to file)
01940  *      Return: 0 if OK; 1 on error
01941  *
01942  *  Notes:
01943  *      (1) This takes a color image, a grayscale (intensity) version,
01944  *          a LUT from intensity to bin number, and the number of bins.
01945  *          It computes the average color for pixels whose intensity
01946  *          is in each bin.  This is returned as an array of l_uint32
01947  *          colors in our standard RGBA ordering.
01948  *      (2) This function generates equal width intensity bins and
01949  *          finds the average color in each bin.  Compare this with
01950  *          pixGetRankColorArray(), which rank orders the pixels
01951  *          by the value of the selected component in each pixel,
01952  *          sets up bins with equal population (not intensity width!),
01953  *          and gets the average color in each bin.
01954  */
01955 l_int32
01956 pixGetBinnedColor(PIX        *pixs,
01957                   PIX        *pixg,
01958                   l_int32     factor,
01959                   l_int32     nbins,
01960                   NUMA       *nalut,
01961                   l_uint32  **pcarray,
01962                   l_int32     debugflag)
01963 {
01964 l_int32     i, j, w, h, wpls, wplg, grayval, bin, rval, gval, bval;
01965 l_int32     npts, avepts, maxpts;
01966 l_uint32   *datas, *datag, *lines, *lineg, *carray;
01967 l_float64   norm;
01968 l_float64  *rarray, *garray, *barray, *narray;
01969 
01970     PROCNAME("pixGetBinnedColor");
01971 
01972     if (!pcarray)
01973         return ERROR_INT("&carray not defined", procName, 1);
01974     *pcarray = NULL;
01975     if (!pixs)
01976         return ERROR_INT("pixs not defined", procName, 1);
01977     if (!pixg)
01978         return ERROR_INT("pixg not defined", procName, 1);
01979     if (!nalut)
01980         return ERROR_INT("nalut not defined", procName, 1);
01981     if (factor < 1) {
01982         L_WARNING("sampling factor less than 1; setting to 1", procName);
01983         factor = 1;
01984     }
01985 
01986         /* Find the color for each rank bin.  Note that we can have
01987          * multiple bins filled with pixels having the same gray value.
01988          * Therefore, because in general the mapping from gray value
01989          * to bin number is not unique, if a bin fills up (actually,
01990          * we allow it to slightly overfill), we roll the excess
01991          * over to the next bin, etc. */
01992     pixGetDimensions(pixs, &w, &h, NULL);
01993     npts = (w + factor - 1) * (h + factor - 1) / (factor * factor);
01994     avepts = (npts + nbins - 1) / nbins;  /* average number of pts in a bin */
01995     maxpts = (l_int32)((1.0 + 0.5 / (l_float32)nbins) * avepts);
01996     datas = pixGetData(pixs);
01997     wpls = pixGetWpl(pixs);
01998     datag = pixGetData(pixg);
01999     wplg = pixGetWpl(pixg);
02000     rarray = (l_float64 *)CALLOC(nbins, sizeof(l_float64));
02001     garray = (l_float64 *)CALLOC(nbins, sizeof(l_float64));
02002     barray = (l_float64 *)CALLOC(nbins, sizeof(l_float64));
02003     narray = (l_float64 *)CALLOC(nbins, sizeof(l_float64));
02004     for (i = 0; i < h; i += factor) {
02005         lines = datas + i * wpls;
02006         lineg = datag + i * wplg;
02007         for (j = 0; j < w; j += factor) {
02008             grayval = GET_DATA_BYTE(lineg, j);
02009             numaGetIValue(nalut, grayval, &bin);
02010             extractRGBValues(lines[j], &rval, &gval, &bval);
02011             while (narray[bin] >= maxpts && bin < nbins - 1)
02012                 bin++;
02013             rarray[bin] += rval;
02014             garray[bin] += gval;
02015             barray[bin] += bval;
02016             narray[bin] += 1.0;  /* count samples in each bin */
02017         }
02018     }
02019 
02020     for (i = 0; i < nbins; i++) {
02021         norm = 1. / narray[i];
02022         rarray[i] *= norm;
02023         garray[i] *= norm;
02024         barray[i] *= norm;
02025 /*        fprintf(stderr, "narray[%d] = %f\n", i, narray[i]);  */
02026     }
02027 
02028     if (debugflag) {
02029         l_int32  type;
02030         NUMA *nared, *nagreen, *nablue;
02031         nared = numaCreate(nbins);
02032         nagreen = numaCreate(nbins);
02033         nablue = numaCreate(nbins);
02034         for (i = 0; i < nbins; i++) {
02035             numaAddNumber(nared, rarray[i]);
02036             numaAddNumber(nagreen, garray[i]);
02037             numaAddNumber(nablue, barray[i]);
02038         }
02039         type = (debugflag == 1) ? GPLOT_X11 : GPLOT_PNG;
02040         gplotSimple1(nared, type, "/tmp/rtnared",
02041                      "Average red val vs. rank bin");
02042         gplotSimple1(nagreen, type, "/tmp/rtnagreen",
02043                      "Average green val vs. rank bin");
02044         gplotSimple1(nablue, type, "/tmp/rtnablue",
02045                      "Average blue val vs. rank bin");
02046         numaDestroy(&nared);
02047         numaDestroy(&nagreen);
02048         numaDestroy(&nablue);
02049     }
02050 
02051         /* Save colors for all bins  in a single array */
02052     if ((carray = (l_uint32 *)CALLOC(nbins, sizeof(l_uint32))) == NULL)
02053         return ERROR_INT("rankcolor not made", procName, 1);
02054     *pcarray = carray;
02055     for (i = 0; i < nbins; i++) {
02056         rval = (l_int32)(rarray[i] + 0.5);
02057         gval = (l_int32)(garray[i] + 0.5);
02058         bval = (l_int32)(barray[i] + 0.5);
02059         composeRGBPixel(rval, gval, bval, carray + i);
02060     }
02061 
02062     FREE(rarray);
02063     FREE(garray);
02064     FREE(barray);
02065     FREE(narray);
02066     return 0;
02067 }
02068 
02069 
02070 /*!
02071  *  pixDisplayColorArray()
02072  *
02073  *      Input:  carray (array of colors: 0xrrggbb00)
02074  *              ncolors (size of array)
02075  *              side (size of each color square; suggest 200)
02076  *              ncols (number of columns in output color matrix)
02077  *              textflag (1 to label each square with text; 0 otherwise)
02078  *      Return: pixd (color array), or null on error
02079  */
02080 PIX *
02081 pixDisplayColorArray(l_uint32  *carray,
02082                      l_int32    ncolors,
02083                      l_int32    side,
02084                      l_int32    ncols,
02085                      l_int32    textflag)
02086 {
02087 char     textstr[256];
02088 l_int32  i, rval, gval, bval;
02089 L_BMF   *bmf6;
02090 PIX     *pixt, *pixd;
02091 PIXA    *pixa;
02092 
02093     PROCNAME("pixDisplayColorArray");
02094 
02095     if (!carray)
02096         return (PIX *)ERROR_PTR("carray not defined", procName, NULL);
02097 
02098     bmf6 = NULL;
02099     if (textflag)
02100         bmf6 = bmfCreate("./fonts", 6);
02101 
02102     pixa = pixaCreate(ncolors);
02103     for (i = 0; i < ncolors; i++) {
02104         pixt = pixCreate(side, side, 32);
02105         pixSetAllArbitrary(pixt, carray[i]);
02106         if (textflag) {
02107             extractRGBValues(carray[i], &rval, &gval, &bval);
02108             snprintf(textstr, sizeof(textstr),
02109                      "%d: (%d %d %d)", i, rval, gval, bval);
02110             pixSaveTiledWithText(pixt, pixa, side, (i % ncols == 0) ? 1 : 0,
02111                                  20, 2, bmf6, textstr, 0xff000000, L_ADD_BELOW);
02112         }
02113         else
02114             pixSaveTiled(pixt, pixa, 1, (i % ncols == 0) ? 1 : 0, 20, 32);
02115         pixDestroy(&pixt);
02116     }
02117     pixd = pixaDisplay(pixa, 0, 0);
02118 
02119     pixaDestroy(&pixa);
02120     bmfDestroy(&bmf6);
02121     return pixd;
02122 }
02123 
02124 
02125 /*-------------------------------------------------------------*
02126  *                 Pixelwise aligned statistics                *
02127  *-------------------------------------------------------------*/
02128 /*!
02129  *  pixaGetAlignedStats()
02130  *
02131  *      Input:  pixa (of identically sized, 8 bpp pix; not cmapped)
02132  *              type (L_MEAN_ABSVAL, L_MEDIAN_VAL, L_MODE_VAL, L_MODE_COUNT)
02133  *              nbins (of histogram for median and mode; ignored for mean)
02134  *              thresh (on histogram for mode val; ignored for all other types)
02135  *      Return: pix (with pixelwise aligned stats), or null on error.
02136  *
02137  *  Notes:
02138  *      (1) Each pixel in the returned pix represents an average
02139  *          (or median, or mode) over the corresponding pixels in each
02140  *          pix in the pixa.
02141  *      (2) The @thresh parameter works with L_MODE_VAL only, and
02142  *          sets a minimum occupancy of the mode bin.
02143  *          If the occupancy of the mode bin is less than @thresh, the
02144  *          mode value is returned as 0.  To always return the actual
02145  *          mode value, set @thresh = 0.  See pixGetRowStats().
02146  */
02147 PIX *
02148 pixaGetAlignedStats(PIXA     *pixa,
02149                     l_int32   type,
02150                     l_int32   nbins,
02151                     l_int32   thresh)
02152 {
02153 l_int32     j, n, w, h, d;
02154 l_float32  *colvect;
02155 PIX        *pixt, *pixd;
02156 
02157     PROCNAME("pixaGetAlignedStats");
02158 
02159     if (!pixa)
02160         return (PIX *)ERROR_PTR("pixa not defined", procName, NULL);
02161     if (type != L_MEAN_ABSVAL && type != L_MEDIAN_VAL &&
02162         type != L_MODE_VAL && type != L_MODE_COUNT)
02163         return (PIX *)ERROR_PTR("invalid type", procName, NULL);
02164     n = pixaGetCount(pixa);
02165     if (n == 0)
02166         return (PIX *)ERROR_PTR("no pix in pixa", procName, NULL);
02167     pixaGetPixDimensions(pixa, 0, &w, &h, &d);
02168     if (d != 8)
02169         return (PIX *)ERROR_PTR("pix not 8 bpp", procName, NULL);
02170 
02171     pixd = pixCreate(w, h, 8);
02172     pixt = pixCreate(n, h, 8);
02173     colvect = (l_float32 *)CALLOC(h, sizeof(l_float32));
02174     for (j = 0; j < w; j++) {
02175         pixaExtractColumnFromEachPix(pixa, j, pixt);
02176         pixGetRowStats(pixt, type, nbins, thresh, colvect);
02177         pixSetPixelColumn(pixd, j, colvect);
02178     }
02179 
02180     FREE(colvect);
02181     pixDestroy(&pixt);
02182     return pixd;
02183 }
02184 
02185 
02186 /*!
02187  *  pixaExtractColumnFromEachPix()
02188  *
02189  *      Input:  pixa (of identically sized, 8 bpp; not cmapped)
02190  *              col (column index)
02191  *              pixd (pix into which each column is inserted)
02192  *      Return: 0 if OK, 1 on error
02193  */
02194 l_int32
02195 pixaExtractColumnFromEachPix(PIXA    *pixa,
02196                              l_int32  col,
02197                              PIX     *pixd)
02198 {
02199 l_int32    i, k, n, w, h, ht, val, wplt, wpld;
02200 l_uint32  *datad, *datat;
02201 PIX       *pixt;
02202 
02203     PROCNAME("pixaExtractColumnFromEachPix");
02204 
02205     if (!pixa)
02206         return ERROR_INT("pixa not defined", procName, 1);
02207     if (!pixd || pixGetDepth(pixd) != 8)
02208         return ERROR_INT("pixa not defined or not 8 bpp", procName, 1);
02209     n = pixaGetCount(pixa);
02210     pixGetDimensions(pixd, &w, &h, NULL);
02211     if (n != w)
02212         return ERROR_INT("pix width != n", procName, 1);
02213     pixt = pixaGetPix(pixa, 0, L_CLONE);
02214     wplt = pixGetWpl(pixt);
02215     pixGetDimensions(pixt, NULL, &ht, NULL);
02216     pixDestroy(&pixt);
02217     if (h != ht)
02218         return ERROR_INT("pixd height != column height", procName, 1);
02219 
02220     datad = pixGetData(pixd);
02221     wpld = pixGetWpl(pixd);
02222     for (k = 0; k < n; k++) {
02223         pixt = pixaGetPix(pixa, k, L_CLONE);
02224         datat = pixGetData(pixt);
02225         for (i = 0; i < h; i++) {
02226             val = GET_DATA_BYTE(datat, col);
02227             SET_DATA_BYTE(datad + i * wpld, k, val);
02228             datat += wplt;
02229         }
02230         pixDestroy(&pixt);
02231     }
02232 
02233     return 0;
02234 }
02235 
02236 
02237 /*!
02238  *  pixGetRowStats()
02239  *
02240  *      Input:  pixs (8 bpp; not cmapped)
02241  *              type (L_MEAN_ABSVAL, L_MEDIAN_VAL, L_MODE_VAL, L_MODE_COUNT)
02242  *              nbins (of histogram for median and mode; ignored for mean)
02243  *              thresh (on histogram for mode; ignored for mean and median)
02244  *              colvect (vector of results gathered across the rows of pixs)
02245  *      Return: 0 if OK, 1 on error
02246  *
02247  *  Notes:
02248  *      (1) This computes a column vector of statistics using each
02249  *          row of a Pix.  The result is put in @colvect.
02250  *      (2) The @thresh parameter works with L_MODE_VAL only, and
02251  *          sets a minimum occupancy of the mode bin.
02252  *          If the occupancy of the mode bin is less than @thresh, the
02253  *          mode value is returned as 0.  To always return the actual
02254  *          mode value, set @thresh = 0.
02255  *      (3) What is the meaning of this @thresh parameter?
02256  *          For each row, the total count in the histogram is w, the
02257  *          image width.  So @thresh, relative to w, gives a measure
02258  *          of the ratio of the bin width to the width of the distribution.
02259  *          The larger @thresh, the narrower the distribution must be
02260  *          for the mode value to be returned (instead of returning 0).
02261  *      (4) If the Pix consists of a set of corresponding columns,
02262  *          one for each Pix in a Pixa, the width of the Pix is the
02263  *          number of Pix in the Pixa and the column vector can
02264  *          be stored as a column in a Pix of the same size as
02265  *          each Pix in the Pixa.
02266  */
02267 l_int32
02268 pixGetRowStats(PIX        *pixs,
02269                l_int32     type,
02270                l_int32     nbins,
02271                l_int32     thresh,
02272                l_float32  *colvect)
02273 {
02274 l_int32    i, j, k, w, h, val, wpls, sum, target, max, modeval;
02275 l_int32   *histo, *gray2bin, *bin2gray;
02276 l_uint32  *lines, *datas;
02277 
02278     PROCNAME("pixGetRowStats");
02279 
02280     if (!pixs || pixGetDepth(pixs) != 8)
02281         return ERROR_INT("pixs not defined or not 8 bpp", procName, 1);
02282     if (!colvect)
02283         return ERROR_INT("colvect not defined", procName, 1);
02284     if (type != L_MEAN_ABSVAL && type != L_MEDIAN_VAL &&
02285         type != L_MODE_VAL && type != L_MODE_COUNT)
02286         return ERROR_INT("invalid type", procName, 1);
02287     if (type != L_MEAN_ABSVAL && (nbins < 1 || nbins > 256))
02288         return ERROR_INT("invalid nbins", procName, 1);
02289     pixGetDimensions(pixs, &w, &h, NULL);
02290 
02291     datas = pixGetData(pixs);
02292     wpls = pixGetWpl(pixs);
02293     if (type == L_MEAN_ABSVAL) {
02294         for (i = 0; i < h; i++) {
02295             sum = 0;
02296             lines = datas + i * wpls;
02297             for (j = 0; j < w; j++)
02298                 sum += GET_DATA_BYTE(lines, j);
02299             colvect[i] = (l_float32)sum / (l_float32)w;
02300         }
02301         return 0;
02302     }
02303 
02304         /* We need a histogram; binwidth ~ 256 / nbins */
02305     histo = (l_int32 *)CALLOC(nbins, sizeof(l_int32));
02306     gray2bin = (l_int32 *)CALLOC(256, sizeof(l_int32));
02307     bin2gray = (l_int32 *)CALLOC(nbins, sizeof(l_int32));
02308     for (i = 0; i < 256; i++)  /* gray value --> histo bin */
02309         gray2bin[i] = (i * nbins) / 256;
02310     for (i = 0; i < nbins; i++)  /* histo bin --> gray value */
02311         bin2gray[i] = (i * 256 + 128) / nbins;
02312 
02313     for (i = 0; i < h; i++) {
02314         lines = datas + i * wpls;
02315         for (k = 0; k < nbins; k++)
02316             histo[k] = 0;
02317         for (j = 0; j < w; j++) {
02318             val = GET_DATA_BYTE(lines, j);
02319             histo[gray2bin[val]]++;
02320         }
02321 
02322         if (type == L_MEDIAN_VAL) {
02323             sum = 0;
02324             target = (w + 1) / 2;
02325             for (k = 0; k < nbins; k++) {
02326                 sum += histo[k];
02327                 if (sum >= target) {
02328                     colvect[i] = bin2gray[k];
02329                     break;
02330                 }
02331             }
02332         }
02333         else if (type == L_MODE_VAL) {
02334             max = 0;
02335             modeval = 0;
02336             for (k = 0; k < nbins; k++) {
02337                 if (histo[k] > max) {
02338                     max = histo[k];
02339                     modeval = k;
02340                 }
02341             }
02342             if (max < thresh)
02343                 colvect[i] = 0;
02344             else
02345                 colvect[i] = bin2gray[modeval];
02346         }
02347         else {  /* type == L_MODE_COUNT */
02348             max = 0;
02349             modeval = 0;
02350             for (k = 0; k < nbins; k++) {
02351                 if (histo[k] > max) {
02352                     max = histo[k];
02353                     modeval = k;
02354                 }
02355             }
02356             colvect[i] = max;
02357         }
02358     }
02359 
02360     FREE(histo);
02361     FREE(gray2bin);
02362     FREE(bin2gray);
02363     return 0;
02364 }
02365 
02366 
02367 /*!
02368  *  pixGetColumnStats()
02369  *
02370  *      Input:  pixs (8 bpp; not cmapped)
02371  *              type (L_MEAN_ABSVAL, L_MEDIAN_VAL, L_MODE_VAL, L_MODE_COUNT)
02372  *              nbins (of histogram for median and mode; ignored for mean)
02373  *              thresh (on histogram for mode val; ignored for all other types)
02374  *              rowvect (vector of results gathered down the columns of pixs)
02375  *      Return: 0 if OK, 1 on error
02376  *
02377  *  Notes:
02378  *      (1) This computes a row vector of statistics using each
02379  *          column of a Pix.  The result is put in @rowvect.
02380  *      (2) The @thresh parameter works with L_MODE_VAL only, and
02381  *          sets a minimum occupancy of the mode bin.
02382  *          If the occupancy of the mode bin is less than @thresh, the
02383  *          mode value is returned as 0.  To always return the actual
02384  *          mode value, set @thresh = 0.
02385  *      (3) What is the meaning of this @thresh parameter?
02386  *          For each column, the total count in the histogram is h, the
02387  *          image height.  So @thresh, relative to h, gives a measure
02388  *          of the ratio of the bin width to the width of the distribution.
02389  *          The larger @thresh, the narrower the distribution must be
02390  *          for the mode value to be returned (instead of returning 0).
02391  */
02392 l_int32
02393 pixGetColumnStats(PIX        *pixs,
02394                   l_int32     type,
02395                   l_int32     nbins,
02396                   l_int32     thresh,
02397                   l_float32  *rowvect)
02398 {
02399 l_int32    i, j, k, w, h, val, wpls, sum, target, max, modeval;
02400 l_int32   *histo, *gray2bin, *bin2gray;
02401 l_uint32  *datas;
02402 
02403     PROCNAME("pixGetColumnStats");
02404 
02405     if (!pixs || pixGetDepth(pixs) != 8)
02406         return ERROR_INT("pixs not defined or not 8 bpp", procName, 1);
02407     if (!rowvect)
02408         return ERROR_INT("rowvect not defined", procName, 1);
02409     if (type != L_MEAN_ABSVAL && type != L_MEDIAN_VAL &&
02410         type != L_MODE_VAL && type != L_MODE_COUNT)
02411         return ERROR_INT("invalid type", procName, 1);
02412     if (type != L_MEAN_ABSVAL && (nbins < 1 || nbins > 256))
02413         return ERROR_INT("invalid nbins", procName, 1);
02414     pixGetDimensions(pixs, &w, &h, NULL);
02415 
02416     datas = pixGetData(pixs);
02417     wpls = pixGetWpl(pixs);
02418     if (type == L_MEAN_ABSVAL) {
02419         for (j = 0; j < w; j++) {
02420             sum = 0;
02421             for (i = 0; i < h; i++)
02422                 sum += GET_DATA_BYTE(datas + i * wpls, j);
02423             rowvect[j] = (l_float32)sum / (l_float32)h;
02424         }
02425         return 0;
02426     }
02427 
02428         /* We need a histogram; binwidth ~ 256 / nbins */
02429     histo = (l_int32 *)CALLOC(nbins, sizeof(l_int32));
02430     gray2bin = (l_int32 *)CALLOC(256, sizeof(l_int32));
02431     bin2gray = (l_int32 *)CALLOC(nbins, sizeof(l_int32));
02432     for (i = 0; i < 256; i++)  /* gray value --> histo bin */
02433         gray2bin[i] = (i * nbins) / 256;
02434     for (i = 0; i < nbins; i++)  /* histo bin --> gray value */
02435         bin2gray[i] = (i * 256 + 128) / nbins;
02436 
02437     for (j = 0; j < w; j++) {
02438         for (i = 0; i < h; i++) {
02439             val = GET_DATA_BYTE(datas + i * wpls, j);
02440             histo[gray2bin[val]]++;
02441         }
02442 
02443         if (type == L_MEDIAN_VAL) {
02444             sum = 0;
02445             target = (h + 1) / 2;
02446             for (k = 0; k < nbins; k++) {
02447                 sum += histo[k];
02448                 if (sum >= target) {
02449                     rowvect[j] = bin2gray[k];
02450                     break;
02451                 }
02452             }
02453         }
02454         else if (type == L_MODE_VAL) {
02455             max = 0;
02456             modeval = 0;
02457             for (k = 0; k < nbins; k++) {
02458                 if (histo[k] > max) {
02459                     max = histo[k];
02460                     modeval = k;
02461                 }
02462             }
02463             if (max < thresh)
02464                 rowvect[j] = 0;
02465             else
02466                 rowvect[j] = bin2gray[modeval];
02467         }
02468         else {  /* type == L_MODE_COUNT */
02469             max = 0;
02470             modeval = 0;
02471             for (k = 0; k < nbins; k++) {
02472                 if (histo[k] > max) {
02473                     max = histo[k];
02474                     modeval = k;
02475                 }
02476             }
02477             rowvect[j] = max;
02478         }
02479         for (k = 0; k < nbins; k++)
02480             histo[k] = 0;
02481     }
02482 
02483     FREE(histo);
02484     FREE(gray2bin);
02485     FREE(bin2gray);
02486     return 0;
02487 }
02488 
02489 
02490 /*!
02491  *  pixSetPixelColumn()
02492  *
02493  *      Input:  pix (8 bpp; not cmapped)
02494  *              col (column index)
02495  *              colvect (vector of floats)
02496  *      Return: 0 if OK, 1 on error
02497  */
02498 l_int32
02499 pixSetPixelColumn(PIX        *pix,
02500                   l_int32     col,
02501                   l_float32  *colvect)
02502 {
02503 l_int32    i, w, h, wpl;
02504 l_uint32  *data;
02505 
02506     PROCNAME("pixSetCPixelColumn");
02507 
02508     if (!pix || pixGetDepth(pix) != 8)
02509         return ERROR_INT("pix not defined or not 8 bpp", procName, 1);
02510     if (!colvect)
02511         return ERROR_INT("colvect not defined", procName, 1);
02512     pixGetDimensions(pix, &w, &h, NULL);
02513     if (col < 0 || col > w)
02514         return ERROR_INT("invalid col", procName, 1);
02515 
02516     data = pixGetData(pix);
02517     wpl = pixGetWpl(pix);
02518     for (i = 0; i < h; i++)
02519         SET_DATA_BYTE(data + i * wpl, col, (l_int32)colvect[i]);
02520 
02521     return 0;
02522 }
02523 
02524 
02525 /*-------------------------------------------------------------*
02526  *              Foreground/background estimation               *
02527  *-------------------------------------------------------------*/
02528 /*!
02529  *  pixThresholdForFgBg()
02530  *
02531  *      Input:  pixs (any depth; cmapped ok)
02532  *              factor (subsampling factor; integer >= 1)
02533  *              thresh (threshold for generating foreground mask)
02534  *              &fgval (<optional return> average foreground value)
02535  *              &bgval (<optional return> average background value)
02536  *      Return: 0 if OK, 1 on error
02537  */
02538 l_int32
02539 pixThresholdForFgBg(PIX      *pixs,
02540                     l_int32   factor,
02541                     l_int32   thresh,
02542                     l_int32  *pfgval,
02543                     l_int32  *pbgval)
02544 {
02545 l_float32  fval;
02546 PIX       *pixg, *pixm;
02547 
02548     PROCNAME("pixThresholdForFgBg");
02549 
02550     if (!pixs)
02551         return ERROR_INT("pixs not defined", procName, 1);
02552 
02553         /* Generate a subsampled 8 bpp version and a mask over the fg */
02554     pixg = pixConvertTo8BySampling(pixs, factor, 0);
02555     pixm = pixThresholdToBinary(pixg, thresh);
02556 
02557     if (pfgval) {
02558         pixGetAverageMasked(pixg, pixm, 0, 0, 1, L_MEAN_ABSVAL, &fval);
02559         *pfgval = (l_int32)(fval + 0.5);
02560     }
02561 
02562     if (pbgval) {
02563         pixInvert(pixm, pixm);
02564         pixGetAverageMasked(pixg, pixm, 0, 0, 1, L_MEAN_ABSVAL, &fval);
02565         *pbgval = (l_int32)(fval + 0.5);
02566     }
02567 
02568     pixDestroy(&pixg);
02569     pixDestroy(&pixm);
02570     return 0;
02571 }
02572 
02573 
02574 /*!
02575  *  pixSplitDistributionFgBg()
02576  *
02577  *      Input:  pixs (any depth; cmapped ok)
02578  *              scorefract (fraction of the max score, used to determine
02579  *                          the range over which the histogram min is searched)
02580  *              factor (subsampling factor; integer >= 1)
02581  *              &thresh (<optional return> best threshold for separating)
02582  *              &fgval (<optional return> average foreground value)
02583  *              &bgval (<optional return> average background value)
02584  *              debugflag (1 for plotting of distribution and split point)
02585  *      Return: 0 if OK, 1 on error
02586  *
02587  *  Notes:
02588  *      (1) See numaSplitDistribution() for details on the underlying
02589  *          method of choosing a threshold.
02590  */
02591 l_int32
02592 pixSplitDistributionFgBg(PIX       *pixs,
02593                          l_float32  scorefract,
02594                          l_int32    factor,
02595                          l_int32   *pthresh,
02596                          l_int32   *pfgval,
02597                          l_int32   *pbgval,
02598                          l_int32    debugflag)
02599 {
02600 char       buf[256];
02601 l_int32    thresh;
02602 l_float32  avefg, avebg, maxnum;
02603 GPLOT     *gplot;
02604 NUMA      *na, *nascore, *nax, *nay;
02605 PIX       *pixg;
02606 
02607     PROCNAME("pixSplitDistributionFgBg");
02608 
02609     if (pthresh) *pthresh = 0;
02610     if (pfgval) *pfgval = 0;
02611     if (pbgval) *pbgval = 0;
02612     if (!pixs)
02613         return ERROR_INT("pixs not defined", procName, 1);
02614 
02615         /* Generate a subsampled 8 bpp version */
02616     pixg = pixConvertTo8BySampling(pixs, factor, 0);
02617 
02618         /* Make the fg/bg estimates */
02619     na = pixGetGrayHistogram(pixg, 1);
02620     if (debugflag) {
02621         numaSplitDistribution(na, scorefract, &thresh, &avefg, &avebg,
02622                               NULL, NULL, &nascore);
02623         numaDestroy(&nascore);
02624     }
02625     else
02626         numaSplitDistribution(na, scorefract, &thresh, &avefg, &avebg,
02627                               NULL, NULL, NULL);
02628 
02629     if (pthresh) *pthresh = thresh;
02630     if (pfgval) *pfgval = (l_int32)(avefg + 0.5);
02631     if (pbgval) *pbgval = (l_int32)(avebg + 0.5);
02632 
02633     if (debugflag) {
02634         gplot = gplotCreate("/tmp/histplot", GPLOT_PNG, "Histogram",
02635                             "Grayscale value", "Number of pixels");
02636         gplotAddPlot(gplot, NULL, na, GPLOT_LINES, NULL);
02637         nax = numaMakeConstant(thresh, 2);
02638         numaGetMax(na, &maxnum, NULL);
02639         nay = numaMakeConstant(0, 2);
02640         numaReplaceNumber(nay, 1, (l_int32)(0.5 * maxnum));
02641         snprintf(buf, sizeof(buf), "score fract = %3.1f", scorefract);
02642         gplotAddPlot(gplot, nax, nay, GPLOT_LINES, buf);
02643         gplotMakeOutput(gplot);
02644         gplotDestroy(&gplot);
02645         numaDestroy(&nax);
02646         numaDestroy(&nay);
02647     }
02648 
02649     pixDestroy(&pixg);
02650     numaDestroy(&na);
02651     return 0;
02652 }
02653 
02654 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines