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

Generated by: LCOV version 1.14