Leptonica 1.68
C Image Processing Library

grayquant.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  *  grayquant.c
00018  *                     
00019  *      Thresholding from 8 bpp to 1 bpp
00020  *
00021  *          Floyd-Steinberg dithering to binary
00022  *              PIX    *pixDitherToBinary()
00023  *              PIX    *pixDitherToBinarySpec()
00024  *
00025  *          Simple (pixelwise) binarization with fixed threshold
00026  *              PIX    *pixThresholdToBinary()
00027  *
00028  *          Binarization with variable threshold
00029  *              PIX    *pixVarThresholdToBinary()
00030  *
00031  *          Slower implementation of Floyd-Steinberg dithering, using LUTs
00032  *              PIX    *pixDitherToBinaryLUT()
00033  *
00034  *          Generate a binary mask from pixels of particular values
00035  *              PIX    *pixGenerateMaskByValue()
00036  *              PIX    *pixGenerateMaskByBand()
00037  *
00038  *      Thresholding from 8 bpp to 2 bpp
00039  *
00040  *          Dithering to 2 bpp
00041  *              PIX      *pixDitherTo2bpp()
00042  *              PIX      *pixDitherTo2bppSpec()
00043  *
00044  *          Simple (pixelwise) thresholding to 2 bpp with optional cmap
00045  *              PIX      *pixThresholdTo2bpp()
00046  *
00047  *      Simple (pixelwise) thresholding from 8 bpp to 4 bpp
00048  *              PIX      *pixThresholdTo4bpp()
00049  *
00050  *      Simple (pixelwise) quantization on 8 bpp grayscale
00051  *              PIX      *pixThresholdOn8bpp()
00052  *
00053  *      Arbitrary (pixelwise) thresholding from 8 bpp to 2, 4 or 8 bpp
00054  *              PIX      *pixThresholdGrayArb()
00055  *
00056  *      Quantization tables for linear thresholds of grayscale images
00057  *              l_int32  *makeGrayQuantIndexTable()
00058  *              l_int32  *makeGrayQuantTargetTable()
00059  *
00060  *      Quantization table for arbitrary thresholding of grayscale images
00061  *              l_int32   makeGrayQuantTableArb()
00062  *              l_int32   makeGrayQuantColormapArb()
00063  *
00064  *      Thresholding from 32 bpp rgb to 1 bpp
00065  *      (really color quantization, but it's better placed in this file)
00066  *              PIX      *pixGenerateMaskByBand32()
00067  *              PIX      *pixGenerateMaskByDiscr32()
00068  *
00069  *      Histogram-based grayscale quantization
00070  *              PIX      *pixGrayQuantFromHisto()
00071  *       static l_int32   numaFillCmapFromHisto()
00072  *
00073  *      Color quantize grayscale image using existing colormap
00074  *              PIX      *pixGrayQuantFromCmap()
00075  */
00076 
00077 #include <stdio.h>
00078 #include <stdlib.h>
00079 #include <string.h>
00080 #include <math.h>
00081 #include "allheaders.h"
00082 
00083 
00084 static l_int32 numaFillCmapFromHisto(NUMA *na, PIXCMAP *cmap,
00085                                      l_float32 minfract, l_int32 maxsize,
00086                                      l_int32 **plut);
00087 
00088 
00089 /*------------------------------------------------------------------*
00090  *             Binarization by Floyd-Steinberg dithering            *
00091  *------------------------------------------------------------------*/
00092 /*!
00093  *  pixDitherToBinary()
00094  *
00095  *      Input:  pixs
00096  *      Return: pixd (dithered binary), or null on error
00097  *
00098  *  The Floyd-Steinberg error diffusion dithering algorithm
00099  *  binarizes an 8 bpp grayscale image to a threshold of 128.
00100  *  If a pixel has a value above 127, it is binarized to white
00101  *  and the excess (below 255) is subtracted from three 
00102  *  neighboring pixels in the fractions 3/8 to (i, j+1),
00103  *  3/8 to (i+1, j) and 1/4 to (i+1,j+1), truncating to 0
00104  *  if necessary.  Likewise, if it the pixel has a value 
00105  *  below 128, it is binarized to black and the excess above 0
00106  *  is added to the neighboring pixels, truncating to 255 if necessary.
00107  *
00108  *  This function differs from straight dithering in that it allows
00109  *  clipping of grayscale to 0 or 255 if the values are
00110  *  sufficiently close, without distribution of the excess.
00111  *  This uses default values to specify the range of lower
00112  *  and upper values (near 0 and 255, rsp) that are clipped
00113  *  to black and white without propagating the excess.
00114  *  Not propagating the excess has the effect of reducing the
00115  *  snake patterns in parts of the image that are nearly black or white;
00116  *  however, it also prevents the attempt to reproduce gray for those values.
00117  *
00118  *  The implementation is straightforward.  It uses a pair of
00119  *  line buffers to avoid changing pixs.  It is about 2x faster
00120  *  than the implementation using LUTs.
00121  */
00122 PIX *
00123 pixDitherToBinary(PIX  *pixs)
00124 {
00125     PROCNAME("pixDitherToBinary");
00126 
00127     if (!pixs)
00128         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00129     if (pixGetDepth(pixs) != 8)
00130         return (PIX *)ERROR_PTR("must be 8 bpp for dithering", procName, NULL);
00131 
00132     return pixDitherToBinarySpec(pixs, DEFAULT_CLIP_LOWER_1,
00133                                  DEFAULT_CLIP_UPPER_1);
00134 }
00135 
00136 
00137 /*!
00138  *  pixDitherToBinarySpec()
00139  *
00140  *      Input:  pixs
00141  *              lowerclip (lower clip distance to black; use 0 for default)
00142  *              upperclip (upper clip distance to white; use 0 for default)
00143  *      Return: pixd (dithered binary), or null on error
00144  *
00145  *  Notes:
00146  *      (1) See comments above in pixDitherToBinary() for details.
00147  *      (2) The input parameters lowerclip and upperclip specify the range
00148  *          of lower and upper values (near 0 and 255, rsp) that are
00149  *          clipped to black and white without propagating the excess.
00150  *          For that reason, lowerclip and upperclip should be small numbers.
00151  */
00152 PIX *
00153 pixDitherToBinarySpec(PIX     *pixs,
00154                       l_int32  lowerclip,
00155                       l_int32  upperclip)
00156 {
00157 l_int32    w, h, d, wplt, wpld;
00158 l_uint32  *datat, *datad;
00159 l_uint32  *bufs1, *bufs2;
00160 PIX       *pixt, *pixd;
00161 
00162     PROCNAME("pixDitherToBinarySpec");
00163 
00164     if (!pixs)
00165         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00166     pixGetDimensions(pixs, &w, &h, &d);
00167     if (d != 8)
00168         return (PIX *)ERROR_PTR("must be 8 bpp for dithering", procName, NULL);
00169     if (lowerclip < 0 || lowerclip > 255)
00170         return (PIX *)ERROR_PTR("invalid value for lowerclip", procName, NULL);
00171     if (upperclip < 0 || upperclip > 255)
00172         return (PIX *)ERROR_PTR("invalid value for upperclip", procName, NULL);
00173 
00174     if ((pixd = pixCreate(w, h, 1)) == NULL)
00175         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
00176     pixCopyResolution(pixd, pixs);
00177     datad = pixGetData(pixd);
00178     wpld = pixGetWpl(pixd);
00179 
00180         /* Remove colormap if it exists */
00181     pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
00182     datat = pixGetData(pixt);
00183     wplt = pixGetWpl(pixt);
00184 
00185         /* Two line buffers, 1 for current line and 2 for next line */
00186     if ((bufs1 = (l_uint32 *)CALLOC(wplt, sizeof(l_uint32))) == NULL)
00187         return (PIX *)ERROR_PTR("bufs1 not made", procName, NULL);
00188     if ((bufs2 = (l_uint32 *)CALLOC(wplt, sizeof(l_uint32))) == NULL)
00189         return (PIX *)ERROR_PTR("bufs2 not made", procName, NULL);
00190 
00191     ditherToBinaryLow(datad, w, h, wpld, datat, wplt, bufs1, bufs2,
00192                       lowerclip, upperclip);
00193 
00194     FREE(bufs1);
00195     FREE(bufs2);
00196     pixDestroy(&pixt);
00197 
00198     return pixd;
00199 }
00200 
00201 
00202 /*------------------------------------------------------------------*
00203  *       Simple (pixelwise) binarization with fixed threshold       *
00204  *------------------------------------------------------------------*/
00205 /*!
00206  *  pixThresholdToBinary()
00207  *
00208  *      Input:  pixs (4 or 8 bpp)
00209  *              threshold value
00210  *      Return: pixd (1 bpp), or null on error
00211  *
00212  *  Notes:
00213  *      (1) If the source pixel is less than the threshold value,
00214  *          the dest will be 1; otherwise, it will be 0
00215  */
00216 PIX *
00217 pixThresholdToBinary(PIX     *pixs,
00218                      l_int32  thresh)
00219 {
00220 l_int32    d, w, h, wplt, wpld;
00221 l_uint32  *datat, *datad;
00222 PIX       *pixt, *pixd;
00223 
00224     PROCNAME("pixThresholdToBinary");
00225 
00226     if (!pixs)
00227         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00228     pixGetDimensions(pixs, &w, &h, &d);
00229     if (d != 4 && d != 8)
00230         return (PIX *)ERROR_PTR("pixs must be 4 or 8 bpp", procName, NULL);
00231     if (thresh < 0)
00232         return (PIX *)ERROR_PTR("thresh must be non-negative", procName, NULL);
00233     if (d == 4 && thresh > 16)
00234         return (PIX *)ERROR_PTR("4 bpp thresh not in {0-16}", procName, NULL);
00235     if (d == 8 && thresh > 256)
00236         return (PIX *)ERROR_PTR("8 bpp thresh not in {0-256}", procName, NULL);
00237 
00238     if ((pixd = pixCreate(w, h, 1)) == NULL)
00239         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
00240     pixCopyResolution(pixd, pixs);
00241     datad = pixGetData(pixd);
00242     wpld = pixGetWpl(pixd);
00243 
00244         /* Remove colormap if it exists.  If there is a colormap,
00245          * pixt will be 8 bpp regardless of the depth of pixs. */
00246     pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
00247     datat = pixGetData(pixt);
00248     wplt = pixGetWpl(pixt);
00249     if (pixGetColormap(pixs) && d == 4) {  /* promoted to 8 bpp */
00250         d = 8;
00251         thresh *= 16;
00252     }
00253 
00254     thresholdToBinaryLow(datad, w, h, wpld, datat, d, wplt, thresh);
00255     pixDestroy(&pixt);
00256     return pixd;
00257 }
00258 
00259 
00260 /*------------------------------------------------------------------*
00261  *                Binarization with variable threshold              *
00262  *------------------------------------------------------------------*/
00263 /*!
00264  *  pixVarThresholdToBinary()
00265  *
00266  *      Input:  pixs (8 bpp)
00267  *              pixg (8 bpp; contains threshold values for each pixel)
00268  *      Return: pixd (1 bpp), or null on error
00269  *
00270  *  Notes:
00271  *      (1) If the pixel in pixs is less than the corresponding pixel
00272  *          in pixg, the dest will be 1; otherwise it will be 0.
00273  */
00274 PIX *
00275 pixVarThresholdToBinary(PIX  *pixs,
00276                         PIX  *pixg)
00277 {
00278 l_int32    i, j, vals, valg, w, h, d, wpls, wplg, wpld;
00279 l_uint32  *datas, *datag, *datad, *lines, *lineg, *lined;
00280 PIX       *pixd;
00281 
00282     PROCNAME("pixVarThresholdToBinary");
00283 
00284     if (!pixs)
00285         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00286     if (!pixg)
00287         return (PIX *)ERROR_PTR("pixg not defined", procName, NULL);
00288     if (!pixSizesEqual(pixs, pixg))
00289         return (PIX *)ERROR_PTR("pix sizes not equal", procName, NULL);
00290     pixGetDimensions(pixs, &w, &h, &d);
00291     if (d != 8)
00292         return (PIX *)ERROR_PTR("pixs must be 8 bpp", procName, NULL);
00293 
00294     pixd = pixCreate(w, h, 1);
00295     datad = pixGetData(pixd);
00296     wpld = pixGetWpl(pixd);
00297     datas = pixGetData(pixs);
00298     wpls = pixGetWpl(pixs);
00299     datag = pixGetData(pixg);
00300     wplg = pixGetWpl(pixg);
00301     for (i = 0; i < h; i++) {
00302         lines = datas + i * wpls;
00303         lineg = datag + i * wplg;
00304         lined = datad + i * wpld;
00305         for (j = 0; j < w; j++) {
00306             vals = GET_DATA_BYTE(lines, j);
00307             valg = GET_DATA_BYTE(lineg, j);
00308             if (vals < valg)
00309                 SET_DATA_BIT(lined, j);
00310         }
00311     }
00312 
00313     return pixd;
00314 }
00315 
00316 
00317 /*--------------------------------------------------------------------*
00318  *    Slower implementation of binarization by dithering using LUTs   *
00319  *--------------------------------------------------------------------*/
00320 /*!
00321  *  pixDitherToBinaryLUT()
00322  *
00323  *      Input:  pixs
00324  *              lowerclip (lower clip distance to black; use -1 for default)
00325  *              upperclip (upper clip distance to white; use -1 for default)
00326  *      Return: pixd (dithered binary), or null on error
00327  *
00328  *  This implementation is deprecated.  You should use pixDitherToBinary().
00329  *
00330  *  See comments in pixDitherToBinary()
00331  *
00332  *  This implementation additionally uses three lookup tables to
00333  *  generate the output pixel value and the excess or deficit
00334  *  carried over to the neighboring pixels.
00335  */
00336 PIX *
00337 pixDitherToBinaryLUT(PIX     *pixs,
00338                      l_int32  lowerclip,
00339                      l_int32  upperclip)
00340 {
00341 l_int32    w, h, d, wplt, wpld;
00342 l_int32   *tabval, *tab38, *tab14;
00343 l_uint32  *datat, *datad;
00344 l_uint32  *bufs1, *bufs2;
00345 PIX       *pixt, *pixd;
00346 
00347     PROCNAME("pixDitherToBinaryLUT");
00348 
00349     if (!pixs)
00350         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00351     pixGetDimensions(pixs, &w, &h, &d);
00352     if (d != 8)
00353         return (PIX *)ERROR_PTR("must be 8 bpp for dithering", procName, NULL);
00354     if (lowerclip < 0)
00355         lowerclip = DEFAULT_CLIP_LOWER_1;
00356     if (upperclip < 0)
00357         upperclip = DEFAULT_CLIP_UPPER_1;
00358 
00359     if ((pixd = pixCreate(w, h, 1)) == NULL)
00360         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
00361     pixCopyResolution(pixd, pixs);
00362     datad = pixGetData(pixd);
00363     wpld = pixGetWpl(pixd);
00364 
00365         /* Remove colormap if it exists */
00366     pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
00367     datat = pixGetData(pixt);
00368     wplt = pixGetWpl(pixt);
00369 
00370         /* Two line buffers, 1 for current line and 2 for next line */
00371     if ((bufs1 = (l_uint32 *)CALLOC(wplt, sizeof(l_uint32))) == NULL)
00372         return (PIX *)ERROR_PTR("bufs1 not made", procName, NULL);
00373     if ((bufs2 = (l_uint32 *)CALLOC(wplt, sizeof(l_uint32))) == NULL)
00374         return (PIX *)ERROR_PTR("bufs2 not made", procName, NULL);
00375 
00376         /* 3 lookup tables: 1-bit value, (3/8)excess, and (1/4)excess */
00377     make8To1DitherTables(&tabval, &tab38, &tab14, lowerclip, upperclip);
00378 
00379     ditherToBinaryLUTLow(datad, w, h, wpld, datat, wplt, bufs1, bufs2,
00380                          tabval, tab38, tab14);
00381 
00382     FREE(bufs1);
00383     FREE(bufs2);
00384     FREE(tabval);
00385     FREE(tab38);
00386     FREE(tab14);
00387     pixDestroy(&pixt);
00388 
00389     return pixd;
00390 }
00391 
00392 
00393 /*--------------------------------------------------------------------*
00394  *       Generate a binary mask from pixels of particular value(s)    *
00395  *--------------------------------------------------------------------*/
00396 /*!
00397  *  pixGenerateMaskByValue()
00398  *
00399  *      Input:  pixs (4 or 8 bpp, or colormapped)
00400  *              val (of pixels for which we set 1 in dest)
00401  *              usecmap (1 to retain cmap values; 0 to convert to gray)
00402  *      Return: pixd (1 bpp), or null on error
00403  *
00404  *  Notes:
00405  *      (1) @val is the gray value of the pixels that we are selecting.
00406  *      (2) If pixs is colormapped, @usecmap determines if the colormap
00407  *          values are used, or if the colormap is removed to gray and
00408  *          the gray values are used.  For the latter, it generates
00409  *          an approximate grayscale value for each pixel, and then looks
00410  *          for gray pixels with the value @val.
00411  */
00412 PIX *
00413 pixGenerateMaskByValue(PIX     *pixs,
00414                        l_int32  val,
00415                        l_int32  usecmap)
00416 {
00417 l_int32    i, j, w, h, d, wplg, wpld;
00418 l_uint32  *datag, *datad, *lineg, *lined;
00419 PIX       *pixg, *pixd;
00420 
00421     PROCNAME("pixGenerateMaskByValue");
00422 
00423     if (!pixs)
00424         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00425     d = pixGetDepth(pixs);
00426     if (d != 4 && d != 8)
00427         return (PIX *)ERROR_PTR("not 4 or 8 bpp", procName, NULL);
00428 
00429     if (!usecmap && pixGetColormap(pixs))
00430         pixg = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
00431     else
00432         pixg = pixClone(pixs);
00433     pixGetDimensions(pixg, &w, &h, &d);
00434     if (d == 4 && (val < 0 || val > 15)) {
00435         pixDestroy(&pixg);
00436         return (PIX *)ERROR_PTR("val out of 4 bpp range", procName, NULL);
00437     }
00438     if (d == 8 && (val < 0 || val > 255)) {
00439         pixDestroy(&pixg);
00440         return (PIX *)ERROR_PTR("val out of 8 bpp range", procName, NULL);
00441     }
00442 
00443     pixd = pixCreate(w, h, 1);
00444     pixCopyResolution(pixd, pixg);
00445     datag = pixGetData(pixg);
00446     wplg = pixGetWpl(pixg);
00447     datad = pixGetData(pixd);
00448     wpld = pixGetWpl(pixd);
00449     for (i = 0; i < h; i++) {
00450         lineg = datag + i * wplg;
00451         lined = datad + i * wpld;
00452         for (j = 0; j < w; j++) {
00453             if (d == 4) {
00454                 if (GET_DATA_QBIT(lineg, j) == val)
00455                     SET_DATA_BIT(lined, j);
00456             }
00457             else {  /* d == 8 */
00458                 if (GET_DATA_BYTE(lineg, j) == val)
00459                     SET_DATA_BIT(lined, j);
00460             }
00461         }
00462     }
00463 
00464     pixDestroy(&pixg);
00465     return pixd;
00466 }
00467 
00468 
00469 /*!
00470  *  pixGenerateMaskByBand()
00471  *
00472  *      Input:  pixs (4 or 8 bpp, or colormapped)
00473  *              lower, upper (two pixel values from which a range, either
00474  *                            between (inband) or outside of (!inband),
00475  *                            determines which pixels in pixs cause us to
00476  *                            set a 1 in the dest mask)
00477  *              inband (1 for finding pixels in [lower, upper];
00478  *                      0 for finding pixels in [0, lower) union (upper, 255])
00479  *              usecmap (1 to retain cmap values; 0 to convert to gray)
00480  *      Return: pixd (1 bpp), or null on error
00481  *
00482  *  Notes:
00483  *      (1) Generates a 1 bpp mask pixd, the same size as pixs, where
00484  *          the fg pixels in the mask are those either within the specified
00485  *          band (for inband == 1) or outside the specified band
00486  *          (for inband == 0).
00487  *      (2) If pixs is colormapped, @usecmap determines if the colormap
00488  *          values are used, or if the colormap is removed to gray and
00489  *          the gray values are used.  For the latter, it generates
00490  *          an approximate grayscale value for each pixel, and then looks
00491  *          for gray pixels with the value @val.
00492  */
00493 PIX *
00494 pixGenerateMaskByBand(PIX     *pixs,
00495                       l_int32  lower,
00496                       l_int32  upper,
00497                       l_int32  inband,
00498                       l_int32  usecmap)
00499 {
00500 l_int32    i, j, w, h, d, wplg, wpld, val;
00501 l_uint32  *datag, *datad, *lineg, *lined;
00502 PIX       *pixg, *pixd;
00503 
00504     PROCNAME("pixGenerateMaskByBand");
00505 
00506     if (!pixs)
00507         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00508     d = pixGetDepth(pixs);
00509     if (d != 4 && d != 8)
00510         return (PIX *)ERROR_PTR("not 4 or 8 bpp", procName, NULL);
00511     if (lower < 0 || lower > upper)
00512         return (PIX *)ERROR_PTR("lower < 0 or lower > upper!", procName, NULL);
00513 
00514     if (!usecmap && pixGetColormap(pixs))
00515         pixg = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
00516     else
00517         pixg = pixClone(pixs);
00518     pixGetDimensions(pixg, &w, &h, &d);
00519     if (d == 4 && upper > 15) {
00520         pixDestroy(&pixg);
00521         return (PIX *)ERROR_PTR("d == 4 and upper > 15", procName, NULL);
00522     }
00523     if (d == 8 && upper > 255) {
00524         pixDestroy(&pixg);
00525         return (PIX *)ERROR_PTR("d == 8 and upper > 255", procName, NULL);
00526     }
00527 
00528     pixd = pixCreate(w, h, 1);
00529     pixCopyResolution(pixd, pixg);
00530     datag = pixGetData(pixg);
00531     wplg = pixGetWpl(pixg);
00532     datad = pixGetData(pixd);
00533     wpld = pixGetWpl(pixd);
00534     for (i = 0; i < h; i++) {
00535         lineg = datag + i * wplg;
00536         lined = datad + i * wpld;
00537         for (j = 0; j < w; j++) {
00538             if (d == 4)
00539                 val = GET_DATA_QBIT(lineg, j);
00540             else  /* d == 8 */
00541                 val = GET_DATA_BYTE(lineg, j);
00542             if (inband) {
00543                 if (val >= lower && val <= upper)
00544                     SET_DATA_BIT(lined, j);
00545             } 
00546             else {  /* out of band */
00547                 if (val < lower || val > upper)
00548                     SET_DATA_BIT(lined, j);
00549             }
00550         }
00551     }
00552 
00553     pixDestroy(&pixg);
00554     return pixd;
00555 }
00556 
00557 
00558 /*------------------------------------------------------------------*
00559  *                Thresholding to 2 bpp by dithering                *
00560  *------------------------------------------------------------------*/
00561 /*!
00562  *  pixDitherTo2bpp()
00563  *
00564  *      Input:  pixs (8 bpp)
00565  *              cmapflag (1 to generate a colormap)
00566  *      Return: pixd (dithered 2 bpp), or null on error
00567  *
00568  *  An analog of the Floyd-Steinberg error diffusion dithering
00569  *  algorithm is used to "dibitize" an 8 bpp grayscale image
00570  *  to 2 bpp, using equally spaced gray values of 0, 85, 170, and 255,
00571  *  which are served by thresholds of 43, 128 and 213.
00572  *  If cmapflag == 1, the colormap values are set to 0, 85, 170 and 255.
00573  *  If a pixel has a value between 0 and 42, it is dibitized
00574  *  to 0, and the excess (above 0) is added to the
00575  *  three neighboring pixels, in the fractions 3/8 to (i, j+1),
00576  *  3/8 to (i+1, j) and 1/4 to (i+1, j+1), truncating to 255 if
00577  *  necessary.  If a pixel has a value between 43 and 127, it is
00578  *  dibitized to 1, and the excess (above 85) is added to the three
00579  *  neighboring pixels as before.  If the value is below 85, the
00580  *  excess is subtracted.  With a value between 128
00581  *  and 212, it is dibitized to 2, with the excess on either side
00582  *  of 170 distributed as before.  Finally, with a value between
00583  *  213 and 255, it is dibitized to 3, with the excess (below 255)
00584  *  subtracted from the neighbors.  We always truncate to 0 or 255.
00585  *  The details can be seen in the lookup table generation.
00586  *
00587  *  This function differs from straight dithering in that it allows
00588  *  clipping of grayscale to 0 or 255 if the values are
00589  *  sufficiently close, without distribution of the excess.
00590  *  This uses default values (from pix.h) to specify the range of lower
00591  *  and upper values (near 0 and 255, rsp) that are clipped to black
00592  *  and white without propagating the excess.
00593  *  Not propagating the excess has the effect of reducing the snake
00594  *  patterns in parts of the image that are nearly black or white;
00595  *  however, it also prevents any attempt to reproduce gray for those values.
00596  *
00597  *  The implementation uses 3 lookup tables for simplicity, and
00598  *  a pair of line buffers to avoid modifying pixs.
00599  */
00600 PIX *
00601 pixDitherTo2bpp(PIX     *pixs,
00602                 l_int32  cmapflag)
00603 {
00604     PROCNAME("pixDitherTo2bpp");
00605 
00606     if (!pixs)
00607         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00608     if (pixGetDepth(pixs) != 8)
00609         return (PIX *)ERROR_PTR("must be 8 bpp for dithering", procName, NULL);
00610 
00611     return pixDitherTo2bppSpec(pixs, DEFAULT_CLIP_LOWER_2,
00612                                DEFAULT_CLIP_UPPER_2, cmapflag);
00613 }
00614 
00615 
00616 /*!
00617  *  pixDitherTo2bppSpec()
00618  *
00619  *      Input:  pixs (8 bpp)
00620  *              lowerclip (lower clip distance to black; use 0 for default)
00621  *              upperclip (upper clip distance to white; use 0 for default)
00622  *              cmapflag (1 to generate a colormap)
00623  *      Return: pixd (dithered 2 bpp), or null on error
00624  *
00625  *  Notes:
00626  *      (1) See comments above in pixDitherTo2bpp() for details.
00627  *      (2) The input parameters lowerclip and upperclip specify the range
00628  *          of lower and upper values (near 0 and 255, rsp) that are
00629  *          clipped to black and white without propagating the excess.
00630  *          For that reason, lowerclip and upperclip should be small numbers.
00631  */
00632 PIX *
00633 pixDitherTo2bppSpec(PIX     *pixs,
00634                     l_int32  lowerclip,
00635                     l_int32  upperclip,
00636                     l_int32  cmapflag)
00637 {
00638 l_int32    w, h, d, wplt, wpld;
00639 l_int32   *tabval, *tab38, *tab14;
00640 l_uint32  *datat, *datad;
00641 l_uint32  *bufs1, *bufs2;
00642 PIX       *pixt, *pixd;
00643 PIXCMAP   *cmap;
00644 
00645     PROCNAME("pixDitherTo2bppSpec");
00646 
00647     if (!pixs)
00648         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00649     pixGetDimensions(pixs, &w, &h, &d);
00650     if (d != 8)
00651         return (PIX *)ERROR_PTR("must be 8 bpp for dithering", procName, NULL);
00652     if (lowerclip < 0 || lowerclip > 255)
00653         return (PIX *)ERROR_PTR("invalid value for lowerclip", procName, NULL);
00654     if (upperclip < 0 || upperclip > 255)
00655         return (PIX *)ERROR_PTR("invalid value for upperclip", procName, NULL);
00656 
00657     if ((pixd = pixCreate(w, h, 2)) == NULL)
00658         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
00659     pixCopyResolution(pixd, pixs);
00660     datad = pixGetData(pixd);
00661     wpld = pixGetWpl(pixd);
00662 
00663         /* If there is a colormap, remove it */
00664     pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
00665     datat = pixGetData(pixt);
00666     wplt = pixGetWpl(pixt);
00667 
00668         /* Two line buffers, 1 for current line and 2 for next line */
00669     if ((bufs1 = (l_uint32 *)CALLOC(wplt, sizeof(l_uint32))) == NULL)
00670         return (PIX *)ERROR_PTR("bufs1 not made", procName, NULL);
00671     if ((bufs2 = (l_uint32 *)CALLOC(wplt, sizeof(l_uint32))) == NULL)
00672         return (PIX *)ERROR_PTR("bufs2 not made", procName, NULL);
00673 
00674         /* 3 lookup tables: 2-bit value, (3/8)excess, and (1/4)excess */
00675     make8To2DitherTables(&tabval, &tab38, &tab14, lowerclip, upperclip);
00676 
00677     ditherTo2bppLow(datad, w, h, wpld, datat, wplt, bufs1, bufs2,
00678                     tabval, tab38, tab14);
00679 
00680     if (cmapflag) {
00681         cmap = pixcmapCreateLinear(2, 4);
00682         pixSetColormap(pixd, cmap);
00683     }
00684 
00685     FREE(bufs1);
00686     FREE(bufs2);
00687     FREE(tabval);
00688     FREE(tab38);
00689     FREE(tab14);
00690     pixDestroy(&pixt);
00691 
00692     return pixd;
00693 }
00694 
00695 
00696 /*--------------------------------------------------------------------*
00697  *  Simple (pixelwise) thresholding to 2 bpp with optional colormap   *
00698  *--------------------------------------------------------------------*/
00699 /*!
00700  *  pixThresholdTo2bpp()
00701  *
00702  *      Input:  pixs (8 bpp)
00703  *              nlevels (equally spaced; must be between 2 and 4)
00704  *              cmapflag (1 to build colormap; 0 otherwise)
00705  *      Return: pixd (2 bpp, optionally with colormap), or null on error
00706  *
00707  *  Notes:
00708  *      (1) Valid values for nlevels is the set {2, 3, 4}.
00709  *      (2) Any colormap on the input pixs is removed to 8 bpp grayscale.
00710  *      (3) This function is typically invoked with cmapflag == 1.
00711  *          In the situation where no colormap is desired, nlevels is
00712  *          ignored and pixs is thresholded to 4 levels.
00713  *      (4) The target output colors are equally spaced, with the
00714  *          darkest at 0 and the lightest at 255.  The thresholds are
00715  *          chosen halfway between adjacent output values.  A table
00716  *          is built that specifies the mapping from src to dest.
00717  *      (5) If cmapflag == 1, a colormap of size 'nlevels' is made,
00718  *          and the pixel values in pixs are replaced by their
00719  *          appropriate color indices.  The number of holdouts,
00720  *          4 - nlevels, will be between 0 and 2.
00721  *      (6) If you don't want the thresholding to be equally spaced,
00722  *          either first transform the 8 bpp src using pixGammaTRC().
00723  *          or, if cmapflag == 1, after calling this function you can use
00724  *          pixcmapResetColor() to change any individual colors.
00725  *      (7) If a colormap is generated, it will specify (to display
00726  *          programs) exactly how each level is to be represented in RGB
00727  *          space.  When representing text, 3 levels is far better than
00728  *          2 because of the antialiasing of the single gray level,
00729  *          and 4 levels (black, white and 2 gray levels) is getting
00730  *          close to the perceptual quality of a (nearly continuous)
00731  *          grayscale image.  With 2 bpp, you can set up a colormap
00732  *          and allocate from 2 to 4 levels to represent antialiased text.
00733  *          Any left over colormap entries can be used for coloring regions.
00734  *          For the same number of levels, the file size of a 2 bpp image
00735  *          is about 10% smaller than that of a 4 bpp result for the same
00736  *          number of levels.  For both 2 bpp and 4 bpp, using 4 levels you
00737  *          get compression far better than that of jpeg, because the
00738  *          quantization to 4 levels will remove the jpeg ringing in the
00739  *          background near character edges.
00740  */
00741 PIX *
00742 pixThresholdTo2bpp(PIX     *pixs,
00743                    l_int32  nlevels,
00744                    l_int32  cmapflag)
00745 {
00746 l_int32   *qtab;
00747 l_int32    w, h, d, wplt, wpld;
00748 l_uint32  *datat, *datad;
00749 PIX       *pixt, *pixd;
00750 PIXCMAP   *cmap;
00751 
00752     PROCNAME("pixThresholdTo2bpp");
00753 
00754     if (!pixs)
00755         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00756     pixGetDimensions(pixs, &w, &h, &d);
00757     if (d != 8)
00758         return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
00759     if (nlevels < 2 || nlevels > 4)
00760         return (PIX *)ERROR_PTR("nlevels not in {2, 3, 4}", procName, NULL);
00761 
00762         /* Make the appropriate table */
00763     if (cmapflag)
00764         qtab = makeGrayQuantIndexTable(nlevels);
00765     else
00766         qtab = makeGrayQuantTargetTable(4, 2);
00767 
00768     if ((pixd = pixCreate(w, h, 2)) == NULL)
00769         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
00770     pixCopyResolution(pixd, pixs);
00771     datad = pixGetData(pixd);
00772     wpld = pixGetWpl(pixd);
00773 
00774     if (cmapflag) {   /* hold out (4 - nlevels) cmap entries */
00775         cmap = pixcmapCreateLinear(2, nlevels);
00776         pixSetColormap(pixd, cmap);
00777     }
00778 
00779         /* If there is a colormap in the src, remove it */
00780     pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
00781     datat = pixGetData(pixt);
00782     wplt = pixGetWpl(pixt);
00783 
00784     thresholdTo2bppLow(datad, h, wpld, datat, wplt, qtab);
00785 
00786     if (qtab) FREE(qtab);
00787     pixDestroy(&pixt);
00788     return pixd;
00789 }
00790 
00791 
00792 /*----------------------------------------------------------------------*
00793  *               Simple (pixelwise) thresholding to 4 bpp               *
00794  *----------------------------------------------------------------------*/
00795 /*!
00796  *  pixThresholdTo4bpp()
00797  *
00798  *      Input:  pixs (8 bpp, can have colormap)
00799  *              nlevels (equally spaced; must be between 2 and 16)
00800  *              cmapflag (1 to build colormap; 0 otherwise)
00801  *      Return: pixd (4 bpp, optionally with colormap), or null on error
00802  *
00803  *  Notes:
00804  *      (1) Valid values for nlevels is the set {2, ... 16}.
00805  *      (2) Any colormap on the input pixs is removed to 8 bpp grayscale.
00806  *      (3) This function is typically invoked with cmapflag == 1.
00807  *          In the situation where no colormap is desired, nlevels is
00808  *          ignored and pixs is thresholded to 16 levels.
00809  *      (4) The target output colors are equally spaced, with the
00810  *          darkest at 0 and the lightest at 255.  The thresholds are
00811  *          chosen halfway between adjacent output values.  A table
00812  *          is built that specifies the mapping from src to dest.
00813  *      (5) If cmapflag == 1, a colormap of size 'nlevels' is made,
00814  *          and the pixel values in pixs are replaced by their
00815  *          appropriate color indices.  The number of holdouts,
00816  *          16 - nlevels, will be between 0 and 14.
00817  *      (6) If you don't want the thresholding to be equally spaced,
00818  *          either first transform the 8 bpp src using pixGammaTRC().
00819  *          or, if cmapflag == 1, after calling this function you can use
00820  *          pixcmapResetColor() to change any individual colors.
00821  *      (7) If a colormap is generated, it will specify, to display
00822  *          programs, exactly how each level is to be represented in RGB
00823  *          space.  When representing text, 3 levels is far better than
00824  *          2 because of the antialiasing of the single gray level,
00825  *          and 4 levels (black, white and 2 gray levels) is getting
00826  *          close to the perceptual quality of a (nearly continuous)
00827  *          grayscale image.  Therefore, with 4 bpp, you can set up a
00828  *          colormap, allocate a relatively small fraction of the 16
00829  *          possible values to represent antialiased text, and use the
00830  *          other colormap entries for other things, such as coloring
00831  *          text or background.  Two other reasons for using a small number
00832  *          of gray values for antialiased text are (1) PNG compression
00833  *          gets worse as the number of levels that are used is increased,
00834  *          and (2) using a small number of levels will filter out most of
00835  *          the jpeg ringing that is typically introduced near sharp edges
00836  *          of text.  This filtering is partly responsible for the improved
00837  *          compression.
00838  */
00839 PIX *
00840 pixThresholdTo4bpp(PIX     *pixs,
00841                    l_int32  nlevels,
00842                    l_int32  cmapflag)
00843 {
00844 l_int32   *qtab;
00845 l_int32    w, h, d, wplt, wpld;
00846 l_uint32  *datat, *datad;
00847 PIX       *pixt, *pixd;
00848 PIXCMAP   *cmap;
00849 
00850     PROCNAME("pixThresholdTo4bpp");
00851 
00852     if (!pixs)
00853         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00854     pixGetDimensions(pixs, &w, &h, &d);
00855     if (d != 8)
00856         return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
00857     if (nlevels < 2 || nlevels > 16)
00858         return (PIX *)ERROR_PTR("nlevels not in [2,...,16]", procName, NULL);
00859 
00860         /* Make the appropriate table */
00861     if (cmapflag)
00862         qtab = makeGrayQuantIndexTable(nlevels);
00863     else
00864         qtab = makeGrayQuantTargetTable(16, 4);
00865 
00866     if ((pixd = pixCreate(w, h, 4)) == NULL)
00867         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
00868     pixCopyResolution(pixd, pixs);
00869     datad = pixGetData(pixd);
00870     wpld = pixGetWpl(pixd);
00871 
00872     if (cmapflag) {   /* hold out (16 - nlevels) cmap entries */
00873         cmap = pixcmapCreateLinear(4, nlevels);
00874         pixSetColormap(pixd, cmap);
00875     }
00876 
00877         /* If there is a colormap in the src, remove it */
00878     pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
00879     datat = pixGetData(pixt);
00880     wplt = pixGetWpl(pixt);
00881 
00882     thresholdTo4bppLow(datad, h, wpld, datat, wplt, qtab);
00883 
00884     if (qtab) FREE(qtab);
00885     pixDestroy(&pixt);
00886     return pixd;
00887 }
00888 
00889 
00890 /*----------------------------------------------------------------------*
00891  *    Simple (pixelwise) thresholding on 8 bpp with optional colormap   *
00892  *----------------------------------------------------------------------*/
00893 /*!
00894  *  pixThresholdOn8bpp()
00895  *
00896  *      Input:  pixs (8 bpp, can have colormap)
00897  *              nlevels (equally spaced; must be between 2 and 256)
00898  *              cmapflag (1 to build colormap; 0 otherwise)
00899  *      Return: pixd (8 bpp, optionally with colormap), or null on error
00900  *
00901  *  Notes:
00902  *      (1) Valid values for nlevels is the set {2,...,256}.
00903  *      (2) Any colormap on the input pixs is removed to 8 bpp grayscale.
00904  *      (3) If cmapflag == 1, a colormap of size 'nlevels' is made,
00905  *          and the pixel values in pixs are replaced by their
00906  *          appropriate color indices.  Otherwise, the pixel values
00907  *          are the actual thresholded (i.e., quantized) grayscale values.
00908  *      (4) If you don't want the thresholding to be equally spaced,
00909  *          first transform the input 8 bpp src using pixGammaTRC().
00910  */
00911 PIX *
00912 pixThresholdOn8bpp(PIX     *pixs,
00913                    l_int32  nlevels,
00914                    l_int32  cmapflag)
00915 {
00916 l_int32   *qtab;  /* quantization table */
00917 l_int32    i, j, w, h, wpld, val, newval;
00918 l_uint32  *datad, *lined;
00919 PIX       *pixd;
00920 PIXCMAP   *cmap;
00921 
00922     PROCNAME("pixThresholdOn8bpp");
00923 
00924     if (!pixs)
00925         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00926     if (pixGetDepth(pixs) != 8)
00927         return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
00928     if (nlevels < 2 || nlevels > 256)
00929         return (PIX *)ERROR_PTR("nlevels not in [2,...,256]", procName, NULL);
00930 
00931     if (cmapflag)
00932         qtab = makeGrayQuantIndexTable(nlevels);
00933     else
00934         qtab = makeGrayQuantTargetTable(nlevels, 8);
00935 
00936         /* Get a new pixd; if there is a colormap in the src, remove it */
00937     if (pixGetColormap(pixs))
00938         pixd = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
00939     else
00940         pixd = pixCopy(NULL, pixs);
00941 
00942     if (cmapflag) {   /* hold out (256 - nlevels) cmap entries */
00943         cmap = pixcmapCreateLinear(8, nlevels);
00944         pixSetColormap(pixd, cmap);
00945     }
00946 
00947     pixGetDimensions(pixd, &w, &h, NULL);
00948     datad = pixGetData(pixd);
00949     wpld = pixGetWpl(pixd);
00950     for (i = 0; i < h; i++) {
00951         lined = datad + i * wpld;
00952         for (j = 0; j < w; j++) {
00953             val = GET_DATA_BYTE(lined, j);
00954             newval = qtab[val];
00955             SET_DATA_BYTE(lined, j, newval);
00956         }
00957     }
00958 
00959     if (qtab) FREE(qtab);
00960     return pixd;
00961 }
00962 
00963 
00964 /*----------------------------------------------------------------------*
00965  *    Arbitrary (pixelwise) thresholding from 8 bpp to 2, 4 or 8 bpp    *
00966  *----------------------------------------------------------------------*/
00967 /*!
00968  *  pixThresholdGrayArb()
00969  *
00970  *      Input:  pixs (8 bpp grayscale; can have colormap)
00971  *              edgevals (string giving edge value of each bin)
00972  *              outdepth (0, 2, 4 or 8 bpp; 0 is default for min depth)
00973  *              use_average (1 if use the average pixel value in colormap)
00974  *              setblack (1 if darkest color is set to black)
00975  *              setwhite (1 if lightest color is set to white)
00976  *      Return: pixd (2, 4 or 8 bpp quantized image with colormap),
00977  *                    or null on error
00978  *
00979  *  Notes:
00980  *      (1) This function allows exact specification of the quantization bins.  
00981  *          The string @edgevals is a space-separated set of values
00982  *          specifying the dividing points between output quantization bins.
00983  *          These threshold values are assigned to the bin with higher
00984  *          values, so that each of them is the smallest value in their bin.
00985  *      (2) The output image (pixd) depth is specified by @outdepth.  The
00986  *          number of bins is the number of edgevals + 1.  The
00987  *          relation between outdepth and the number of bins is:
00988  *               outdepth = 2       nbins <= 4
00989  *               outdepth = 4       nbins <= 16 
00990  *               outdepth = 8       nbins <= 256
00991  *          With @outdepth == 0, the minimum required depth for the
00992  *          given number of bins is used.
00993  *          The output pixd has a colormap.
00994  *      (3) The last 3 args determine the specific values that go into
00995  *          the colormap.
00996  *      (4) For @use_average:
00997  *            - if TRUE, the average value of pixels falling in the bin is
00998  *              chosen as the representative gray value.  Otherwise,
00999  *            - if FALSE, the central value of each bin is chosen as
01000  *              the representative value.
01001  *          The colormap holds the representative value.
01002  *      (5) For @setblack, if TRUE the darkest color is set to (0,0,0).
01003  *      (6) For @setwhite, if TRUE the lightest color is set to (255,255,255).
01004  *      (7) An alternative to using this function to quantize to
01005  *          unequally-spaced bins is to first transform the 8 bpp pixs
01006  *          using pixGammaTRC(), and follow this with pixThresholdTo4bpp().
01007  */
01008 PIX *
01009 pixThresholdGrayArb(PIX         *pixs,
01010                     const char  *edgevals,
01011                     l_int32      outdepth,
01012                     l_int32      use_average,
01013                     l_int32      setblack,
01014                     l_int32      setwhite)
01015 {
01016 l_int32   *qtab;
01017 l_int32    w, h, d, i, j, n, wplt, wpld, val, newval;
01018 l_uint32  *datat, *datad, *linet, *lined;
01019 NUMA      *na;
01020 PIX       *pixt, *pixd;
01021 PIXCMAP   *cmap;
01022 
01023     PROCNAME("pixThresholdGrayArb");
01024 
01025     if (!pixs)
01026         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
01027     pixGetDimensions(pixs, &w, &h, &d);
01028     if (d != 8)
01029         return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
01030     if (!edgevals)
01031         return (PIX *)ERROR_PTR("edgevals not defined", procName, NULL);
01032     if (outdepth != 0 && outdepth != 2 && outdepth != 4 && outdepth != 8)
01033         return (PIX *)ERROR_PTR("invalid outdepth", procName, NULL);
01034 
01035         /* Parse and sort (if required) the bin edge values */
01036     na = parseStringForNumbers(edgevals, " \t\n,");
01037     n = numaGetCount(na);
01038     if (n > 255)
01039         return (PIX *)ERROR_PTR("more than 256 levels", procName, NULL);
01040     if (outdepth == 0) {
01041         if (n <= 3)
01042             outdepth = 2;
01043         else if (n <= 15)
01044             outdepth = 4;
01045         else
01046             outdepth = 8;
01047     }
01048     else if (n + 1 > (1 << outdepth)) {
01049         L_WARNING("outdepth too small; setting to 8 bpp", procName);
01050         outdepth = 8;
01051     }
01052     numaSort(na, na, L_SORT_INCREASING);
01053 
01054         /* Make the quantization LUT and the colormap */
01055     makeGrayQuantTableArb(na, outdepth, &qtab, &cmap);
01056     if (use_average) {  /* use the average value in each bin */
01057         pixcmapDestroy(&cmap);
01058         makeGrayQuantColormapArb(pixs, qtab, outdepth, &cmap);
01059     }
01060     pixcmapSetBlackAndWhite(cmap, setblack, setwhite);
01061     numaDestroy(&na);
01062 
01063     if ((pixd = pixCreate(w, h, outdepth)) == NULL)
01064         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
01065     pixCopyResolution(pixd, pixs);
01066     pixSetColormap(pixd, cmap);
01067     datad = pixGetData(pixd);
01068     wpld = pixGetWpl(pixd);
01069 
01070         /* If there is a colormap in the src, remove it */
01071     pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
01072     datat = pixGetData(pixt);
01073     wplt = pixGetWpl(pixt);
01074 
01075     if (outdepth == 2)
01076         thresholdTo2bppLow(datad, h, wpld, datat, wplt, qtab);
01077     else if (outdepth == 4)
01078         thresholdTo4bppLow(datad, h, wpld, datat, wplt, qtab);
01079     else {
01080         for (i = 0; i < h; i++) {
01081             lined = datad + i * wpld;
01082             linet = datat + i * wplt;
01083             for (j = 0; j < w; j++) {
01084                 val = GET_DATA_BYTE(linet, j);
01085                 newval = qtab[val];
01086                 SET_DATA_BYTE(lined, j, newval);
01087             }
01088         }
01089     }
01090 
01091     FREE(qtab);
01092     pixDestroy(&pixt);
01093     return pixd;
01094 }
01095 
01096 
01097 /*----------------------------------------------------------------------*
01098  *     Quantization tables for linear thresholds of grayscale images    *
01099  *----------------------------------------------------------------------*/
01100 /*!
01101  *  makeGrayQuantIndexTable()
01102  *
01103  *      Input:  nlevels (number of output levels)
01104  *      Return: table (maps input gray level to colormap index,
01105  *                     or null on error)
01106  *  Notes:
01107  *      (1) 'nlevels' is some number between 2 and 256 (typically 8 or less).
01108  *      (2) The table is typically used for quantizing 2, 4 and 8 bpp
01109  *          grayscale src pix, and generating a colormapped dest pix.
01110  */
01111 l_int32 *
01112 makeGrayQuantIndexTable(l_int32  nlevels)
01113 {
01114 l_int32   *tab;
01115 l_int32    i, j, thresh;
01116 
01117     PROCNAME("makeGrayQuantIndexTable");
01118 
01119     if ((tab = (l_int32 *)CALLOC(256, sizeof(l_int32))) == NULL)
01120         return (l_int32 *)ERROR_PTR("calloc fail for tab", procName, NULL);
01121     for (i = 0; i < 256; i++) {
01122         for (j = 0; j < nlevels; j++) {
01123             thresh = 255 * (2 * j + 1) / (2 * nlevels - 2);
01124             if (i <= thresh) {
01125                 tab[i] = j;
01126 /*                fprintf(stderr, "tab[%d] = %d\n", i, j); */
01127                 break;
01128             }
01129         }
01130     }
01131     return tab;
01132 }
01133 
01134 
01135 /*!
01136  *  makeGrayQuantTargetTable()
01137  *
01138  *      Input:  nlevels (number of output levels)
01139  *              depth (of dest pix, in bpp; 2, 4 or 8 bpp)
01140  *      Return: table (maps input gray level to thresholded gray level,
01141  *                     or null on error)
01142  *
01143  *  Notes:
01144  *      (1) nlevels is some number between 2 and 2^(depth)
01145  *      (2) The table is used in two similar ways:
01146  *           - for 8 bpp, it quantizes to a given number of target levels
01147  *           - for 2 and 4 bpp, it thresholds to appropriate target values
01148  *             that will use the full dynamic range of the dest pix.
01149  *      (3) For depth = 8, the number of thresholds chosen is
01150  *          ('nlevels' - 1), and the 'nlevels' values stored in the
01151  *          table are at the two at the extreme ends, (0, 255), plus
01152  *          plus ('nlevels' - 2) values chosen at equal intervals between.
01153  *          For example, for depth = 8 and 'nlevels' = 3, the two
01154  *          threshold values are 3f and bf, and the three target pixel
01155  *          values are 0, 7f and ff.
01156  *      (4) For depth < 8, we ignore nlevels, and always use the maximum
01157  *          number of levels, which is 2^(depth).
01158  *          If you want nlevels < the maximum number, you should always
01159  *          use a colormap.
01160  */
01161 l_int32 *
01162 makeGrayQuantTargetTable(l_int32  nlevels,
01163                          l_int32  depth)
01164 {
01165 l_int32   *tab;
01166 l_int32    i, j, thresh, maxval, quantval;
01167 
01168     PROCNAME("makeGrayQuantTargetTable");
01169 
01170     if ((tab = (l_int32 *)CALLOC(256, sizeof(l_int32))) == NULL)
01171         return (l_int32 *)ERROR_PTR("calloc fail for tab", procName, NULL);
01172     maxval = (1 << depth) - 1;
01173     if (depth < 8)
01174         nlevels = 1 << depth;
01175     for (i = 0; i < 256; i++) {
01176         for (j = 0; j < nlevels; j++) {
01177             thresh = 255 * (2 * j + 1) / (2 * nlevels - 2);
01178             if (i <= thresh) {
01179                 quantval = maxval * j / (nlevels - 1);
01180                 tab[i] = quantval;
01181 /*                fprintf(stderr, "tab[%d] = %d\n", i, tab[i]); */
01182                 break;
01183             }
01184         }
01185     }
01186     return tab;
01187 }
01188 
01189 
01190 /*----------------------------------------------------------------------*
01191  *   Quantization table for arbitrary thresholding of grayscale images  *
01192  *----------------------------------------------------------------------*/
01193 /*!
01194  *  makeGrayQuantTableArb()
01195  *
01196  *      Input:  na (numa of bin boundaries)
01197  *              outdepth (of colormap: 1, 2, 4 or 8)
01198  *              &tab (<return> table mapping input gray level to cmap index)
01199  *              &cmap (<return> colormap)
01200  *      Return: 0 if OK, 1 on error
01201  *
01202  *  Notes:
01203  *      (1) The number of bins is the count of @na + 1.
01204  *      (2) The bin boundaries in na must be sorted in increasing order.
01205  *      (3) The table is an inverse colormap: it maps input gray level
01206  *          to colormap index (the bin number).
01207  *      (4) The colormap generated here has quantized values at the
01208  *          center of each bin.  If you want to use the average gray
01209  *          value of pixels within the bin, discard the colormap and
01210  *          compute it using makeGrayQuantColormapArb().
01211  *      (5) Returns an error if there are not enough levels in the
01212  *          output colormap for the number of bins.  The number
01213  *          of bins must not exceed 2^outdepth.
01214  */
01215 l_int32
01216 makeGrayQuantTableArb(NUMA      *na,
01217                       l_int32    outdepth,
01218                       l_int32  **ptab,
01219                       PIXCMAP  **pcmap)
01220 {
01221 l_int32   i, j, n, jstart, ave, val;
01222 l_int32  *tab;
01223 PIXCMAP  *cmap;
01224 
01225     PROCNAME("makeGrayQuantTableArb");
01226 
01227     if (!ptab)
01228         return ERROR_INT("&tab not defined", procName, 1);
01229     *ptab = NULL;
01230     if (!pcmap)
01231         return ERROR_INT("&cmap not defined", procName, 1);
01232     *pcmap = NULL;
01233     if (!na)
01234         return ERROR_INT("na not defined", procName, 1);
01235     n = numaGetCount(na);
01236     if (n + 1 > (1 << outdepth))
01237         return ERROR_INT("more bins than cmap levels", procName, 1);
01238 
01239     if ((tab = (l_int32 *)CALLOC(256, sizeof(l_int32))) == NULL)
01240         return ERROR_INT("calloc fail for tab", procName, 1);
01241     if ((cmap = pixcmapCreate(outdepth)) == NULL)
01242         return ERROR_INT("cmap not made", procName, 1);
01243     *ptab = tab;
01244     *pcmap = cmap;
01245 
01246         /* First n bins */
01247     jstart = 0;
01248     for (i = 0; i < n; i++) {
01249         numaGetIValue(na, i, &val);
01250         ave = (jstart + val) / 2;
01251         pixcmapAddColor(cmap, ave, ave, ave);
01252         for (j = jstart; j < val; j++)
01253             tab[j] = i;
01254         jstart = val;
01255     }
01256 
01257         /* Last bin */
01258     ave = (jstart + 255) / 2;
01259     pixcmapAddColor(cmap, ave, ave, ave);
01260     for (j = jstart; j < 256; j++) 
01261         tab[j] = n;
01262 
01263     return 0;
01264 }
01265 
01266 
01267 /*!
01268  *  makeGrayQuantColormapArb()
01269  *
01270  *      Input:  pixs (8 bpp)
01271  *              tab (table mapping input gray level to cmap index)
01272  *              outdepth (of colormap: 1, 2, 4 or 8)
01273  *              &cmap (<return> colormap)
01274  *      Return: 0 if OK, 1 on error
01275  *
01276  *  Notes:
01277  *      (1) The table is a 256-entry inverse colormap: it maps input gray
01278  *          level to colormap index (the bin number).  It is computed
01279  *          using makeGrayQuantTableArb().
01280  *      (2) The colormap generated here has quantized values at the
01281  *          average gray value of the pixels that are in each bin.
01282  *      (3) Returns an error if there are not enough levels in the
01283  *          output colormap for the number of bins.  The number
01284  *          of bins must not exceed 2^outdepth.
01285  */
01286 l_int32
01287 makeGrayQuantColormapArb(PIX       *pixs,
01288                          l_int32   *tab,
01289                          l_int32    outdepth,
01290                          PIXCMAP  **pcmap)
01291 {
01292 l_int32    i, j, index, w, h, d, nbins, wpl, factor, val;
01293 l_int32   *bincount, *binave, *binstart;
01294 l_uint32  *line, *data;
01295 
01296     PROCNAME("makeGrayQuantColormapArb");
01297 
01298     if (!pcmap)
01299         return ERROR_INT("&cmap not defined", procName, 1);
01300     *pcmap = NULL;
01301     if (!pixs)
01302         return ERROR_INT("pixs not defined", procName, 1);
01303     pixGetDimensions(pixs, &w, &h, &d);
01304     if (d != 8)
01305         return ERROR_INT("pixs not 8 bpp", procName, 1);
01306     if (!tab)
01307         return ERROR_INT("tab not defined", procName, 1);
01308     nbins = tab[255] + 1;
01309     if (nbins > (1 << outdepth))
01310         return ERROR_INT("more bins than cmap levels", procName, 1);
01311 
01312         /* Find the count and weighted count for each bin */
01313     if ((bincount = (l_int32 *)CALLOC(nbins, sizeof(l_int32))) == NULL)
01314         return ERROR_INT("calloc fail for bincount", procName, 1);
01315     if ((binave = (l_int32 *)CALLOC(nbins, sizeof(l_int32))) == NULL)
01316         return ERROR_INT("calloc fail for binave", procName, 1);
01317     factor = (l_int32)(sqrt((l_float64)(w * h) / 30000.) + 0.5);
01318     factor = L_MAX(1, factor);
01319     data = pixGetData(pixs);
01320     wpl = pixGetWpl(pixs);
01321     for (i = 0; i < h; i += factor) {
01322         line = data + i * wpl;
01323         for (j = 0; j < w; j += factor) {
01324             val = GET_DATA_BYTE(line, j);
01325             bincount[tab[val]]++;
01326             binave[tab[val]] += val;
01327         }
01328     }
01329 
01330         /* Find the smallest gray values in each bin */
01331     if ((binstart = (l_int32 *)CALLOC(nbins, sizeof(l_int32))) == NULL)
01332         return ERROR_INT("calloc fail for binstart", procName, 1);
01333     for (i = 1, index = 1; i < 256; i++) {
01334         if (tab[i] < index) continue;
01335         if (tab[i] == index)
01336             binstart[index++] = i;
01337     }
01338 
01339         /* Get the averages.  If there are no samples in a bin, use
01340          * the center value of the bin. */
01341     *pcmap = pixcmapCreate(outdepth);
01342     for (i = 0; i < nbins; i++) {
01343         if (bincount[i])
01344             val = binave[i] / bincount[i];
01345         else {  /* no samples in the bin */
01346             if (i < nbins - 1)
01347                 val = (binstart[i] + binstart[i + 1]) / 2;
01348             else  /* last bin */
01349                 val = (binstart[i] + 255) / 2;
01350         }
01351         pixcmapAddColor(*pcmap, val, val, val);
01352     }
01353 
01354     FREE(bincount);
01355     FREE(binave);
01356     FREE(binstart);
01357     return 0;
01358 }
01359             
01360 
01361 /*--------------------------------------------------------------------*
01362  *                 Thresholding from 32 bpp rgb to 1 bpp              *
01363  *--------------------------------------------------------------------*/
01364 /*!
01365  *  pixGenerateMaskByBand32()
01366  *
01367  *      Input:  pixs (32 bpp)
01368  *              refval (reference rgb value)
01369  *              delm (max amount below the ref value for any component)
01370  *              delp (max amount above the ref value for any component)
01371  *      Return: pixd (1 bpp), or null on error
01372  *
01373  *  Notes:
01374  *      (1) Generates a 1 bpp mask pixd, the same size as pixs, where
01375  *          the fg pixels in the mask are those where each component
01376  *          is within -delm to +delp of the reference value.
01377  */
01378 PIX *
01379 pixGenerateMaskByBand32(PIX    *pixs,
01380                         l_uint32  refval,
01381                         l_int32   delm,
01382                         l_int32   delp)
01383 {
01384 l_int32    i, j, w, h, d, wpls, wpld;
01385 l_int32    rref, gref, bref, rval, gval, bval;
01386 l_uint32   pixel;
01387 l_uint32  *datas, *datad, *lines, *lined;
01388 PIX       *pixd;
01389 
01390     PROCNAME("pixGenerateMaskByBand32");
01391 
01392     if (!pixs)
01393         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
01394     pixGetDimensions(pixs, &w, &h, &d);
01395     if (d != 32)
01396         return (PIX *)ERROR_PTR("not 32 bpp", procName, NULL);
01397     if (delm < 0 || delp < 0)
01398         return (PIX *)ERROR_PTR("delm and delp must be >= 0", procName, NULL);
01399 
01400     extractRGBValues(refval, &rref, &gref, &bref);
01401     pixd = pixCreate(w, h, 1);
01402     pixCopyResolution(pixd, pixs);
01403     datas = pixGetData(pixs);
01404     wpls = pixGetWpl(pixs);
01405     datad = pixGetData(pixd);
01406     wpld = pixGetWpl(pixd);
01407     for (i = 0; i < h; i++) {
01408         lines = datas + i * wpls;
01409         lined = datad + i * wpld;
01410         for (j = 0; j < w; j++) {
01411             pixel = lines[j];
01412             rval = (pixel >> L_RED_SHIFT) & 0xff;
01413             if (rval < rref - delm || rval > rref + delp)
01414                 continue;
01415             gval = (pixel >> L_GREEN_SHIFT) & 0xff;
01416             if (gval < gref - delm || gval > gref + delp)
01417                 continue;
01418             bval = (pixel >> L_BLUE_SHIFT) & 0xff;
01419             if (bval < bref - delm || bval > bref + delp)
01420                 continue;
01421             SET_DATA_BIT(lined, j);
01422         }
01423     }
01424 
01425     return pixd;
01426 }
01427 
01428 
01429 /*!
01430  *  pixGenerateMaskByDiscr32()
01431  *
01432  *      Input:  pixs (32 bpp)
01433  *              refval1 (reference rgb value)
01434  *              refval2 (reference rgb value)
01435  *              distflag (L_MANHATTAN_DISTANCE, L_EUCLIDEAN_DISTANCE)
01436  *      Return: pixd (1 bpp), or null on error
01437  *
01438  *  Notes:
01439  *      (1) Generates a 1 bpp mask pixd, the same size as pixs, where
01440  *          the fg pixels in the mask are those where the pixel in pixs
01441  *          is "closer" to refval1 than to refval2.
01442  *      (2) "Closer" can be defined in several ways, such as:
01443  *            - manhattan distance (L1)
01444  *            - euclidean distance (L2)
01445  *            - majority vote of the individual components
01446  *          Here, we have a choice of L1 or L2.
01447  */
01448 PIX *
01449 pixGenerateMaskByDiscr32(PIX      *pixs,
01450                          l_uint32  refval1,
01451                          l_uint32  refval2,
01452                          l_int32   distflag)
01453 {
01454 l_int32    i, j, w, h, d, wpls, wpld;
01455 l_int32    rref1, gref1, bref1, rref2, gref2, bref2, rval, gval, bval;
01456 l_uint32   pixel, dist1, dist2;
01457 l_uint32  *datas, *datad, *lines, *lined;
01458 PIX       *pixd;
01459 
01460     PROCNAME("pixGenerateMaskByDiscr32");
01461 
01462     if (!pixs)
01463         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
01464     pixGetDimensions(pixs, &w, &h, &d);
01465     if (d != 32)
01466         return (PIX *)ERROR_PTR("not 32 bpp", procName, NULL);
01467     if (distflag != L_MANHATTAN_DISTANCE && distflag != L_EUCLIDEAN_DISTANCE)
01468         return (PIX *)ERROR_PTR("invalid distflag", procName, NULL);
01469 
01470     extractRGBValues(refval1, &rref1, &gref1, &bref1);
01471     extractRGBValues(refval2, &rref2, &gref2, &bref2);
01472     pixd = pixCreate(w, h, 1);
01473     pixCopyResolution(pixd, pixs);
01474     datas = pixGetData(pixs);
01475     wpls = pixGetWpl(pixs);
01476     datad = pixGetData(pixd);
01477     wpld = pixGetWpl(pixd);
01478     for (i = 0; i < h; i++) {
01479         lines = datas + i * wpls;
01480         lined = datad + i * wpld;
01481         for (j = 0; j < w; j++) {
01482             pixel = lines[j];
01483             extractRGBValues(pixel, &rval, &gval, &bval);
01484             if (distflag == L_MANHATTAN_DISTANCE) {
01485                 dist1 = L_ABS(rref1 - rval);
01486                 dist2 = L_ABS(rref2 - rval);
01487                 dist1 += L_ABS(gref1 - gval);
01488                 dist2 += L_ABS(gref2 - gval);
01489                 dist1 += L_ABS(bref1 - bval);
01490                 dist2 += L_ABS(bref2 - bval);
01491             }
01492             else {
01493                 dist1 = (rref1 - rval) * (rref1 - rval);
01494                 dist2 = (rref2 - rval) * (rref2 - rval);
01495                 dist1 += (gref1 - gval) * (gref1 - gval);
01496                 dist2 += (gref2 - gval) * (gref2 - gval);
01497                 dist1 += (bref1 - bval) * (bref1 - bval);
01498                 dist2 += (bref2 - bval) * (bref2 - bval);
01499             }
01500             if (dist1 < dist2)
01501                 SET_DATA_BIT(lined, j);
01502         }
01503     }
01504 
01505     return pixd;
01506 }
01507 
01508 
01509 /*----------------------------------------------------------------------*
01510  *                Histogram-based grayscale quantization                *
01511  *----------------------------------------------------------------------*/
01512 /*!
01513  *  pixGrayQuantFromHisto()
01514  *
01515  *      Input:  pixd (<optional> quantized pix with cmap; can be null)
01516  *              pixs (8 bpp gray input pix; not cmapped)
01517  *              pixm (<optional> mask over pixels in pixs to quantize)
01518  *              minfract (minimum fraction of pixels in a set of adjacent
01519  *                        histo bins that causes the set to be automatically
01520  *                        set aside as a color in the colormap; must be
01521  *                        at least 0.01)
01522  *              maxsize (maximum number of adjacent bins allowed to represent
01523  *                       a color, regardless of the population of pixels
01524  *                       in the bins; must be at least 2)
01525  *      Return: pixd (8 bpp, cmapped), or null on error
01526  *
01527  *  Notes:
01528  *      (1) This is useful for quantizing images with relatively few
01529  *          colors, but which may have both color and gray pixels.
01530  *          If there are color pixels, it is assumed that an input
01531  *          rgb image has been color quantized first so that:
01532  *            - pixd has a colormap describing the color pixels
01533  *            - pixm is a mask over the non-color pixels in pixd
01534  *            - the colormap in pixd, and the color pixels in pixd,
01535  *              have been repacked to go from 0 to n-1 (n colors)
01536  *          If there are no color pixels, pixd and pixm are both null,
01537  *          and all pixels in pixs are quantized to gray.
01538  *      (2) A 256-entry histogram is built of the gray values in pixs.
01539  *          If pixm exists, the pixels contributing to the histogram are
01540  *          restricted to the fg of pixm.  A colormap and LUT are generated
01541  *          from this histogram.  We break up the array into a set
01542  *          of intervals, each one constituting a color in the colormap:
01543  *          An interval is identified by summing histogram bins until
01544  *          either the sum equals or exceeds the @minfract of the total
01545  *          number of pixels, or the span itself equals or exceeds @maxsize.
01546  *          The color of each bin is always an average of the pixels
01547  *          that constitute it.
01548  *      (3) Note that we do not specify the number of gray colors in
01549  *          the colormap.  Instead, we specify two parameters that
01550  *          describe the accuracy of the color assignments; this and
01551  *          the actual image determine the number of resulting colors.
01552  *      (4) If a mask exists and it is not the same size as pixs, make
01553  *          a new mask the same size as pixs, with the original mask
01554  *          aligned at the UL corners.  Set all additional pixels
01555  *          in the (larger) new mask set to 1, causing those pixels
01556  *          in pixd to be set as gray.
01557  *      (5) We estimate the total number of colors (color plus gray);
01558  *          if it exceeds 255, return null.
01559  */
01560 PIX *
01561 pixGrayQuantFromHisto(PIX       *pixd,
01562                       PIX       *pixs,
01563                       PIX       *pixm,
01564                       l_float32  minfract,
01565                       l_int32    maxsize)
01566 {
01567 l_int32    w, h, wd, hd, wm, hm, wpls, wplm, wpld;
01568 l_int32    nc, nestim, i, j, vals, vald;
01569 l_int32   *lut;
01570 l_uint32  *datas, *datam, *datad, *lines, *linem, *lined;
01571 NUMA      *na;
01572 PIX       *pixmr;  /* resized mask */
01573 PIXCMAP   *cmap;
01574 
01575     PROCNAME("pixGrayQuantFromHisto");
01576 
01577     if (!pixs || pixGetDepth(pixs) != 8)
01578         return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", procName, NULL);
01579     if (minfract < 0.01) {
01580         L_WARNING("minfract < 0.01; setting to 0.05", procName);
01581         minfract = 0.05;
01582     }
01583     if (maxsize < 2) {
01584         L_WARNING("maxsize < 2; setting to 10", procName);
01585         maxsize = 10;
01586     }
01587     if ((pixd && !pixm) || (!pixd && pixm))
01588         return (PIX *)ERROR_PTR("(pixd,pixm) not defined together",
01589                                 procName, NULL);
01590     pixGetDimensions(pixs, &w, &h, NULL);
01591     if (pixd) {
01592         if (pixGetDepth(pixm) != 1)
01593             return (PIX *)ERROR_PTR("pixm not 1 bpp", procName, NULL);
01594         if ((cmap = pixGetColormap(pixd)) == NULL)
01595             return (PIX *)ERROR_PTR("pixd not cmapped", procName, NULL);
01596         pixGetDimensions(pixd, &wd, &hd, NULL); 
01597         if (w != wd || h != hd)
01598             return (PIX *)ERROR_PTR("pixs, pixd sizes differ", procName, NULL);
01599         nc = pixcmapGetCount(cmap);
01600         nestim = nc + (l_int32)(1.5 * 255 / maxsize);
01601         fprintf(stderr, "nestim = %d\n", nestim);
01602         if (nestim > 255) {
01603             L_ERROR_INT("Estimate %d colors!", procName, nestim);
01604             return (PIX *)ERROR_PTR("probably too many colors", procName, NULL);
01605         }
01606         pixGetDimensions(pixm, &wm, &hm, NULL); 
01607         if (w != wm || h != hm) {  /* resize the mask */
01608             L_WARNING("mask and dest sizes not equal", procName);
01609             pixmr = pixCreateNoInit(w, h, 1);
01610             pixRasterop(pixmr, 0, 0, wm, hm, PIX_SRC, pixm, 0, 0);
01611             pixRasterop(pixmr, wm, 0, w - wm, h, PIX_SET, NULL, 0, 0);
01612             pixRasterop(pixmr, 0, hm, wm, h - hm, PIX_SET, NULL, 0, 0);
01613         }
01614         else
01615             pixmr = pixClone(pixm);
01616     }
01617     else {
01618         pixd = pixCreateTemplate(pixs);
01619         cmap = pixcmapCreate(8);
01620         pixSetColormap(pixd, cmap);
01621     }
01622 
01623         /* Use original mask, if it exists, to select gray pixels */
01624     na = pixGetGrayHistogramMasked(pixs, pixm, 0, 0, 1);
01625 
01626         /* Fill out the cmap with gray colors, and generate the lut
01627          * for pixel assignment.  Issue a warning on failure.  */
01628     if (numaFillCmapFromHisto(na, cmap, minfract, maxsize, &lut))
01629         L_ERROR("ran out of colors in cmap!", procName);
01630     numaDestroy(&na);
01631 
01632         /* Assign the gray pixels to their cmap indices */
01633     datas = pixGetData(pixs);
01634     datad = pixGetData(pixd);
01635     wpls = pixGetWpl(pixs);
01636     wpld = pixGetWpl(pixd);
01637     if (!pixm) {
01638         for (i = 0; i < h; i++) {
01639             lines = datas + i * wpls;
01640             lined = datad + i * wpld;
01641             for (j = 0; j < w; j++) {
01642                 vals = GET_DATA_BYTE(lines, j);
01643                 vald = lut[vals];
01644                 SET_DATA_BYTE(lined, j, vald);
01645             }
01646         }
01647         FREE(lut);
01648         return pixd;
01649     }
01650 
01651     datam = pixGetData(pixmr);
01652     wplm = pixGetWpl(pixmr);
01653     for (i = 0; i < h; i++) {
01654         lines = datas + i * wpls;
01655         linem = datam + i * wplm;
01656         lined = datad + i * wpld;
01657         for (j = 0; j < w; j++) {
01658             if (!GET_DATA_BIT(linem, j))
01659                 continue;
01660             vals = GET_DATA_BYTE(lines, j);
01661             vald = lut[vals];
01662             SET_DATA_BYTE(lined, j, vald);
01663         }
01664     }
01665     pixDestroy(&pixmr);
01666     FREE(lut);
01667     return pixd;
01668 }
01669                  
01670 
01671 /*!
01672  *  numaFillCmapFromHisto()
01673  *
01674  *      Input:  na (histogram of gray values)
01675  *              cmap (8 bpp cmap, possibly initialized with color value)
01676  *              minfract (minimum fraction of pixels in a set of adjacent
01677  *                        histo bins that causes the set to be automatically
01678  *                        set aside as a color in the colormap; must be
01679  *                        at least 0.01)
01680  *              maxsize (maximum number of adjacent bins allowed to represent
01681  *                       a color, regardless of the population of pixels
01682  *                       in the bins; must be at least 2)
01683  *             &lut (<return> lookup table from gray value to colormap index)
01684  *      Return: 0 if OK, 1 on error
01685  *
01686  *  Notes:
01687  *      (1) This static function must be called from pixGrayQuantFromHisto()
01688  */
01689 static l_int32
01690 numaFillCmapFromHisto(NUMA      *na,
01691                       PIXCMAP   *cmap,
01692                       l_float32  minfract,
01693                       l_int32    maxsize,
01694                       l_int32  **plut)
01695 {
01696 l_int32    mincount, index, sum, wtsum, span, istart, i, val, ret;
01697 l_int32   *iahisto, *lut;
01698 l_float32  total;
01699 
01700     PROCNAME("numaFillCmapFromHisto");
01701 
01702     if (!plut)
01703         return ERROR_INT("&lut not defined", procName, 1);
01704     *plut = NULL;
01705     if (!na)
01706         return ERROR_INT("na not defined", procName, 1);
01707     if (!cmap)
01708         return ERROR_INT("cmap not defined", procName, 1);
01709    
01710     numaGetSum(na, &total);
01711     mincount = (l_int32)(minfract * total);
01712     iahisto = numaGetIArray(na);
01713     if ((lut = (l_int32 *)CALLOC(256, sizeof(l_int32))) == NULL)
01714         return ERROR_INT("lut not made", procName, 1);
01715     *plut = lut;
01716     index = pixcmapGetCount(cmap);  /* start with number of colors
01717                                      * already reserved */
01718 
01719         /* March through, associating colors with sets of adjacent
01720          * gray levels.  During the process, the LUT that gives
01721          * the colormap index for each gray level is computed.
01722          * To complete a color, either the total count must equal
01723          * or exceed @mincount, or the current span of colors must
01724          * equal or exceed @maxsize.  An empty span is not converted
01725          * into a color; it is simply ignored.  When a span is completed for a
01726          * color, the weighted color in the span is added to the colormap. */
01727     sum = 0;
01728     wtsum = 0;
01729     istart = 0;
01730     ret = 0;
01731     for (i = 0; i < 256; i++) {
01732         lut[i] = index;
01733         sum += iahisto[i];
01734         wtsum += i * iahisto[i];
01735         span = i - istart + 1;
01736         if (sum < mincount && span < maxsize)
01737             continue; 
01738 
01739         if (sum == 0) {  /* empty span; don't save */
01740             istart = i + 1;
01741             continue;
01742         }
01743 
01744             /* Found new color; sum > 0 */
01745         val = (l_int32)((l_float32)wtsum / (l_float32)sum + 0.5);
01746         ret = pixcmapAddColor(cmap, val, val, val);
01747         istart = i + 1;
01748         sum = 0;
01749         wtsum = 0;
01750         index++;
01751     }
01752     if (istart < 256 && sum > 0) {  /* last one */
01753         span = 256 - istart;
01754         val = (l_int32)((l_float32)wtsum / (l_float32)sum + 0.5);
01755         ret = pixcmapAddColor(cmap, val, val, val);
01756     }
01757 
01758     FREE(iahisto);
01759     return ret;
01760 }
01761 
01762 
01763 /*----------------------------------------------------------------------*
01764  *        Color quantize grayscale image using existing colormap        *
01765  *----------------------------------------------------------------------*/
01766 /*!
01767  *  pixGrayQuantFromCmap()
01768  *
01769  *      Input:  pixs (8 bpp grayscale without cmap)
01770  *              cmap (to quantize to; of dest pix)
01771  *              mindepth (minimum depth of pixd: can be 2, 4 or 8 bpp)
01772  *      Return: pixd (2, 4 or 8 bpp, colormapped), or null on error
01773  *
01774  *  Notes:
01775  *      (1) In use, pixs is an 8 bpp grayscale image without a colormap.
01776  *          If there is an existing colormap, a warning is issued and
01777  *          a copy of the input pixs is returned.
01778  */
01779 PIX *
01780 pixGrayQuantFromCmap(PIX      *pixs,
01781                      PIXCMAP  *cmap,
01782                      l_int32   mindepth)
01783 {
01784 l_int32    i, j, index, w, h, d, depth, wpls, wpld;
01785 l_int32    hascolor, vals, vald;
01786 l_int32   *tab;
01787 l_uint32  *datas, *datad, *lines, *lined;
01788 PIXCMAP   *cmapd;
01789 PIX       *pixd;
01790 
01791     PROCNAME("pixGrayQuantFromCmap");
01792 
01793     if (!pixs)
01794         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
01795     if (pixGetColormap(pixs) != NULL) {
01796         L_WARNING("pixs already has a colormap; returning a copy", procName);
01797         return pixCopy(NULL, pixs);
01798     }
01799     pixGetDimensions(pixs, &w, &h, &d);
01800     if (d != 8)
01801         return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
01802     if (!cmap)
01803         return (PIX *)ERROR_PTR("cmap not defined", procName, NULL);
01804     if (mindepth != 2 && mindepth != 4 && mindepth != 8)
01805         return (PIX *)ERROR_PTR("invalid mindepth", procName, NULL);
01806 
01807         /* Make sure the colormap is gray */
01808     pixcmapHasColor(cmap, &hascolor);
01809     if (hascolor) {
01810         L_WARNING("Converting colormap colors to gray", procName);
01811         cmapd = pixcmapColorToGray(cmap, 0.3, 0.5, 0.2);
01812     }
01813     else
01814         cmapd = pixcmapCopy(cmap);
01815 
01816         /* Make LUT into colormap */
01817     if ((tab = (l_int32 *)CALLOC(256, sizeof(l_int32))) == NULL)
01818         return (PIX *)ERROR_PTR("tab not made", procName, NULL);
01819     for (i = 0; i < 256; i++) {
01820         pixcmapGetNearestGrayIndex(cmapd, i, &index);
01821         tab[i] = index;
01822     }
01823 
01824     pixcmapGetMinDepth(cmap, &depth);
01825     depth = L_MAX(depth, mindepth);
01826     pixd = pixCreate(w, h, depth); 
01827     pixSetColormap(pixd, cmapd);
01828     pixCopyResolution(pixd, pixs);
01829     pixCopyInputFormat(pixd, pixs);
01830     datas = pixGetData(pixs);
01831     datad = pixGetData(pixd);
01832     wpls = pixGetWpl(pixs);
01833     wpld = pixGetWpl(pixd);
01834     for (i = 0; i < h; i++) {
01835         lines = datas + i * wpls;
01836         lined = datad + i * wpld;
01837         for (j = 0; j < w; j++) {
01838             vals = GET_DATA_BYTE(lines, j);
01839             vald = tab[vals];
01840             if (depth == 2)
01841                 SET_DATA_DIBIT(lined, j, vald);
01842             else if (depth == 4)
01843                 SET_DATA_QBIT(lined, j, vald);
01844             else  /* depth == 8 */
01845                 SET_DATA_BYTE(lined, j, vald);
01846         }
01847     }
01848 
01849     FREE(tab);
01850     return pixd;
01851 }
01852 
01853 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines