Leptonica 1.68
C Image Processing Library

colorcontent.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  *  colorcontent.c
00018  *                     
00019  *      Builds an image of the color content, on a per-pixel basis,
00020  *      as a measure of the amount of divergence of each color
00021  *      component (R,G,B) from gray.
00022  *         l_int32    pixColorContent()
00023  *
00024  *      Finds the 'amount' of color in an image, on a per-pixel basis,
00025  *      as a measure of the difference of the pixel color from gray.
00026  *         PIX       *pixColorMagnitude()
00027  *
00028  *      Generates a mask over pixels that have sufficient color and
00029  *      are not too close to gray pixels.
00030  *         PIX       *pixMaskOverColorPixels()
00031  *
00032  *      Finds the fraction of pixels with "color" that are not close to black
00033  *         l_int32    pixColorFraction()
00034  *
00035  *      Finds the number of perceptually significant gray intensities
00036  *      in a grayscale image.
00037  *         l_int32    pixNumSignificantGrayColors()
00038  *
00039  *      Identifies images where color quantization will cause posterization
00040  *      due to the existence of many colors in low-gradient regions.
00041  *         l_int32    pixColorsForQuantization()
00042  *
00043  *      Finds the number of unique colors in an image
00044  *         l_int32    pixNumColors()
00045  *
00046  *  Color is tricky.  If we consider gray (r = g = b) to have no color
00047  *  content, how should we define the color content in each component
00048  *  of an arbitrary pixel, as well as the overall color magnitude?
00049  *
00050  *  I can think of three ways to define the color content in each component:
00051  *
00052  *  (1) Linear.  For each component, take the difference from the average
00053  *      of all three.
00054  *  (2) Linear.  For each component, take the difference from the average
00055  *      of the other two.
00056  *  (3) Nonlinear.  For each component, take the minimum of the differences
00057  *      from the other two.
00058  *
00059  *  How might one choose from among these?  Consider two different situations:
00060  *  (a) r = g = 0, b = 255            {255}   /255/
00061  *  (b) r = 0, g = 127, b = 255       {191}   /128/
00062  *  How much g is in each of these?  The three methods above give:
00063  *  (a)  1: 85   2: 127   3: 0        [85]
00064  *  (b)  1: 0    2: 0     3: 127      [0]
00065  *  How much b is in each of these?
00066  *  (a)  1: 170  2: 255   3: 255      [255]
00067  *  (b)  1: 127  2: 191   3: 127      [191]
00068  *  The number I'd "like" to give is in [].  (Please don't ask why, it's
00069  *  just a feeling.
00070  *
00071  *  So my preferences seem to be somewhere between (1) and (2).
00072  *  (3) is just too "decisive!"  Let's pick (2).
00073  *
00074  *  We also allow compensation for white imbalance.  For each
00075  *  component, we do a linear TRC (gamma = 1.0), where the black
00076  *  point remains at 0 and the white point is given by the input
00077  *  parameter.  This is equivalent to doing a global remapping,
00078  *  as with pixGlobalNormRGB(), followed by color content (or magnitude)
00079  *  computation, but without the overhead of first creating the
00080  *  white point normalized image.
00081  *
00082  *  Another useful property is the overall color magnitude in the pixel.
00083  *  For this there are again several choices, such as:
00084  *      (a) rms deviation from the mean
00085  *      (b) the average L1 deviation from the mean
00086  *      (c) the maximum (over components) of one of the color
00087  *          content measures given above.
00088  *
00089  *  For now, we will choose two of the methods in (c):
00090  *     L_MAX_DIFF_FROM_AVERAGE_2
00091  *        Define the color magnitude as the maximum over components
00092  *        of the difference between the component value and the
00093  *        average of the other two.  It is easy to show that
00094  *        this is equivalent to selecting the two component values
00095  *        that are closest to each other, averaging them, and
00096  *        using the distance from that average to the third component.
00097  *        For (a) and (b) above, this value is in {..}.
00098  *    L_MAX_MIN_DIFF_FROM_2
00099  *        Define the color magnitude as the maximum over components
00100  *        of the minimum difference between the component value and the
00101  *        other two values.  It is easy to show that this is equivalent
00102  *        to selecting the intermediate value of the three differences
00103  *        between the three components.  For (a) and (b) above,
00104  *        this value is in /../.
00105  */
00106 
00107 #include <stdio.h>
00108 #include <stdlib.h>
00109 #include "allheaders.h"
00110 
00111 
00112 /*!
00113  *  pixColorContent()
00114  *
00115  *      Input:  pixs  (32 bpp rgb or 8 bpp colormapped)
00116  *              rwhite, gwhite, bwhite (color value associated with white point)
00117  *              mingray (min gray value for which color is measured)
00118  *              &pixr (<optional return> 8 bpp red 'content')
00119  *              &pixg (<optional return> 8 bpp green 'content')
00120  *              &pixb (<optional return> 8 bpp blue 'content')
00121  *      Return: 0 if OK, 1 on error
00122  *
00123  *  Notes:
00124  *      (1) This returns the color content in each component, which is
00125  *          a measure of the deviation from gray, and is defined
00126  *          as the difference between the component and the average of
00127  *          the other two components.  See the discussion at the
00128  *          top of this file.
00129  *      (2) The three numbers (rwhite, gwhite and bwhite) can be thought
00130  *          of as the values in the image corresponding to white.
00131  *          They are used to compensate for an unbalanced color white point.
00132  *          They must either be all 0 or all non-zero.  To turn this
00133  *          off, set them all to 0.
00134  *      (3) If the maximum component after white point correction,
00135  *          max(r,g,b), is less than mingray, all color components
00136  *          for that pixel are set to zero.
00137  *          Use mingray = 0 to turn off this filtering of dark pixels.
00138  *      (4) Therefore, use 0 for all four input parameters if the color
00139  *          magnitude is to be calculated without either white balance
00140  *          correction or dark filtering.
00141  */
00142 l_int32
00143 pixColorContent(PIX     *pixs,
00144                 l_int32  rwhite,
00145                 l_int32  gwhite,
00146                 l_int32  bwhite,
00147                 l_int32  mingray,
00148                 PIX    **ppixr,
00149                 PIX    **ppixg,
00150                 PIX    **ppixb)
00151 {
00152 l_int32    w, h, d, i, j, wplc, wplr, wplg, wplb;
00153 l_int32    rval, gval, bval, rgdiff, rbdiff, gbdiff, maxval, colorval;
00154 l_int32   *rtab, *gtab, *btab;
00155 l_uint32   pixel;
00156 l_uint32  *datac, *datar, *datag, *datab, *linec, *liner, *lineg, *lineb;
00157 NUMA      *nar, *nag, *nab;
00158 PIX       *pixc;   /* rgb */
00159 PIX       *pixr, *pixg, *pixb;   /* 8 bpp grayscale */
00160 PIXCMAP   *cmap;
00161 
00162     PROCNAME("pixColorContent");
00163 
00164     if (!pixs)
00165         return ERROR_INT("pixs not defined", procName, 1);
00166     if (!ppixr && !ppixg && !ppixb)
00167         return ERROR_INT("nothing to compute", procName, 1);
00168     if (mingray < 0) mingray = 0;
00169     pixGetDimensions(pixs, &w, &h, &d);
00170     if (mingray > 255)
00171         return ERROR_INT("mingray > 255", procName, 1);
00172     if (rwhite < 0 || gwhite < 0 || bwhite < 0)
00173         return ERROR_INT("some white vals are negative", procName, 1);
00174     if ((rwhite || gwhite || bwhite) && (rwhite * gwhite * bwhite == 0))
00175         return ERROR_INT("white vals not all zero or all nonzero", procName, 1);
00176 
00177     cmap = pixGetColormap(pixs);
00178     if (!cmap && d != 32)
00179         return ERROR_INT("pixs neither cmapped nor 32 bpp", procName, 1);
00180     if (cmap)
00181         pixc = pixRemoveColormap(pixs, REMOVE_CMAP_TO_FULL_COLOR);
00182     else
00183         pixc = pixClone(pixs);
00184 
00185     pixr = pixg = pixb = NULL;
00186     w = pixGetWidth(pixc);
00187     h = pixGetHeight(pixc);
00188     if (ppixr) {
00189         pixr = pixCreate(w, h, 8);
00190         datar = pixGetData(pixr);
00191         wplr = pixGetWpl(pixr);
00192         *ppixr = pixr;
00193     }
00194     if (ppixg) {
00195         pixg = pixCreate(w, h, 8);
00196         datag = pixGetData(pixg);
00197         wplg = pixGetWpl(pixg);
00198         *ppixg = pixg;
00199     }
00200     if (ppixb) {
00201         pixb = pixCreate(w, h, 8);
00202         datab = pixGetData(pixb);
00203         wplb = pixGetWpl(pixb);
00204         *ppixb = pixb;
00205     }
00206 
00207     datac = pixGetData(pixc);
00208     wplc = pixGetWpl(pixc);
00209     if (rwhite) {  /* all white pt vals are nonzero */
00210         nar = numaGammaTRC(1.0, 0, rwhite);
00211         rtab = numaGetIArray(nar);
00212         nag = numaGammaTRC(1.0, 0, gwhite);
00213         gtab = numaGetIArray(nag);
00214         nab = numaGammaTRC(1.0, 0, bwhite);
00215         btab = numaGetIArray(nab);
00216     }
00217     for (i = 0; i < h; i++) {
00218         linec = datac + i * wplc;
00219         if (pixr)
00220             liner = datar + i * wplr;
00221         if (pixg)
00222             lineg = datag + i * wplg;
00223         if (pixb)
00224             lineb = datab + i * wplb;
00225         for (j = 0; j < w; j++) {
00226             pixel = linec[j];
00227             extractRGBValues(pixel, &rval, &gval, &bval);
00228             if (rwhite) {  /* color correct for white point */
00229                 rval = rtab[rval];
00230                 gval = gtab[gval];
00231                 bval = btab[bval];
00232             }
00233             if (mingray > 0) {  /* dark pixels have no color value */
00234                 maxval = L_MAX(rval, gval);
00235                 maxval = L_MAX(maxval, bval);
00236                 if (maxval < mingray)
00237                     continue;  /* colorval = 0 for each component */
00238             }
00239             rgdiff = L_ABS(rval - gval);
00240             rbdiff = L_ABS(rval - bval);
00241             gbdiff = L_ABS(gval - bval);
00242             if (pixr) {
00243                 colorval = (rgdiff + rbdiff) / 2;
00244                 SET_DATA_BYTE(liner, j, colorval);
00245             }
00246             if (pixg) {
00247                 colorval = (rgdiff + gbdiff) / 2;
00248                 SET_DATA_BYTE(lineg, j, colorval);
00249             }
00250             if (pixb) {
00251                 colorval = (rbdiff + gbdiff) / 2;
00252                 SET_DATA_BYTE(lineb, j, colorval);
00253             }
00254         }
00255     }
00256 
00257     if (rwhite) {
00258         numaDestroy(&nar);
00259         numaDestroy(&nag);
00260         numaDestroy(&nab);
00261         FREE(rtab);
00262         FREE(gtab);
00263         FREE(btab);
00264     }
00265     pixDestroy(&pixc);
00266     return 0;
00267 }
00268 
00269 
00270 /*!
00271  *  pixColorMagnitude()
00272  *
00273  *      Input:  pixs  (32 bpp rgb or 8 bpp colormapped)
00274  *              rwhite, gwhite, bwhite (color value associated with white point)
00275  *              type (chooses the method for calculating the color magnitude:
00276  *                    L_MAX_DIFF_FROM_AVERAGE_2, L_MAX_MIN_DIFF_FROM_2,
00277  *                    L_MAX_DIFF)
00278  *      Return: pixd (8 bpp, amount of color in each source pixel),
00279  *                    or NULL on error
00280  *
00281  *  Notes:
00282  *      (1) For an RGB image, a gray pixel is one where all three components
00283  *          are equal.  We define the amount of color in an RGB pixel by
00284  *          considering the absolute value of the differences between the
00285  *          three color components.  Consider the two largest
00286  *          of these differences.  The pixel component in common to these
00287  *          two differences is the color farthest from the other two.
00288  *          The color magnitude in an RGB pixel can be taken as:
00289  *              * the average of these two differences; i.e., the
00290  *                average distance from the two components that are
00291  *                nearest to each other to the third component, or
00292  *              * the minimum value of these two differences; i.e., the
00293  *                maximum over all components of the minimum distance
00294  *                from that component to the other two components.
00295  *          Even more simply, the color magnitude can be taken as
00296  *              * the maximum difference between component values
00297  *      (2) As an example, suppose that R and G are the closest in
00298  *          magnitude.  Then the color is determined as:
00299  *              * the average distance of B from these two; namely,
00300  *                (|B - R| + |B - G|) / 2, which can also be found
00301  *                from |B - (R + G) / 2|, or
00302  *              * the minimum distance of B from these two; namely,
00303  *                min(|B - R|, |B - G|).
00304  *              * the max(|B - R|, |B - G|)
00305  *      (3) The three numbers (rwhite, gwhite and bwhite) can be thought
00306  *          of as the values in the image corresponding to white.
00307  *          They are used to compensate for an unbalanced color white point.
00308  *          They must either be all 0 or all non-zero.  To turn this
00309  *          off, set them all to 0.
00310  *      (4) We allow the following methods for choosing the color
00311  *          magnitude from the three components:
00312  *              * L_MAX_DIFF_FROM_AVERAGE_2
00313  *              * L_MAX_MIN_DIFF_FROM_2
00314  *              * L_MAX_DIFF
00315  *          These are described above in (1) and (2), as well as at
00316  *          the top of this file.
00317  */
00318 PIX *
00319 pixColorMagnitude(PIX     *pixs,
00320                   l_int32  rwhite,
00321                   l_int32  gwhite,
00322                   l_int32  bwhite,
00323                   l_int32  type)
00324 {
00325 l_int32    w, h, d, i, j, wplc, wpld;
00326 l_int32    rval, gval, bval, rdist, gdist, bdist, colorval;
00327 l_int32    rgdist, rbdist, gbdist, mindist, maxdist, minval, maxval;
00328 l_int32   *rtab, *gtab, *btab;
00329 l_uint32   pixel;
00330 l_uint32  *datac, *datad, *linec, *lined;
00331 NUMA      *nar, *nag, *nab;
00332 PIX       *pixc, *pixd;
00333 PIXCMAP   *cmap;
00334 
00335     PROCNAME("pixColorMagnitude");
00336 
00337     if (!pixs)
00338         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00339     pixGetDimensions(pixs, &w, &h, &d);
00340     if (type != L_MAX_DIFF_FROM_AVERAGE_2 && type != L_MAX_MIN_DIFF_FROM_2 &&
00341         type != L_MAX_DIFF)
00342         return (PIX *)ERROR_PTR("invalid type", procName, NULL);
00343     if (rwhite < 0 || gwhite < 0 || bwhite < 0)
00344         return (PIX *)ERROR_PTR("some white vals are negative", procName, NULL);
00345     if ((rwhite || gwhite || bwhite) && (rwhite * gwhite * bwhite == 0))
00346         return (PIX *)ERROR_PTR("white vals not all zero or all nonzero",
00347                                 procName, NULL);
00348 
00349     cmap = pixGetColormap(pixs);
00350     if (!cmap && d != 32)
00351         return (PIX *)ERROR_PTR("pixs not cmapped or 32 bpp", procName, NULL);
00352     if (cmap)
00353         pixc = pixRemoveColormap(pixs, REMOVE_CMAP_TO_FULL_COLOR);
00354     else
00355         pixc = pixClone(pixs);
00356 
00357     pixd = pixCreate(w, h, 8);
00358     datad = pixGetData(pixd);
00359     wpld = pixGetWpl(pixd);
00360     datac = pixGetData(pixc);
00361     wplc = pixGetWpl(pixc);
00362     if (rwhite) {  /* all white pt vals are nonzero */
00363         nar = numaGammaTRC(1.0, 0, rwhite);
00364         rtab = numaGetIArray(nar);
00365         nag = numaGammaTRC(1.0, 0, gwhite);
00366         gtab = numaGetIArray(nag);
00367         nab = numaGammaTRC(1.0, 0, bwhite);
00368         btab = numaGetIArray(nab);
00369     }
00370     for (i = 0; i < h; i++) {
00371         linec = datac + i * wplc;
00372         lined = datad + i * wpld;
00373         for (j = 0; j < w; j++) {
00374             pixel = linec[j];
00375             extractRGBValues(pixel, &rval, &gval, &bval);
00376             if (rwhite) {  /* color correct for white point */
00377                 rval = rtab[rval];
00378                 gval = gtab[gval];
00379                 bval = btab[bval];
00380             }
00381             if (type == L_MAX_DIFF_FROM_AVERAGE_2) {
00382                 rdist = ((gval + bval ) / 2 - rval);
00383                 rdist = L_ABS(rdist);
00384                 gdist = ((rval + bval ) / 2 - gval);
00385                 gdist = L_ABS(gdist);
00386                 bdist = ((rval + gval ) / 2 - bval);
00387                 bdist = L_ABS(bdist);
00388                 colorval = L_MAX(rdist, gdist);
00389                 colorval = L_MAX(colorval, bdist);
00390             }
00391             else if (type == L_MAX_MIN_DIFF_FROM_2) { /* choose intermed dist */
00392                 rgdist = L_ABS(rval - gval);
00393                 rbdist = L_ABS(rval - bval);
00394                 gbdist = L_ABS(gval - bval);
00395                 maxdist = L_MAX(rgdist, rbdist);
00396                 if (gbdist >= maxdist)
00397                     colorval = maxdist;
00398                 else {  /* gbdist is smallest or intermediate */
00399                     mindist = L_MIN(rgdist, rbdist);
00400                     colorval = L_MAX(mindist, gbdist);
00401                 }
00402             }
00403             else {  /* type == L_MAX_DIFF */
00404                 minval = L_MIN(rval, gval);
00405                 minval = L_MIN(minval, bval);
00406                 maxval = L_MAX(rval, gval);
00407                 maxval = L_MAX(maxval, bval);
00408                 colorval = maxval - minval;
00409             }
00410             SET_DATA_BYTE(lined, j, colorval);
00411         }
00412     }
00413 
00414     if (rwhite) {
00415         numaDestroy(&nar);
00416         numaDestroy(&nag);
00417         numaDestroy(&nab);
00418         FREE(rtab);
00419         FREE(gtab);
00420         FREE(btab);
00421     }
00422     pixDestroy(&pixc);
00423     return pixd;
00424 }
00425 
00426 
00427 /*!
00428  *  pixMaskOverColorPixels()
00429  *
00430  *      Input:  pixs  (32 bpp rgb or 8 bpp colormapped)
00431  *              threshdiff (threshold for minimum of the max difference
00432  *                          between components)
00433  *              mindist (minimum allowed distance from nearest non-color pixel)
00434  *      Return: pixd (1 bpp, mask over color pixels), or null on error
00435  *
00436  *  Notes:
00437  *      (1) The generated mask identifies each pixel as either color or
00438  *          non-color.  For a pixel to be color, it must satisfy two
00439  *          constraints:
00440  *            (a) The max difference between the r,g and b components must
00441  *                equal or exceed a threshold @threshdiff.
00442  *            (b) It must be at least @mindist (in an 8-connected way)
00443  *                from the nearest non-color pixel.
00444  *      (2) The distance constraint (b) is only applied if @mindist > 1.
00445  *          For example, if @mindist == 2, the color pixels identified
00446  *          by (a) are eroded by a 3x3 Sel.  In general, the Sel size
00447  *          for erosion is 2 * (@mindist - 1) + 1.
00448  *          Why have this constraint?  In scanned images that are
00449  *          essentially gray, color artifacts are typically introduced
00450  *          in transition regions near sharp edges that go from dark
00451  *          to light, so this allows these transition regions to be removed.
00452  */
00453 PIX *
00454 pixMaskOverColorPixels(PIX     *pixs,
00455                        l_int32  threshdiff,
00456                        l_int32  mindist)
00457 {
00458 l_int32    w, h, d, i, j, wpls, wpld, size;
00459 l_int32    rval, gval, bval, minval, maxval;
00460 l_uint32  *datas, *datad, *lines, *lined;
00461 PIX       *pixc, *pixd;
00462 PIXCMAP   *cmap;
00463 
00464     PROCNAME("pixMaskOverColorPixels");
00465 
00466     if (!pixs)
00467         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00468     pixGetDimensions(pixs, &w, &h, &d);
00469 
00470     cmap = pixGetColormap(pixs);
00471     if (!cmap && d != 32)
00472         return (PIX *)ERROR_PTR("pixs not cmapped or 32 bpp", procName, NULL);
00473     if (cmap)
00474         pixc = pixRemoveColormap(pixs, REMOVE_CMAP_TO_FULL_COLOR);
00475     else
00476         pixc = pixClone(pixs);
00477 
00478     pixd = pixCreate(w, h, 1);
00479     datad = pixGetData(pixd);
00480     wpld = pixGetWpl(pixd);
00481     datas = pixGetData(pixc);
00482     wpls = pixGetWpl(pixc);
00483     for (i = 0; i < h; i++) {
00484         lines = datas + i * wpls;
00485         lined = datad + i * wpld;
00486         for (j = 0; j < w; j++) {
00487             extractRGBValues(lines[j], &rval, &gval, &bval);
00488             minval = L_MIN(rval, gval);
00489             minval = L_MIN(minval, bval);
00490             maxval = L_MAX(rval, gval);
00491             maxval = L_MAX(maxval, bval);
00492             if (maxval - minval >= threshdiff)
00493                 SET_DATA_BIT(lined, j);
00494         }
00495     }
00496 
00497     if (mindist > 1) {
00498         size = 2 * (mindist - 1) + 1;
00499         pixErodeBrick(pixd, pixd, size, size);
00500     }
00501 
00502     pixDestroy(&pixc);
00503     return pixd;
00504 }
00505 
00506 
00507 /*!
00508  *  pixColorFraction()
00509  *
00510  *      Input:  pixs  (32 bpp rgb)
00511  *              darkthresh (threshold near black; if the lightest component
00512  *                          is below this, the pixel is not considered in
00513  *                          the statistics; typ. 20)
00514  *              lightthresh (threshold near white; if the darkest component
00515  *                           is above this, the pixel is not considered in
00516  *                           the statistics; typ. 244)
00517  *              diffthresh (thresh for the maximum difference between
00518  *                          component value; below this the pixel is not
00519  *                          considered to have sufficient color)
00520  *              factor (subsampling factor)
00521  *              &pixfract (<return> fraction of pixels in intermediate
00522  *                         brightness range that were considered
00523  *                         for color content)
00524  *              &colorfract (<return> fraction of pixels that meet the
00525  *                           criterion for sufficient color; 0.0 on error)
00526  *      Return: 0 if OK, 1 on error
00527  *
00528  *  Notes:
00529  *      (1) This function is asking the question: to what extent does the
00530  *          image appear to have color?   The amount of color a pixel
00531  *          appears to have depends on both the deviation of the
00532  *          individual components from their average and on the average
00533  *          intensity itself.  For example, the color will be much more
00534  *          obvious with a small deviation from white than the same
00535  *          deviation from black.
00536  *      (2) Any pixel that meets these three tests is considered a
00537  *          colorful pixel:
00538  *            (a) the lightest component must equal or exceed @darkthresh
00539  *            (b) the darkest component must not exceed @lightthresh
00540  *            (c) the max difference between components must equal or
00541  *                exceed @diffthresh.
00542  *      (3) The dark pixels are removed from consideration because
00543  *          they don't appear to have color.
00544  *      (4) The very lightest pixels are removed because if an image
00545  *          has a lot of "white", the color fraction will be artificially
00546  *          low, even if all the other pixels are colorful.
00547  *      (5) If pixfract is very small, there are few pixels that are neither
00548  *          black nor white.  If colorfract is very small, the pixels
00549  *          that are neither black nor white have very little color
00550  *          content.  The product 'pixfract * colorfract' gives the
00551  *          fraction of pixels with significant color content.
00552  *      (6) One use of this function is as a preprocessing step for median
00553  *          cut quantization (colorquant2.c), which does a very poor job
00554  *          splitting the color space into rectangular volume elements when
00555  *          all the pixels are near the diagonal of the color cube.  For
00556  *          octree quantization of an image with only gray values, the
00557  *          2^(level) octcubes on the diagonal are the only ones
00558  *          that can be occupied.
00559  */
00560 l_int32
00561 pixColorFraction(PIX        *pixs,
00562                  l_int32     darkthresh,
00563                  l_int32     lightthresh,
00564                  l_int32     diffthresh,
00565                  l_int32     factor,
00566                  l_float32  *ppixfract,
00567                  l_float32  *pcolorfract)
00568 {
00569 l_int32    i, j, w, h, wpl, rval, gval, bval, minval, maxval;
00570 l_int32    total, npix, ncolor;
00571 l_uint32   pixel;
00572 l_uint32  *data, *line;
00573 
00574     PROCNAME("pixColorFraction");
00575 
00576     if (!ppixfract || !pcolorfract)
00577         return ERROR_INT("&pixfract and &colorfract not both defined",
00578                          procName, 1);
00579     *ppixfract = 0.0;
00580     *pcolorfract = 0.0;
00581     if (!pixs || pixGetDepth(pixs) != 32)
00582         return ERROR_INT("pixs not defined or not 32 bpp", procName, 1);
00583 
00584     pixGetDimensions(pixs, &w, &h, NULL);
00585     data = pixGetData(pixs);
00586     wpl = pixGetWpl(pixs);
00587     npix = ncolor = total = 0;
00588     for (i = 0; i < h; i += factor) {
00589         line = data + i * wpl;
00590         for (j = 0; j < w; j += factor) {
00591             total++;
00592             pixel = line[j];
00593             extractRGBValues(pixel, &rval, &gval, &bval);
00594             minval = L_MIN(rval, gval);
00595             minval = L_MIN(minval, bval);
00596             if (minval > lightthresh)  /* near white */
00597                 continue;
00598             maxval = L_MAX(rval, gval);
00599             maxval = L_MAX(maxval, bval);
00600             if (maxval < darkthresh)  /* near black */
00601                 continue;
00602 
00603             npix++;
00604             if (maxval - minval >= diffthresh)
00605                 ncolor++;
00606         }
00607     }
00608 
00609     if (npix == 0) {
00610         L_WARNING("No pixels found for consideration", procName);
00611         return 0;
00612     }
00613     *ppixfract = (l_float32)npix / (l_float32)total;
00614     *pcolorfract = (l_float32)ncolor / (l_float32)npix;
00615     return 0;
00616 }
00617 
00618 
00619 /*!
00620  *  pixNumSignificantGrayColors()
00621  *
00622  *      Input:  pixs  (8 bpp gray)
00623  *              darkthresh (dark threshold for minimum intensity to be
00624  *                          considered; typ. 20)
00625  *              lightthresh (threshold near white, for maximum intensity
00626  *                           to be considered; typ. 236)
00627  *              minfract (minimum fraction of all pixels to include a level
00628  *                        as significant; typ. 0.0001; should be < 0.001)
00629  *              factor (subsample factor; integer >= 1)
00630  *              &ncolors (<return> number of significant colors; 0 on error)
00631  *      Return: 0 if OK, 1 on error
00632  *
00633  *  Notes:
00634  *      (1) This function is asking the question: how many perceptually
00635  *          significant gray color levels is in this pix?
00636  *          A color level must meet 3 criteria to be significant:
00637  *            - it can't be too close to black
00638  *            - it can't be too close to white
00639  *            - it must have at least some minimum fractional population
00640  *      (2) Use -1 for default values for darkthresh, lightthresh and minfract.
00641  *      (3) Choose default of darkthresh = 20, because variations in very
00642  *          dark pixels are not visually significant.
00643  *      (4) Choose default of lightthresh = 236, because document images
00644  *          that have been jpeg'd typically have near-white pixels in the
00645  *          8x8 jpeg blocks, and these should not be counted.  It is desirable
00646  *          to obtain a clean image by quantizing this noise away.
00647  */
00648 l_int32
00649 pixNumSignificantGrayColors(PIX       *pixs,
00650                             l_int32    darkthresh,
00651                             l_int32    lightthresh,
00652                             l_float32  minfract,
00653                             l_int32    factor,
00654                             l_int32   *pncolors)
00655 {
00656 l_int32  i, w, h, count, mincount, ncolors;
00657 NUMA    *na;
00658 
00659     PROCNAME("pixNumSignificantGrayColors");
00660 
00661     if (!pncolors)
00662         return ERROR_INT("&ncolors not defined", procName, 1);
00663     *pncolors = 0;
00664     if (!pixs || pixGetDepth(pixs) != 8)
00665         return ERROR_INT("pixs not defined or not 8 bpp", procName, 1);
00666     if (darkthresh < 0) darkthresh = 20;  /* defaults */
00667     if (lightthresh < 0) lightthresh = 236;
00668     if (minfract < 0.0) minfract = 0.0001;
00669     if (minfract > 1.0)
00670         return ERROR_INT("minfract > 1.0", procName, 1);
00671     if (minfract >= 0.001)
00672         L_WARNING("minfract too big; likely to underestimate ncolors",
00673                   procName);
00674     if (lightthresh > 255 || darkthresh >= lightthresh)
00675         return ERROR_INT("invalid thresholds", procName, 1);
00676     if (factor < 1) factor = 1;
00677 
00678     pixGetDimensions(pixs, &w, &h, NULL);
00679     mincount = (l_int32)(minfract * w * h);
00680     if ((na = pixGetGrayHistogram(pixs, factor)) == NULL)
00681         return ERROR_INT("na not made", procName, 1);
00682     ncolors = 2;  /* add in black and white */
00683     for (i = darkthresh; i <= lightthresh; i++) {
00684         numaGetIValue(na, i, &count);
00685         if (count >= mincount)
00686             ncolors++;
00687     }
00688 
00689     *pncolors = ncolors;
00690     numaDestroy(&na);
00691     return 0;
00692 }
00693 
00694 
00695 /*!
00696  *  pixColorsForQuantization()
00697  *      Input:  pixs (8 bpp gray or 32 bpp rgb; with or without colormap)
00698  *              thresh (binary threshold on edge gradient; 0 for default)
00699  *              &ncolors (<return> the number of colors found)
00700  *              &iscolor (<optional return> 1 if significant color is found;
00701  *                        0 otherwise.  If pixs is 8 bpp, and does not have
00702  *                        a colormap with color entries, this is 0)
00703  *              debug (1 to output masked image that is tested for colors;
00704  *                     0 otherwise)
00705  *      Return: 0 if OK, 1 on error.
00706  *
00707  *  Notes:
00708  *      (1) This function finds a measure of the number of colors that are
00709  *          found in low-gradient regions of an image.  By its
00710  *          magnitude relative to some threshold (not specified in
00711  *          this function), it gives a good indication of whether
00712  *          quantization will generate posterization.   This number
00713  *          is larger for images with regions of slowly varying
00714  *          intensity (if 8 bpp) or color (if rgb). Such images, if
00715  *          quantized, may require dithering to avoid posterization,
00716  *          and lossless compression is then expected to be poor.
00717  *      (2) If pixs has a colormap, the number of colors returned is
00718  *          the number in the colormap.
00719  *      (3) It is recommended that document images be reduced to a width
00720  *          of 800 pixels before applying this function.  Then it can
00721  *          be expected that color detection will be fairly accurate
00722  *          and the number of colors will reflect both the content and
00723  *          the type of compression to be used.  For less than 15 colors,
00724  *          there is unlikely to be a halftone image, and lossless
00725  *          quantization should give both a good visual result and
00726  *          better compression.
00727  *      (4) When using the default threshold on the gradient (15),
00728  *          images (both gray and rgb) where ncolors is greater than
00729  *          about 15 will compress poorly with either lossless
00730  *          compression or dithered quantization, and they may be
00731  *          posterized with non-dithered quantization.
00732  *      (5) For grayscale images, or images without significant color,
00733  *          this returns the number of significant gray levels in
00734  *          the low-gradient regions.  The actual number of gray levels
00735  *          can be large due to jpeg compression noise in the background.
00736  *      (6) Similarly, for color images, the actual number of different
00737  *          (r,g,b) colors in the low-gradient regions (rather than the
00738  *          number of occupied level 4 octcubes) can be quite large, e.g.,
00739  *          due to jpeg compression noise, even for regions that appear
00740  *          to be of a single color.  By quantizing to level 4 octcubes,
00741  *          most of these superfluous colors are removed from the counting.
00742  *      (7) The image is tested for color.  If there is very little color,
00743  *          it is thresholded to gray and the number of gray levels in
00744  *          the low gradient regions is found.  If the image has color,
00745  *          the number of occupied level 4 octcubes is found.
00746  *      (8) The number of colors in the low-gradient regions increases
00747  *          monotonically with the threshold @thresh on the edge gradient.
00748  *      (9) Background: grayscale and color quantization is often useful
00749  *          to achieve highly compressed images with little visible
00750  *          distortion.  However, gray or color washes (regions of
00751  *          low gradient) can defeat this approach to high compression.
00752  *          How can one determine if an image is expected to compress
00753  *          well using gray or color quantization?  We use the fact that
00754  *            * gray washes, when quantized with less than 50 intensities,
00755  *              have posterization (visible boundaries between regions
00756  *              of uniform 'color') and poor lossless compression
00757  *            * color washes, when quantized with level 4 octcubes,
00758  *              typically result in both posterization and the occupancy
00759  *              of many level 4 octcubes.
00760  *          Images can have colors either intrinsically or as jpeg
00761  *          compression artifacts.  This function reduces but does not
00762  *          completely eliminate measurement of jpeg quantization noise
00763  *          in the white background of grayscale or color images.
00764  */
00765 l_int32
00766 pixColorsForQuantization(PIX      *pixs,
00767                          l_int32   thresh,
00768                          l_int32  *pncolors,
00769                          l_int32  *piscolor,
00770                          l_int32   debug)
00771 {
00772 l_int32    w, h, d, minside, factor;
00773 l_float32  pixfract, colorfract;
00774 PIX       *pixt, *pixsc, *pixg, *pixe, *pixb, *pixm;
00775 PIXCMAP   *cmap;
00776 
00777     PROCNAME("pixColorsForQuantization");
00778 
00779     if (!pncolors)
00780         return ERROR_INT("&ncolors not defined", procName, 1);
00781     *pncolors = 0;
00782     if (!pixs)
00783         return ERROR_INT("pixs not defined", procName, 1);
00784     if ((cmap = pixGetColormap(pixs)) != NULL) {
00785         *pncolors = pixcmapGetCount(cmap);
00786         if (piscolor)
00787             pixcmapHasColor(cmap, piscolor);
00788         return 0;
00789     }
00790 
00791     pixGetDimensions(pixs, &w, &h, &d);
00792     if (d != 8 && d != 32)
00793         return ERROR_INT("pixs not 8 or 32 bpp", procName, 1);
00794     if (thresh <= 0) 
00795         thresh = 15;
00796     if (piscolor)
00797         *piscolor = 0;
00798 
00799         /* First test if 32 bpp has any significant color; if not,
00800          * convert it to gray.  Colors whose average values are within
00801          * 20 of black or 8 of white are ignored because they're not
00802          * very 'colorful'.  If less than 2.5/10000 of the pixels have
00803          * significant color, consider the image to be gray. */
00804     minside = L_MIN(w, h);
00805     if (d == 8)
00806         pixt = pixClone(pixs);
00807     else {  /* d == 32 */
00808         factor = L_MAX(1, minside / 400);
00809         pixColorFraction(pixs, 20, 248, 30, factor, &pixfract, &colorfract);
00810         if (pixfract * colorfract < 0.00025) {
00811             pixt = pixGetRGBComponent(pixs, COLOR_RED);
00812             d = 8;
00813         }
00814         else {  /* d == 32 */
00815             pixt = pixClone(pixs);
00816             if (piscolor)
00817                 *piscolor = 1;
00818         }
00819     }
00820 
00821         /* If the smallest side is less than 1000, do not downscale.
00822          * If it is in [1000 ... 2000), downscale by 2x.  If it is >= 2000,
00823          * downscale by 4x.  Factors of 2 are chosen for speed.  The
00824          * actual resolution at which subsequent calculations take place
00825          * is not strongly dependent on downscaling.  */
00826     factor = L_MAX(1, minside / 500);
00827     if (factor == 1)
00828         pixsc = pixCopy(NULL, pixt);  /* to be sure pixs is unchanged */
00829     else if (factor == 2 || factor == 3)
00830         pixsc = pixScaleAreaMap2(pixt);
00831     else
00832         pixsc = pixScaleAreaMap(pixt, 0.25, 0.25);
00833 
00834         /* Basic edge mask generation procedure:
00835          *   - work on a grayscale image
00836          *   - get a 1 bpp edge mask by using an edge filter and
00837          *     thresholding to get fg pixels at the edges
00838          *   - for gray, dilate with a 3x3 brick Sel to get mask over
00839          *     all pixels within a distance of 1 pixel from the nearest
00840          *     edge pixel
00841          *   - for color, dilate with a 7x7 brick Sel to get mask over
00842          *     all pixels within a distance of 3 pixels from the nearest
00843          *     edge pixel  */
00844     if (d == 8)
00845         pixg = pixClone(pixsc);
00846     else  /* d == 32 */
00847         pixg = pixConvertRGBToLuminance(pixsc);
00848     pixe = pixSobelEdgeFilter(pixg, L_ALL_EDGES);
00849     pixb = pixThresholdToBinary(pixe, thresh);
00850     pixInvert(pixb, pixb);
00851     if (d == 8)
00852         pixm = pixMorphSequence(pixb, "d3.3", 0);
00853     else
00854         pixm = pixMorphSequence(pixb, "d7.7", 0);
00855 
00856         /* Mask the near-edge pixels to white, and count the colors.
00857          * If grayscale, don't count colors within 20 levels of
00858          * black or white, and only count colors with a fraction
00859          * of at least 1/10000 of the image pixels.
00860          * If color, count the number of level 4 octcubes that
00861          * contain at least 20 pixels.  These magic numbers are guesses
00862          * as to what might work, based on a small data set.  Results
00863          * should not be overly sensitive to their actual values. */
00864     if (d == 8) {
00865         pixSetMasked(pixg, pixm, 0xff);
00866         if (debug) pixWrite("junkpix8.png", pixg, IFF_PNG);
00867         pixNumSignificantGrayColors(pixg, 20, 236, 0.0001, 1, pncolors);
00868     }
00869     else {  /* d == 32 */
00870         pixSetMasked(pixsc, pixm, 0xffffffff);
00871         if (debug) pixWrite("junkpix32.png", pixsc, IFF_PNG);
00872         pixNumberOccupiedOctcubes(pixsc, 4, 20, -1, pncolors);
00873     }
00874 
00875     pixDestroy(&pixt);
00876     pixDestroy(&pixsc);
00877     pixDestroy(&pixg);
00878     pixDestroy(&pixe);
00879     pixDestroy(&pixb);
00880     pixDestroy(&pixm);
00881     return 0;
00882 }
00883 
00884 
00885 /*!
00886  *  pixNumColors()
00887  *      Input:  pixs (2, 4, 8, 32 bpp)
00888  *              factor (subsampling factor; integer)
00889  *              &ncolors (<return> the number of colors found, or 0 if
00890  *                        there are more than 256)
00891  *      Return: 0 if OK, 1 on error.
00892  *
00893  *  Notes:
00894  *      (1) This returns the actual number of colors found in the image,
00895  *          even if there is a colormap.  If @factor == 1 and the
00896  *          number of colors differs from the number of entries
00897  *          in the colormap, a warning is issued.
00898  *      (2) Use @factor == 1 to find the actual number of colors.
00899  *          Use @factor > 1 to quickly find the approximate number of colors.
00900  *      (3) For d = 2, 4 or 8 bpp grayscale, this returns the number
00901  *          of colors found in the image in 'ncolors'.
00902  *      (4) For d = 32 bpp (rgb), if the number of colors is
00903  *          greater than 256, this returns 0 in 'ncolors'.
00904  */
00905 l_int32
00906 pixNumColors(PIX      *pixs,
00907              l_int32   factor,
00908              l_int32  *pncolors)
00909 {
00910 l_int32    w, h, d, i, j, wpl, hashsize, sum, count;
00911 l_int32    rval, gval, bval, val;
00912 l_int32   *inta;
00913 l_uint32   pixel;
00914 l_uint32  *data, *line;
00915 PIXCMAP   *cmap;
00916 
00917     PROCNAME("pixNumColors");
00918 
00919     if (!pncolors)
00920         return ERROR_INT("&ncolors not defined", procName, 1);
00921     *pncolors = 0;
00922     if (!pixs)
00923         return ERROR_INT("pixs not defined", procName, 1);
00924     pixGetDimensions(pixs, &w, &h, &d);
00925     if (d != 2 && d != 4 && d != 8 && d != 32)
00926         return ERROR_INT("d not in {2, 4, 8, 32}", procName, 1);
00927     if (factor < 1) factor = 1;
00928 
00929     data = pixGetData(pixs);
00930     wpl = pixGetWpl(pixs);
00931     sum = 0;
00932     if (d != 32) {  /* grayscale */
00933         inta = (l_int32 *)CALLOC(256, sizeof(l_int32));
00934         for (i = 0; i < h; i += factor) {
00935             line = data + i * wpl;
00936             for (j = 0; j < w; j += factor) {
00937                 if (d == 8)
00938                     val = GET_DATA_BYTE(line, j);
00939                 else if (d == 4)
00940                     val = GET_DATA_QBIT(line, j);
00941                 else  /* d == 2 */
00942                     val = GET_DATA_DIBIT(line, j);
00943                 inta[val] = 1;
00944             }
00945         }
00946         for (i = 0; i < 256; i++)
00947             if (inta[i]) sum++;
00948         *pncolors = sum;
00949         FREE(inta);
00950 
00951         if (factor == 1 && ((cmap = pixGetColormap(pixs)) != NULL)) {
00952             count = pixcmapGetCount(cmap);
00953             if (sum != count) 
00954                 L_WARNING_INT("colormap size %d differs from actual colors",
00955                               procName, count);
00956         }
00957         return 0;
00958     }
00959 
00960         /* 32 bpp rgb; quit if we get above 256 colors */
00961     hashsize = 5507;  /* big and prime; collisions are not likely */
00962     inta = (l_int32 *)CALLOC(hashsize, sizeof(l_int32));
00963     for (i = 0; i < h; i += factor) {
00964         line = data + i * wpl;
00965         for (j = 0; j < w; j += factor) {
00966             pixel = line[j];
00967             extractRGBValues(pixel, &rval, &gval, &bval);
00968             val = (137 * rval + 269 * gval + 353 * bval) % hashsize;
00969             if (inta[val] == 0) {
00970                 inta[val] = 1;
00971                 sum++;
00972                 if (sum > 256) {
00973                     FREE(inta);
00974                     return 0;
00975                 }
00976             }
00977         }
00978     }
00979 
00980     *pncolors = sum;
00981     FREE(inta);
00982     return 0;
00983 }
00984 
00985 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines