Leptonica 1.68
C Image Processing Library

colorseg.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  *  colorseg.c
00018  *
00019  *    Unsupervised color segmentation
00020  *
00021  *               PIX     *pixColorSegment()
00022  *               PIX     *pixColorSegmentCluster()
00023  *       static  l_int32  pixColorSegmentTryCluster()
00024  *               l_int32  pixAssignToNearestColor()
00025  *               l_int32  pixColorSegmentClean()
00026  *               l_int32  pixColorSegmentRemoveColors()
00027  */
00028 
00029 #include "allheaders.h"
00030 
00031     /* Maximum allowed iterations in Phase 1. */
00032 static const l_int32  MAX_ALLOWED_ITERATIONS = 20;
00033 
00034     /* Factor by which max dist is increased on each iteration */
00035 static const l_float32  DIST_EXPAND_FACT = 1.3;
00036 
00037     /* Octcube division level for computing nearest colormap color using LUT.
00038      * Using 4 should suffice for up to 50 - 100 colors, and it is
00039      * very fast.  Using 5 takes 8 times as long to set up the LUT
00040      * for little perceptual gain, even with 100 colors. */
00041 static const l_int32  LEVEL_IN_OCTCUBE = 4;
00042 
00043 
00044 static l_int32 pixColorSegmentTryCluster(PIX *pixd, PIX *pixs,
00045                                          l_int32 maxdist, l_int32 maxcolors);
00046 
00047 
00048 /*------------------------------------------------------------------*
00049  *                 Unsupervised color segmentation                  *
00050  *------------------------------------------------------------------*/
00051 /*!
00052  *  pixColorSegment()
00053  *
00054  *      Input:  pixs  (32 bpp; 24-bit color)
00055  *              maxdist (max euclidean dist to existing cluster)
00056  *              maxcolors (max number of colors allowed in first pass)
00057  *              selsize (linear size of sel for closing to remove noise)
00058  *              finalcolors (max number of final colors allowed after 4th pass)
00059  *      Return: pixd (8 bit with colormap), or null on error
00060  *
00061  *  Color segmentation proceeds in four phases:
00062  *
00063  *  Phase 1:  pixColorSegmentCluster()
00064  *  The image is traversed in raster order.  Each pixel either
00065  *  becomes the representative for a new cluster or is assigned to an
00066  *  existing cluster.  Assignment is greedy.  The data is stored in
00067  *  a colormapped image.  Three auxiliary arrays are used to hold
00068  *  the colors of the representative pixels, for fast lookup.
00069  *  The average color in each cluster is computed.
00070  *
00071  *  Phase 2.  pixAssignToNearestColor()
00072  *  A second (non-greedy) clustering pass is performed, where each pixel
00073  *  is assigned to the nearest cluster (average).  We also keep track
00074  *  of how many pixels are assigned to each cluster.
00075  *
00076  *  Phase 3.  pixColorSegmentClean()
00077  *  For each cluster, starting with the largest, do a morphological
00078  *  closing to eliminate small components within larger ones.
00079  *
00080  *  Phase 4.  pixColorSegmentRemoveColors()
00081  *  Eliminate all colors except the most populated 'finalcolors'.
00082  *  Then remove unused colors from the colormap, and reassign those
00083  *  pixels to the nearest remaining cluster, using the original pixel values.
00084  *
00085  *  Notes:
00086  *      (1) The goal is to generate a small number of colors.
00087  *          Typically this would be specified by 'finalcolors',
00088  *          a number that would be somewhere between 3 and 6.
00089  *          The parameter 'maxcolors' specifies the maximum number of
00090  *          colors generated in the first phase.  This should be
00091  *          larger than finalcolors, perhaps twice as large.
00092  *          If more than 'maxcolors' are generated in the first phase
00093  *          using the input 'maxdist', the distance is repeatedly
00094  *          increased by a multiplicative factor until the condition
00095  *          is satisfied.  The implicit relation between 'maxdist'
00096  *          and 'maxcolors' is thus adjusted programmatically.
00097  *      (2) As a very rough guideline, given a target value of 'finalcolors',
00098  *          here are approximate values of 'maxdist' and 'maxcolors'
00099  *          to start with:
00100  *
00101  *               finalcolors    maxcolors    maxdist
00102  *               -----------    ---------    -------
00103  *                   3             6          100
00104  *                   4             8           90
00105  *                   5            10           75
00106  *                   6            12           60
00107  *
00108  *          For a given number of finalcolors, if you use too many
00109  *          maxcolors, the result will be noisy.  If you use too few,
00110  *          the result will be a relatively poor assignment of colors.
00111  */
00112 PIX *
00113 pixColorSegment(PIX     *pixs,
00114                 l_int32  maxdist,
00115                 l_int32  maxcolors,
00116                 l_int32  selsize,
00117                 l_int32  finalcolors)
00118 {
00119 l_int32   *countarray;
00120 PIX       *pixd;
00121 
00122     PROCNAME("pixColorSegment");
00123 
00124     if (!pixs)
00125         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00126     if (pixGetDepth(pixs) != 32)
00127         return (PIX *)ERROR_PTR("must be rgb color", procName, NULL);
00128 
00129         /* Phase 1; original segmentation */
00130     if ((pixd = pixColorSegmentCluster(pixs, maxdist, maxcolors)) == NULL)
00131         return (PIX *)ERROR_PTR("pixt1 not made", procName, NULL);
00132 /*    pixWrite("junkpixd1", pixd, IFF_PNG);  */
00133 
00134         /* Phase 2; refinement in pixel assignment */
00135     if ((countarray = (l_int32 *)CALLOC(256, sizeof(l_int32))) == NULL)
00136         return (PIX *)ERROR_PTR("countarray not made", procName, NULL);
00137     pixAssignToNearestColor(pixd, pixs, NULL, LEVEL_IN_OCTCUBE, countarray);
00138 /*    pixWrite("junkpixd2", pixd, IFF_PNG);  */
00139 
00140         /* Phase 3: noise removal by separately closing each color */
00141     pixColorSegmentClean(pixd, selsize, countarray);
00142 /*    pixWrite("junkpixd3", pixd, IFF_PNG);  */
00143     FREE(countarray);
00144 
00145         /* Phase 4: removal of colors with small population and
00146          * reassignment of pixels to remaining colors */
00147     pixColorSegmentRemoveColors(pixd, pixs, finalcolors);
00148     return pixd;
00149 }
00150 
00151 
00152 /*!
00153  *  pixColorSegmentCluster()
00154  *
00155  *      Input:  pixs  (32 bpp; 24-bit color)
00156  *              maxdist (max euclidean dist to existing cluster)
00157  *              maxcolors (max number of colors allowed in first pass)
00158  *      Return: pixd (8 bit with colormap), or null on error
00159  *
00160  *  Notes:
00161  *      (1) This is phase 1.  See description in pixColorSegment().
00162  *      (2) Greedy unsupervised classification.  If the limit 'maxcolors'
00163  *          is exceeded, the computation is repeated with a larger
00164  *          allowed cluster size.
00165  *      (3) On each successive iteration, 'maxdist' is increased by a
00166  *          constant factor.  See comments in pixColorSegment() for
00167  *          a guideline on parameter selection.
00168  *          Note that the diagonal of the 8-bit rgb color cube is about
00169  *          440, so for 'maxdist' = 440, you are guaranteed to get 1 color!
00170  */
00171 PIX *
00172 pixColorSegmentCluster(PIX       *pixs,
00173                        l_int32    maxdist,
00174                        l_int32    maxcolors)
00175 {
00176 l_int32    w, h, newmaxdist, ret, niters, ncolors, success;
00177 PIX       *pixd;
00178 PIXCMAP   *cmap;
00179 
00180     PROCNAME("pixColorSegmentCluster");
00181 
00182     if (!pixs)
00183         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00184     if (pixGetDepth(pixs) != 32)
00185         return (PIX *)ERROR_PTR("must be rgb color", procName, NULL);
00186 
00187     w = pixGetWidth(pixs);
00188     h = pixGetHeight(pixs);
00189     if ((pixd = pixCreate(w, h, 8)) == NULL)
00190         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
00191     cmap = pixcmapCreate(8);
00192     pixSetColormap(pixd, cmap);
00193     pixCopyResolution(pixd, pixs);
00194 
00195     newmaxdist = maxdist;
00196     niters = 0;
00197     success = TRUE;
00198     while (1) {
00199         ret = pixColorSegmentTryCluster(pixd, pixs, newmaxdist, maxcolors);
00200         niters++;
00201         if (!ret) {
00202             ncolors = pixcmapGetCount(cmap);
00203             L_INFO_INT2("Success with %d colors after %d iters", procName,
00204                        ncolors, niters);
00205             break;
00206         }
00207         if (niters == MAX_ALLOWED_ITERATIONS) {
00208             L_WARNING_INT("too many iters; newmaxdist = %d",
00209                           procName, newmaxdist);
00210             success = FALSE;
00211             break;
00212         }
00213         newmaxdist = (l_int32)(DIST_EXPAND_FACT * (l_float32)newmaxdist);
00214     }
00215 
00216     if (!success) {
00217         pixDestroy(&pixd);
00218         return (PIX *)ERROR_PTR("failure in phase 1", procName, NULL);
00219     }
00220 
00221     return pixd;
00222 }
00223 
00224 
00225 /*!
00226  *  pixColorSegmentTryCluster()
00227  *
00228  *      Input:  pixd
00229  *              pixs
00230  *              maxdist
00231  *              maxcolors
00232  *      Return: 0 if OK, 1 on error
00233  *
00234  *  Note: This function should only be called from pixColorSegCluster()
00235  */
00236 static l_int32
00237 pixColorSegmentTryCluster(PIX       *pixd,
00238                           PIX       *pixs,
00239                           l_int32    maxdist,
00240                           l_int32    maxcolors)
00241 {
00242 l_int32    rmap[256], gmap[256], bmap[256];
00243 l_int32    w, h, wpls, wpld, i, j, k, found, ret, index, ncolors;
00244 l_int32    rval, gval, bval, dist2, maxdist2;
00245 l_int32    countarray[256];
00246 l_int32    rsum[256], gsum[256], bsum[256];
00247 l_uint32  *ppixel;
00248 l_uint32  *datas, *datad, *lines, *lined;
00249 PIXCMAP   *cmap;
00250 
00251     PROCNAME("pixColorSegmentTryCluster");
00252 
00253     if (!pixs)
00254         return ERROR_INT("pixs not defined", procName, 1);
00255     if (!pixd)
00256         return ERROR_INT("pixd not defined", procName, 1);
00257 
00258     w = pixGetWidth(pixs);
00259     h = pixGetHeight(pixs);
00260     maxdist2 = maxdist * maxdist;
00261     cmap = pixGetColormap(pixd);
00262     pixcmapClear(cmap);
00263     for (k = 0; k < 256; k++) {
00264         rsum[k] = gsum[k] = bsum[k] = 0;
00265         rmap[k] = gmap[k] = bmap[k] = 0;
00266     }
00267 
00268     datas = pixGetData(pixs);
00269     datad = pixGetData(pixd);
00270     wpls = pixGetWpl(pixs);
00271     wpld = pixGetWpl(pixd);
00272     for (i = 0; i < h; i++) {
00273         lines = datas + i * wpls;
00274         lined = datad + i * wpld;
00275         for (j = 0; j < w; j++) {
00276             ppixel = lines + j;
00277             rval = GET_DATA_BYTE(ppixel, COLOR_RED);
00278             gval = GET_DATA_BYTE(ppixel, COLOR_GREEN);
00279             bval = GET_DATA_BYTE(ppixel, COLOR_BLUE);
00280             ncolors = pixcmapGetCount(cmap);
00281             found = FALSE;
00282             for (k = 0; k < ncolors; k++) {
00283                 dist2 = (rval - rmap[k]) * (rval - rmap[k]) +
00284                         (gval - gmap[k]) * (gval - gmap[k]) +
00285                         (bval - bmap[k]) * (bval - bmap[k]);
00286                 if (dist2 <= maxdist2) {  /* take it; greedy */
00287                     found = TRUE;
00288                     SET_DATA_BYTE(lined, j, k);
00289                     countarray[k]++;
00290                     rsum[k] += rval;
00291                     gsum[k] += gval;
00292                     bsum[k] += bval;
00293                     break;
00294                 }
00295             }
00296             if (!found) {  /* Add a new color */
00297                 ret = pixcmapAddNewColor(cmap, rval, gval, bval, &index);
00298 /*                fprintf(stderr,
00299                         "index = %d, (i,j) = (%d,%d), rgb = (%d, %d, %d)\n",
00300                         index, i, j, rval, gval, bval); */
00301                 if (ret == 0 && index < maxcolors) {
00302                     countarray[index] = 1;
00303                     SET_DATA_BYTE(lined, j, index);
00304                     rmap[index] = rval;
00305                     gmap[index] = gval;
00306                     bmap[index] = bval;
00307                     rsum[index] = rval;
00308                     gsum[index] = gval;
00309                     bsum[index] = bval;
00310                 }
00311                 else  {
00312                     L_INFO_INT("maxcolors exceeded for maxdist = %d",
00313                                procName, maxdist);
00314                     return 1;
00315                 }
00316             }
00317         }
00318     }
00319 
00320         /* Replace the colors in the colormap by the averages */
00321     for (k = 0; k < ncolors; k++) {
00322         rval = rsum[k] / countarray[k];
00323         gval = gsum[k] / countarray[k];
00324         bval = bsum[k] / countarray[k];
00325         pixcmapResetColor(cmap, k, rval, gval, bval);
00326     }
00327 
00328     return 0;
00329 }
00330 
00331 
00332 /*!
00333  *  pixAssignToNearestColor()
00334  *
00335  *      Input:  pixd  (8 bpp, colormapped)
00336  *              pixs  (32 bpp; 24-bit color)
00337  *              pixm  (<optional> 1 bpp)
00338  *              level (of octcube used for finding nearest color in cmap)
00339  *              countarray (<optional> ptr to array, in which we can store
00340  *                          the number of pixels found in each color in
00341  *                          the colormap in pixd)
00342  *      Return: 0 if OK, 1 on error
00343  *
00344  *  Notes:
00345  *      (1) This is used in phase 2 of color segmentation, where pixs
00346  *          is the original input image to pixColorSegment(), and
00347  *          pixd is the colormapped image returned from
00348  *          pixColorSegmentCluster().  It is also used, with a mask,
00349  *          in phase 4.
00350  *      (2) This is an in-place operation.
00351  *      (3) The colormap in pixd is unchanged.
00352  *      (4) pixs and pixd must be the same size (w, h).
00353  *      (5) The selection mask pixm can be null.  If it exists, it must
00354  *          be the same size as pixs and pixd, and only pixels
00355  *          corresponding to fg in pixm are assigned.  Set to
00356  *          NULL if all pixels in pixd are to be assigned.
00357  *      (6) The countarray can be null.  If it exists, it is pre-allocated
00358  *          and of a size at least equal to the size of the colormap in pixd.
00359  *      (7) This does a best-fit (non-greedy) assignment of pixels to
00360  *          existing clusters.  Specifically, it assigns each pixel
00361  *          in pixd to the color index in the pixd colormap that has a
00362  *          color closest to the corresponding rgb pixel in pixs.
00363  *      (8) 'level' is the octcube level used to quickly find the nearest
00364  *          color in the colormap for each pixel.  For color segmentation,
00365  *          this parameter is set to LEVEL_IN_OCTCUBE.
00366  *      (9) We build a mapping table from octcube to colormap index so
00367  *          that this function can run in a time (otherwise) independent
00368  *          of the number of colors in the colormap.  This avoids a
00369  *          brute-force search for the closest colormap color to each
00370  *          pixel in the image.
00371  */
00372 l_int32
00373 pixAssignToNearestColor(PIX      *pixd,
00374                         PIX      *pixs,
00375                         PIX      *pixm,
00376                         l_int32   level,
00377                         l_int32  *countarray)
00378 {
00379 l_int32    w, h, wpls, wpld, wplm, i, j;
00380 l_int32    rval, gval, bval, index;
00381 l_int32   *cmaptab;
00382 l_uint32   octindex;
00383 l_uint32  *rtab, *gtab, *btab;
00384 l_uint32  *ppixel;
00385 l_uint32  *datas, *datad, *datam, *lines, *lined, *linem;
00386 PIXCMAP   *cmap;
00387 
00388     PROCNAME("pixAssignToNearestColor");
00389 
00390     if (!pixd)
00391         return ERROR_INT("pixd not defined", procName, 1);
00392     if ((cmap = pixGetColormap(pixd)) == NULL)
00393         return ERROR_INT("cmap not found", procName, 1);
00394     if (!pixs)
00395         return ERROR_INT("pixs not defined", procName, 1);
00396     if (pixGetDepth(pixs) != 32)
00397         return ERROR_INT("pixs not 32 bpp", procName, 1);
00398 
00399         /* Set up the tables to map rgb to the nearest colormap index */
00400     if (makeRGBToIndexTables(&rtab, &gtab, &btab, level))
00401         return ERROR_INT("index tables not made", procName, 1);
00402     if ((cmaptab = pixcmapToOctcubeLUT(cmap, level, L_MANHATTAN_DISTANCE))
00403             == NULL)
00404         return ERROR_INT("cmaptab not made", procName, 1);
00405 
00406     w = pixGetWidth(pixs);
00407     h = pixGetHeight(pixs);
00408     datas = pixGetData(pixs);
00409     datad = pixGetData(pixd);
00410     wpls = pixGetWpl(pixs);
00411     wpld = pixGetWpl(pixd);
00412     if (pixm) {
00413         datam = pixGetData(pixm);
00414         wplm = pixGetWpl(pixm);
00415     }
00416     for (i = 0; i < h; i++) {
00417         lines = datas + i * wpls;
00418         lined = datad + i * wpld;
00419         if (pixm)
00420             linem = datam + i * wplm;
00421         for (j = 0; j < w; j++) {
00422             if (pixm) {
00423                 if (!GET_DATA_BIT(linem, j))
00424                     continue;
00425             }
00426             ppixel = lines + j;
00427             rval = GET_DATA_BYTE(ppixel, COLOR_RED);
00428             gval = GET_DATA_BYTE(ppixel, COLOR_GREEN);
00429             bval = GET_DATA_BYTE(ppixel, COLOR_BLUE);
00430                 /* Map from rgb to octcube index */
00431             getOctcubeIndexFromRGB(rval, gval, bval, rtab, gtab, btab,
00432                                    &octindex);
00433                 /* Map from octcube index to nearest colormap index */
00434             index = cmaptab[octindex];
00435             if (countarray)
00436                 countarray[index]++;
00437             SET_DATA_BYTE(lined, j, index);
00438         }
00439     }
00440 
00441     FREE(cmaptab);
00442     FREE(rtab);
00443     FREE(gtab);
00444     FREE(btab);
00445     return 0;
00446 }
00447 
00448 
00449 /*!
00450  *  pixColorSegmentClean()
00451  *
00452  *      Input:  pixs  (8 bpp, colormapped)
00453  *              selsize (for closing)
00454  *              countarray (ptr to array containing the number of pixels
00455  *                          found in each color in the colormap)
00456  *      Return: 0 if OK, 1 on error
00457  *
00458  *  Notes:
00459  *      (1) This operation is in-place.
00460  *      (2) This is phase 3 of color segmentation.  It is the first
00461  *          part of a two-step noise removal process.  Colors with a
00462  *          large population are closed first; this operation absorbs
00463  *          small sets of intercolated pixels of a different color.
00464  */
00465 l_int32
00466 pixColorSegmentClean(PIX      *pixs,
00467                      l_int32   selsize,
00468                      l_int32  *countarray)
00469 {
00470 l_int32    i, ncolors, val;
00471 l_uint32   val32;
00472 NUMA      *na, *nasi;
00473 PIX       *pixt1, *pixt2;
00474 PIXCMAP   *cmap;
00475 
00476     PROCNAME("pixColorSegmentClean");
00477 
00478     if (!pixs)
00479         return ERROR_INT("pixs not defined", procName, 1);
00480     if (pixGetDepth(pixs) != 8)
00481         return ERROR_INT("pixs not 8 bpp", procName, 1);
00482     if ((cmap = pixGetColormap(pixs)) == NULL)
00483         return ERROR_INT("cmap not found", procName, 1);
00484     if (!countarray)
00485         return ERROR_INT("countarray not defined", procName, 1);
00486     if (selsize <= 1)
00487         return 0;  /* nothing to do */
00488 
00489         /* Sort colormap indices in decreasing order of pixel population */
00490     ncolors = pixcmapGetCount(cmap);
00491     na = numaCreate(ncolors);
00492     for (i = 0; i < ncolors; i++)
00493         numaAddNumber(na, countarray[i]);
00494     if ((nasi = numaGetSortIndex(na, L_SORT_DECREASING)) == NULL)
00495         return ERROR_INT("nasi not made", procName, 1);
00496 
00497         /* For each color, in order of decreasing population,
00498          * do a closing and absorb the added pixels.  Note that
00499          * if the closing removes pixels at the border, they'll
00500          * still appear in the xor and will be properly (re)set. */
00501     for (i = 0; i < ncolors; i++) {
00502         numaGetIValue(nasi, i, &val);
00503         pixt1 = pixGenerateMaskByValue(pixs, val, 1);
00504         pixt2 = pixCloseSafeCompBrick(NULL, pixt1, selsize, selsize);
00505         pixXor(pixt2, pixt2, pixt1);  /* pixels to be added to type 'val' */
00506         pixcmapGetColor32(cmap, val, &val32);
00507         pixSetMasked(pixs, pixt2, val32);  /* add them */
00508         pixDestroy(&pixt1);
00509         pixDestroy(&pixt2);
00510     }
00511     numaDestroy(&na);
00512     numaDestroy(&nasi);
00513     return 0;
00514 }
00515 
00516 
00517 /*!
00518  *  pixColorSegmentRemoveColors()
00519  *
00520  *      Input:  pixd  (8 bpp, colormapped)
00521  *              pixs  (32 bpp rgb, with initial pixel values)
00522  *              finalcolors (max number of colors to retain)
00523  *      Return: 0 if OK, 1 on error
00524  *
00525  *  Notes:
00526  *      (1) This operation is in-place.
00527  *      (2) This is phase 4 of color segmentation, and the second part
00528  *          of the 2-step noise removal.  Only 'finalcolors' different
00529  *          colors are retained, with colors with smaller populations
00530  *          being replaced by the nearest color of the remaining colors.
00531  *          For highest accuracy, for pixels that are being replaced,
00532  *          we find the nearest colormap color  to the original rgb color.
00533  */
00534 l_int32
00535 pixColorSegmentRemoveColors(PIX     *pixd,
00536                             PIX     *pixs,
00537                             l_int32  finalcolors)
00538 {
00539 l_int32    i, ncolors, index, tempindex;
00540 l_int32   *tab;
00541 l_uint32   tempcolor;
00542 NUMA      *na, *nasi;
00543 PIX       *pixm;
00544 PIXCMAP   *cmap;
00545 
00546     PROCNAME("pixColorSegmentRemoveColors");
00547 
00548     if (!pixd)
00549         return ERROR_INT("pixd not defined", procName, 1);
00550     if (pixGetDepth(pixd) != 8)
00551         return ERROR_INT("pixd not 8 bpp", procName, 1);
00552     if ((cmap = pixGetColormap(pixd)) == NULL)
00553         return ERROR_INT("cmap not found", procName, 1);
00554     if (!pixs)
00555         return ERROR_INT("pixs not defined", procName, 1);
00556     ncolors = pixcmapGetCount(cmap);
00557     if (finalcolors >= ncolors)  /* few enough colors already; nothing to do */
00558         return 0;
00559 
00560         /* Generate a mask over all pixels that are not in the
00561          * 'finalcolors' most populated colors.  Save the colormap
00562          * index of any one of the retained colors in 'tempindex'.
00563          * The LUT has values 0 for the 'finalcolors' most populated colors,
00564          * which will be retained; and 1 for the rest, which are marked
00565          * by fg pixels in pixm and will be removed. */
00566     na = pixGetCmapHistogram(pixd, 1);
00567     if ((nasi = numaGetSortIndex(na, L_SORT_DECREASING)) == NULL) {
00568         numaDestroy(&na);
00569         return ERROR_INT("nasi not made", procName, 1);
00570     }
00571     numaGetIValue(nasi, finalcolors - 1, &tempindex);  /* retain down to this */
00572     pixcmapGetColor32(cmap, tempindex, &tempcolor);  /* use this color */
00573     tab = (l_int32 *)CALLOC(256, sizeof(l_int32));
00574     for (i = finalcolors; i < ncolors; i++) {
00575         numaGetIValue(nasi, i, &index);
00576         tab[index] = 1;
00577     }
00578 
00579     pixm = pixMakeMaskFromLUT(pixd, tab);
00580     FREE(tab);
00581 
00582         /* Reassign the masked pixels temporarily to the saved index
00583          * (tempindex).  This guarantees that no pixels are labeled by
00584          * a colormap index of any colors that will be removed.
00585          * The actual value doesn't matter, as long as it's one
00586          * of the retained colors, because these pixels will later
00587          * be reassigned based on the full set of colors retained
00588          * in the colormap. */
00589     pixSetMasked(pixd, pixm, tempcolor);
00590 
00591         /* Now remove unused colors from the colormap.  This reassigns
00592          * image pixels as required. */
00593     pixRemoveUnusedColors(pixd);
00594 
00595         /* Finally, reassign the pixels under the mask (those that were
00596          * given a 'tempindex' value) to the nearest color in the colormap.
00597          * This is the function used in phase 2 on all image pixels; here
00598          * it is only used on the masked pixels given by pixm. */
00599     pixAssignToNearestColor(pixd, pixs, pixm, LEVEL_IN_OCTCUBE, NULL);
00600 
00601     pixDestroy(&pixm);
00602     numaDestroy(&na);
00603     numaDestroy(&nasi);
00604     return 0;
00605 }
00606 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines