LCOV - code coverage report
Current view: top level - alg - gdalmediancut.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 525 562 93.4 %
Date: 2024-11-21 22:18:42 Functions: 13 18 72.2 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  CIETMap Phase 2
       4             :  * Purpose:  Use median cut algorithm to generate an near-optimal PCT for a
       5             :  *           given RGB image.  Implemented as function GDALComputeMedianCutPCT.
       6             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7             :  *
       8             :  ******************************************************************************
       9             :  * Copyright (c) 2001, Frank Warmerdam
      10             :  * Copyright (c) 2007-2010, Even Rouault <even dot rouault at spatialys.com>
      11             :  *
      12             :  * SPDX-License-Identifier: MIT
      13             :  ******************************************************************************
      14             :  *
      15             :  * This code was based on the tiffmedian.c code from libtiff (www.libtiff.org)
      16             :  * which was based on a paper by Paul Heckbert:
      17             :  *
      18             :  *      "Color  Image Quantization for Frame Buffer Display", Paul
      19             :  *      Heckbert, SIGGRAPH proceedings, 1982, pp. 297-307.
      20             :  *
      21             :  */
      22             : 
      23             : #include "cpl_port.h"
      24             : #include "gdal_alg.h"
      25             : #include "gdal_alg_priv.h"
      26             : 
      27             : #include <climits>
      28             : #include <cstring>
      29             : 
      30             : #include <algorithm>
      31             : #include <limits>
      32             : 
      33             : #include "cpl_conv.h"
      34             : #include "cpl_error.h"
      35             : #include "cpl_progress.h"
      36             : #include "cpl_vsi.h"
      37             : #include "gdal.h"
      38             : #include "gdal_priv.h"
      39             : 
      40      287563 : template <typename T> static T *HISTOGRAM(T *h, int n, int r, int g, int b)
      41             : {
      42      287563 :     const int index = (r * n + g) * n + b;
      43      287563 :     return &h[index];
      44             : }
      45             : 
      46             : #ifndef MAKE_COLOR_CODE_defined
      47             : #define MAKE_COLOR_CODE_defined
      48             : 
      49    17939300 : static int MAKE_COLOR_CODE(int r, int g, int b)
      50             : {
      51    17939300 :     return r | (g << 8) | (b << 16);
      52             : }
      53             : #endif
      54             : 
      55             : // NOTE: If changing the size of this structure, edit
      56             : // MEDIAN_CUT_AND_DITHER_BUFFER_SIZE_65536 in gdal_alg_priv.h and take into
      57             : // account ColorIndex in gdaldither.cpp.
      58             : typedef struct
      59             : {
      60             :     GUInt32 nColorCode;
      61             :     int nCount;
      62             :     GUInt32 nColorCode2;
      63             :     int nCount2;
      64             :     GUInt32 nColorCode3;
      65             :     int nCount3;
      66             : } HashHistogram;
      67             : 
      68             : typedef struct colorbox
      69             : {
      70             :     struct colorbox *next, *prev;
      71             :     int rmin, rmax;
      72             :     int gmin, gmax;
      73             :     int bmin, bmax;
      74             :     GUIntBig total;
      75             : } Colorbox;
      76             : 
      77             : template <class T>
      78             : static void splitbox(Colorbox *ptr, const T *histogram,
      79             :                      const HashHistogram *psHashHistogram, int nCLevels,
      80             :                      Colorbox **pfreeboxes, Colorbox **pusedboxes,
      81             :                      GByte *pabyRedBand, GByte *pabyGreenBand,
      82             :                      GByte *pabyBlueBand, T nPixels);
      83             : 
      84             : template <class T>
      85             : static void shrinkbox(Colorbox *box, const T *histogram, int nCLevels);
      86             : 
      87             : static Colorbox *largest_box(Colorbox *usedboxes);
      88             : 
      89             : /************************************************************************/
      90             : /*                      GDALComputeMedianCutPCT()                       */
      91             : /************************************************************************/
      92             : 
      93             : /**
      94             :  * Compute optimal PCT for RGB image.
      95             :  *
      96             :  * This function implements a median cut algorithm to compute an "optimal"
      97             :  * pseudocolor table for representing an input RGB image.  This PCT could
      98             :  * then be used with GDALDitherRGB2PCT() to convert a 24bit RGB image into
      99             :  * an eightbit pseudo-colored image.
     100             :  *
     101             :  * This code was based on the tiffmedian.c code from libtiff (www.libtiff.org)
     102             :  * which was based on a paper by Paul Heckbert:
     103             :  *
     104             :  * \verbatim
     105             :  *   "Color  Image Quantization for Frame Buffer Display", Paul
     106             :  *   Heckbert, SIGGRAPH proceedings, 1982, pp. 297-307.
     107             :  * \endverbatim
     108             :  *
     109             :  * The red, green and blue input bands do not necessarily need to come
     110             :  * from the same file, but they must be the same width and height.  They will
     111             :  * be clipped to 8bit during reading, so non-eight bit bands are generally
     112             :  * inappropriate.
     113             :  *
     114             :  * @param hRed Red input band.
     115             :  * @param hGreen Green input band.
     116             :  * @param hBlue Blue input band.
     117             :  * @param pfnIncludePixel function used to test which pixels should be included
     118             :  * in the analysis.  At this time this argument is ignored and all pixels are
     119             :  * utilized.  This should normally be NULL.
     120             :  * @param nColors the desired number of colors to be returned (2-256).
     121             :  * @param hColorTable the colors will be returned in this color table object.
     122             :  * @param pfnProgress callback for reporting algorithm progress matching the
     123             :  * GDALProgressFunc() semantics.  May be NULL.
     124             :  * @param pProgressArg callback argument passed to pfnProgress.
     125             :  *
     126             :  * @return returns CE_None on success or CE_Failure if an error occurs.
     127             :  */
     128             : 
     129           3 : extern "C" int CPL_STDCALL GDALComputeMedianCutPCT(
     130             :     GDALRasterBandH hRed, GDALRasterBandH hGreen, GDALRasterBandH hBlue,
     131             :     int (*pfnIncludePixel)(int, int, void *), int nColors,
     132             :     GDALColorTableH hColorTable, GDALProgressFunc pfnProgress,
     133             :     void *pProgressArg)
     134             : 
     135             : {
     136           3 :     VALIDATE_POINTER1(hRed, "GDALComputeMedianCutPCT", CE_Failure);
     137           3 :     const int nXSize = GDALGetRasterBandXSize(hRed);
     138           3 :     const int nYSize = GDALGetRasterBandYSize(hRed);
     139           3 :     if (nYSize == 0)
     140           0 :         return CE_Failure;
     141           3 :     if (static_cast<GUInt32>(nXSize) <
     142           3 :         std::numeric_limits<GUInt32>::max() / static_cast<GUInt32>(nYSize))
     143             :     {
     144           3 :         return GDALComputeMedianCutPCTInternal(
     145             :             hRed, hGreen, hBlue, nullptr, nullptr, nullptr, pfnIncludePixel,
     146             :             nColors, 5, static_cast<GUInt32 *>(nullptr), hColorTable,
     147           3 :             pfnProgress, pProgressArg);
     148             :     }
     149             :     else
     150             :     {
     151           0 :         return GDALComputeMedianCutPCTInternal(
     152             :             hRed, hGreen, hBlue, nullptr, nullptr, nullptr, pfnIncludePixel,
     153             :             nColors, 5, static_cast<GUIntBig *>(nullptr), hColorTable,
     154           0 :             pfnProgress, pProgressArg);
     155             :     }
     156             : }
     157             : 
     158             : #ifndef IsColorCodeSet_defined
     159             : #define IsColorCodeSet_defined
     160             : 
     161    18835800 : static inline bool IsColorCodeSet(GUInt32 nColorCode)
     162             : {
     163    18835800 :     return (nColorCode >> 31) == 0;
     164             : }
     165             : #endif
     166             : 
     167    17549600 : static inline int FindColorCount(const HashHistogram *psHashHistogram,
     168             :                                  GUInt32 nColorCode)
     169             : {
     170             : 
     171    17549600 :     GUInt32 nIdx = nColorCode % PRIME_FOR_65536;
     172             :     while (true)
     173             :     {
     174    17550200 :         if (!IsColorCodeSet(psHashHistogram[nIdx].nColorCode))
     175             :         {
     176    16219100 :             return 0;
     177             :         }
     178     1331150 :         if (psHashHistogram[nIdx].nColorCode == nColorCode)
     179             :         {
     180      141464 :             return psHashHistogram[nIdx].nCount;
     181             :         }
     182     1189680 :         if (!IsColorCodeSet(psHashHistogram[nIdx].nColorCode2))
     183             :         {
     184     1151920 :             return 0;
     185             :         }
     186       37761 :         if (psHashHistogram[nIdx].nColorCode2 == nColorCode)
     187             :         {
     188        4030 :             return psHashHistogram[nIdx].nCount2;
     189             :         }
     190       33731 :         if (!IsColorCodeSet(psHashHistogram[nIdx].nColorCode3))
     191             :         {
     192       33078 :             return 0;
     193             :         }
     194         653 :         if (psHashHistogram[nIdx].nColorCode3 == nColorCode)
     195             :         {
     196          59 :             return psHashHistogram[nIdx].nCount3;
     197             :         }
     198             : 
     199           0 :         do
     200             :         {
     201         594 :             nIdx += 257;
     202         594 :             if (nIdx >= PRIME_FOR_65536)
     203           0 :                 nIdx -= PRIME_FOR_65536;
     204         594 :         } while (IsColorCodeSet(psHashHistogram[nIdx].nColorCode) &&
     205         260 :                  psHashHistogram[nIdx].nColorCode != nColorCode &&
     206         130 :                  IsColorCodeSet(psHashHistogram[nIdx].nColorCode2) &&
     207           0 :                  psHashHistogram[nIdx].nColorCode2 != nColorCode &&
     208         724 :                  IsColorCodeSet(psHashHistogram[nIdx].nColorCode3) &&
     209           0 :                  psHashHistogram[nIdx].nColorCode3 != nColorCode);
     210             :     }
     211             : }
     212             : 
     213      389644 : static inline int *FindAndInsertColorCount(HashHistogram *psHashHistogram,
     214             :                                            GUInt32 nColorCode)
     215             : {
     216      389644 :     GUInt32 nIdx = nColorCode % PRIME_FOR_65536;
     217             :     while (true)
     218             :     {
     219      389644 :         if (psHashHistogram[nIdx].nColorCode == nColorCode)
     220             :         {
     221      329957 :             return &(psHashHistogram[nIdx].nCount);
     222             :         }
     223       59687 :         if (!IsColorCodeSet(psHashHistogram[nIdx].nColorCode))
     224             :         {
     225       56306 :             psHashHistogram[nIdx].nColorCode = nColorCode;
     226       56306 :             psHashHistogram[nIdx].nCount = 0;
     227       56306 :             return &(psHashHistogram[nIdx].nCount);
     228             :         }
     229        3381 :         if (psHashHistogram[nIdx].nColorCode2 == nColorCode)
     230             :         {
     231        1661 :             return &(psHashHistogram[nIdx].nCount2);
     232             :         }
     233        1720 :         if (!IsColorCodeSet(psHashHistogram[nIdx].nColorCode2))
     234             :         {
     235        1687 :             psHashHistogram[nIdx].nColorCode2 = nColorCode;
     236        1687 :             psHashHistogram[nIdx].nCount2 = 0;
     237        1687 :             return &(psHashHistogram[nIdx].nCount2);
     238             :         }
     239          33 :         if (psHashHistogram[nIdx].nColorCode3 == nColorCode)
     240             :         {
     241           5 :             return &(psHashHistogram[nIdx].nCount3);
     242             :         }
     243          28 :         if (!IsColorCodeSet(psHashHistogram[nIdx].nColorCode3))
     244             :         {
     245          28 :             psHashHistogram[nIdx].nColorCode3 = nColorCode;
     246          28 :             psHashHistogram[nIdx].nCount3 = 0;
     247          28 :             return &(psHashHistogram[nIdx].nCount3);
     248             :         }
     249             : 
     250           0 :         do
     251             :         {
     252           0 :             nIdx += 257;
     253           0 :             if (nIdx >= PRIME_FOR_65536)
     254           0 :                 nIdx -= PRIME_FOR_65536;
     255           0 :         } while (IsColorCodeSet(psHashHistogram[nIdx].nColorCode) &&
     256           0 :                  psHashHistogram[nIdx].nColorCode != nColorCode &&
     257           0 :                  IsColorCodeSet(psHashHistogram[nIdx].nColorCode2) &&
     258           0 :                  psHashHistogram[nIdx].nColorCode2 != nColorCode &&
     259           0 :                  IsColorCodeSet(psHashHistogram[nIdx].nColorCode3) &&
     260           0 :                  psHashHistogram[nIdx].nColorCode3 != nColorCode);
     261             :     }
     262             : }
     263             : 
     264             : template <class T>
     265          13 : int GDALComputeMedianCutPCTInternal(
     266             :     GDALRasterBandH hRed, GDALRasterBandH hGreen, GDALRasterBandH hBlue,
     267             :     GByte *pabyRedBand, GByte *pabyGreenBand, GByte *pabyBlueBand,
     268             :     int (*pfnIncludePixel)(int, int, void *), int nColors, int nBits,
     269             :     T *panHistogram,  // NULL, or >= size (1<<nBits)^3 * sizeof(T) bytes.
     270             :     GDALColorTableH hColorTable, GDALProgressFunc pfnProgress,
     271             :     void *pProgressArg)
     272             : 
     273             : {
     274          13 :     VALIDATE_POINTER1(hRed, "GDALComputeMedianCutPCT", CE_Failure);
     275          13 :     VALIDATE_POINTER1(hGreen, "GDALComputeMedianCutPCT", CE_Failure);
     276          13 :     VALIDATE_POINTER1(hBlue, "GDALComputeMedianCutPCT", CE_Failure);
     277             : 
     278          13 :     CPLErr err = CE_None;
     279             : 
     280             :     /* -------------------------------------------------------------------- */
     281             :     /*      Validate parameters.                                            */
     282             :     /* -------------------------------------------------------------------- */
     283          13 :     const int nXSize = GDALGetRasterBandXSize(hRed);
     284          13 :     const int nYSize = GDALGetRasterBandYSize(hRed);
     285             : 
     286          13 :     if (GDALGetRasterBandXSize(hGreen) != nXSize ||
     287          13 :         GDALGetRasterBandYSize(hGreen) != nYSize ||
     288          39 :         GDALGetRasterBandXSize(hBlue) != nXSize ||
     289          13 :         GDALGetRasterBandYSize(hBlue) != nYSize)
     290             :     {
     291           0 :         CPLError(CE_Failure, CPLE_IllegalArg,
     292             :                  "Green or blue band doesn't match size of red band.");
     293             : 
     294           0 :         return CE_Failure;
     295             :     }
     296             : 
     297          13 :     if (pfnIncludePixel != nullptr)
     298             :     {
     299           0 :         CPLError(CE_Failure, CPLE_IllegalArg,
     300             :                  "GDALComputeMedianCutPCT() doesn't currently support "
     301             :                  "pfnIncludePixel function.");
     302             : 
     303           0 :         return CE_Failure;
     304             :     }
     305             : 
     306          13 :     if (nColors <= 0)
     307             :     {
     308           0 :         CPLError(CE_Failure, CPLE_IllegalArg,
     309             :                  "GDALComputeMedianCutPCT(): "
     310             :                  "nColors must be strictly greater than 1.");
     311             : 
     312           0 :         return CE_Failure;
     313             :     }
     314             : 
     315          13 :     if (nColors > 256)
     316             :     {
     317           0 :         CPLError(CE_Failure, CPLE_IllegalArg,
     318             :                  "GDALComputeMedianCutPCT(): "
     319             :                  "nColors must be lesser than or equal to 256.");
     320             : 
     321           0 :         return CE_Failure;
     322             :     }
     323             : 
     324          13 :     if (pfnProgress == nullptr)
     325          11 :         pfnProgress = GDALDummyProgress;
     326             : 
     327             :     /* ==================================================================== */
     328             :     /*      STEP 1: create empty boxes.                                     */
     329             :     /* ==================================================================== */
     330          13 :     if (static_cast<GUInt32>(nXSize) >
     331          13 :         std::numeric_limits<T>::max() / static_cast<GUInt32>(nYSize))
     332             :     {
     333           0 :         CPLError(CE_Warning, CPLE_AppDefined,
     334             :                  "GDALComputeMedianCutPCTInternal() not called "
     335             :                  "with large enough type");
     336             :     }
     337             : 
     338          13 :     T nPixels = 0;
     339          10 :     if (nBits == 8 && pabyRedBand != nullptr && pabyGreenBand != nullptr &&
     340          23 :         pabyBlueBand != nullptr &&
     341          10 :         static_cast<GUInt32>(nXSize) <=
     342          10 :             std::numeric_limits<T>::max() / static_cast<GUInt32>(nYSize))
     343             :     {
     344          10 :         nPixels = static_cast<T>(nXSize) * static_cast<T>(nYSize);
     345             :     }
     346             : 
     347          13 :     const int nCLevels = 1 << nBits;
     348          13 :     const int nCLevelsCube = nCLevels * nCLevels * nCLevels;
     349          13 :     T *histogram = nullptr;
     350          13 :     HashHistogram *psHashHistogram = nullptr;
     351          13 :     if (panHistogram)
     352             :     {
     353          10 :         if (nBits == 8 && static_cast<GUIntBig>(nXSize) * nYSize <= 65536)
     354             :         {
     355             :             // If the image is small enough, then the number of colors
     356             :             // will be limited and using a hashmap, rather than a full table
     357             :             // will be more efficient.
     358           9 :             histogram = nullptr;
     359           9 :             psHashHistogram = reinterpret_cast<HashHistogram *>(panHistogram);
     360           9 :             memset(psHashHistogram, 0xFF,
     361             :                    sizeof(HashHistogram) * PRIME_FOR_65536);
     362             :         }
     363             :         else
     364             :         {
     365           1 :             histogram = panHistogram;
     366           1 :             memset(histogram, 0, nCLevelsCube * sizeof(T));
     367             :         }
     368             :     }
     369             :     else
     370             :     {
     371             :         histogram =
     372           3 :             static_cast<T *>(VSI_CALLOC_VERBOSE(nCLevelsCube, sizeof(T)));
     373           3 :         if (histogram == nullptr)
     374             :         {
     375           0 :             return CE_Failure;
     376             :         }
     377             :     }
     378             :     Colorbox *box_list =
     379          13 :         static_cast<Colorbox *>(CPLMalloc(nColors * sizeof(Colorbox)));
     380          13 :     Colorbox *freeboxes = box_list;
     381          13 :     freeboxes[0].next = &freeboxes[1];
     382          13 :     freeboxes[0].prev = nullptr;
     383        2827 :     for (int i = 1; i < nColors - 1; ++i)
     384             :     {
     385        2814 :         freeboxes[i].next = &freeboxes[i + 1];
     386        2814 :         freeboxes[i].prev = &freeboxes[i - 1];
     387             :     }
     388          13 :     freeboxes[nColors - 1].next = nullptr;
     389          13 :     freeboxes[nColors - 1].prev = &freeboxes[nColors - 2];
     390             : 
     391             :     /* ==================================================================== */
     392             :     /*      Build histogram.                                                */
     393             :     /* ==================================================================== */
     394             : 
     395             :     /* -------------------------------------------------------------------- */
     396             :     /*      Initialize the box datastructures.                              */
     397             :     /* -------------------------------------------------------------------- */
     398          13 :     Colorbox *freeboxes_before = freeboxes;
     399          13 :     freeboxes = freeboxes_before->next;
     400          13 :     if (freeboxes)
     401          13 :         freeboxes->prev = nullptr;
     402             : 
     403          13 :     Colorbox *usedboxes = freeboxes_before;
     404          13 :     usedboxes->next = nullptr;
     405          13 :     usedboxes->rmin = 999;
     406          13 :     usedboxes->gmin = 999;
     407          13 :     usedboxes->bmin = 999;
     408          13 :     usedboxes->rmax = -1;
     409          13 :     usedboxes->gmax = -1;
     410          13 :     usedboxes->bmax = -1;
     411          13 :     usedboxes->total =
     412          13 :         static_cast<GUIntBig>(nXSize) * static_cast<GUIntBig>(nYSize);
     413             : 
     414             :     /* -------------------------------------------------------------------- */
     415             :     /*      Collect histogram.                                              */
     416             :     /* -------------------------------------------------------------------- */
     417             : 
     418             :     // TODO(schwehr): Move these closer to usage after removing gotos.
     419          13 :     const int nColorShift = 8 - nBits;
     420          13 :     int nColorCounter = 0;
     421          13 :     GByte anRed[256] = {};
     422          13 :     GByte anGreen[256] = {};
     423          13 :     GByte anBlue[256] = {};
     424             : 
     425          13 :     GByte *pabyRedLine = static_cast<GByte *>(VSI_MALLOC_VERBOSE(nXSize));
     426          13 :     GByte *pabyGreenLine = static_cast<GByte *>(VSI_MALLOC_VERBOSE(nXSize));
     427          13 :     GByte *pabyBlueLine = static_cast<GByte *>(VSI_MALLOC_VERBOSE(nXSize));
     428             : 
     429          13 :     if (pabyRedLine == nullptr || pabyGreenLine == nullptr ||
     430             :         pabyBlueLine == nullptr)
     431             :     {
     432           0 :         err = CE_Failure;
     433           0 :         goto end_and_cleanup;
     434             :     }
     435             : 
     436        2137 :     for (int iLine = 0; iLine < nYSize; iLine++)
     437             :     {
     438        2124 :         if (!pfnProgress(iLine / static_cast<double>(nYSize),
     439             :                          "Generating Histogram", pProgressArg))
     440             :         {
     441           0 :             CPLError(CE_Failure, CPLE_UserInterrupt, "User Terminated");
     442           0 :             err = CE_Failure;
     443           0 :             goto end_and_cleanup;
     444             :         }
     445             : 
     446        2124 :         err = GDALRasterIO(hRed, GF_Read, 0, iLine, nXSize, 1, pabyRedLine,
     447             :                            nXSize, 1, GDT_Byte, 0, 0);
     448        2124 :         if (err == CE_None)
     449        2124 :             err = GDALRasterIO(hGreen, GF_Read, 0, iLine, nXSize, 1,
     450             :                                pabyGreenLine, nXSize, 1, GDT_Byte, 0, 0);
     451        2124 :         if (err == CE_None)
     452        2124 :             err = GDALRasterIO(hBlue, GF_Read, 0, iLine, nXSize, 1,
     453             :                                pabyBlueLine, nXSize, 1, GDT_Byte, 0, 0);
     454        2124 :         if (err != CE_None)
     455           0 :             goto end_and_cleanup;
     456             : 
     457      479268 :         for (int iPixel = 0; iPixel < nXSize; iPixel++)
     458             :         {
     459      477144 :             const int nRed = pabyRedLine[iPixel] >> nColorShift;
     460      477144 :             const int nGreen = pabyGreenLine[iPixel] >> nColorShift;
     461      477144 :             const int nBlue = pabyBlueLine[iPixel] >> nColorShift;
     462             : 
     463      477144 :             usedboxes->rmin = std::min(usedboxes->rmin, nRed);
     464      477144 :             usedboxes->gmin = std::min(usedboxes->gmin, nGreen);
     465      477144 :             usedboxes->bmin = std::min(usedboxes->bmin, nBlue);
     466      477144 :             usedboxes->rmax = std::max(usedboxes->rmax, nRed);
     467      477144 :             usedboxes->gmax = std::max(usedboxes->gmax, nGreen);
     468      477144 :             usedboxes->bmax = std::max(usedboxes->bmax, nBlue);
     469             : 
     470             :             bool bFirstOccurrence;
     471      477144 :             if (psHashHistogram)
     472             :             {
     473      389644 :                 int *pnColor = FindAndInsertColorCount(
     474      389644 :                     psHashHistogram, MAKE_COLOR_CODE(nRed, nGreen, nBlue));
     475      389644 :                 bFirstOccurrence = (*pnColor == 0);
     476      389644 :                 (*pnColor)++;
     477             :             }
     478             :             else
     479             :             {
     480             :                 T *pnColor =
     481       87500 :                     HISTOGRAM(histogram, nCLevels, nRed, nGreen, nBlue);
     482       87500 :                 bFirstOccurrence = (*pnColor == 0);
     483       87500 :                 (*pnColor)++;
     484             :             }
     485      477144 :             if (bFirstOccurrence)
     486             :             {
     487       78587 :                 if (nColorShift == 0 && nColorCounter < nColors)
     488             :                 {
     489        2305 :                     anRed[nColorCounter] = static_cast<GByte>(nRed);
     490        2305 :                     anGreen[nColorCounter] = static_cast<GByte>(nGreen);
     491        2305 :                     anBlue[nColorCounter] = static_cast<GByte>(nBlue);
     492             :                 }
     493       78587 :                 nColorCounter++;
     494             :             }
     495             :         }
     496             :     }
     497             : 
     498          13 :     if (!pfnProgress(1.0, "Generating Histogram", pProgressArg))
     499             :     {
     500           0 :         CPLError(CE_Failure, CPLE_UserInterrupt, "User Terminated");
     501           0 :         err = CE_Failure;
     502           0 :         goto end_and_cleanup;
     503             :     }
     504             : 
     505          13 :     if (nColorShift == 0 && nColorCounter <= nColors)
     506             :     {
     507             : #if DEBUG_VERBOSE
     508             :         CPLDebug("MEDIAN_CUT", "%d colors found <= %d", nColorCounter, nColors);
     509             : #endif
     510           2 :         for (int iColor = 0; iColor < nColorCounter; iColor++)
     511             :         {
     512           1 :             const GDALColorEntry sEntry = {static_cast<GByte>(anRed[iColor]),
     513           1 :                                            static_cast<GByte>(anGreen[iColor]),
     514           1 :                                            static_cast<GByte>(anBlue[iColor]),
     515             :                                            255};
     516           1 :             GDALSetColorEntry(hColorTable, iColor, &sEntry);
     517             :         }
     518           1 :         goto end_and_cleanup;
     519             :     }
     520             : 
     521             :     /* ==================================================================== */
     522             :     /*      STEP 3: continually subdivide boxes until no more free          */
     523             :     /*      boxes remain or until all colors assigned.                      */
     524             :     /* ==================================================================== */
     525        2584 :     while (freeboxes != nullptr)
     526             :     {
     527        2572 :         auto ptr = largest_box(usedboxes);
     528        2572 :         if (ptr != nullptr)
     529        2572 :             splitbox(ptr, histogram, psHashHistogram, nCLevels, &freeboxes,
     530             :                      &usedboxes, pabyRedBand, pabyGreenBand, pabyBlueBand,
     531             :                      nPixels);
     532             :         else
     533           0 :             freeboxes = nullptr;
     534             :     }
     535             : 
     536             :     /* ==================================================================== */
     537             :     /*      STEP 4: assign colors to all boxes                              */
     538             :     /* ==================================================================== */
     539             :     {
     540          12 :         Colorbox *ptr = usedboxes;
     541        2596 :         for (int i = 0; ptr != nullptr; ++i, ptr = ptr->next)
     542             :         {
     543        2584 :             const GDALColorEntry sEntry = {
     544        2584 :                 static_cast<GByte>(((ptr->rmin + ptr->rmax) << nColorShift) /
     545             :                                    2),
     546        2584 :                 static_cast<GByte>(((ptr->gmin + ptr->gmax) << nColorShift) /
     547             :                                    2),
     548        2584 :                 static_cast<GByte>(((ptr->bmin + ptr->bmax) << nColorShift) /
     549             :                                    2),
     550             :                 255};
     551        2584 :             GDALSetColorEntry(hColorTable, i, &sEntry);
     552             :         }
     553             :     }
     554             : 
     555          12 : end_and_cleanup:
     556          13 :     CPLFree(pabyRedLine);
     557          13 :     CPLFree(pabyGreenLine);
     558          13 :     CPLFree(pabyBlueLine);
     559             : 
     560             :     // We're done with the boxes now.
     561          13 :     CPLFree(box_list);
     562          13 :     freeboxes = nullptr;
     563          13 :     usedboxes = nullptr;
     564             : 
     565          13 :     if (panHistogram == nullptr)
     566           3 :         CPLFree(histogram);
     567             : 
     568          13 :     return err;
     569             : }
     570             : 
     571             : /************************************************************************/
     572             : /*                            largest_box()                             */
     573             : /************************************************************************/
     574             : 
     575        2572 : static Colorbox *largest_box(Colorbox *usedboxes)
     576             : {
     577        2572 :     Colorbox *b = nullptr;
     578             : 
     579      329120 :     for (Colorbox *p = usedboxes; p != nullptr; p = p->next)
     580             :     {
     581      326548 :         if ((p->rmax > p->rmin || p->gmax > p->gmin || p->bmax > p->bmin) &&
     582      299299 :             (b == nullptr || p->total > b->total))
     583             :         {
     584       39803 :             b = p;
     585             :         }
     586             :     }
     587        2572 :     return b;
     588             : }
     589             : 
     590         743 : static void shrinkboxFromBand(Colorbox *ptr, const GByte *pabyRedBand,
     591             :                               const GByte *pabyGreenBand,
     592             :                               const GByte *pabyBlueBand, GUIntBig nPixels)
     593             : {
     594         743 :     int rmin_new = 255;
     595         743 :     int rmax_new = 0;
     596         743 :     int gmin_new = 255;
     597         743 :     int gmax_new = 0;
     598         743 :     int bmin_new = 255;
     599         743 :     int bmax_new = 0;
     600    35470300 :     for (GUIntBig i = 0; i < nPixels; i++)
     601             :     {
     602    35469500 :         const int iR = pabyRedBand[i];
     603    35469500 :         const int iG = pabyGreenBand[i];
     604    35469500 :         const int iB = pabyBlueBand[i];
     605    35469500 :         if (iR >= ptr->rmin && iR <= ptr->rmax && iG >= ptr->gmin &&
     606     5781920 :             iG <= ptr->gmax && iB >= ptr->bmin && iB <= ptr->bmax)
     607             :         {
     608     2154140 :             if (iR < rmin_new)
     609        3143 :                 rmin_new = iR;
     610     2154140 :             if (iR > rmax_new)
     611        4274 :                 rmax_new = iR;
     612     2154140 :             if (iG < gmin_new)
     613        3392 :                 gmin_new = iG;
     614     2154140 :             if (iG > gmax_new)
     615        4635 :                 gmax_new = iG;
     616     2154140 :             if (iB < bmin_new)
     617        4455 :                 bmin_new = iB;
     618     2154140 :             if (iB > bmax_new)
     619        3314 :                 bmax_new = iB;
     620             :         }
     621             :     }
     622             : 
     623         743 :     CPLAssert(rmin_new >= ptr->rmin && rmin_new <= rmax_new &&
     624             :               rmax_new <= ptr->rmax);
     625         743 :     CPLAssert(gmin_new >= ptr->gmin && gmin_new <= gmax_new &&
     626             :               gmax_new <= ptr->gmax);
     627         743 :     CPLAssert(bmin_new >= ptr->bmin && bmin_new <= bmax_new &&
     628             :               bmax_new <= ptr->bmax);
     629         743 :     ptr->rmin = rmin_new;
     630         743 :     ptr->rmax = rmax_new;
     631         743 :     ptr->gmin = gmin_new;
     632         743 :     ptr->gmax = gmax_new;
     633         743 :     ptr->bmin = bmin_new;
     634         743 :     ptr->bmax = bmax_new;
     635         743 : }
     636             : 
     637        3415 : static void shrinkboxFromHashHistogram(Colorbox *box,
     638             :                                        const HashHistogram *psHashHistogram)
     639             : {
     640        3415 :     if (box->rmax > box->rmin)
     641             :     {
     642        4917 :         for (int ir = box->rmin; ir <= box->rmax; ++ir)
     643             :         {
     644       54728 :             for (int ig = box->gmin; ig <= box->gmax; ++ig)
     645             :             {
     646      770529 :                 for (int ib = box->bmin; ib <= box->bmax; ++ib)
     647             :                 {
     648      720718 :                     if (FindColorCount(psHashHistogram,
     649     1441440 :                                        MAKE_COLOR_CODE(ir, ig, ib)) != 0)
     650             :                     {
     651        3313 :                         box->rmin = ir;
     652        3313 :                         goto have_rmin;
     653             :                     }
     654             :                 }
     655             :             }
     656             :         }
     657             :     }
     658         102 : have_rmin:
     659        3415 :     if (box->rmax > box->rmin)
     660             :     {
     661        6050 :         for (int ir = box->rmax; ir >= box->rmin; --ir)
     662             :         {
     663       65302 :             for (int ig = box->gmin; ig <= box->gmax; ++ig)
     664             :             {
     665     1301360 :                 for (int ib = box->bmin; ib <= box->bmax; ++ib)
     666             :                 {
     667     1242110 :                     if (FindColorCount(psHashHistogram,
     668     2484210 :                                        MAKE_COLOR_CODE(ir, ig, ib)) != 0)
     669             :                     {
     670        3310 :                         box->rmax = ir;
     671        3310 :                         goto have_rmax;
     672             :                     }
     673             :                 }
     674             :             }
     675             :         }
     676             :     }
     677             : 
     678         105 : have_rmax:
     679        3415 :     if (box->gmax > box->gmin)
     680             :     {
     681        7027 :         for (int ig = box->gmin; ig <= box->gmax; ++ig)
     682             :         {
     683       71453 :             for (int ir = box->rmin; ir <= box->rmax; ++ir)
     684             :             {
     685     1233930 :                 for (int ib = box->bmin; ib <= box->bmax; ++ib)
     686             :                 {
     687     1169500 :                     if (FindColorCount(psHashHistogram,
     688     2339010 :                                        MAKE_COLOR_CODE(ir, ig, ib)) != 0)
     689             :                     {
     690        3252 :                         box->gmin = ig;
     691        3252 :                         goto have_gmin;
     692             :                     }
     693             :                 }
     694             :             }
     695             :         }
     696             :     }
     697             : 
     698         163 : have_gmin:
     699        3415 :     if (box->gmax > box->gmin)
     700             :     {
     701        8709 :         for (int ig = box->gmax; ig >= box->gmin; --ig)
     702             :         {
     703       99428 :             for (int ir = box->rmin; ir <= box->rmax; ++ir)
     704             :             {
     705       93961 :                 int ib = box->bmin;
     706     1785560 :                 for (; ib <= box->bmax; ++ib)
     707             :                 {
     708     1694840 :                     if (FindColorCount(psHashHistogram,
     709     3389690 :                                        MAKE_COLOR_CODE(ir, ig, ib)) != 0)
     710             :                     {
     711        3242 :                         box->gmax = ig;
     712        3242 :                         goto have_gmax;
     713             :                     }
     714             :                 }
     715             :             }
     716             :         }
     717             :     }
     718             : 
     719         173 : have_gmax:
     720        3415 :     if (box->bmax > box->bmin)
     721             :     {
     722        5004 :         for (int ib = box->bmin; ib <= box->bmax; ++ib)
     723             :         {
     724       36216 :             for (int ir = box->rmin; ir <= box->rmax; ++ir)
     725             :             {
     726      572282 :                 for (int ig = box->gmin; ig <= box->gmax; ++ig)
     727             :                 {
     728      541070 :                     if (FindColorCount(psHashHistogram,
     729     1082140 :                                        MAKE_COLOR_CODE(ir, ig, ib)) != 0)
     730             :                     {
     731        3312 :                         box->bmin = ib;
     732        3312 :                         goto have_bmin;
     733             :                     }
     734             :                 }
     735             :             }
     736             :         }
     737             :     }
     738             : 
     739         103 : have_bmin:
     740        3415 :     if (box->bmax > box->bmin)
     741             :     {
     742        6196 :         for (int ib = box->bmax; ib >= box->bmin; --ib)
     743             :         {
     744       48883 :             for (int ir = box->rmin; ir <= box->rmax; ++ir)
     745             :             {
     746      675385 :                 for (int ig = box->gmin; ig <= box->gmax; ++ig)
     747             :                 {
     748      632698 :                     if (FindColorCount(psHashHistogram,
     749     1265400 :                                        MAKE_COLOR_CODE(ir, ig, ib)) != 0)
     750             :                     {
     751        3298 :                         box->bmax = ib;
     752        3298 :                         goto have_bmax;
     753             :                     }
     754             :                 }
     755             :             }
     756             :         }
     757             :     }
     758             : 
     759         117 : have_bmax:;
     760        3415 : }
     761             : 
     762             : /************************************************************************/
     763             : /*                              splitbox()                              */
     764             : /************************************************************************/
     765             : template <class T>
     766        2572 : static void splitbox(Colorbox *ptr, const T *histogram,
     767             :                      const HashHistogram *psHashHistogram, int nCLevels,
     768             :                      Colorbox **pfreeboxes, Colorbox **pusedboxes,
     769             :                      GByte *pabyRedBand, GByte *pabyGreenBand,
     770             :                      GByte *pabyBlueBand, T nPixels)
     771             : {
     772        2572 :     T hist2[256] = {};
     773        2572 :     int first = 0;
     774        2572 :     int last = 0;
     775             : 
     776             :     enum
     777             :     {
     778             :         RED,
     779             :         GREEN,
     780             :         BLUE
     781             :     } axis;
     782             : 
     783             :     // See which axis is the largest, do a histogram along that axis.  Split at
     784             :     // median point.  Contract both new boxes to fit points and return.
     785             :     {
     786        2572 :         int i = ptr->rmax - ptr->rmin;
     787        2572 :         if (i >= ptr->gmax - ptr->gmin && i >= ptr->bmax - ptr->bmin)
     788         858 :             axis = RED;
     789        1714 :         else if (ptr->gmax - ptr->gmin >= ptr->bmax - ptr->bmin)
     790         785 :             axis = GREEN;
     791             :         else
     792         929 :             axis = BLUE;
     793             :     }
     794             :     // Get histogram along longest axis.
     795        2572 :     const GUInt32 nIters = (ptr->rmax - ptr->rmin + 1) *
     796        2572 :                            (ptr->gmax - ptr->gmin + 1) *
     797        2572 :                            (ptr->bmax - ptr->bmin + 1);
     798             : 
     799        2572 :     switch (axis)
     800             :     {
     801         858 :         case RED:
     802             :         {
     803         858 :             if (nPixels != 0 && nIters > nPixels)
     804             :             {
     805         229 :                 const int rmin = ptr->rmin;
     806         229 :                 const int rmax = ptr->rmax;
     807         229 :                 const int gmin = ptr->gmin;
     808         229 :                 const int gmax = ptr->gmax;
     809         229 :                 const int bmin = ptr->bmin;
     810         229 :                 const int bmax = ptr->bmax;
     811    11014200 :                 for (T iPixel = 0; iPixel < nPixels; iPixel++)
     812             :                 {
     813    11014000 :                     int iR = pabyRedBand[iPixel];
     814    11014000 :                     int iG = pabyGreenBand[iPixel];
     815    11014000 :                     int iB = pabyBlueBand[iPixel];
     816    11014000 :                     if (iR >= rmin && iR <= rmax && iG >= gmin && iG <= gmax &&
     817     1379080 :                         iB >= bmin && iB <= bmax)
     818             :                     {
     819      893690 :                         hist2[iR]++;
     820             :                     }
     821         229 :                 }
     822             :             }
     823         629 :             else if (psHashHistogram)
     824             :             {
     825         472 :                 T *histp = &hist2[ptr->rmin];
     826       11243 :                 for (int ir = ptr->rmin; ir <= ptr->rmax; ++ir)
     827             :                 {
     828       10771 :                     *histp = 0;
     829      226089 :                     for (int ig = ptr->gmin; ig <= ptr->gmax; ++ig)
     830             :                     {
     831     3704290 :                         for (int ib = ptr->bmin; ib <= ptr->bmax; ++ib)
     832             :                         {
     833     3488980 :                             *histp += FindColorCount(
     834     3488980 :                                 psHashHistogram, MAKE_COLOR_CODE(ir, ig, ib));
     835             :                         }
     836             :                     }
     837       10771 :                     histp++;
     838             :                 }
     839             :             }
     840             :             else
     841             :             {
     842         157 :                 T *histp = &hist2[ptr->rmin];
     843        2449 :                 for (int ir = ptr->rmin; ir <= ptr->rmax; ++ir)
     844             :                 {
     845        2292 :                     *histp = 0;
     846       51509 :                     for (int ig = ptr->gmin; ig <= ptr->gmax; ++ig)
     847             :                     {
     848             :                         const T *iptr =
     849       49217 :                             HISTOGRAM(histogram, nCLevels, ir, ig, ptr->bmin);
     850     1135910 :                         for (int ib = ptr->bmin; ib <= ptr->bmax; ++ib)
     851     1086700 :                             *histp += *iptr++;
     852             :                     }
     853        2292 :                     histp++;
     854             :                 }
     855             :             }
     856         858 :             first = ptr->rmin;
     857         858 :             last = ptr->rmax;
     858         858 :             break;
     859             :         }
     860         785 :         case GREEN:
     861             :         {
     862         785 :             if (nPixels != 0 && nIters > nPixels)
     863             :             {
     864         153 :                 const int rmin = ptr->rmin;
     865         153 :                 const int rmax = ptr->rmax;
     866         153 :                 const int gmin = ptr->gmin;
     867         153 :                 const int gmax = ptr->gmax;
     868         153 :                 const int bmin = ptr->bmin;
     869         153 :                 const int bmax = ptr->bmax;
     870     7442490 :                 for (T iPixel = 0; iPixel < nPixels; iPixel++)
     871             :                 {
     872     7442340 :                     const int iR = pabyRedBand[iPixel];
     873     7442340 :                     const int iG = pabyGreenBand[iPixel];
     874     7442340 :                     const int iB = pabyBlueBand[iPixel];
     875     7442340 :                     if (iR >= rmin && iR <= rmax && iG >= gmin && iG <= gmax &&
     876     1575360 :                         iB >= bmin && iB <= bmax)
     877             :                     {
     878      948439 :                         hist2[iG]++;
     879             :                     }
     880         153 :                 }
     881             :             }
     882         632 :             else if (psHashHistogram)
     883             :             {
     884         476 :                 T *histp = &hist2[ptr->gmin];
     885       12600 :                 for (int ig = ptr->gmin; ig <= ptr->gmax; ++ig)
     886             :                 {
     887       12124 :                     *histp = 0;
     888      183557 :                     for (int ir = ptr->rmin; ir <= ptr->rmax; ++ir)
     889             :                     {
     890     3551710 :                         for (int ib = ptr->bmin; ib <= ptr->bmax; ++ib)
     891             :                         {
     892     3380280 :                             *histp += FindColorCount(
     893     3380280 :                                 psHashHistogram, MAKE_COLOR_CODE(ir, ig, ib));
     894             :                         }
     895             :                     }
     896       12124 :                     histp++;
     897             :                 }
     898             :             }
     899             :             else
     900             :             {
     901         156 :                 T *histp = &hist2[ptr->gmin];
     902        2610 :                 for (int ig = ptr->gmin; ig <= ptr->gmax; ++ig)
     903             :                 {
     904        2454 :                     *histp = 0;
     905       40620 :                     for (int ir = ptr->rmin; ir <= ptr->rmax; ++ir)
     906             :                     {
     907             :                         const T *iptr =
     908       38166 :                             HISTOGRAM(histogram, nCLevels, ir, ig, ptr->bmin);
     909      851066 :                         for (int ib = ptr->bmin; ib <= ptr->bmax; ++ib)
     910      812900 :                             *histp += *iptr++;
     911             :                     }
     912        2454 :                     histp++;
     913             :                 }
     914             :             }
     915         785 :             first = ptr->gmin;
     916         785 :             last = ptr->gmax;
     917         785 :             break;
     918             :         }
     919         929 :         case BLUE:
     920             :         {
     921         929 :             if (nPixels != 0 && nIters > nPixels)
     922             :             {
     923         199 :                 const int rmin = ptr->rmin;
     924         199 :                 const int rmax = ptr->rmax;
     925         199 :                 const int gmin = ptr->gmin;
     926         199 :                 const int gmax = ptr->gmax;
     927         199 :                 const int bmin = ptr->bmin;
     928         199 :                 const int bmax = ptr->bmax;
     929     9614150 :                 for (T iPixel = 0; iPixel < nPixels; iPixel++)
     930             :                 {
     931     9613950 :                     const int iR = pabyRedBand[iPixel];
     932     9613950 :                     const int iG = pabyGreenBand[iPixel];
     933     9613950 :                     const int iB = pabyBlueBand[iPixel];
     934     9613950 :                     if (iR >= rmin && iR <= rmax && iG >= gmin && iG <= gmax &&
     935      832271 :                         iB >= bmin && iB <= bmax)
     936             :                     {
     937      649243 :                         hist2[iB]++;
     938             :                     }
     939         199 :                 }
     940             :             }
     941         730 :             else if (psHashHistogram)
     942             :             {
     943         573 :                 T *histp = &hist2[ptr->bmin];
     944       16540 :                 for (int ib = ptr->bmin; ib <= ptr->bmax; ++ib)
     945             :                 {
     946       15967 :                     *histp = 0;
     947      252363 :                     for (int ir = ptr->rmin; ir <= ptr->rmax; ++ir)
     948             :                     {
     949     4915820 :                         for (int ig = ptr->gmin; ig <= ptr->gmax; ++ig)
     950             :                         {
     951     4679430 :                             *histp += FindColorCount(
     952     4679430 :                                 psHashHistogram, MAKE_COLOR_CODE(ir, ig, ib));
     953             :                         }
     954             :                     }
     955       15967 :                     histp++;
     956             :                 }
     957             :             }
     958             :             else
     959             :             {
     960         157 :                 T *histp = &hist2[ptr->bmin];
     961        3487 :                 for (int ib = ptr->bmin; ib <= ptr->bmax; ++ib)
     962             :                 {
     963        3330 :                     *histp = 0;
     964       57185 :                     for (int ir = ptr->rmin; ir <= ptr->rmax; ++ir)
     965             :                     {
     966             :                         const T *iptr =
     967       53855 :                             HISTOGRAM(histogram, nCLevels, ir, ptr->gmin, ib);
     968     1396220 :                         for (int ig = ptr->gmin; ig <= ptr->gmax; ++ig)
     969             :                         {
     970     1342360 :                             *histp += *iptr;
     971     1342360 :                             iptr += nCLevels;
     972             :                         }
     973             :                     }
     974        3330 :                     histp++;
     975             :                 }
     976             :             }
     977         929 :             first = ptr->bmin;
     978         929 :             last = ptr->bmax;
     979         929 :             break;
     980             :         }
     981             :     }
     982             :     // Find median point.
     983        2572 :     T *histp = &hist2[first];
     984        2572 :     int i = first;  // TODO(schwehr): Rename i.
     985             :     {
     986        2572 :         T sum = 0;
     987        2572 :         T sum2 = static_cast<T>(ptr->total / 2);
     988       42342 :         for (; i <= last && (sum += *histp++) < sum2; ++i)
     989             :         {
     990             :         }
     991             :     }
     992        2572 :     if (i == first)
     993         191 :         i++;
     994             : 
     995             :     // Create new box, re-allocate points.
     996        2572 :     Colorbox *new_cb = *pfreeboxes;
     997        2572 :     *pfreeboxes = new_cb->next;
     998        2572 :     if (*pfreeboxes)
     999        2560 :         (*pfreeboxes)->prev = nullptr;
    1000        2572 :     if (*pusedboxes)
    1001        2572 :         (*pusedboxes)->prev = new_cb;
    1002        2572 :     new_cb->next = *pusedboxes;
    1003        2572 :     *pusedboxes = new_cb;
    1004             : 
    1005        2572 :     histp = &hist2[first];
    1006             :     {
    1007        2572 :         T sum1 = 0;
    1008       42533 :         for (int j = first; j < i; j++)
    1009       39961 :             sum1 += *histp++;
    1010        2572 :         T sum2 = 0;
    1011       65856 :         for (int j = i; j <= last; j++)
    1012       63284 :             sum2 += *histp++;
    1013        2572 :         new_cb->total = sum1;
    1014        2572 :         ptr->total = sum2;
    1015             :     }
    1016        2572 :     new_cb->rmin = ptr->rmin;
    1017        2572 :     new_cb->rmax = ptr->rmax;
    1018        2572 :     new_cb->gmin = ptr->gmin;
    1019        2572 :     new_cb->gmax = ptr->gmax;
    1020        2572 :     new_cb->bmin = ptr->bmin;
    1021        2572 :     new_cb->bmax = ptr->bmax;
    1022        2572 :     switch (axis)
    1023             :     {
    1024         858 :         case RED:
    1025         858 :             new_cb->rmax = i - 1;
    1026         858 :             ptr->rmin = i;
    1027         858 :             break;
    1028         785 :         case GREEN:
    1029         785 :             new_cb->gmax = i - 1;
    1030         785 :             ptr->gmin = i;
    1031         785 :             break;
    1032         929 :         case BLUE:
    1033         929 :             new_cb->bmax = i - 1;
    1034         929 :             ptr->bmin = i;
    1035         929 :             break;
    1036             :     }
    1037             : 
    1038        2572 :     if (nPixels != 0 &&
    1039        2295 :         static_cast<T>(new_cb->rmax - new_cb->rmin + 1) *
    1040        2295 :                 static_cast<T>(new_cb->gmax - new_cb->gmin + 1) *
    1041        2295 :                 static_cast<T>(new_cb->bmax - new_cb->bmin + 1) >
    1042             :             nPixels)
    1043             :     {
    1044         325 :         shrinkboxFromBand(new_cb, pabyRedBand, pabyGreenBand, pabyBlueBand,
    1045             :                           nPixels);
    1046             :     }
    1047        2247 :     else if (psHashHistogram != nullptr)
    1048             :     {
    1049        1748 :         shrinkboxFromHashHistogram(new_cb, psHashHistogram);
    1050             :     }
    1051             :     else
    1052             :     {
    1053         499 :         shrinkbox(new_cb, histogram, nCLevels);
    1054             :     }
    1055             : 
    1056        2572 :     if (nPixels != 0 && static_cast<T>(ptr->rmax - ptr->rmin + 1) *
    1057        2295 :                                 static_cast<T>(ptr->gmax - ptr->gmin + 1) *
    1058        2295 :                                 static_cast<T>(ptr->bmax - ptr->bmin + 1) >
    1059             :                             nPixels)
    1060             :     {
    1061         418 :         shrinkboxFromBand(ptr, pabyRedBand, pabyGreenBand, pabyBlueBand,
    1062             :                           nPixels);
    1063             :     }
    1064        2154 :     else if (psHashHistogram != nullptr)
    1065             :     {
    1066        1667 :         shrinkboxFromHashHistogram(ptr, psHashHistogram);
    1067             :     }
    1068             :     else
    1069             :     {
    1070         487 :         shrinkbox(ptr, histogram, nCLevels);
    1071             :     }
    1072        2572 : }
    1073             : 
    1074             : /************************************************************************/
    1075             : /*                             shrinkbox()                              */
    1076             : /************************************************************************/
    1077             : template <class T>
    1078         986 : static void shrinkbox(Colorbox *box, const T *histogram, int nCLevels)
    1079             : {
    1080         986 :     if (box->rmax > box->rmin)
    1081             :     {
    1082         972 :         for (int ir = box->rmin; ir <= box->rmax; ++ir)
    1083             :         {
    1084        7471 :             for (int ig = box->gmin; ig <= box->gmax; ++ig)
    1085             :             {
    1086             :                 const T *histp =
    1087        7202 :                     HISTOGRAM(histogram, nCLevels, ir, ig, box->bmin);
    1088      162688 :                 for (int ib = box->bmin; ib <= box->bmax; ++ib)
    1089             :                 {
    1090      156189 :                     if (*histp++ != 0)
    1091             :                     {
    1092         703 :                         box->rmin = ir;
    1093         703 :                         goto have_rmin;
    1094             :                     }
    1095             :                 }
    1096             :             }
    1097             :         }
    1098             :     }
    1099         283 : have_rmin:
    1100         986 :     if (box->rmax > box->rmin)
    1101             :     {
    1102        1384 :         for (int ir = box->rmax; ir >= box->rmin; --ir)
    1103             :         {
    1104       10381 :             for (int ig = box->gmin; ig <= box->gmax; ++ig)
    1105             :             {
    1106             :                 const T *histp =
    1107        9691 :                     HISTOGRAM(histogram, nCLevels, ir, ig, box->bmin);
    1108      261708 :                 for (int ib = box->bmin; ib <= box->bmax; ++ib)
    1109             :                 {
    1110      252711 :                     if (*histp++ != 0)
    1111             :                     {
    1112         694 :                         box->rmax = ir;
    1113         694 :                         goto have_rmax;
    1114             :                     }
    1115             :                 }
    1116             :             }
    1117             :         }
    1118             :     }
    1119             : 
    1120         292 : have_rmax:
    1121         986 :     if (box->gmax > box->gmin)
    1122             :     {
    1123        1173 :         for (int ig = box->gmin; ig <= box->gmax; ++ig)
    1124             :         {
    1125       10451 :             for (int ir = box->rmin; ir <= box->rmax; ++ir)
    1126             :             {
    1127             :                 const T *histp =
    1128        9963 :                     HISTOGRAM(histogram, nCLevels, ir, ig, box->bmin);
    1129      251615 :                 for (int ib = box->bmin; ib <= box->bmax; ++ib)
    1130             :                 {
    1131      242337 :                     if (*histp++ != 0)
    1132             :                     {
    1133         685 :                         box->gmin = ig;
    1134         685 :                         goto have_gmin;
    1135             :                     }
    1136             :                 }
    1137             :             }
    1138             :         }
    1139             :     }
    1140             : 
    1141         301 : have_gmin:
    1142         986 :     if (box->gmax > box->gmin)
    1143             :     {
    1144        1598 :         for (int ig = box->gmax; ig >= box->gmin; --ig)
    1145             :         {
    1146       17164 :             for (int ir = box->rmin; ir <= box->rmax; ++ir)
    1147             :             {
    1148             :                 const T *histp =
    1149       16244 :                     HISTOGRAM(histogram, nCLevels, ir, ig, box->bmin);
    1150      353961 :                 for (int ib = box->bmin; ib <= box->bmax; ++ib)
    1151             :                 {
    1152      338395 :                     if (*histp++ != 0)
    1153             :                     {
    1154         678 :                         box->gmax = ig;
    1155         678 :                         goto have_gmax;
    1156             :                     }
    1157             :                 }
    1158             :             }
    1159             :         }
    1160             :     }
    1161             : 
    1162         308 : have_gmax:
    1163         986 :     if (box->bmax > box->bmin)
    1164             :     {
    1165         939 :         for (int ib = box->bmin; ib <= box->bmax; ++ib)
    1166             :         {
    1167        5880 :             for (int ir = box->rmin; ir <= box->rmax; ++ir)
    1168             :             {
    1169             :                 const T *histp =
    1170        5642 :                     HISTOGRAM(histogram, nCLevels, ir, box->gmin, ib);
    1171      102928 :                 for (int ig = box->gmin; ig <= box->gmax; ++ig)
    1172             :                 {
    1173       97987 :                     if (*histp != 0)
    1174             :                     {
    1175         701 :                         box->bmin = ib;
    1176         701 :                         goto have_bmin;
    1177             :                     }
    1178       97286 :                     histp += nCLevels;
    1179             :                 }
    1180             :             }
    1181             :         }
    1182             :     }
    1183             : 
    1184         285 : have_bmin:
    1185         986 :     if (box->bmax > box->bmin)
    1186             :     {
    1187        1341 :         for (int ib = box->bmax; ib >= box->bmin; --ib)
    1188             :         {
    1189       10742 :             for (int ir = box->rmin; ir <= box->rmax; ++ir)
    1190             :             {
    1191             :                 const T *histp =
    1192       10083 :                     HISTOGRAM(histogram, nCLevels, ir, box->gmin, ib);
    1193      112931 :                 for (int ig = box->gmin; ig <= box->gmax; ++ig)
    1194             :                 {
    1195      103530 :                     if (*histp != 0)
    1196             :                     {
    1197         682 :                         box->bmax = ib;
    1198         682 :                         goto have_bmax;
    1199             :                     }
    1200      102848 :                     histp += nCLevels;
    1201             :                 }
    1202             :             }
    1203             :         }
    1204             :     }
    1205             : 
    1206         304 : have_bmax:;
    1207         986 : }
    1208             : 
    1209             : // Explicitly instantiate template functions.
    1210             : template int GDALComputeMedianCutPCTInternal<GUInt32>(
    1211             :     GDALRasterBandH hRed, GDALRasterBandH hGreen, GDALRasterBandH hBlue,
    1212             :     GByte *pabyRedBand, GByte *pabyGreenBand, GByte *pabyBlueBand,
    1213             :     int (*pfnIncludePixel)(int, int, void *), int nColors, int nBits,
    1214             :     GUInt32 *panHistogram, GDALColorTableH hColorTable,
    1215             :     GDALProgressFunc pfnProgress, void *pProgressArg);
    1216             : 
    1217             : template int GDALComputeMedianCutPCTInternal<GUIntBig>(
    1218             :     GDALRasterBandH hRed, GDALRasterBandH hGreen, GDALRasterBandH hBlue,
    1219             :     GByte *pabyRedBand, GByte *pabyGreenBand, GByte *pabyBlueBand,
    1220             :     int (*pfnIncludePixel)(int, int, void *), int nColors, int nBits,
    1221             :     GUIntBig *panHistogram, GDALColorTableH hColorTable,
    1222             :     GDALProgressFunc pfnProgress, void *pProgressArg);

Generated by: LCOV version 1.14