LCOV - code coverage report
Current view: top level - apps - gdalenhance.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 234 285 82.1 %
Date: 2025-11-11 01:53:33 Functions: 7 7 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL Utilities
       4             :  * Purpose:  Command line application to do image enhancement.
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  * ****************************************************************************
       8             :  * Copyright (c) 2007, Frank Warmerdam <warmerdam@pobox.com>
       9             :  * Copyright (c) 2007-2011, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "cpl_string.h"
      15             : #include "cpl_conv.h"
      16             : #include "cpl_multiproc.h"
      17             : #include "gdal_version.h"
      18             : #include "gdal.h"
      19             : #include "gdal_cpp_functions.h"
      20             : #include "vrtdataset.h"
      21             : #include "commonutils.h"
      22             : 
      23             : #include <algorithm>
      24             : 
      25             : static int ComputeEqualizationLUTs(GDALDatasetH hDataset, int nLUTBins,
      26             :                                    double **ppadfScaleMin,
      27             :                                    double **padfScaleMax, int ***ppapanLUTs,
      28             :                                    GDALProgressFunc pfnProgress);
      29             : 
      30             : static CPLErr ReadLUTs(const char *pszConfigFile, int nBandCount, int nLUTBins,
      31             :                        int ***ppapanLUTs, double **ppadfScaleMin,
      32             :                        double **ppadfScaleMax);
      33             : static void WriteLUTs(int **papanLUTs, int nBandCount, int nLUTBins,
      34             :                       double *padfScaleMin, double *padfScaleMax,
      35             :                       const char *pszConfigFile);
      36             : static CPLErr WriteEnhanced(GDALDatasetH hDataset, int **papanLUTs,
      37             :                             int nLUTBins, double *padfScaleMin,
      38             :                             double *padfScaleMax, GDALDataType eOutputType,
      39             :                             GDALDriverH hDriver, const char *pszDest,
      40             :                             char **papszCreateOptions,
      41             :                             GDALProgressFunc pfnProgress);
      42             : 
      43             : static CPLErr EnhancerCallback(void *hCBData, int nXOff, int nYOff, int nXSize,
      44             :                                int nYSize, void *pData);
      45             : 
      46             : typedef struct
      47             : {
      48             :     GDALRasterBand *poSrcBand;
      49             :     GDALDataType eWrkType;
      50             :     double dfScaleMin;
      51             :     double dfScaleMax;
      52             :     int nLUTBins;
      53             :     const int *panLUT;
      54             : } EnhanceCBInfo;
      55             : 
      56             : /* ******************************************************************** */
      57             : /*                               Usage()                                */
      58             : /* ******************************************************************** */
      59             : 
      60           1 : static void Usage()
      61             : 
      62             : {
      63           1 :     printf("Usage: gdalenhance [--help] [--help-general]\n"
      64             :            "       [-of <format>] [-co <NAME>=<VALUE>]...\n"
      65             :            "       [-ot {Byte/Int16/UInt16/UInt32/Int32/Float32/Float64/\n"
      66             :            "             CInt16/CInt32/CFloat32/CFloat64}]\n"
      67             :            //            "       [-src_scale[_n] src_min src_max]\n"
      68             :            //            "       [-dst_scale[_n] dst_min dst_max]\n"
      69             :            //            "       [-lutbins count]\n"
      70             :            //            "       [-s_nodata[_n] value]\n"
      71             :            //            "       [-stddev multiplier]\n"
      72             :            "       [-equalize]\n"
      73             :            "       [-config <filename>]\n"
      74             :            "       <src_dataset> <dst_dataset>\n\n");
      75           1 :     printf("%s\n\n", GDALVersionInfo("--version"));
      76           1 :     exit(1);
      77             : }
      78             : 
      79             : /************************************************************************/
      80             : /*                             ProxyMain()                              */
      81             : /************************************************************************/
      82             : 
      83          10 : MAIN_START(argc, argv)
      84             : 
      85             : {
      86          10 :     GDALDatasetH hDataset = nullptr;
      87          10 :     const char *pszSource = nullptr, *pszDest = nullptr, *pszFormat = nullptr;
      88          10 :     GDALDriverH hDriver = nullptr;
      89          10 :     GDALDataType eOutputType = GDT_Unknown;
      90          10 :     char **papszCreateOptions = nullptr;
      91          10 :     GDALProgressFunc pfnProgress = GDALTermProgress;
      92          10 :     int nBandCount = 0;
      93          10 :     int nLUTBins = 256;
      94          10 :     const char *pszMethod = "minmax";
      95             :     //    double              dfStdDevMult = 0.0;
      96          10 :     double *padfScaleMin = nullptr;
      97          10 :     double *padfScaleMax = nullptr;
      98          10 :     int **papanLUTs = nullptr;
      99          10 :     const char *pszConfigFile = nullptr;
     100          10 :     int nRetCode = 0;
     101             : 
     102             :     /* Check strict compilation and runtime library version as we use C++ API */
     103          10 :     if (!GDAL_CHECK_VERSION(argv[0]))
     104           0 :         exit(1);
     105             :     /* -------------------------------------------------------------------- */
     106             :     /*      Register standard GDAL drivers, and process generic GDAL        */
     107             :     /*      command options.                                                */
     108             :     /* -------------------------------------------------------------------- */
     109          10 :     GDALAllRegister();
     110          10 :     argc = GDALGeneralCmdLineProcessor(argc, &argv, 0);
     111          10 :     if (argc < 1)
     112             :     {
     113           1 :         GDALDestroyDriverManager();
     114           1 :         exit(0);
     115             :     }
     116             : 
     117             :     /* -------------------------------------------------------------------- */
     118             :     /*      Handle command line arguments.                                  */
     119             :     /* -------------------------------------------------------------------- */
     120          42 :     for (int i = 1; i < argc; i++)
     121             :     {
     122          33 :         if (EQUAL(argv[i], "--utility_version"))
     123             :         {
     124           0 :             printf("%s was compiled against GDAL %s and is running against "
     125             :                    "GDAL %s\n",
     126             :                    argv[0], GDAL_RELEASE_NAME, GDALVersionInfo("RELEASE_NAME"));
     127           0 :             goto exit;
     128             :         }
     129          33 :         else if (EQUAL(argv[i], "--help"))
     130             :         {
     131           0 :             Usage();
     132             :         }
     133          33 :         else if (i < argc - 1 &&
     134          27 :                  (EQUAL(argv[i], "-of") || EQUAL(argv[i], "-f")))
     135             :         {
     136           0 :             pszFormat = argv[++i];
     137             :         }
     138             : 
     139          33 :         else if (i < argc - 1 && EQUAL(argv[i], "-ot"))
     140             :         {
     141          17 :             for (int iType = 1; iType < GDT_TypeCount; iType++)
     142             :             {
     143          16 :                 if (GDALGetDataTypeName(static_cast<GDALDataType>(iType)) !=
     144          32 :                         nullptr &&
     145          16 :                     EQUAL(GDALGetDataTypeName(static_cast<GDALDataType>(iType)),
     146             :                           argv[i + 1]))
     147             :                 {
     148           1 :                     eOutputType = static_cast<GDALDataType>(iType);
     149             :                 }
     150             :             }
     151             : 
     152           1 :             if (eOutputType == GDT_Unknown)
     153             :             {
     154           0 :                 printf("Unknown output pixel type: %s\n", argv[i + 1]);
     155           0 :                 Usage();
     156             :             }
     157           1 :             i++;
     158             :         }
     159             : 
     160          32 :         else if (STARTS_WITH_CI(argv[i], "-s_nodata"))
     161             :         {
     162             :             // TODO
     163           0 :             i += 1;
     164             :         }
     165             : 
     166          32 :         else if (i < argc - 1 && EQUAL(argv[i], "-co"))
     167             :         {
     168           1 :             papszCreateOptions = CSLAddString(papszCreateOptions, argv[++i]);
     169             :         }
     170             : 
     171          31 :         else if (i < argc - 1 && STARTS_WITH_CI(argv[i], "-src_scale"))
     172             :         {
     173             :             // TODO
     174           0 :             i += 2;
     175             :         }
     176             : 
     177          31 :         else if (i < argc - 2 && STARTS_WITH_CI(argv[i], "-dst_scale"))
     178             :         {
     179             :             // TODO
     180           0 :             i += 2;
     181             :         }
     182             : 
     183          31 :         else if (i < argc - 1 && EQUAL(argv[i], "-config"))
     184             :         {
     185           5 :             pszConfigFile = argv[++i];
     186             :         }
     187             : 
     188          26 :         else if (EQUAL(argv[i], "-equalize"))
     189             :         {
     190           4 :             pszMethod = "equalize";
     191             :         }
     192             : 
     193          22 :         else if (EQUAL(argv[i], "-quiet"))
     194             :         {
     195           6 :             pfnProgress = GDALDummyProgress;
     196             :         }
     197             : 
     198          16 :         else if (argv[i][0] == '-')
     199             :         {
     200           0 :             printf("Option %s incomplete, or not recognised.\n\n", argv[i]);
     201           0 :             Usage();
     202             :         }
     203          16 :         else if (pszSource == nullptr)
     204             :         {
     205           9 :             pszSource = argv[i];
     206             :         }
     207           7 :         else if (pszDest == nullptr)
     208             :         {
     209           7 :             pszDest = argv[i];
     210             :         }
     211             : 
     212             :         else
     213             :         {
     214           0 :             printf("Too many command options.\n\n");
     215           0 :             Usage();
     216             :         }
     217             :     }
     218             : 
     219           9 :     if (pszSource == nullptr)
     220             :     {
     221           0 :         Usage();
     222             :     }
     223             : 
     224             :     /* -------------------------------------------------------------------- */
     225             :     /*      Attempt to open source file.                                    */
     226             :     /* -------------------------------------------------------------------- */
     227             : 
     228           9 :     hDataset = GDALOpenShared(pszSource, GA_ReadOnly);
     229             : 
     230           9 :     if (hDataset == nullptr)
     231             :     {
     232           0 :         fprintf(stderr, "GDALOpen failed - %d\n%s\n", CPLGetLastErrorNo(),
     233             :                 CPLGetLastErrorMsg());
     234           0 :         goto exit;
     235             :     }
     236             : 
     237           9 :     nBandCount = GDALGetRasterCount(hDataset);
     238             : 
     239             :     /* -------------------------------------------------------------------- */
     240             :     /*      Find the output driver.                                         */
     241             :     /* -------------------------------------------------------------------- */
     242             :     {
     243           9 :         CPLString osFormat;
     244           9 :         if (pszFormat == nullptr && pszDest != nullptr)
     245             :         {
     246           7 :             osFormat = GetOutputDriverForRaster(pszDest);
     247           7 :             if (osFormat.empty())
     248             :             {
     249           0 :                 GDALDestroyDriverManager();
     250           0 :                 exit(1);
     251             :             }
     252             :         }
     253           2 :         else if (pszFormat != nullptr)
     254             :         {
     255           0 :             osFormat = pszFormat;
     256             :         }
     257           9 :         if (EQUAL(osFormat.c_str(), "VRT"))
     258             :         {
     259           0 :             printf("Output format VRT is not supported\n");
     260           0 :             GDALDestroyDriverManager();
     261           0 :             exit(1);
     262             :         }
     263             : 
     264           9 :         if (!osFormat.empty())
     265             :         {
     266           7 :             hDriver = GDALGetDriverByName(osFormat);
     267           7 :             if (hDriver == nullptr)
     268             :             {
     269             :                 int iDr;
     270             : 
     271           0 :                 printf("Output driver `%s' not recognised.\n",
     272             :                        osFormat.c_str());
     273           0 :                 printf("The following format drivers are enabled and support "
     274             :                        "writing:\n");
     275           0 :                 for (iDr = 0; iDr < GDALGetDriverCount(); iDr++)
     276             :                 {
     277           0 :                     hDriver = GDALGetDriver(iDr);
     278             : 
     279           0 :                     if (GDALGetMetadataItem(hDriver, GDAL_DCAP_RASTER,
     280           0 :                                             nullptr) != nullptr &&
     281           0 :                         (GDALGetMetadataItem(hDriver, GDAL_DCAP_CREATE,
     282           0 :                                              nullptr) != nullptr ||
     283           0 :                          GDALGetMetadataItem(hDriver, GDAL_DCAP_CREATECOPY,
     284             :                                              nullptr) != nullptr))
     285             :                     {
     286           0 :                         printf("  %s: %s\n", GDALGetDriverShortName(hDriver),
     287             :                                GDALGetDriverLongName(hDriver));
     288             :                     }
     289             :                 }
     290           0 :                 printf("\n");
     291           0 :                 goto exit;
     292             :             }
     293             :         }
     294             :     }
     295             : 
     296             :     /* -------------------------------------------------------------------- */
     297             :     /*      If histogram equalization is requested, do it now.              */
     298             :     /* -------------------------------------------------------------------- */
     299           9 :     if (EQUAL(pszMethod, "equalize"))
     300             :     {
     301           4 :         ComputeEqualizationLUTs(hDataset, nLUTBins, &padfScaleMin,
     302             :                                 &padfScaleMax, &papanLUTs, pfnProgress);
     303             :     }
     304             : 
     305             :     /* -------------------------------------------------------------------- */
     306             :     /*      If we have a config file, assume it is for input and read       */
     307             :     /*      it.                                                             */
     308             :     /* -------------------------------------------------------------------- */
     309           5 :     else if (pszConfigFile != nullptr)
     310             :     {
     311           4 :         if (ReadLUTs(pszConfigFile, nBandCount, nLUTBins, &papanLUTs,
     312           4 :                      &padfScaleMin, &padfScaleMax) != CE_None)
     313             :         {
     314           2 :             nRetCode = 1;
     315           2 :             goto exit;
     316             :         }
     317             :     }
     318             : 
     319           7 :     if (padfScaleMin == nullptr || padfScaleMax == nullptr)
     320             :     {
     321           1 :         fprintf(stderr, "-equalize or -config filename command line options "
     322             :                         "must be specified.\n");
     323           1 :         Usage();
     324             :     }
     325             : 
     326             :     /* -------------------------------------------------------------------- */
     327             :     /*      If there is no destination, just report the scaling values      */
     328             :     /*      and luts.                                                       */
     329             :     /* -------------------------------------------------------------------- */
     330           6 :     if (pszDest == nullptr)
     331             :     {
     332           2 :         WriteLUTs(papanLUTs, nBandCount, nLUTBins, padfScaleMin, padfScaleMax,
     333             :                   pszConfigFile);
     334             :     }
     335             :     else
     336             :     {
     337           4 :         if (WriteEnhanced(hDataset, papanLUTs, nLUTBins, padfScaleMin,
     338             :                           padfScaleMax, eOutputType, hDriver, pszDest,
     339           4 :                           papszCreateOptions, pfnProgress) != CE_None)
     340             :         {
     341           1 :             nRetCode = 1;
     342             :         }
     343             :     }
     344             : 
     345             :     /* -------------------------------------------------------------------- */
     346             :     /*      Cleanup and exit.                                               */
     347             :     /* -------------------------------------------------------------------- */
     348           3 : exit:
     349           8 :     GDALClose(hDataset);
     350           8 :     GDALDumpOpenDatasets(stderr);
     351           8 :     GDALDestroyDriverManager();
     352           8 :     CSLDestroy(argv);
     353           8 :     CSLDestroy(papszCreateOptions);
     354           8 :     if (papanLUTs)
     355             :     {
     356          28 :         for (int iBand = 0; iBand < nBandCount; iBand++)
     357             :         {
     358          21 :             CPLFree(papanLUTs[iBand]);
     359             :         }
     360           7 :         CPLFree(papanLUTs);
     361             :     }
     362           8 :     CPLFree(padfScaleMin);
     363           8 :     CPLFree(padfScaleMax);
     364             : 
     365           8 :     exit(nRetCode);
     366             : }
     367             : 
     368           0 : MAIN_END
     369             : 
     370             : /************************************************************************/
     371             : /*                      ComputeEqualizationLUTs()                       */
     372             : /*                                                                      */
     373             : /*      Get an image histogram, and compute equalization luts from      */
     374             : /*      it.                                                             */
     375             : /************************************************************************/
     376             : 
     377           4 : static int ComputeEqualizationLUTs(GDALDatasetH hDataset, int nLUTBins,
     378             :                                    double **ppadfScaleMin,
     379             :                                    double **ppadfScaleMax, int ***ppapanLUTs,
     380             :                                    GDALProgressFunc pfnProgress)
     381             : 
     382             : {
     383           4 :     int nBandCount = GDALGetRasterCount(hDataset);
     384             : 
     385             :     // For now we always compute min/max
     386           4 :     *ppadfScaleMin =
     387           4 :         static_cast<double *>(CPLCalloc(sizeof(double), nBandCount));
     388           4 :     *ppadfScaleMax =
     389           4 :         static_cast<double *>(CPLCalloc(sizeof(double), nBandCount));
     390             : 
     391           4 :     *ppapanLUTs = static_cast<int **>(CPLCalloc(sizeof(int *), nBandCount));
     392             : 
     393             :     /* ==================================================================== */
     394             :     /*      Process all bands.                                              */
     395             :     /* ==================================================================== */
     396          16 :     for (int iBand = 0; iBand < nBandCount; iBand++)
     397             :     {
     398          12 :         GDALRasterBandH hBand = GDALGetRasterBand(hDataset, iBand + 1);
     399          12 :         GUIntBig *panHistogram = nullptr;
     400          12 :         int nHistSize = 0;
     401             : 
     402             :         /* ----------------------------------------------------------------- */
     403             :         /*      Get a reasonable histogram.                                  */
     404             :         /* ----------------------------------------------------------------- */
     405          24 :         const CPLErr eErr = GDALGetDefaultHistogramEx(
     406          12 :             hBand, *ppadfScaleMin + iBand, *ppadfScaleMax + iBand, &nHistSize,
     407             :             &panHistogram, TRUE, pfnProgress, nullptr);
     408             : 
     409          12 :         if (eErr != CE_None)
     410           0 :             return FALSE;
     411             : 
     412          12 :         panHistogram[0] = 0;  // zero out extremes (nodata, etc)
     413          12 :         panHistogram[nHistSize - 1] = 0;
     414             : 
     415             :         /* ----------------------------------------------------------------- */
     416             :         /*      Total histogram count, and build cumulative histogram.       */
     417             :         /*      We take care to use big integers as there may be more than 4 */
     418             :         /*      Gigapixels.                                                  */
     419             :         /* ----------------------------------------------------------------- */
     420             :         GUIntBig *panCumHist = static_cast<GUIntBig *>(
     421          12 :             VSI_CALLOC_VERBOSE(sizeof(GUIntBig), nHistSize));
     422          12 :         if (!panCumHist)
     423           0 :             return FALSE;
     424          12 :         GUIntBig nTotal = 0;
     425             : 
     426        3084 :         for (int iHist = 0; iHist < nHistSize; iHist++)
     427             :         {
     428        3072 :             panCumHist[iHist] = nTotal + panHistogram[iHist] / 2;
     429        3072 :             nTotal += panHistogram[iHist];
     430             :         }
     431             : 
     432          12 :         CPLFree(panHistogram);
     433             : 
     434          12 :         if (nTotal == 0)
     435             :         {
     436           0 :             CPLError(CE_Warning, CPLE_AppDefined,
     437             :                      "Zero value entries in histogram, results will not be "
     438             :                      "meaningful.");
     439           0 :             nTotal = 1;
     440             :         }
     441             : 
     442             :         /* ----------------------------------------------------------------- */
     443             :         /*      Now compute a LUT from the cumulative histogram.             */
     444             :         /* ----------------------------------------------------------------- */
     445             :         int *panLUT =
     446          12 :             static_cast<int *>(VSI_CALLOC_VERBOSE(sizeof(int), nLUTBins));
     447          12 :         if (!panLUT)
     448             :         {
     449           0 :             CPLFree(panCumHist);
     450           0 :             return FALSE;
     451             :         }
     452             : 
     453        3084 :         for (int iLUT = 0; iLUT < nLUTBins; iLUT++)
     454             :         {
     455        3072 :             const int iHist = static_cast<int>(
     456        3072 :                 (static_cast<int64_t>(iLUT) * nHistSize) / nLUTBins);
     457        3072 :             const int nValue =
     458        3072 :                 static_cast<int>((panCumHist[iHist] * nLUTBins) / nTotal);
     459             : 
     460        3072 :             panLUT[iLUT] = std::max(0, std::min(nLUTBins - 1, nValue));
     461             :         }
     462             : 
     463          12 :         CPLFree(panCumHist);
     464             : 
     465          12 :         (*ppapanLUTs)[iBand] = panLUT;
     466             :     }
     467             : 
     468           4 :     return TRUE;
     469             : }
     470             : 
     471             : /************************************************************************/
     472             : /*                          EnhancerCallback()                          */
     473             : /*                                                                      */
     474             : /*      This is the VRT callback that actually does the image rescaling.*/
     475             : /************************************************************************/
     476             : 
     477          10 : static CPLErr EnhancerCallback(void *hCBData, int nXOff, int nYOff, int nXSize,
     478             :                                int nYSize, void *pData)
     479             : 
     480             : {
     481          10 :     const EnhanceCBInfo *psEInfo = static_cast<const EnhanceCBInfo *>(hCBData);
     482             : 
     483          10 :     if (psEInfo->eWrkType != GDT_Byte)
     484             :     {
     485           1 :         CPLError(CE_Failure, CPLE_AppDefined,
     486             :                  "Currently gdalenhance only supports Byte output.");
     487           1 :         return CE_Failure;
     488             :     }
     489             : 
     490           9 :     GByte *pabyOutImage = static_cast<GByte *>(pData);
     491             :     float *pafSrcImage = static_cast<float *>(
     492           9 :         VSI_MALLOC3_VERBOSE(sizeof(float), nXSize, nYSize));
     493           9 :     if (!pafSrcImage)
     494           0 :         return CE_Failure;
     495             : 
     496           9 :     CPLErr eErr = psEInfo->poSrcBand->RasterIO(
     497             :         GF_Read, nXOff, nYOff, nXSize, nYSize, pafSrcImage, nXSize, nYSize,
     498             :         GDT_Float32, 0, 0, nullptr);
     499             : 
     500           9 :     if (eErr != CE_None)
     501             :     {
     502           0 :         CPLFree(pafSrcImage);
     503           0 :         return eErr;
     504             :     }
     505             : 
     506           9 :     const size_t nPixelCount = static_cast<size_t>(nXSize) * nYSize;
     507             :     int bHaveNoData;
     508             :     const float fNoData =
     509           9 :         static_cast<float>(psEInfo->poSrcBand->GetNoDataValue(&bHaveNoData));
     510           9 :     const double dfScale =
     511           9 :         psEInfo->nLUTBins / (psEInfo->dfScaleMax - psEInfo->dfScaleMin);
     512             : 
     513       22509 :     for (size_t iPixel = 0; iPixel < nPixelCount; iPixel++)
     514             :     {
     515       22500 :         if (bHaveNoData && pafSrcImage[iPixel] == fNoData)
     516             :         {
     517           0 :             pabyOutImage[iPixel] = static_cast<GByte>(fNoData);
     518           0 :             continue;
     519             :         }
     520             : 
     521       22500 :         const double dfBin =
     522       22500 :             (pafSrcImage[iPixel] - psEInfo->dfScaleMin) * dfScale;
     523       22500 :         int iBin = 0;
     524       22500 :         if (!(dfBin > 0))
     525             :         {
     526             :             // nothing to do
     527             :         }
     528       22500 :         else if (!(dfBin < psEInfo->nLUTBins - 1))
     529             :         {
     530           0 :             iBin = psEInfo->nLUTBins - 1;
     531             :         }
     532             :         else
     533             :         {
     534       22500 :             iBin = static_cast<int>(dfBin);
     535             :         }
     536             : 
     537       22500 :         if (psEInfo->panLUT)
     538       22500 :             pabyOutImage[iPixel] = static_cast<GByte>(psEInfo->panLUT[iBin]);
     539             :         else
     540           0 :             pabyOutImage[iPixel] = static_cast<GByte>(iBin);
     541             :     }
     542             : 
     543           9 :     CPLFree(pafSrcImage);
     544             : 
     545           9 :     return CE_None;
     546             : }
     547             : 
     548             : /************************************************************************/
     549             : /*                      ReadLUTs()                                      */
     550             : /*                                                                      */
     551             : /*               Read a LUT for each band from a file.                  */
     552             : /************************************************************************/
     553             : 
     554           4 : CPLErr ReadLUTs(const char *pszConfigFile, int nBandCount, int nLUTBins,
     555             :                 int ***ppapanLUTs, double **ppadfScaleMin,
     556             :                 double **ppadfScaleMax)
     557             : {
     558           8 :     const CPLStringList aosLines(CSLLoad(pszConfigFile));
     559             : 
     560           4 :     if (aosLines.size() != nBandCount)
     561             :     {
     562           1 :         CPLError(CE_Failure, CPLE_AppDefined,
     563             :                  "Did not get %d lines in config file as expected.\n",
     564             :                  nBandCount);
     565           1 :         return CE_Failure;
     566             :     }
     567             : 
     568           3 :     *ppadfScaleMin =
     569           3 :         static_cast<double *>(CPLCalloc(nBandCount, sizeof(double)));
     570           3 :     *ppadfScaleMax =
     571           3 :         static_cast<double *>(CPLCalloc(nBandCount, sizeof(double)));
     572           3 :     *ppapanLUTs = static_cast<int **>(CPLCalloc(sizeof(int *), nBandCount));
     573             : 
     574          10 :     for (int iBand = 0; iBand < nBandCount; iBand++)
     575             :     {
     576           8 :         const CPLStringList aosTokens(CSLTokenizeString(aosLines[iBand]));
     577             : 
     578          15 :         if (aosTokens.size() < (nLUTBins + 3) ||
     579           7 :             atoi(aosTokens[0]) != iBand + 1)
     580             :         {
     581           1 :             CPLError(CE_Failure, CPLE_AppDefined,
     582             :                      "Line %d seems to be corrupt.\n", iBand + 1);
     583           1 :             return CE_Failure;
     584             :         }
     585             : 
     586             :         // Process scale min/max
     587             : 
     588           7 :         (*ppadfScaleMin)[iBand] = CPLAtof(aosTokens[1]);
     589           7 :         (*ppadfScaleMax)[iBand] = CPLAtof(aosTokens[2]);
     590             : 
     591             :         // process lut
     592             : 
     593          14 :         (*ppapanLUTs)[iBand] =
     594           7 :             static_cast<int *>(CPLCalloc(nLUTBins, sizeof(int)));
     595             : 
     596        1799 :         for (int iLUT = 0; iLUT < nLUTBins; iLUT++)
     597        1792 :             (*ppapanLUTs)[iBand][iLUT] = atoi(aosTokens[iLUT + 3]);
     598             :     }
     599             : 
     600           2 :     return CE_None;
     601             : }
     602             : 
     603             : /************************************************************************/
     604             : /*                      WriteLUTs()                                     */
     605             : /*                                                                      */
     606             : /*      Write the LUT for each band to a file or stdout.                */
     607             : /************************************************************************/
     608             : 
     609           2 : void WriteLUTs(int **papanLUTs, int nBandCount, int nLUTBins,
     610             :                double *padfScaleMin, double *padfScaleMax,
     611             :                const char *pszConfigFile)
     612             : {
     613           2 :     FILE *fpConfig = stdout;
     614           2 :     if (pszConfigFile)
     615           1 :         fpConfig = fopen(pszConfigFile, "w");
     616             : 
     617           8 :     for (int iBand = 0; iBand < nBandCount; iBand++)
     618             :     {
     619           6 :         fprintf(fpConfig, "%d:Band ", iBand + 1);
     620           6 :         fprintf(fpConfig, "%g:ScaleMin %g:ScaleMax ", padfScaleMin[iBand],
     621           6 :                 padfScaleMax[iBand]);
     622             : 
     623           6 :         if (papanLUTs)
     624             :         {
     625        1542 :             for (int iLUT = 0; iLUT < nLUTBins; iLUT++)
     626        1536 :                 fprintf(fpConfig, "%d ", papanLUTs[iBand][iLUT]);
     627             :         }
     628           6 :         fprintf(fpConfig, "\n");
     629             :     }
     630             : 
     631           2 :     if (pszConfigFile)
     632           1 :         fclose(fpConfig);
     633           2 : }
     634             : 
     635             : /************************************************************************/
     636             : /*                      WriteEnhanced()                                 */
     637             : /*                                                                      */
     638             : /*      Write an enhanced image using the provided LUTs.                */
     639             : /************************************************************************/
     640             : 
     641           4 : CPLErr WriteEnhanced(GDALDatasetH hDataset, int **papanLUTs, int nLUTBins,
     642             :                      double *padfScaleMin, double *padfScaleMax,
     643             :                      GDALDataType eOutputType, GDALDriverH hDriver,
     644             :                      const char *pszDest, char **papszCreateOptions,
     645             :                      GDALProgressFunc pfnProgress)
     646             : {
     647           4 :     int nBandCount = GDALGetRasterCount(hDataset);
     648             : 
     649             :     EnhanceCBInfo *pasEInfo = static_cast<EnhanceCBInfo *>(
     650           4 :         CPLCalloc(nBandCount, sizeof(EnhanceCBInfo)));
     651             : 
     652             :     /* -------------------------------------------------------------------- */
     653             :     /*      Make a virtual clone.                                           */
     654             :     /* -pixe------------------------------------------------------------------- */
     655           4 :     VRTDataset *poVDS = new VRTDataset(GDALGetRasterXSize(hDataset),
     656           4 :                                        GDALGetRasterYSize(hDataset));
     657             : 
     658           4 :     if (GDALGetGCPCount(hDataset) == 0)
     659             :     {
     660           4 :         const char *pszProjection = GDALGetProjectionRef(hDataset);
     661           4 :         if (pszProjection != nullptr && strlen(pszProjection) > 0)
     662           4 :             poVDS->SetProjection(pszProjection);
     663             : 
     664           4 :         GDALGeoTransform gt;
     665           4 :         if (GDALDataset::FromHandle(hDataset)->GetGeoTransform(gt) == CE_None)
     666           4 :             poVDS->SetGeoTransform(gt);
     667             :     }
     668             :     else
     669             :     {
     670           0 :         poVDS->SetGCPs(GDALGetGCPCount(hDataset), GDALGetGCPs(hDataset),
     671             :                        GDALGetGCPProjection(hDataset));
     672             :     }
     673             : 
     674           4 :     poVDS->SetMetadata(GDALDataset::FromHandle(hDataset)->GetMetadata());
     675             : 
     676          16 :     for (int iBand = 0; iBand < nBandCount; iBand++)
     677             :     {
     678             :         VRTSourcedRasterBand *poVRTBand;
     679             :         GDALRasterBand *poSrcBand;
     680             :         GDALDataType eBandType;
     681             : 
     682          12 :         poSrcBand = GDALDataset::FromHandle(hDataset)->GetRasterBand(iBand + 1);
     683             : 
     684             :         /* ---------------------------------------------------------------- */
     685             :         /*      Select output data type to match source.                    */
     686             :         /* ---------------------------------------------------------------- */
     687          12 :         if (eOutputType == GDT_Unknown)
     688           9 :             eBandType = GDT_Byte;
     689             :         else
     690           3 :             eBandType = eOutputType;
     691             : 
     692             :         /* ---------------------------------------------------------------- */
     693             :         /*      Create this band.                                           */
     694             :         /* ---------------------------------------------------------------- */
     695          12 :         poVDS->AddBand(eBandType, nullptr);
     696          12 :         poVRTBand = cpl::down_cast<VRTSourcedRasterBand *>(
     697             :             poVDS->GetRasterBand(iBand + 1));
     698             : 
     699             :         /* ---------------------------------------------------------------- */
     700             :         /*     Create a function based source with info on how to apply the */
     701             :         /*     enhancement.                                                 */
     702             :         /* ---------------------------------------------------------------- */
     703          12 :         pasEInfo[iBand].poSrcBand = poSrcBand;
     704          12 :         pasEInfo[iBand].eWrkType = eBandType;
     705          12 :         pasEInfo[iBand].dfScaleMin = padfScaleMin[iBand];
     706          12 :         pasEInfo[iBand].dfScaleMax = padfScaleMax[iBand];
     707          12 :         pasEInfo[iBand].nLUTBins = nLUTBins;
     708             : 
     709          12 :         if (papanLUTs)
     710          12 :             pasEInfo[iBand].panLUT = papanLUTs[iBand];
     711             : 
     712          12 :         poVRTBand->AddFuncSource(EnhancerCallback, pasEInfo + iBand);
     713             : 
     714             :         /* ---------------------------------------------------------------- */
     715             :         /*      copy over some other information of interest.               */
     716             :         /* ---------------------------------------------------------------- */
     717          12 :         poVRTBand->SetColorInterpretation(poSrcBand->GetColorInterpretation());
     718          12 :         if (strlen(poSrcBand->GetDescription()) > 0)
     719           0 :             poVRTBand->SetDescription(poSrcBand->GetDescription());
     720          12 :         if (poSrcBand->GetRasterDataType() == poVRTBand->GetRasterDataType())
     721           9 :             GDALCopyNoDataValue(poVRTBand, poSrcBand);
     722             :     }
     723             : 
     724             :     /* -------------------------------------------------------------------- */
     725             :     /*      Write to the output file using CopyCreate().                    */
     726             :     /* -------------------------------------------------------------------- */
     727             :     GDALDatasetH hOutDS =
     728           4 :         GDALCreateCopy(hDriver, pszDest, static_cast<GDALDatasetH>(poVDS),
     729             :                        FALSE, papszCreateOptions, pfnProgress, nullptr);
     730           4 :     CPLErr eErr = CE_None;
     731           4 :     if (hOutDS == nullptr)
     732             :     {
     733           1 :         eErr = CE_Failure;
     734             :     }
     735             :     else
     736             :     {
     737           3 :         GDALClose(hOutDS);
     738             :     }
     739             : 
     740           4 :     GDALClose(poVDS);
     741           4 :     CPLFree(pasEInfo);
     742             : 
     743           4 :     return eErr;
     744             : }

Generated by: LCOV version 1.14