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