Coverage Report

Created: 2025-08-28 06:57

/src/gdal/alg/gdalpansharpen.cpp
Line
Count
Source (jump to first uncovered line)
1
/******************************************************************************
2
 *
3
 * Project:  GDAL Pansharpening module
4
 * Purpose:  Implementation of pansharpening.
5
 * Author:   Even Rouault <even.rouault at spatialys.com>
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2015, Even Rouault <even.rouault at spatialys.com>
9
 * Copyright (c) 2015, Airbus DS Geo SA (weighted Brovey algorithm)
10
 *
11
 * SPDX-License-Identifier: MIT
12
 ****************************************************************************/
13
14
#include "cpl_port.h"
15
#include "cpl_worker_thread_pool.h"
16
#include "gdalpansharpen.h"
17
18
#include <algorithm>
19
#include <array>
20
#include <cstddef>
21
#include <cstdio>
22
#include <cstdlib>
23
#include <cstring>
24
#include <limits>
25
#include <new>
26
27
#include "cpl_conv.h"
28
#include "cpl_error.h"
29
#include "cpl_float.h"
30
#include "cpl_multiproc.h"
31
#include "cpl_vsi.h"
32
#include "../frmts/mem/memdataset.h"
33
#include "../frmts/vrt/vrtdataset.h"
34
#include "gdal_priv.h"
35
#include "gdal_priv_templates.hpp"
36
// #include "gdalsse_priv.h"
37
38
// Limit types to practical use cases.
39
#define LIMIT_TYPES 1
40
41
/************************************************************************/
42
/*                     GDALCreatePansharpenOptions()                    */
43
/************************************************************************/
44
45
/** Create pansharpening options.
46
 *
47
 * @return a newly allocated pansharpening option structure that must be freed
48
 * with GDALDestroyPansharpenOptions().
49
 *
50
 * @since GDAL 2.1
51
 */
52
53
GDALPansharpenOptions *GDALCreatePansharpenOptions()
54
0
{
55
0
    GDALPansharpenOptions *psOptions = static_cast<GDALPansharpenOptions *>(
56
0
        CPLCalloc(1, sizeof(GDALPansharpenOptions)));
57
0
    psOptions->ePansharpenAlg = GDAL_PSH_WEIGHTED_BROVEY;
58
0
    psOptions->eResampleAlg = GRIORA_Cubic;
59
0
    return psOptions;
60
0
}
61
62
/************************************************************************/
63
/*                     GDALDestroyPansharpenOptions()                   */
64
/************************************************************************/
65
66
/** Destroy pansharpening options.
67
 *
68
 * @param psOptions a pansharpening option structure allocated with
69
 * GDALCreatePansharpenOptions()
70
 *
71
 * @since GDAL 2.1
72
 */
73
74
void GDALDestroyPansharpenOptions(GDALPansharpenOptions *psOptions)
75
0
{
76
0
    if (psOptions == nullptr)
77
0
        return;
78
0
    CPLFree(psOptions->padfWeights);
79
0
    CPLFree(psOptions->pahInputSpectralBands);
80
0
    CPLFree(psOptions->panOutPansharpenedBands);
81
0
    CPLFree(psOptions);
82
0
}
83
84
/************************************************************************/
85
/*                      GDALClonePansharpenOptions()                    */
86
/************************************************************************/
87
88
/** Clone pansharpening options.
89
 *
90
 * @param psOptions a pansharpening option structure allocated with
91
 * GDALCreatePansharpenOptions()
92
 * @return a newly allocated pansharpening option structure that must be freed
93
 * with GDALDestroyPansharpenOptions().
94
 *
95
 * @since GDAL 2.1
96
 */
97
98
GDALPansharpenOptions *
99
GDALClonePansharpenOptions(const GDALPansharpenOptions *psOptions)
100
0
{
101
0
    GDALPansharpenOptions *psNewOptions = GDALCreatePansharpenOptions();
102
0
    psNewOptions->ePansharpenAlg = psOptions->ePansharpenAlg;
103
0
    psNewOptions->eResampleAlg = psOptions->eResampleAlg;
104
0
    psNewOptions->nBitDepth = psOptions->nBitDepth;
105
0
    psNewOptions->nWeightCount = psOptions->nWeightCount;
106
0
    if (psOptions->padfWeights)
107
0
    {
108
0
        psNewOptions->padfWeights = static_cast<double *>(
109
0
            CPLMalloc(sizeof(double) * psOptions->nWeightCount));
110
0
        memcpy(psNewOptions->padfWeights, psOptions->padfWeights,
111
0
               sizeof(double) * psOptions->nWeightCount);
112
0
    }
113
0
    psNewOptions->hPanchroBand = psOptions->hPanchroBand;
114
0
    psNewOptions->nInputSpectralBands = psOptions->nInputSpectralBands;
115
0
    if (psOptions->pahInputSpectralBands)
116
0
    {
117
0
        const size_t nSize =
118
0
            sizeof(GDALRasterBandH) * psOptions->nInputSpectralBands;
119
0
        psNewOptions->pahInputSpectralBands =
120
0
            static_cast<GDALRasterBandH *>(CPLMalloc(nSize));
121
0
        memcpy(psNewOptions->pahInputSpectralBands,
122
0
               psOptions->pahInputSpectralBands, nSize);
123
0
    }
124
0
    psNewOptions->nOutPansharpenedBands = psOptions->nOutPansharpenedBands;
125
0
    if (psOptions->panOutPansharpenedBands)
126
0
    {
127
0
        psNewOptions->panOutPansharpenedBands = static_cast<int *>(
128
0
            CPLMalloc(sizeof(int) * psOptions->nOutPansharpenedBands));
129
0
        memcpy(psNewOptions->panOutPansharpenedBands,
130
0
               psOptions->panOutPansharpenedBands,
131
0
               sizeof(int) * psOptions->nOutPansharpenedBands);
132
0
    }
133
0
    psNewOptions->bHasNoData = psOptions->bHasNoData;
134
0
    psNewOptions->dfNoData = psOptions->dfNoData;
135
0
    psNewOptions->nThreads = psOptions->nThreads;
136
0
    return psNewOptions;
137
0
}
138
139
/************************************************************************/
140
/*                        GDALPansharpenOperation()                     */
141
/************************************************************************/
142
143
/** Pansharpening operation constructor.
144
 *
145
 * The object is ready to be used after Initialize() has been called.
146
 */
147
0
GDALPansharpenOperation::GDALPansharpenOperation() = default;
148
149
/************************************************************************/
150
/*                       ~GDALPansharpenOperation()                     */
151
/************************************************************************/
152
153
/** Pansharpening operation destructor.
154
 */
155
156
GDALPansharpenOperation::~GDALPansharpenOperation()
157
0
{
158
0
    GDALDestroyPansharpenOptions(psOptions);
159
0
    for (size_t i = 0; i < aVDS.size(); i++)
160
0
        delete aVDS[i];
161
0
    delete poThreadPool;
162
0
}
163
164
/************************************************************************/
165
/*                              Initialize()                            */
166
/************************************************************************/
167
168
/** Initialize the pansharpening operation.
169
 *
170
 * @param psOptionsIn pansharpening options. Must not be NULL.
171
 *
172
 * @return CE_None in case of success, CE_Failure in case of failure.
173
 */
174
CPLErr
175
GDALPansharpenOperation::Initialize(const GDALPansharpenOptions *psOptionsIn)
176
0
{
177
0
    if (psOptionsIn->hPanchroBand == nullptr)
178
0
    {
179
0
        CPLError(CE_Failure, CPLE_AppDefined, "hPanchroBand not set");
180
0
        return CE_Failure;
181
0
    }
182
0
    if (psOptionsIn->nInputSpectralBands <= 0)
183
0
    {
184
0
        CPLError(CE_Failure, CPLE_AppDefined,
185
0
                 "No input spectral bands defined");
186
0
        return CE_Failure;
187
0
    }
188
0
    if (psOptionsIn->padfWeights == nullptr ||
189
0
        psOptionsIn->nWeightCount != psOptionsIn->nInputSpectralBands)
190
0
    {
191
0
        CPLError(CE_Failure, CPLE_AppDefined,
192
0
                 "No weights defined, or not the same number as input "
193
0
                 "spectral bands");
194
0
        return CE_Failure;
195
0
    }
196
197
0
    auto poPanchroBand = GDALRasterBand::FromHandle(psOptionsIn->hPanchroBand);
198
0
    auto poPanchroDS = poPanchroBand->GetDataset();
199
0
    if (poPanchroDS == nullptr)
200
0
    {
201
0
        CPLError(CE_Failure, CPLE_AppDefined,
202
0
                 "Cannot retrieve dataset associated with hPanchroBand");
203
0
        return CE_Failure;
204
0
    }
205
    // Make sure that the band is really a first level child of the owning dataset
206
0
    if (poPanchroDS->GetRasterBand(poPanchroBand->GetBand()) != poPanchroBand)
207
0
    {
208
0
        CPLError(CE_Failure, CPLE_AppDefined,
209
0
                 "poPanchroDS->GetRasterBand(poPanchroBand->GetBand()) != "
210
0
                 "poPanchroBand");
211
0
        return CE_Failure;
212
0
    }
213
0
    GDALGeoTransform panchroGT;
214
0
    if (poPanchroDS->GetGeoTransform(panchroGT) != CE_None)
215
0
    {
216
0
        CPLError(CE_Failure, CPLE_AppDefined,
217
0
                 "Panchromatic band has no associated geotransform");
218
0
        return CE_Failure;
219
0
    }
220
221
0
    GDALRasterBandH hRefBand = psOptionsIn->pahInputSpectralBands[0];
222
0
    auto poRefBand = GDALRasterBand::FromHandle(hRefBand);
223
0
    auto poRefBandDS = poRefBand->GetDataset();
224
0
    if (poRefBandDS == nullptr)
225
0
    {
226
0
        CPLError(
227
0
            CE_Failure, CPLE_AppDefined,
228
0
            "Cannot retrieve dataset associated with ahInputSpectralBands[0]");
229
0
        return CE_Failure;
230
0
    }
231
    // Make sure that the band is really a first level child of the owning dataset
232
0
    if (poRefBandDS->GetRasterBand(poRefBand->GetBand()) != poRefBand)
233
0
    {
234
0
        CPLError(
235
0
            CE_Failure, CPLE_AppDefined,
236
0
            "poRefBandDS->GetRasterBand(poRefBand->GetBand()) != poRefBand");
237
0
        return CE_Failure;
238
0
    }
239
240
0
    GDALGeoTransform refMSGT;
241
0
    if (poRefBandDS->GetGeoTransform(refMSGT) != CE_None)
242
0
    {
243
0
        CPLError(CE_Failure, CPLE_AppDefined,
244
0
                 "ahInputSpectralBands[0] band has no associated geotransform");
245
0
        return CE_Failure;
246
0
    }
247
248
0
    GDALGeoTransform invMSGT;
249
0
    if (!refMSGT.GetInverse(invMSGT))
250
0
    {
251
0
        CPLError(CE_Failure, CPLE_AppDefined,
252
0
                 "ahInputSpectralBands[0] geotransform is not invertible");
253
0
        return CE_Failure;
254
0
    }
255
256
    // Do InvMSGT * PanchroGT multiplication
257
0
    m_panToMSGT[1] = invMSGT[1] * panchroGT[1] + invMSGT[2] * panchroGT[4];
258
0
    m_panToMSGT[2] = invMSGT[1] * panchroGT[2] + invMSGT[2] * panchroGT[5];
259
0
    m_panToMSGT[0] =
260
0
        invMSGT[1] * panchroGT[0] + invMSGT[2] * panchroGT[3] + invMSGT[0];
261
0
    m_panToMSGT[4] = invMSGT[4] * panchroGT[1] + invMSGT[5] * panchroGT[4];
262
0
    m_panToMSGT[5] = invMSGT[4] * panchroGT[2] + invMSGT[5] * panchroGT[5];
263
0
    m_panToMSGT[3] =
264
0
        invMSGT[4] * panchroGT[0] + invMSGT[5] * panchroGT[3] + invMSGT[3];
265
#if 0
266
    CPLDebug("GDAL", "m_panToMSGT[] = %g %g %g %g %g %g",
267
           m_panToMSGT[0], m_panToMSGT[1], m_panToMSGT[2],
268
           m_panToMSGT[3], m_panToMSGT[4], m_panToMSGT[5]);
269
#endif
270
0
    if (std::fabs(m_panToMSGT[2]) > 1e-10 || std::fabs(m_panToMSGT[4]) > 1e-10)
271
0
    {
272
0
        CPLError(CE_Failure, CPLE_NotSupported,
273
0
                 "Composition of panchromatic and multispectral geotransform "
274
0
                 "has rotational terms");
275
0
        return CE_Failure;
276
0
    }
277
278
0
    bool bSameDataset = psOptionsIn->nInputSpectralBands > 1;
279
0
    if (bSameDataset)
280
0
        anInputBands.push_back(GDALGetBandNumber(hRefBand));
281
0
    for (int i = 1; i < psOptionsIn->nInputSpectralBands; i++)
282
0
    {
283
0
        GDALRasterBandH hBand = psOptionsIn->pahInputSpectralBands[i];
284
0
        if (GDALGetRasterBandXSize(hBand) != GDALGetRasterBandXSize(hRefBand) ||
285
0
            GDALGetRasterBandYSize(hBand) != GDALGetRasterBandYSize(hRefBand))
286
0
        {
287
0
            CPLError(CE_Failure, CPLE_AppDefined,
288
0
                     "Dimensions of input spectral band %d different from "
289
0
                     "first spectral band",
290
0
                     i + 1);
291
0
            return CE_Failure;
292
0
        }
293
294
0
        auto poBand = GDALRasterBand::FromHandle(hBand);
295
0
        auto poBandDS = poBand->GetDataset();
296
0
        if (poBandDS == nullptr)
297
0
        {
298
0
            CPLError(CE_Failure, CPLE_AppDefined,
299
0
                     "Cannot retrieve dataset associated with "
300
0
                     "input spectral band %d",
301
0
                     i + 1);
302
0
            return CE_Failure;
303
0
        }
304
        // Make sure that the band is really a first level child of the owning dataset
305
0
        if (poBandDS->GetRasterBand(poBand->GetBand()) != poBand)
306
0
        {
307
0
            CPLError(CE_Failure, CPLE_AppDefined,
308
0
                     "poBandDS->GetRasterBand(poBand->GetBand()) != poBand");
309
0
            return CE_Failure;
310
0
        }
311
312
0
        GDALGeoTransform MSGT;
313
0
        if (poBandDS->GetGeoTransform(MSGT) != CE_None)
314
0
        {
315
0
            CPLError(
316
0
                CE_Failure, CPLE_AppDefined,
317
0
                "input spectral band %d band has no associated geotransform",
318
0
                i + 1);
319
0
            return CE_Failure;
320
0
        }
321
0
        if (MSGT != refMSGT)
322
0
        {
323
0
            CPLError(CE_Failure, CPLE_AppDefined,
324
0
                     "input spectral band %d has a different "
325
0
                     "geotransform than the first spectral band",
326
0
                     i + 1);
327
0
            return CE_Failure;
328
0
        }
329
330
0
        if (bSameDataset)
331
0
        {
332
0
            if (GDALGetBandDataset(hBand) != GDALGetBandDataset(hRefBand))
333
0
            {
334
0
                anInputBands.resize(0);
335
0
                bSameDataset = false;
336
0
            }
337
0
            else
338
0
            {
339
0
                anInputBands.push_back(GDALGetBandNumber(hBand));
340
0
            }
341
0
        }
342
0
    }
343
0
    if (psOptionsIn->nOutPansharpenedBands == 0)
344
0
    {
345
0
        CPLError(CE_Warning, CPLE_AppDefined,
346
0
                 "No output pansharpened band defined");
347
0
    }
348
0
    for (int i = 0; i < psOptionsIn->nOutPansharpenedBands; i++)
349
0
    {
350
0
        if (psOptionsIn->panOutPansharpenedBands[i] < 0 ||
351
0
            psOptionsIn->panOutPansharpenedBands[i] >=
352
0
                psOptionsIn->nInputSpectralBands)
353
0
        {
354
0
            CPLError(CE_Failure, CPLE_AppDefined,
355
0
                     "Invalid value panOutPansharpenedBands[%d] = %d", i,
356
0
                     psOptionsIn->panOutPansharpenedBands[i]);
357
0
            return CE_Failure;
358
0
        }
359
0
    }
360
361
0
    GDALDataType eWorkDataType = poPanchroBand->GetRasterDataType();
362
0
    if (psOptionsIn->nBitDepth)
363
0
    {
364
0
        if (psOptionsIn->nBitDepth < 0 || psOptionsIn->nBitDepth > 31 ||
365
0
            (eWorkDataType == GDT_Byte && psOptionsIn->nBitDepth > 8) ||
366
0
            (eWorkDataType == GDT_UInt16 && psOptionsIn->nBitDepth > 16))
367
0
        {
368
0
            CPLError(CE_Failure, CPLE_AppDefined,
369
0
                     "Invalid value nBitDepth = %d for type %s",
370
0
                     psOptionsIn->nBitDepth,
371
0
                     GDALGetDataTypeName(eWorkDataType));
372
0
            return CE_Failure;
373
0
        }
374
0
    }
375
376
0
    psOptions = GDALClonePansharpenOptions(psOptionsIn);
377
0
    if (psOptions->nBitDepth == GDALGetDataTypeSizeBits(eWorkDataType))
378
0
        psOptions->nBitDepth = 0;
379
0
    if (psOptions->nBitDepth &&
380
0
        !(eWorkDataType == GDT_Byte || eWorkDataType == GDT_UInt16 ||
381
0
          eWorkDataType == GDT_UInt32 || eWorkDataType == GDT_UInt64))
382
0
    {
383
0
        CPLError(CE_Warning, CPLE_AppDefined,
384
0
                 "Ignoring nBitDepth = %d for type %s", psOptions->nBitDepth,
385
0
                 GDALGetDataTypeName(eWorkDataType));
386
0
        psOptions->nBitDepth = 0;
387
0
    }
388
389
    // Detect negative weights.
390
0
    for (int i = 0; i < psOptions->nInputSpectralBands; i++)
391
0
    {
392
0
        if (psOptions->padfWeights[i] < 0.0)
393
0
        {
394
0
            bPositiveWeights = FALSE;
395
0
            break;
396
0
        }
397
0
    }
398
399
0
    for (int i = 0; i < psOptions->nInputSpectralBands; i++)
400
0
    {
401
0
        aMSBands.push_back(
402
0
            GDALRasterBand::FromHandle(psOptions->pahInputSpectralBands[i]));
403
0
    }
404
405
0
    if (psOptions->bHasNoData)
406
0
    {
407
0
        bool bNeedToWrapInVRT = false;
408
0
        for (int i = 0; i < psOptions->nInputSpectralBands; i++)
409
0
        {
410
0
            GDALRasterBand *poBand =
411
0
                GDALRasterBand::FromHandle(psOptions->pahInputSpectralBands[i]);
412
0
            int bHasNoData = FALSE;
413
0
            double dfNoData = poBand->GetNoDataValue(&bHasNoData);
414
0
            if (!bHasNoData || dfNoData != psOptions->dfNoData)
415
0
                bNeedToWrapInVRT = true;
416
0
        }
417
418
0
        if (bNeedToWrapInVRT)
419
0
        {
420
            // Wrap spectral bands in a VRT if they don't have the nodata value.
421
0
            VRTDataset *poVDS = nullptr;
422
0
            for (int i = 0; i < psOptions->nInputSpectralBands; i++)
423
0
            {
424
0
                GDALRasterBand *poSrcBand = aMSBands[i];
425
0
                int iVRTBand = 1;
426
0
                if (anInputBands.empty() || i == 0)
427
0
                {
428
0
                    poVDS = new VRTDataset(poSrcBand->GetXSize(),
429
0
                                           poSrcBand->GetYSize());
430
0
                    aVDS.push_back(poVDS);
431
0
                }
432
0
                if (!anInputBands.empty())
433
0
                {
434
0
                    anInputBands[i] = i + 1;
435
0
                    iVRTBand = i + 1;
436
0
                }
437
0
                poVDS->AddBand(poSrcBand->GetRasterDataType(), nullptr);
438
0
                VRTSourcedRasterBand *poVRTBand =
439
0
                    dynamic_cast<VRTSourcedRasterBand *>(
440
0
                        poVDS->GetRasterBand(iVRTBand));
441
0
                if (poVRTBand == nullptr)
442
0
                    return CE_Failure;
443
0
                aMSBands[i] = poVRTBand;
444
0
                poVRTBand->SetNoDataValue(psOptions->dfNoData);
445
0
                const char *pszNBITS =
446
0
                    poSrcBand->GetMetadataItem("NBITS", "IMAGE_STRUCTURE");
447
0
                if (pszNBITS)
448
0
                    poVRTBand->SetMetadataItem("NBITS", pszNBITS,
449
0
                                               "IMAGE_STRUCTURE");
450
451
0
                VRTSimpleSource *poSimpleSource = new VRTSimpleSource();
452
0
                poVRTBand->ConfigureSource(
453
0
                    poSimpleSource, poSrcBand, FALSE, 0, 0,
454
0
                    poSrcBand->GetXSize(), poSrcBand->GetYSize(), 0, 0,
455
0
                    poSrcBand->GetXSize(), poSrcBand->GetYSize());
456
0
                poVRTBand->AddSource(poSimpleSource);
457
0
            }
458
0
        }
459
0
    }
460
461
    // Setup thread pool.
462
0
    int nThreads = psOptions->nThreads;
463
0
    if (nThreads == -1)
464
0
        nThreads = CPLGetNumCPUs();
465
0
    else if (nThreads == 0)
466
0
    {
467
0
        const char *pszNumThreads =
468
0
            CPLGetConfigOption("GDAL_NUM_THREADS", nullptr);
469
0
        if (pszNumThreads)
470
0
        {
471
0
            if (EQUAL(pszNumThreads, "ALL_CPUS"))
472
0
                nThreads = CPLGetNumCPUs();
473
0
            else
474
0
                nThreads = std::max(0, std::min(128, atoi(pszNumThreads)));
475
0
        }
476
0
    }
477
0
    if (nThreads > 1)
478
0
    {
479
0
        CPLDebug("PANSHARPEN", "Using %d threads", nThreads);
480
0
        poThreadPool = new (std::nothrow) CPLWorkerThreadPool();
481
        // coverity[tainted_data]
482
0
        if (poThreadPool == nullptr ||
483
0
            !poThreadPool->Setup(nThreads, nullptr, nullptr))
484
0
        {
485
0
            delete poThreadPool;
486
0
            poThreadPool = nullptr;
487
0
        }
488
0
    }
489
490
0
    GDALRIOResampleAlg eResampleAlg = psOptions->eResampleAlg;
491
0
    if (eResampleAlg != GRIORA_NearestNeighbour)
492
0
    {
493
0
        const char *pszResampling =
494
0
            (eResampleAlg == GRIORA_Bilinear)      ? "BILINEAR"
495
0
            : (eResampleAlg == GRIORA_Cubic)       ? "CUBIC"
496
0
            : (eResampleAlg == GRIORA_CubicSpline) ? "CUBICSPLINE"
497
0
            : (eResampleAlg == GRIORA_Lanczos)     ? "LANCZOS"
498
0
            : (eResampleAlg == GRIORA_Average)     ? "AVERAGE"
499
0
            : (eResampleAlg == GRIORA_RMS)         ? "RMS"
500
0
            : (eResampleAlg == GRIORA_Mode)        ? "MODE"
501
0
            : (eResampleAlg == GRIORA_Gauss)       ? "GAUSS"
502
0
                                                   : "UNKNOWN";
503
504
0
        GDALGetResampleFunction(pszResampling, &nKernelRadius);
505
0
    }
506
507
0
    return CE_None;
508
0
}
509
510
/************************************************************************/
511
/*                    WeightedBroveyWithNoData()                        */
512
/************************************************************************/
513
514
template <class WorkDataType, class OutDataType>
515
void GDALPansharpenOperation::WeightedBroveyWithNoData(
516
    const WorkDataType *pPanBuffer,
517
    const WorkDataType *pUpsampledSpectralBuffer, OutDataType *pDataBuf,
518
    size_t nValues, size_t nBandValues, WorkDataType nMaxValue) const
519
0
{
520
0
    WorkDataType noData, validValue;
521
0
    GDALCopyWord(psOptions->dfNoData, noData);
522
523
    if constexpr (!(std::numeric_limits<WorkDataType>::is_integer))
524
0
        validValue = static_cast<WorkDataType>(noData + 1e-5);
525
0
    else if (noData == std::numeric_limits<WorkDataType>::min())
526
0
        validValue = std::numeric_limits<WorkDataType>::min() + 1;
527
0
    else
528
0
        validValue = noData - 1;
529
530
0
    for (size_t j = 0; j < nValues; j++)
531
0
    {
532
0
        double dfPseudoPanchro = 0.0;
533
0
        for (int i = 0; i < psOptions->nInputSpectralBands; i++)
534
0
        {
535
0
            WorkDataType nSpectralVal =
536
0
                pUpsampledSpectralBuffer[i * nBandValues + j];
537
0
            if (nSpectralVal == noData)
538
0
            {
539
0
                dfPseudoPanchro = 0.0;
540
0
                break;
541
0
            }
542
0
            dfPseudoPanchro += psOptions->padfWeights[i] * nSpectralVal;
543
0
        }
544
0
        if (dfPseudoPanchro != 0.0 && pPanBuffer[j] != noData)
545
0
        {
546
0
            const double dfFactor = pPanBuffer[j] / dfPseudoPanchro;
547
0
            for (int i = 0; i < psOptions->nOutPansharpenedBands; i++)
548
0
            {
549
0
                WorkDataType nRawValue = pUpsampledSpectralBuffer
550
0
                    [psOptions->panOutPansharpenedBands[i] * nBandValues + j];
551
0
                WorkDataType nPansharpenedValue;
552
0
                GDALCopyWord(nRawValue * dfFactor, nPansharpenedValue);
553
0
                if (nMaxValue != 0 && nPansharpenedValue > nMaxValue)
554
0
                    nPansharpenedValue = nMaxValue;
555
                // We don't want a valid value to be mapped to NoData.
556
0
                if (nPansharpenedValue == noData)
557
0
                    nPansharpenedValue = validValue;
558
0
                GDALCopyWord(nPansharpenedValue, pDataBuf[i * nBandValues + j]);
559
0
            }
560
0
        }
561
0
        else
562
0
        {
563
0
            for (int i = 0; i < psOptions->nOutPansharpenedBands; i++)
564
0
            {
565
0
                GDALCopyWord(noData, pDataBuf[i * nBandValues + j]);
566
0
            }
567
0
        }
568
0
    }
569
0
}
Unexecuted instantiation: void GDALPansharpenOperation::WeightedBroveyWithNoData<unsigned char, unsigned char>(unsigned char const*, unsigned char const*, unsigned char*, unsigned long, unsigned long, unsigned char) const
Unexecuted instantiation: void GDALPansharpenOperation::WeightedBroveyWithNoData<unsigned short, unsigned short>(unsigned short const*, unsigned short const*, unsigned short*, unsigned long, unsigned long, unsigned short) const
Unexecuted instantiation: void GDALPansharpenOperation::WeightedBroveyWithNoData<unsigned char, unsigned short>(unsigned char const*, unsigned char const*, unsigned short*, unsigned long, unsigned long, unsigned char) const
Unexecuted instantiation: void GDALPansharpenOperation::WeightedBroveyWithNoData<unsigned char, double>(unsigned char const*, unsigned char const*, double*, unsigned long, unsigned long, unsigned char) const
Unexecuted instantiation: void GDALPansharpenOperation::WeightedBroveyWithNoData<unsigned short, unsigned char>(unsigned short const*, unsigned short const*, unsigned char*, unsigned long, unsigned long, unsigned short) const
Unexecuted instantiation: void GDALPansharpenOperation::WeightedBroveyWithNoData<unsigned short, double>(unsigned short const*, unsigned short const*, double*, unsigned long, unsigned long, unsigned short) const
Unexecuted instantiation: void GDALPansharpenOperation::WeightedBroveyWithNoData<double, unsigned char>(double const*, double const*, unsigned char*, unsigned long, unsigned long, double) const
Unexecuted instantiation: void GDALPansharpenOperation::WeightedBroveyWithNoData<double, unsigned short>(double const*, double const*, unsigned short*, unsigned long, unsigned long, double) const
Unexecuted instantiation: void GDALPansharpenOperation::WeightedBroveyWithNoData<double, double>(double const*, double const*, double*, unsigned long, unsigned long, double) const
570
571
/************************************************************************/
572
/*                           ComputeFactor()                            */
573
/************************************************************************/
574
575
template <class T>
576
static inline double ComputeFactor(T panValue, double dfPseudoPanchro)
577
0
{
578
0
    if (dfPseudoPanchro == 0.0)
579
0
        return 0.0;
580
581
0
    return panValue / dfPseudoPanchro;
582
0
}
Unexecuted instantiation: gdalpansharpen.cpp:double ComputeFactor<unsigned char>(unsigned char, double)
Unexecuted instantiation: gdalpansharpen.cpp:double ComputeFactor<unsigned short>(unsigned short, double)
Unexecuted instantiation: gdalpansharpen.cpp:double ComputeFactor<double>(double, double)
583
584
/************************************************************************/
585
/*                           ClampAndRound()                            */
586
/************************************************************************/
587
588
template <class T> static inline T ClampAndRound(double dfVal, T nMaxValue)
589
0
{
590
0
    if (dfVal > nMaxValue)
591
0
        return nMaxValue;
592
0
    else
593
0
        return static_cast<T>(dfVal + 0.5);
594
0
}
Unexecuted instantiation: gdalpansharpen.cpp:unsigned char ClampAndRound<unsigned char>(double, unsigned char)
Unexecuted instantiation: gdalpansharpen.cpp:unsigned short ClampAndRound<unsigned short>(double, unsigned short)
595
596
/************************************************************************/
597
/*                         WeightedBrovey()                             */
598
/************************************************************************/
599
600
template <class WorkDataType, class OutDataType, int bHasBitDepth>
601
void GDALPansharpenOperation::WeightedBrovey3(
602
    const WorkDataType *pPanBuffer,
603
    const WorkDataType *pUpsampledSpectralBuffer, OutDataType *pDataBuf,
604
    size_t nValues, size_t nBandValues, WorkDataType nMaxValue) const
605
0
{
606
0
    if (psOptions->bHasNoData)
607
0
    {
608
0
        WeightedBroveyWithNoData<WorkDataType, OutDataType>(
609
0
            pPanBuffer, pUpsampledSpectralBuffer, pDataBuf, nValues,
610
0
            nBandValues, nMaxValue);
611
0
        return;
612
0
    }
613
614
0
    for (size_t j = 0; j < nValues; j++)
615
0
    {
616
0
        double dfFactor = 0.0;
617
        // if( pPanBuffer[j] == 0 )
618
        //     dfFactor = 1.0;
619
        // else
620
0
        {
621
0
            double dfPseudoPanchro = 0.0;
622
0
            for (int i = 0; i < psOptions->nInputSpectralBands; i++)
623
0
                dfPseudoPanchro +=
624
0
                    psOptions->padfWeights[i] *
625
0
                    pUpsampledSpectralBuffer[i * nBandValues + j];
626
0
            dfFactor = ComputeFactor(pPanBuffer[j], dfPseudoPanchro);
627
0
        }
628
629
0
        for (int i = 0; i < psOptions->nOutPansharpenedBands; i++)
630
0
        {
631
0
            WorkDataType nRawValue =
632
0
                pUpsampledSpectralBuffer[psOptions->panOutPansharpenedBands[i] *
633
0
                                             nBandValues +
634
0
                                         j];
635
0
            WorkDataType nPansharpenedValue;
636
0
            GDALCopyWord(nRawValue * dfFactor, nPansharpenedValue);
637
            if constexpr (bHasBitDepth)
638
0
            {
639
0
                if (nPansharpenedValue > nMaxValue)
640
0
                    nPansharpenedValue = nMaxValue;
641
0
            }
642
0
            GDALCopyWord(nPansharpenedValue, pDataBuf[i * nBandValues + j]);
643
0
        }
644
0
    }
645
0
}
Unexecuted instantiation: void GDALPansharpenOperation::WeightedBrovey3<unsigned char, unsigned char, 0>(unsigned char const*, unsigned char const*, unsigned char*, unsigned long, unsigned long, unsigned char) const
Unexecuted instantiation: void GDALPansharpenOperation::WeightedBrovey3<unsigned char, unsigned char, 1>(unsigned char const*, unsigned char const*, unsigned char*, unsigned long, unsigned long, unsigned char) const
Unexecuted instantiation: void GDALPansharpenOperation::WeightedBrovey3<unsigned short, unsigned short, 0>(unsigned short const*, unsigned short const*, unsigned short*, unsigned long, unsigned long, unsigned short) const
Unexecuted instantiation: void GDALPansharpenOperation::WeightedBrovey3<unsigned short, unsigned short, 1>(unsigned short const*, unsigned short const*, unsigned short*, unsigned long, unsigned long, unsigned short) const
Unexecuted instantiation: void GDALPansharpenOperation::WeightedBrovey3<unsigned char, unsigned short, 0>(unsigned char const*, unsigned char const*, unsigned short*, unsigned long, unsigned long, unsigned char) const
Unexecuted instantiation: void GDALPansharpenOperation::WeightedBrovey3<unsigned char, unsigned short, 1>(unsigned char const*, unsigned char const*, unsigned short*, unsigned long, unsigned long, unsigned char) const
Unexecuted instantiation: void GDALPansharpenOperation::WeightedBrovey3<unsigned char, double, 0>(unsigned char const*, unsigned char const*, double*, unsigned long, unsigned long, unsigned char) const
Unexecuted instantiation: void GDALPansharpenOperation::WeightedBrovey3<unsigned char, double, 1>(unsigned char const*, unsigned char const*, double*, unsigned long, unsigned long, unsigned char) const
Unexecuted instantiation: void GDALPansharpenOperation::WeightedBrovey3<unsigned short, unsigned char, 0>(unsigned short const*, unsigned short const*, unsigned char*, unsigned long, unsigned long, unsigned short) const
Unexecuted instantiation: void GDALPansharpenOperation::WeightedBrovey3<unsigned short, unsigned char, 1>(unsigned short const*, unsigned short const*, unsigned char*, unsigned long, unsigned long, unsigned short) const
Unexecuted instantiation: void GDALPansharpenOperation::WeightedBrovey3<unsigned short, double, 0>(unsigned short const*, unsigned short const*, double*, unsigned long, unsigned long, unsigned short) const
Unexecuted instantiation: void GDALPansharpenOperation::WeightedBrovey3<unsigned short, double, 1>(unsigned short const*, unsigned short const*, double*, unsigned long, unsigned long, unsigned short) const
Unexecuted instantiation: void GDALPansharpenOperation::WeightedBrovey3<double, unsigned char, 0>(double const*, double const*, unsigned char*, unsigned long, unsigned long, double) const
Unexecuted instantiation: void GDALPansharpenOperation::WeightedBrovey3<double, unsigned short, 0>(double const*, double const*, unsigned short*, unsigned long, unsigned long, double) const
Unexecuted instantiation: void GDALPansharpenOperation::WeightedBrovey3<double, double, 0>(double const*, double const*, double*, unsigned long, unsigned long, double) const
646
647
/* We restrict to 64bit processors because they are guaranteed to have SSE2 */
648
/* Could possibly be used too on 32bit, but we would need to check at runtime */
649
#if defined(__x86_64) || defined(_M_X64) || defined(USE_NEON_OPTIMIZATIONS)
650
651
#define USE_SSE2
652
#include "gdalsse_priv.h"
653
654
template <class T, int NINPUT, int NOUTPUT>
655
size_t GDALPansharpenOperation::WeightedBroveyPositiveWeightsInternal(
656
    const T *pPanBuffer, const T *pUpsampledSpectralBuffer, T *pDataBuf,
657
    size_t nValues, size_t nBandValues, T nMaxValue) const
658
0
{
659
0
    static_assert(NINPUT == 3 || NINPUT == 4);
660
0
    static_assert(NOUTPUT == 3 || NOUTPUT == 4);
661
0
    const XMMReg4Double w0 =
662
0
        XMMReg4Double::Load1ValHighAndLow(psOptions->padfWeights + 0);
663
0
    const XMMReg4Double w1 =
664
0
        XMMReg4Double::Load1ValHighAndLow(psOptions->padfWeights + 1);
665
0
    const XMMReg4Double w2 =
666
0
        XMMReg4Double::Load1ValHighAndLow(psOptions->padfWeights + 2);
667
0
    [[maybe_unused]] const XMMReg4Double w3 =
668
0
        (NINPUT == 3)
669
0
            ? XMMReg4Double::Zero()
670
0
            : XMMReg4Double::Load1ValHighAndLow(psOptions->padfWeights + 3);
671
672
0
    const XMMReg4Double zero = XMMReg4Double::Zero();
673
0
    double dfMaxValue = nMaxValue;
674
0
    const XMMReg4Double maxValue =
675
0
        XMMReg4Double::Load1ValHighAndLow(&dfMaxValue);
676
677
0
    size_t j = 0;  // Used after for.
678
0
    for (; j + 3 < nValues; j += 4)
679
0
    {
680
0
        XMMReg4Double pseudoPanchro = zero;
681
682
0
        XMMReg4Double val0 = XMMReg4Double::Load4Val(pUpsampledSpectralBuffer +
683
0
                                                     0 * nBandValues + j);
684
0
        XMMReg4Double val1 = XMMReg4Double::Load4Val(pUpsampledSpectralBuffer +
685
0
                                                     1 * nBandValues + j);
686
0
        XMMReg4Double val2 = XMMReg4Double::Load4Val(pUpsampledSpectralBuffer +
687
0
                                                     2 * nBandValues + j);
688
0
        XMMReg4Double val3;
689
        if constexpr (NINPUT == 4 || NOUTPUT == 4)
690
0
        {
691
0
            val3 = XMMReg4Double::Load4Val(pUpsampledSpectralBuffer +
692
0
                                           3 * nBandValues + j);
693
0
        }
694
695
0
        pseudoPanchro += w0 * val0;
696
0
        pseudoPanchro += w1 * val1;
697
0
        pseudoPanchro += w2 * val2;
698
        if constexpr (NINPUT == 4)
699
0
            pseudoPanchro += w3 * val3;
700
701
        /* Little trick to avoid use of ternary operator due to one of the
702
         * branch being zero */
703
0
        XMMReg4Double factor = XMMReg4Double::And(
704
0
            XMMReg4Double::NotEquals(pseudoPanchro, zero),
705
0
            XMMReg4Double::Load4Val(pPanBuffer + j) / pseudoPanchro);
706
707
0
        val0 = XMMReg4Double::Min(val0 * factor, maxValue);
708
0
        val1 = XMMReg4Double::Min(val1 * factor, maxValue);
709
0
        val2 = XMMReg4Double::Min(val2 * factor, maxValue);
710
        if constexpr (NOUTPUT == 4)
711
0
        {
712
0
            val3 = XMMReg4Double::Min(val3 * factor, maxValue);
713
0
        }
714
0
        val0.Store4Val(pDataBuf + 0 * nBandValues + j);
715
0
        val1.Store4Val(pDataBuf + 1 * nBandValues + j);
716
0
        val2.Store4Val(pDataBuf + 2 * nBandValues + j);
717
        if constexpr (NOUTPUT == 4)
718
0
        {
719
0
            val3.Store4Val(pDataBuf + 3 * nBandValues + j);
720
0
        }
721
0
    }
722
0
    return j;
723
0
}
Unexecuted instantiation: unsigned long GDALPansharpenOperation::WeightedBroveyPositiveWeightsInternal<unsigned char, 3, 3>(unsigned char const*, unsigned char const*, unsigned char*, unsigned long, unsigned long, unsigned char) const
Unexecuted instantiation: unsigned long GDALPansharpenOperation::WeightedBroveyPositiveWeightsInternal<unsigned char, 4, 4>(unsigned char const*, unsigned char const*, unsigned char*, unsigned long, unsigned long, unsigned char) const
Unexecuted instantiation: unsigned long GDALPansharpenOperation::WeightedBroveyPositiveWeightsInternal<unsigned char, 4, 3>(unsigned char const*, unsigned char const*, unsigned char*, unsigned long, unsigned long, unsigned char) const
Unexecuted instantiation: unsigned long GDALPansharpenOperation::WeightedBroveyPositiveWeightsInternal<unsigned short, 3, 3>(unsigned short const*, unsigned short const*, unsigned short*, unsigned long, unsigned long, unsigned short) const
Unexecuted instantiation: unsigned long GDALPansharpenOperation::WeightedBroveyPositiveWeightsInternal<unsigned short, 4, 4>(unsigned short const*, unsigned short const*, unsigned short*, unsigned long, unsigned long, unsigned short) const
Unexecuted instantiation: unsigned long GDALPansharpenOperation::WeightedBroveyPositiveWeightsInternal<unsigned short, 4, 3>(unsigned short const*, unsigned short const*, unsigned short*, unsigned long, unsigned long, unsigned short) const
724
725
#else
726
727
template <class T, int NINPUT, int NOUTPUT>
728
size_t GDALPansharpenOperation::WeightedBroveyPositiveWeightsInternal(
729
    const T *pPanBuffer, const T *pUpsampledSpectralBuffer, T *pDataBuf,
730
    size_t nValues, size_t nBandValues, T nMaxValue) const
731
{
732
    static_assert(NINPUT == 3 || NINPUT == 4);
733
    const double dfw0 = psOptions->padfWeights[0];
734
    const double dfw1 = psOptions->padfWeights[1];
735
    const double dfw2 = psOptions->padfWeights[2];
736
    // cppcheck-suppress knownConditionTrueFalse
737
    [[maybe_unused]] const double dfw3 =
738
        (NINPUT == 3) ? 0 : psOptions->padfWeights[3];
739
    size_t j = 0;  // Used after for.
740
    for (; j + 1 < nValues; j += 2)
741
    {
742
        double dfFactor = 0.0;
743
        double dfFactor2 = 0.0;
744
        double dfPseudoPanchro = 0.0;
745
        double dfPseudoPanchro2 = 0.0;
746
747
        dfPseudoPanchro += dfw0 * pUpsampledSpectralBuffer[j];
748
        dfPseudoPanchro2 += dfw0 * pUpsampledSpectralBuffer[j + 1];
749
750
        dfPseudoPanchro += dfw1 * pUpsampledSpectralBuffer[nBandValues + j];
751
        dfPseudoPanchro2 +=
752
            dfw1 * pUpsampledSpectralBuffer[nBandValues + j + 1];
753
754
        dfPseudoPanchro += dfw2 * pUpsampledSpectralBuffer[2 * nBandValues + j];
755
        dfPseudoPanchro2 +=
756
            dfw2 * pUpsampledSpectralBuffer[2 * nBandValues + j + 1];
757
758
        if constexpr (NINPUT == 4)
759
        {
760
            dfPseudoPanchro +=
761
                dfw3 * pUpsampledSpectralBuffer[3 * nBandValues + j];
762
            dfPseudoPanchro2 +=
763
                dfw3 * pUpsampledSpectralBuffer[3 * nBandValues + j + 1];
764
        }
765
766
        dfFactor = ComputeFactor(pPanBuffer[j], dfPseudoPanchro);
767
        dfFactor2 = ComputeFactor(pPanBuffer[j + 1], dfPseudoPanchro2);
768
769
        for (int i = 0; i < NOUTPUT; i++)
770
        {
771
            T nRawValue = pUpsampledSpectralBuffer[i * nBandValues + j];
772
            double dfTmp = nRawValue * dfFactor;
773
            pDataBuf[i * nBandValues + j] = ClampAndRound(dfTmp, nMaxValue);
774
775
            T nRawValue2 = pUpsampledSpectralBuffer[i * nBandValues + j + 1];
776
            double dfTmp2 = nRawValue2 * dfFactor2;
777
            pDataBuf[i * nBandValues + j + 1] =
778
                ClampAndRound(dfTmp2, nMaxValue);
779
        }
780
    }
781
    return j;
782
}
783
#endif
784
785
template <class T>
786
void GDALPansharpenOperation::WeightedBroveyPositiveWeights(
787
    const T *pPanBuffer, const T *pUpsampledSpectralBuffer, T *pDataBuf,
788
    size_t nValues, size_t nBandValues, T nMaxValue) const
789
0
{
790
0
    if (psOptions->bHasNoData)
791
0
    {
792
0
        WeightedBroveyWithNoData<T, T>(pPanBuffer, pUpsampledSpectralBuffer,
793
0
                                       pDataBuf, nValues, nBandValues,
794
0
                                       nMaxValue);
795
0
        return;
796
0
    }
797
798
0
    if (nMaxValue == 0)
799
0
        nMaxValue = cpl::NumericLimits<T>::max();
800
0
    size_t j;
801
0
    if (psOptions->nInputSpectralBands == 3 &&
802
0
        psOptions->nOutPansharpenedBands == 3 &&
803
0
        psOptions->panOutPansharpenedBands[0] == 0 &&
804
0
        psOptions->panOutPansharpenedBands[1] == 1 &&
805
0
        psOptions->panOutPansharpenedBands[2] == 2)
806
0
    {
807
0
        j = WeightedBroveyPositiveWeightsInternal<T, 3, 3>(
808
0
            pPanBuffer, pUpsampledSpectralBuffer, pDataBuf, nValues,
809
0
            nBandValues, nMaxValue);
810
0
    }
811
0
    else if (psOptions->nInputSpectralBands == 4 &&
812
0
             psOptions->nOutPansharpenedBands == 4 &&
813
0
             psOptions->panOutPansharpenedBands[0] == 0 &&
814
0
             psOptions->panOutPansharpenedBands[1] == 1 &&
815
0
             psOptions->panOutPansharpenedBands[2] == 2 &&
816
0
             psOptions->panOutPansharpenedBands[3] == 3)
817
0
    {
818
0
        j = WeightedBroveyPositiveWeightsInternal<T, 4, 4>(
819
0
            pPanBuffer, pUpsampledSpectralBuffer, pDataBuf, nValues,
820
0
            nBandValues, nMaxValue);
821
0
    }
822
0
    else if (psOptions->nInputSpectralBands == 4 &&
823
0
             psOptions->nOutPansharpenedBands == 3 &&
824
0
             psOptions->panOutPansharpenedBands[0] == 0 &&
825
0
             psOptions->panOutPansharpenedBands[1] == 1 &&
826
0
             psOptions->panOutPansharpenedBands[2] == 2)
827
0
    {
828
0
        j = WeightedBroveyPositiveWeightsInternal<T, 4, 3>(
829
0
            pPanBuffer, pUpsampledSpectralBuffer, pDataBuf, nValues,
830
0
            nBandValues, nMaxValue);
831
0
    }
832
0
    else
833
0
    {
834
0
        for (j = 0; j + 1 < nValues; j += 2)
835
0
        {
836
0
            double dfFactor = 0.0;
837
0
            double dfFactor2 = 0.0;
838
0
            double dfPseudoPanchro = 0.0;
839
0
            double dfPseudoPanchro2 = 0.0;
840
0
            for (int i = 0; i < psOptions->nInputSpectralBands; i++)
841
0
            {
842
0
                dfPseudoPanchro +=
843
0
                    psOptions->padfWeights[i] *
844
0
                    pUpsampledSpectralBuffer[i * nBandValues + j];
845
0
                dfPseudoPanchro2 +=
846
0
                    psOptions->padfWeights[i] *
847
0
                    pUpsampledSpectralBuffer[i * nBandValues + j + 1];
848
0
            }
849
850
0
            dfFactor = ComputeFactor(pPanBuffer[j], dfPseudoPanchro);
851
0
            dfFactor2 = ComputeFactor(pPanBuffer[j + 1], dfPseudoPanchro2);
852
853
0
            for (int i = 0; i < psOptions->nOutPansharpenedBands; i++)
854
0
            {
855
0
                const T nRawValue = pUpsampledSpectralBuffer
856
0
                    [psOptions->panOutPansharpenedBands[i] * nBandValues + j];
857
0
                const double dfTmp = nRawValue * dfFactor;
858
0
                pDataBuf[i * nBandValues + j] = ClampAndRound(dfTmp, nMaxValue);
859
860
0
                const T nRawValue2 = pUpsampledSpectralBuffer
861
0
                    [psOptions->panOutPansharpenedBands[i] * nBandValues + j +
862
0
                     1];
863
0
                const double dfTmp2 = nRawValue2 * dfFactor2;
864
0
                pDataBuf[i * nBandValues + j + 1] =
865
0
                    ClampAndRound(dfTmp2, nMaxValue);
866
0
            }
867
0
        }
868
0
    }
869
0
    for (; j < nValues; j++)
870
0
    {
871
0
        double dfFactor = 0.0;
872
0
        double dfPseudoPanchro = 0.0;
873
0
        for (int i = 0; i < psOptions->nInputSpectralBands; i++)
874
0
            dfPseudoPanchro += psOptions->padfWeights[i] *
875
0
                               pUpsampledSpectralBuffer[i * nBandValues + j];
876
0
        dfFactor = ComputeFactor(pPanBuffer[j], dfPseudoPanchro);
877
878
0
        for (int i = 0; i < psOptions->nOutPansharpenedBands; i++)
879
0
        {
880
0
            T nRawValue =
881
0
                pUpsampledSpectralBuffer[psOptions->panOutPansharpenedBands[i] *
882
0
                                             nBandValues +
883
0
                                         j];
884
0
            double dfTmp = nRawValue * dfFactor;
885
0
            pDataBuf[i * nBandValues + j] = ClampAndRound(dfTmp, nMaxValue);
886
0
        }
887
0
    }
888
0
}
Unexecuted instantiation: void GDALPansharpenOperation::WeightedBroveyPositiveWeights<unsigned char>(unsigned char const*, unsigned char const*, unsigned char*, unsigned long, unsigned long, unsigned char) const
Unexecuted instantiation: void GDALPansharpenOperation::WeightedBroveyPositiveWeights<unsigned short>(unsigned short const*, unsigned short const*, unsigned short*, unsigned long, unsigned long, unsigned short) const
889
890
template <class WorkDataType, class OutDataType>
891
void GDALPansharpenOperation::WeightedBrovey(
892
    const WorkDataType *pPanBuffer,
893
    const WorkDataType *pUpsampledSpectralBuffer, OutDataType *pDataBuf,
894
    size_t nValues, size_t nBandValues, WorkDataType nMaxValue) const
895
0
{
896
0
    if (nMaxValue == 0)
897
0
        WeightedBrovey3<WorkDataType, OutDataType, FALSE>(
898
0
            pPanBuffer, pUpsampledSpectralBuffer, pDataBuf, nValues,
899
0
            nBandValues, 0);
900
0
    else
901
0
    {
902
0
        WeightedBrovey3<WorkDataType, OutDataType, TRUE>(
903
0
            pPanBuffer, pUpsampledSpectralBuffer, pDataBuf, nValues,
904
0
            nBandValues, nMaxValue);
905
0
    }
906
0
}
Unexecuted instantiation: void GDALPansharpenOperation::WeightedBrovey<unsigned char, unsigned short>(unsigned char const*, unsigned char const*, unsigned short*, unsigned long, unsigned long, unsigned char) const
Unexecuted instantiation: void GDALPansharpenOperation::WeightedBrovey<unsigned char, double>(unsigned char const*, unsigned char const*, double*, unsigned long, unsigned long, unsigned char) const
Unexecuted instantiation: void GDALPansharpenOperation::WeightedBrovey<unsigned short, unsigned char>(unsigned short const*, unsigned short const*, unsigned char*, unsigned long, unsigned long, unsigned short) const
Unexecuted instantiation: void GDALPansharpenOperation::WeightedBrovey<unsigned short, double>(unsigned short const*, unsigned short const*, double*, unsigned long, unsigned long, unsigned short) const
907
908
template <class T>
909
void GDALPansharpenOperation::WeightedBroveyGByteOrUInt16(
910
    const T *pPanBuffer, const T *pUpsampledSpectralBuffer, T *pDataBuf,
911
    size_t nValues, size_t nBandValues, T nMaxValue) const
912
0
{
913
0
    if (bPositiveWeights)
914
0
    {
915
0
        WeightedBroveyPositiveWeights(pPanBuffer, pUpsampledSpectralBuffer,
916
0
                                      pDataBuf, nValues, nBandValues,
917
0
                                      nMaxValue);
918
0
    }
919
0
    else if (nMaxValue == 0)
920
0
    {
921
0
        WeightedBrovey3<T, T, FALSE>(pPanBuffer, pUpsampledSpectralBuffer,
922
0
                                     pDataBuf, nValues, nBandValues, 0);
923
0
    }
924
0
    else
925
0
    {
926
0
        WeightedBrovey3<T, T, TRUE>(pPanBuffer, pUpsampledSpectralBuffer,
927
0
                                    pDataBuf, nValues, nBandValues, nMaxValue);
928
0
    }
929
0
}
Unexecuted instantiation: void GDALPansharpenOperation::WeightedBroveyGByteOrUInt16<unsigned char>(unsigned char const*, unsigned char const*, unsigned char*, unsigned long, unsigned long, unsigned char) const
Unexecuted instantiation: void GDALPansharpenOperation::WeightedBroveyGByteOrUInt16<unsigned short>(unsigned short const*, unsigned short const*, unsigned short*, unsigned long, unsigned long, unsigned short) const
930
931
template <>
932
void GDALPansharpenOperation::WeightedBrovey<GByte, GByte>(
933
    const GByte *pPanBuffer, const GByte *pUpsampledSpectralBuffer,
934
    GByte *pDataBuf, size_t nValues, size_t nBandValues, GByte nMaxValue) const
935
0
{
936
0
    WeightedBroveyGByteOrUInt16(pPanBuffer, pUpsampledSpectralBuffer, pDataBuf,
937
0
                                nValues, nBandValues, nMaxValue);
938
0
}
939
940
template <>
941
void GDALPansharpenOperation::WeightedBrovey<GUInt16, GUInt16>(
942
    const GUInt16 *pPanBuffer, const GUInt16 *pUpsampledSpectralBuffer,
943
    GUInt16 *pDataBuf, size_t nValues, size_t nBandValues,
944
    GUInt16 nMaxValue) const
945
0
{
946
0
    WeightedBroveyGByteOrUInt16(pPanBuffer, pUpsampledSpectralBuffer, pDataBuf,
947
0
                                nValues, nBandValues, nMaxValue);
948
0
}
949
950
template <class WorkDataType>
951
CPLErr GDALPansharpenOperation::WeightedBrovey(
952
    const WorkDataType *pPanBuffer,
953
    const WorkDataType *pUpsampledSpectralBuffer, void *pDataBuf,
954
    GDALDataType eBufDataType, size_t nValues, size_t nBandValues,
955
    WorkDataType nMaxValue) const
956
0
{
957
0
    switch (eBufDataType)
958
0
    {
959
0
        case GDT_Byte:
960
0
            WeightedBrovey(pPanBuffer, pUpsampledSpectralBuffer,
961
0
                           static_cast<GByte *>(pDataBuf), nValues, nBandValues,
962
0
                           nMaxValue);
963
0
            break;
964
965
0
        case GDT_UInt16:
966
0
            WeightedBrovey(pPanBuffer, pUpsampledSpectralBuffer,
967
0
                           static_cast<GUInt16 *>(pDataBuf), nValues,
968
0
                           nBandValues, nMaxValue);
969
0
            break;
970
971
#ifndef LIMIT_TYPES
972
        case GDT_Int8:
973
            WeightedBrovey(pPanBuffer, pUpsampledSpectralBuffer,
974
                           static_cast<GInt8 *>(pDataBuf), nValues, nBandValues,
975
                           nMaxValue);
976
            break;
977
978
        case GDT_Int16:
979
            WeightedBrovey(pPanBuffer, pUpsampledSpectralBuffer,
980
                           static_cast<GInt16 *>(pDataBuf), nValues,
981
                           nBandValues, nMaxValue);
982
            break;
983
984
        case GDT_UInt32:
985
            WeightedBrovey(pPanBuffer, pUpsampledSpectralBuffer,
986
                           static_cast<GUInt32 *>(pDataBuf), nValues,
987
                           nBandValues, nMaxValue);
988
            break;
989
990
        case GDT_Int32:
991
            WeightedBrovey(pPanBuffer, pUpsampledSpectralBuffer,
992
                           static_cast<GInt32 *>(pDataBuf), nValues,
993
                           nBandValues, nMaxValue);
994
            break;
995
996
        case GDT_UInt64:
997
            WeightedBrovey(pPanBuffer, pUpsampledSpectralBuffer,
998
                           static_cast<std::uint64_t *>(pDataBuf), nValues,
999
                           nBandValues, nMaxValue);
1000
            break;
1001
1002
        case GDT_Int64:
1003
            WeightedBrovey(pPanBuffer, pUpsampledSpectralBuffer,
1004
                           static_cast<std::int64_t *>(pDataBuf), nValues,
1005
                           nBandValues, nMaxValue);
1006
            break;
1007
1008
        case GDT_Float16:
1009
            WeightedBrovey(pPanBuffer, pUpsampledSpectralBuffer,
1010
                           static_cast<GFloat16 *>(pDataBuf), nValues,
1011
                           nBandValues, nMaxValue);
1012
            break;
1013
1014
        case GDT_Float32:
1015
            WeightedBrovey(pPanBuffer, pUpsampledSpectralBuffer,
1016
                           static_cast<float *>(pDataBuf), nValues, nBandValues,
1017
                           nMaxValue);
1018
            break;
1019
#endif
1020
1021
0
        case GDT_Float64:
1022
0
            WeightedBrovey(pPanBuffer, pUpsampledSpectralBuffer,
1023
0
                           static_cast<double *>(pDataBuf), nValues,
1024
0
                           nBandValues, nMaxValue);
1025
0
            break;
1026
1027
0
        default:
1028
0
            CPLError(CE_Failure, CPLE_NotSupported,
1029
0
                     "eBufDataType not supported");
1030
0
            return CE_Failure;
1031
0
            break;
1032
0
    }
1033
1034
0
    return CE_None;
1035
0
}
Unexecuted instantiation: CPLErr GDALPansharpenOperation::WeightedBrovey<unsigned char>(unsigned char const*, unsigned char const*, void*, GDALDataType, unsigned long, unsigned long, unsigned char) const
Unexecuted instantiation: CPLErr GDALPansharpenOperation::WeightedBrovey<unsigned short>(unsigned short const*, unsigned short const*, void*, GDALDataType, unsigned long, unsigned long, unsigned short) const
1036
1037
template <class WorkDataType>
1038
CPLErr GDALPansharpenOperation::WeightedBrovey(
1039
    const WorkDataType *pPanBuffer,
1040
    const WorkDataType *pUpsampledSpectralBuffer, void *pDataBuf,
1041
    GDALDataType eBufDataType, size_t nValues, size_t nBandValues) const
1042
0
{
1043
0
    switch (eBufDataType)
1044
0
    {
1045
0
        case GDT_Byte:
1046
0
            WeightedBrovey3<WorkDataType, GByte, FALSE>(
1047
0
                pPanBuffer, pUpsampledSpectralBuffer,
1048
0
                static_cast<GByte *>(pDataBuf), nValues, nBandValues, 0);
1049
0
            break;
1050
1051
0
        case GDT_UInt16:
1052
0
            WeightedBrovey3<WorkDataType, GUInt16, FALSE>(
1053
0
                pPanBuffer, pUpsampledSpectralBuffer,
1054
0
                static_cast<GUInt16 *>(pDataBuf), nValues, nBandValues, 0);
1055
0
            break;
1056
1057
#ifndef LIMIT_TYPES
1058
        case GDT_Int8:
1059
            WeightedBrovey3<WorkDataType, GInt8, FALSE>(
1060
                pPanBuffer, pUpsampledSpectralBuffer,
1061
                static_cast<GInt8 *>(pDataBuf), nValues, nBandValues, 0);
1062
            break;
1063
1064
        case GDT_Int16:
1065
            WeightedBrovey3<WorkDataType, GInt16, FALSE>(
1066
                pPanBuffer, pUpsampledSpectralBuffer,
1067
                static_cast<GInt16 *>(pDataBuf), nValues, nBandValues, 0);
1068
            break;
1069
1070
        case GDT_UInt32:
1071
            WeightedBrovey3<WorkDataType, GUInt32, FALSE>(
1072
                pPanBuffer, pUpsampledSpectralBuffer,
1073
                static_cast<GUInt32 *>(pDataBuf), nValues, nBandValues, 0);
1074
            break;
1075
1076
        case GDT_Int32:
1077
            WeightedBrovey3<WorkDataType, GInt32, FALSE>(
1078
                pPanBuffer, pUpsampledSpectralBuffer,
1079
                static_cast<GInt32 *>(pDataBuf), nValues, nBandValues, 0);
1080
            break;
1081
1082
        case GDT_UInt64:
1083
            WeightedBrovey3<WorkDataType, std::uint64_t, FALSE>(
1084
                pPanBuffer, pUpsampledSpectralBuffer,
1085
                static_cast<std::uint64_t *>(pDataBuf), nValues, nBandValues,
1086
                0);
1087
            break;
1088
1089
        case GDT_Int64:
1090
            WeightedBrovey3<WorkDataType, std::int64_t, FALSE>(
1091
                pPanBuffer, pUpsampledSpectralBuffer,
1092
                static_cast<std::int64_t *>(pDataBuf), nValues, nBandValues, 0);
1093
            break;
1094
1095
        case GDT_Float16:
1096
            WeightedBrovey3<WorkDataType, GFloat16, FALSE>(
1097
                pPanBuffer, pUpsampledSpectralBuffer,
1098
                static_cast<GFloat16 *>(pDataBuf), nValues, nBandValues, 0);
1099
            break;
1100
1101
        case GDT_Float32:
1102
            WeightedBrovey3<WorkDataType, float, FALSE>(
1103
                pPanBuffer, pUpsampledSpectralBuffer,
1104
                static_cast<float *>(pDataBuf), nValues, nBandValues, 0);
1105
            break;
1106
#endif
1107
1108
0
        case GDT_Float64:
1109
0
            WeightedBrovey3<WorkDataType, double, FALSE>(
1110
0
                pPanBuffer, pUpsampledSpectralBuffer,
1111
0
                static_cast<double *>(pDataBuf), nValues, nBandValues, 0);
1112
0
            break;
1113
1114
0
        default:
1115
0
            CPLError(CE_Failure, CPLE_NotSupported,
1116
0
                     "eBufDataType not supported");
1117
0
            return CE_Failure;
1118
0
            break;
1119
0
    }
1120
1121
0
    return CE_None;
1122
0
}
1123
1124
/************************************************************************/
1125
/*                           ClampValues()                              */
1126
/************************************************************************/
1127
1128
template <class T>
1129
static void ClampValues(T *panBuffer, size_t nValues, T nMaxVal)
1130
0
{
1131
0
    for (size_t i = 0; i < nValues; i++)
1132
0
    {
1133
0
        if (panBuffer[i] > nMaxVal)
1134
0
            panBuffer[i] = nMaxVal;
1135
0
    }
1136
0
}
Unexecuted instantiation: gdalpansharpen.cpp:void ClampValues<unsigned char>(unsigned char*, unsigned long, unsigned char)
Unexecuted instantiation: gdalpansharpen.cpp:void ClampValues<unsigned short>(unsigned short*, unsigned long, unsigned short)
1137
1138
/************************************************************************/
1139
/*                         ProcessRegion()                              */
1140
/************************************************************************/
1141
1142
/** Executes a pansharpening operation on a rectangular region of the
1143
 * resulting dataset.
1144
 *
1145
 * The window is expressed with respect to the dimensions of the panchromatic
1146
 * band.
1147
 *
1148
 * Spectral bands are upsampled and merged with the panchromatic band according
1149
 * to the select algorithm and options.
1150
 *
1151
 * @param nXOff pixel offset.
1152
 * @param nYOff pixel offset.
1153
 * @param nXSize width of the pansharpened region to compute.
1154
 * @param nYSize height of the pansharpened region to compute.
1155
 * @param pDataBuf output buffer. Must be nXSize * nYSize *
1156
 *                 GDALGetDataTypeSizeBytes(eBufDataType) *
1157
 *                 psOptions->nOutPansharpenedBands large.
1158
 *                 It begins with all values of the first output band, followed
1159
 *                 by values of the second output band, etc...
1160
 * @param eBufDataType data type of the output buffer
1161
 *
1162
 * @return CE_None in case of success, CE_Failure in case of failure.
1163
 *
1164
 * @since GDAL 2.1
1165
 */
1166
CPLErr GDALPansharpenOperation::ProcessRegion(int nXOff, int nYOff, int nXSize,
1167
                                              int nYSize, void *pDataBuf,
1168
                                              GDALDataType eBufDataType)
1169
0
{
1170
0
    if (psOptions == nullptr)
1171
0
        return CE_Failure;
1172
1173
    // TODO: Avoid allocating buffers each time.
1174
0
    GDALRasterBand *poPanchroBand =
1175
0
        GDALRasterBand::FromHandle(psOptions->hPanchroBand);
1176
0
    GDALDataType eWorkDataType = poPanchroBand->GetRasterDataType();
1177
0
#ifdef LIMIT_TYPES
1178
0
    if (eWorkDataType != GDT_Byte && eWorkDataType != GDT_UInt16)
1179
0
        eWorkDataType = GDT_Float64;
1180
0
#endif
1181
0
    const int nDataTypeSize = GDALGetDataTypeSizeBytes(eWorkDataType);
1182
0
    GByte *pUpsampledSpectralBuffer = static_cast<GByte *>(VSI_MALLOC3_VERBOSE(
1183
0
        nXSize, nYSize,
1184
0
        cpl::fits_on<int>(psOptions->nInputSpectralBands * nDataTypeSize)));
1185
0
    GByte *pPanBuffer = static_cast<GByte *>(
1186
0
        VSI_MALLOC3_VERBOSE(nXSize, nYSize, nDataTypeSize));
1187
0
    if (pUpsampledSpectralBuffer == nullptr || pPanBuffer == nullptr)
1188
0
    {
1189
0
        VSIFree(pUpsampledSpectralBuffer);
1190
0
        VSIFree(pPanBuffer);
1191
0
        return CE_Failure;
1192
0
    }
1193
1194
0
    CPLErr eErr = poPanchroBand->RasterIO(GF_Read, nXOff, nYOff, nXSize, nYSize,
1195
0
                                          pPanBuffer, nXSize, nYSize,
1196
0
                                          eWorkDataType, 0, 0, nullptr);
1197
0
    if (eErr != CE_None)
1198
0
    {
1199
0
        VSIFree(pUpsampledSpectralBuffer);
1200
0
        VSIFree(pPanBuffer);
1201
0
        return CE_Failure;
1202
0
    }
1203
1204
0
    int nTasks = 0;
1205
0
    if (poThreadPool)
1206
0
    {
1207
0
        nTasks = poThreadPool->GetThreadCount();
1208
0
        if (nTasks > nYSize)
1209
0
            nTasks = nYSize;
1210
0
    }
1211
1212
0
    GDALRasterIOExtraArg sExtraArg;
1213
0
    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
1214
0
    const GDALRIOResampleAlg eResampleAlg = psOptions->eResampleAlg;
1215
    // cppcheck-suppress redundantAssignment
1216
0
    sExtraArg.eResampleAlg = eResampleAlg;
1217
0
    sExtraArg.bFloatingPointWindowValidity = TRUE;
1218
0
    sExtraArg.dfXOff = m_panToMSGT[0] + nXOff * m_panToMSGT[1];
1219
0
    sExtraArg.dfYOff = m_panToMSGT[3] + nYOff * m_panToMSGT[5];
1220
0
    sExtraArg.dfXSize = nXSize * m_panToMSGT[1];
1221
0
    sExtraArg.dfYSize = nYSize * m_panToMSGT[5];
1222
0
    if (sExtraArg.dfXOff + sExtraArg.dfXSize > aMSBands[0]->GetXSize())
1223
0
        sExtraArg.dfXSize = aMSBands[0]->GetXSize() - sExtraArg.dfXOff;
1224
0
    if (sExtraArg.dfYOff + sExtraArg.dfYSize > aMSBands[0]->GetYSize())
1225
0
        sExtraArg.dfYSize = aMSBands[0]->GetYSize() - sExtraArg.dfYOff;
1226
0
    int nSpectralXOff = static_cast<int>(sExtraArg.dfXOff);
1227
0
    int nSpectralYOff = static_cast<int>(sExtraArg.dfYOff);
1228
0
    int nSpectralXSize = static_cast<int>(0.49999 + sExtraArg.dfXSize);
1229
0
    int nSpectralYSize = static_cast<int>(0.49999 + sExtraArg.dfYSize);
1230
0
    if (nSpectralXOff + nSpectralXSize > aMSBands[0]->GetXSize())
1231
0
        nSpectralXSize = aMSBands[0]->GetXSize() - nSpectralXOff;
1232
0
    if (nSpectralYOff + nSpectralYSize > aMSBands[0]->GetYSize())
1233
0
        nSpectralYSize = aMSBands[0]->GetYSize() - nSpectralYOff;
1234
0
    if (nSpectralXSize == 0)
1235
0
        nSpectralXSize = 1;
1236
0
    if (nSpectralYSize == 0)
1237
0
        nSpectralYSize = 1;
1238
1239
    // When upsampling, extract the multispectral data at
1240
    // full resolution in a temp buffer, and then do the upsampling.
1241
0
    if (nSpectralXSize < nXSize && nSpectralYSize < nYSize &&
1242
0
        eResampleAlg != GRIORA_NearestNeighbour && nYSize > 1)
1243
0
    {
1244
        // Take some margin to take into account the radius of the
1245
        // resampling kernel.
1246
0
        int nXOffExtract = nSpectralXOff - nKernelRadius;
1247
0
        int nYOffExtract = nSpectralYOff - nKernelRadius;
1248
0
        int nXSizeExtract = nSpectralXSize + 1 + 2 * nKernelRadius;
1249
0
        int nYSizeExtract = nSpectralYSize + 1 + 2 * nKernelRadius;
1250
0
        if (nXOffExtract < 0)
1251
0
        {
1252
0
            nXSizeExtract += nXOffExtract;
1253
0
            nXOffExtract = 0;
1254
0
        }
1255
0
        if (nYOffExtract < 0)
1256
0
        {
1257
0
            nYSizeExtract += nYOffExtract;
1258
0
            nYOffExtract = 0;
1259
0
        }
1260
0
        if (nXOffExtract + nXSizeExtract > aMSBands[0]->GetXSize())
1261
0
            nXSizeExtract = aMSBands[0]->GetXSize() - nXOffExtract;
1262
0
        if (nYOffExtract + nYSizeExtract > aMSBands[0]->GetYSize())
1263
0
            nYSizeExtract = aMSBands[0]->GetYSize() - nYOffExtract;
1264
1265
0
        GByte *pSpectralBuffer = static_cast<GByte *>(VSI_MALLOC3_VERBOSE(
1266
0
            nXSizeExtract, nYSizeExtract,
1267
0
            cpl::fits_on<int>(psOptions->nInputSpectralBands * nDataTypeSize)));
1268
0
        if (pSpectralBuffer == nullptr)
1269
0
        {
1270
0
            VSIFree(pUpsampledSpectralBuffer);
1271
0
            VSIFree(pPanBuffer);
1272
0
            return CE_Failure;
1273
0
        }
1274
1275
0
        if (!anInputBands.empty())
1276
0
        {
1277
            // Use dataset RasterIO when possible.
1278
0
            eErr = aMSBands[0]->GetDataset()->RasterIO(
1279
0
                GF_Read, nXOffExtract, nYOffExtract, nXSizeExtract,
1280
0
                nYSizeExtract, pSpectralBuffer, nXSizeExtract, nYSizeExtract,
1281
0
                eWorkDataType, static_cast<int>(anInputBands.size()),
1282
0
                &anInputBands[0], 0, 0, 0, nullptr);
1283
0
        }
1284
0
        else
1285
0
        {
1286
0
            for (int i = 0;
1287
0
                 eErr == CE_None && i < psOptions->nInputSpectralBands; i++)
1288
0
            {
1289
0
                eErr = aMSBands[i]->RasterIO(
1290
0
                    GF_Read, nXOffExtract, nYOffExtract, nXSizeExtract,
1291
0
                    nYSizeExtract,
1292
0
                    pSpectralBuffer + static_cast<size_t>(i) * nXSizeExtract *
1293
0
                                          nYSizeExtract * nDataTypeSize,
1294
0
                    nXSizeExtract, nYSizeExtract, eWorkDataType, 0, 0, nullptr);
1295
0
            }
1296
0
        }
1297
0
        if (eErr != CE_None)
1298
0
        {
1299
0
            VSIFree(pSpectralBuffer);
1300
0
            VSIFree(pUpsampledSpectralBuffer);
1301
0
            VSIFree(pPanBuffer);
1302
0
            return CE_Failure;
1303
0
        }
1304
1305
        // Create a MEM dataset that wraps the input buffer.
1306
0
        auto poMEMDS = MEMDataset::Create("", nXSizeExtract, nYSizeExtract, 0,
1307
0
                                          eWorkDataType, nullptr);
1308
1309
0
        for (int i = 0; i < psOptions->nInputSpectralBands; i++)
1310
0
        {
1311
0
            GByte *pabyBuffer =
1312
0
                pSpectralBuffer + static_cast<size_t>(i) * nDataTypeSize *
1313
0
                                      nXSizeExtract * nYSizeExtract;
1314
0
            GDALRasterBandH hMEMBand = MEMCreateRasterBandEx(
1315
0
                poMEMDS, i + 1, pabyBuffer, eWorkDataType, 0, 0, false);
1316
0
            poMEMDS->AddMEMBand(hMEMBand);
1317
1318
0
            const char *pszNBITS =
1319
0
                aMSBands[i]->GetMetadataItem("NBITS", "IMAGE_STRUCTURE");
1320
0
            if (pszNBITS)
1321
0
                poMEMDS->GetRasterBand(i + 1)->SetMetadataItem(
1322
0
                    "NBITS", pszNBITS, "IMAGE_STRUCTURE");
1323
1324
0
            if (psOptions->bHasNoData)
1325
0
                poMEMDS->GetRasterBand(i + 1)->SetNoDataValue(
1326
0
                    psOptions->dfNoData);
1327
0
        }
1328
1329
0
        if (nTasks <= 1)
1330
0
        {
1331
0
            nSpectralXOff -= nXOffExtract;
1332
0
            nSpectralYOff -= nYOffExtract;
1333
0
            sExtraArg.dfXOff -= nXOffExtract;
1334
0
            sExtraArg.dfYOff -= nYOffExtract;
1335
0
            CPL_IGNORE_RET_VAL(poMEMDS->RasterIO(
1336
0
                GF_Read, nSpectralXOff, nSpectralYOff, nSpectralXSize,
1337
0
                nSpectralYSize, pUpsampledSpectralBuffer, nXSize, nYSize,
1338
0
                eWorkDataType, psOptions->nInputSpectralBands, nullptr, 0, 0, 0,
1339
0
                &sExtraArg));
1340
0
        }
1341
0
        else
1342
0
        {
1343
            // We are abusing the contract of the GDAL API by using the
1344
            // MEMDataset from several threads. In this case, this is safe. In
1345
            // case, that would no longer be the case we could create as many
1346
            // MEMDataset as threads pointing to the same buffer.
1347
1348
            // To avoid races in threads, we query now the mask flags,
1349
            // so that implicit mask bands are created now.
1350
0
            for (int i = 0; i < poMEMDS->GetRasterCount(); i++)
1351
0
            {
1352
0
                poMEMDS->GetRasterBand(i + 1)->GetMaskFlags();
1353
0
            }
1354
1355
0
            std::vector<GDALPansharpenResampleJob> asJobs;
1356
0
            asJobs.resize(nTasks);
1357
0
            GDALPansharpenResampleJob *pasJobs = &(asJobs[0]);
1358
0
            {
1359
0
                std::vector<void *> ahJobData;
1360
0
                ahJobData.resize(nTasks);
1361
1362
#ifdef DEBUG_TIMING
1363
                struct timeval tv;
1364
#endif
1365
0
                for (int i = 0; i < nTasks; i++)
1366
0
                {
1367
0
                    const size_t iStartLine =
1368
0
                        (static_cast<size_t>(i) * nYSize) / nTasks;
1369
0
                    const size_t iNextStartLine =
1370
0
                        (static_cast<size_t>(i + 1) * nYSize) / nTasks;
1371
0
                    pasJobs[i].poMEMDS = poMEMDS;
1372
0
                    pasJobs[i].eResampleAlg = eResampleAlg;
1373
0
                    pasJobs[i].dfXOff = sExtraArg.dfXOff - nXOffExtract;
1374
0
                    pasJobs[i].dfYOff = m_panToMSGT[3] +
1375
0
                                        (nYOff + iStartLine) * m_panToMSGT[5] -
1376
0
                                        nYOffExtract;
1377
0
                    pasJobs[i].dfXSize = sExtraArg.dfXSize;
1378
0
                    pasJobs[i].dfYSize =
1379
0
                        (iNextStartLine - iStartLine) * m_panToMSGT[5];
1380
0
                    if (pasJobs[i].dfXOff + pasJobs[i].dfXSize > nXSizeExtract)
1381
0
                    {
1382
0
                        pasJobs[i].dfXSize = nYSizeExtract - pasJobs[i].dfXOff;
1383
0
                    }
1384
0
                    if (pasJobs[i].dfYOff + pasJobs[i].dfYSize >
1385
0
                        aMSBands[0]->GetYSize())
1386
0
                    {
1387
0
                        pasJobs[i].dfYSize =
1388
0
                            aMSBands[0]->GetYSize() - pasJobs[i].dfYOff;
1389
0
                    }
1390
0
                    pasJobs[i].nXOff = static_cast<int>(pasJobs[i].dfXOff);
1391
0
                    pasJobs[i].nYOff = static_cast<int>(pasJobs[i].dfYOff);
1392
0
                    pasJobs[i].nXSize =
1393
0
                        static_cast<int>(0.4999 + pasJobs[i].dfXSize);
1394
0
                    pasJobs[i].nYSize =
1395
0
                        static_cast<int>(0.4999 + pasJobs[i].dfYSize);
1396
0
                    if (pasJobs[i].nXOff + pasJobs[i].nXSize > nXSizeExtract)
1397
0
                    {
1398
0
                        pasJobs[i].nXSize = nXSizeExtract - pasJobs[i].nXOff;
1399
0
                    }
1400
0
                    if (pasJobs[i].nYOff + pasJobs[i].nYSize > nYSizeExtract)
1401
0
                    {
1402
0
                        pasJobs[i].nYSize = nYSizeExtract - pasJobs[i].nYOff;
1403
0
                    }
1404
0
                    if (pasJobs[i].nXSize == 0)
1405
0
                        pasJobs[i].nXSize = 1;
1406
0
                    if (pasJobs[i].nYSize == 0)
1407
0
                        pasJobs[i].nYSize = 1;
1408
0
                    pasJobs[i].pBuffer = pUpsampledSpectralBuffer +
1409
0
                                         static_cast<size_t>(iStartLine) *
1410
0
                                             nXSize * nDataTypeSize;
1411
0
                    pasJobs[i].eDT = eWorkDataType;
1412
0
                    pasJobs[i].nBufXSize = nXSize;
1413
0
                    pasJobs[i].nBufYSize =
1414
0
                        static_cast<int>(iNextStartLine - iStartLine);
1415
0
                    pasJobs[i].nBandCount = psOptions->nInputSpectralBands;
1416
0
                    pasJobs[i].nBandSpace =
1417
0
                        static_cast<GSpacing>(nXSize) * nYSize * nDataTypeSize;
1418
#ifdef DEBUG_TIMING
1419
                    pasJobs[i].ptv = &tv;
1420
#endif
1421
0
                    pasJobs[i].eErr = CE_Failure;
1422
1423
0
                    ahJobData[i] = &(pasJobs[i]);
1424
0
                }
1425
#ifdef DEBUG_TIMING
1426
                gettimeofday(&tv, nullptr);
1427
#endif
1428
0
                poThreadPool->SubmitJobs(PansharpenResampleJobThreadFunc,
1429
0
                                         ahJobData);
1430
0
                poThreadPool->WaitCompletion();
1431
1432
0
                for (int i = 0; i < nTasks; i++)
1433
0
                {
1434
0
                    if (pasJobs[i].eErr == CE_Failure)
1435
0
                    {
1436
0
                        CPLError(CE_Failure, CPLE_AppDefined, "%s",
1437
0
                                 pasJobs[i].osLastErrorMsg.c_str());
1438
0
                        GDALClose(poMEMDS);
1439
0
                        VSIFree(pSpectralBuffer);
1440
0
                        VSIFree(pUpsampledSpectralBuffer);
1441
0
                        VSIFree(pPanBuffer);
1442
1443
0
                        return CE_Failure;
1444
0
                    }
1445
0
                }
1446
0
            }
1447
0
        }
1448
1449
0
        GDALClose(poMEMDS);
1450
1451
0
        VSIFree(pSpectralBuffer);
1452
0
    }
1453
0
    else
1454
0
    {
1455
0
        if (!anInputBands.empty())
1456
0
        {
1457
            // Use dataset RasterIO when possible.
1458
0
            eErr = aMSBands[0]->GetDataset()->RasterIO(
1459
0
                GF_Read, nSpectralXOff, nSpectralYOff, nSpectralXSize,
1460
0
                nSpectralYSize, pUpsampledSpectralBuffer, nXSize, nYSize,
1461
0
                eWorkDataType, static_cast<int>(anInputBands.size()),
1462
0
                &anInputBands[0], 0, 0, 0, &sExtraArg);
1463
0
        }
1464
0
        else
1465
0
        {
1466
0
            for (int i = 0;
1467
0
                 eErr == CE_None && i < psOptions->nInputSpectralBands; i++)
1468
0
            {
1469
0
                eErr = aMSBands[i]->RasterIO(
1470
0
                    GF_Read, nSpectralXOff, nSpectralYOff, nSpectralXSize,
1471
0
                    nSpectralYSize,
1472
0
                    pUpsampledSpectralBuffer + static_cast<size_t>(i) * nXSize *
1473
0
                                                   nYSize * nDataTypeSize,
1474
0
                    nXSize, nYSize, eWorkDataType, 0, 0, &sExtraArg);
1475
0
            }
1476
0
        }
1477
0
        if (eErr != CE_None)
1478
0
        {
1479
0
            VSIFree(pUpsampledSpectralBuffer);
1480
0
            VSIFree(pPanBuffer);
1481
0
            return CE_Failure;
1482
0
        }
1483
0
    }
1484
1485
    // In case NBITS was not set on the spectral bands, clamp the values
1486
    // if overshoot might have occurred.
1487
0
    int nBitDepth = psOptions->nBitDepth;
1488
0
    if (nBitDepth &&
1489
0
        (eResampleAlg == GRIORA_Cubic || eResampleAlg == GRIORA_CubicSpline ||
1490
0
         eResampleAlg == GRIORA_Lanczos))
1491
0
    {
1492
0
        for (int i = 0; i < psOptions->nInputSpectralBands; i++)
1493
0
        {
1494
0
            GDALRasterBand *poBand = aMSBands[i];
1495
0
            int nBandBitDepth = 0;
1496
0
            const char *pszNBITS =
1497
0
                poBand->GetMetadataItem("NBITS", "IMAGE_STRUCTURE");
1498
0
            if (pszNBITS)
1499
0
                nBandBitDepth = atoi(pszNBITS);
1500
0
            if (nBandBitDepth < nBitDepth)
1501
0
            {
1502
0
                if (eWorkDataType == GDT_Byte && nBitDepth >= 0 &&
1503
0
                    nBitDepth <= 8)
1504
0
                {
1505
0
                    ClampValues(
1506
0
                        reinterpret_cast<GByte *>(pUpsampledSpectralBuffer) +
1507
0
                            static_cast<size_t>(i) * nXSize * nYSize,
1508
0
                        static_cast<size_t>(nXSize) * nYSize,
1509
0
                        static_cast<GByte>((1 << nBitDepth) - 1));
1510
0
                }
1511
0
                else if (eWorkDataType == GDT_UInt16 && nBitDepth >= 0 &&
1512
0
                         nBitDepth <= 16)
1513
0
                {
1514
0
                    ClampValues(
1515
0
                        reinterpret_cast<GUInt16 *>(pUpsampledSpectralBuffer) +
1516
0
                            static_cast<size_t>(i) * nXSize * nYSize,
1517
0
                        static_cast<size_t>(nXSize) * nYSize,
1518
0
                        static_cast<GUInt16>((1 << nBitDepth) - 1));
1519
0
                }
1520
#ifndef LIMIT_TYPES
1521
                else if (eWorkDataType == GDT_UInt32)
1522
                {
1523
                    ClampValues(reinterpret_cast<GUInt32*>(pUpsampledSpectralBuffer) +
1524
                                static_cast<size_t>(i) * nXSize * nYSize,
1525
                                static_cast<size_t>(nXSize)*nYSize,
1526
                                (static_cast<GUInt32>((1 << nBitDepth)-1));
1527
                }
1528
#endif
1529
0
            }
1530
0
        }
1531
0
    }
1532
1533
0
    const GUInt32 nMaxValue = (nBitDepth >= 0 && nBitDepth <= 31)
1534
0
                                  ? (1U << nBitDepth) - 1
1535
0
                                  : UINT32_MAX;
1536
1537
0
    double *padfTempBuffer = nullptr;
1538
0
    GDALDataType eBufDataTypeOri = eBufDataType;
1539
0
    void *pDataBufOri = pDataBuf;
1540
    // CFloat64 is the query type used by gdallocationinfo...
1541
0
#ifdef LIMIT_TYPES
1542
0
    if (eBufDataType != GDT_Byte && eBufDataType != GDT_UInt16)
1543
#else
1544
    if (eBufDataType == GDT_CFloat64)
1545
#endif
1546
0
    {
1547
0
        padfTempBuffer = static_cast<double *>(VSI_MALLOC3_VERBOSE(
1548
0
            nXSize, nYSize, psOptions->nOutPansharpenedBands * sizeof(double)));
1549
0
        if (padfTempBuffer == nullptr)
1550
0
        {
1551
0
            VSIFree(pUpsampledSpectralBuffer);
1552
0
            VSIFree(pPanBuffer);
1553
0
            return CE_Failure;
1554
0
        }
1555
0
        pDataBuf = padfTempBuffer;
1556
0
        eBufDataType = GDT_Float64;
1557
0
    }
1558
1559
0
    if (nTasks > 1)
1560
0
    {
1561
0
        std::vector<GDALPansharpenJob> asJobs;
1562
0
        asJobs.resize(nTasks);
1563
0
        GDALPansharpenJob *pasJobs = &(asJobs[0]);
1564
0
        {
1565
0
            std::vector<void *> ahJobData;
1566
0
            ahJobData.resize(nTasks);
1567
#ifdef DEBUG_TIMING
1568
            struct timeval tv;
1569
#endif
1570
0
            for (int i = 0; i < nTasks; i++)
1571
0
            {
1572
0
                const size_t iStartLine =
1573
0
                    (static_cast<size_t>(i) * nYSize) / nTasks;
1574
0
                const size_t iNextStartLine =
1575
0
                    (static_cast<size_t>(i + 1) * nYSize) / nTasks;
1576
0
                pasJobs[i].poPansharpenOperation = this;
1577
0
                pasJobs[i].eWorkDataType = eWorkDataType;
1578
0
                pasJobs[i].eBufDataType = eBufDataType;
1579
0
                pasJobs[i].pPanBuffer =
1580
0
                    pPanBuffer + iStartLine * nXSize * nDataTypeSize;
1581
0
                pasJobs[i].pUpsampledSpectralBuffer =
1582
0
                    pUpsampledSpectralBuffer +
1583
0
                    iStartLine * nXSize * nDataTypeSize;
1584
0
                pasJobs[i].pDataBuf =
1585
0
                    static_cast<GByte *>(pDataBuf) +
1586
0
                    iStartLine * nXSize *
1587
0
                        GDALGetDataTypeSizeBytes(eBufDataType);
1588
0
                pasJobs[i].nValues = (iNextStartLine - iStartLine) * nXSize;
1589
0
                pasJobs[i].nBandValues = static_cast<size_t>(nXSize) * nYSize;
1590
0
                pasJobs[i].nMaxValue = nMaxValue;
1591
#ifdef DEBUG_TIMING
1592
                pasJobs[i].ptv = &tv;
1593
#endif
1594
0
                ahJobData[i] = &(pasJobs[i]);
1595
0
            }
1596
#ifdef DEBUG_TIMING
1597
            gettimeofday(&tv, nullptr);
1598
#endif
1599
0
            poThreadPool->SubmitJobs(PansharpenJobThreadFunc, ahJobData);
1600
0
            poThreadPool->WaitCompletion();
1601
0
        }
1602
1603
0
        eErr = CE_None;
1604
0
        for (int i = 0; i < nTasks; i++)
1605
0
        {
1606
0
            if (pasJobs[i].eErr != CE_None)
1607
0
                eErr = CE_Failure;
1608
0
        }
1609
0
    }
1610
0
    else
1611
0
    {
1612
0
        eErr = PansharpenChunk(eWorkDataType, eBufDataType, pPanBuffer,
1613
0
                               pUpsampledSpectralBuffer, pDataBuf,
1614
0
                               static_cast<size_t>(nXSize) * nYSize,
1615
0
                               static_cast<size_t>(nXSize) * nYSize, nMaxValue);
1616
0
    }
1617
1618
0
    if (padfTempBuffer)
1619
0
    {
1620
0
        GDALCopyWords64(padfTempBuffer, GDT_Float64, sizeof(double),
1621
0
                        pDataBufOri, eBufDataTypeOri,
1622
0
                        GDALGetDataTypeSizeBytes(eBufDataTypeOri),
1623
0
                        static_cast<size_t>(nXSize) * nYSize *
1624
0
                            psOptions->nOutPansharpenedBands);
1625
0
        VSIFree(padfTempBuffer);
1626
0
    }
1627
1628
0
    VSIFree(pUpsampledSpectralBuffer);
1629
0
    VSIFree(pPanBuffer);
1630
1631
0
    return eErr;
1632
0
}
1633
1634
/************************************************************************/
1635
/*                   PansharpenResampleJobThreadFunc()                  */
1636
/************************************************************************/
1637
1638
void GDALPansharpenOperation::PansharpenResampleJobThreadFunc(void *pUserData)
1639
0
{
1640
0
    GDALPansharpenResampleJob *psJob =
1641
0
        static_cast<GDALPansharpenResampleJob *>(pUserData);
1642
1643
#ifdef DEBUG_TIMING
1644
    struct timeval tv;
1645
    gettimeofday(&tv, nullptr);
1646
    const GIntBig launch_time =
1647
        static_cast<GIntBig>(psJob->ptv->tv_sec) * 1000000 +
1648
        static_cast<GIntBig>(psJob->ptv->tv_usec);
1649
    const GIntBig start_job = static_cast<GIntBig>(tv.tv_sec) * 1000000 +
1650
                              static_cast<GIntBig>(tv.tv_usec);
1651
#endif
1652
1653
0
    GDALRasterIOExtraArg sExtraArg;
1654
0
    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
1655
    // cppcheck-suppress redundantAssignment
1656
0
    sExtraArg.eResampleAlg = psJob->eResampleAlg;
1657
0
    sExtraArg.bFloatingPointWindowValidity = TRUE;
1658
0
    sExtraArg.dfXOff = psJob->dfXOff;
1659
0
    sExtraArg.dfYOff = psJob->dfYOff;
1660
0
    sExtraArg.dfXSize = psJob->dfXSize;
1661
0
    sExtraArg.dfYSize = psJob->dfYSize;
1662
1663
0
    std::vector<int> anBands;
1664
0
    for (int i = 0; i < psJob->nBandCount; ++i)
1665
0
        anBands.push_back(i + 1);
1666
    // This call to RasterIO() in a thread to poMEMDS shared between several
1667
    // threads is really risky, but works given the implementation details...
1668
    // Do not do this at home!
1669
0
    psJob->eErr = psJob->poMEMDS->RasterIO(
1670
0
        GF_Read, psJob->nXOff, psJob->nYOff, psJob->nXSize, psJob->nYSize,
1671
0
        psJob->pBuffer, psJob->nBufXSize, psJob->nBufYSize, psJob->eDT,
1672
0
        psJob->nBandCount, anBands.data(), 0, 0, psJob->nBandSpace, &sExtraArg);
1673
0
    if (CPLGetLastErrorType() == CE_Failure)
1674
0
        psJob->osLastErrorMsg = CPLGetLastErrorMsg();
1675
1676
#ifdef DEBUG_TIMING
1677
    struct timeval tv_end;
1678
    gettimeofday(&tv_end, nullptr);
1679
    const GIntBig end = static_cast<GIntBig>(tv_end.tv_sec) * 1000000 +
1680
                        static_cast<GIntBig>(tv_end.tv_usec);
1681
    if (start_job - launch_time > 500)
1682
        /*ok*/ printf("Resample: Delay before start=" CPL_FRMT_GIB
1683
                      ", completion time=" CPL_FRMT_GIB "\n",
1684
                      start_job - launch_time, end - start_job);
1685
#endif
1686
0
}
1687
1688
/************************************************************************/
1689
/*                      PansharpenJobThreadFunc()                       */
1690
/************************************************************************/
1691
1692
void GDALPansharpenOperation::PansharpenJobThreadFunc(void *pUserData)
1693
0
{
1694
0
    GDALPansharpenJob *psJob = static_cast<GDALPansharpenJob *>(pUserData);
1695
1696
#ifdef DEBUG_TIMING
1697
    struct timeval tv;
1698
    gettimeofday(&tv, nullptr);
1699
    const GIntBig launch_time =
1700
        static_cast<GIntBig>(psJob->ptv->tv_sec) * 1000000 +
1701
        static_cast<GIntBig>(psJob->ptv->tv_usec);
1702
    const GIntBig start_job = static_cast<GIntBig>(tv.tv_sec) * 1000000 +
1703
                              static_cast<GIntBig>(tv.tv_usec);
1704
#endif
1705
1706
#if 0
1707
    for( int i = 0; i < 1000000; i++ )
1708
        acc += i * i;
1709
    psJob->eErr = CE_None;
1710
#else
1711
0
    psJob->eErr = psJob->poPansharpenOperation->PansharpenChunk(
1712
0
        psJob->eWorkDataType, psJob->eBufDataType, psJob->pPanBuffer,
1713
0
        psJob->pUpsampledSpectralBuffer, psJob->pDataBuf, psJob->nValues,
1714
0
        psJob->nBandValues, psJob->nMaxValue);
1715
0
#endif
1716
1717
#ifdef DEBUG_TIMING
1718
    struct timeval tv_end;
1719
    gettimeofday(&tv_end, nullptr);
1720
    const GIntBig end = static_cast<GIntBig>(tv_end.tv_sec) * 1000000 +
1721
                        static_cast<GIntBig>(tv_end.tv_usec);
1722
    if (start_job - launch_time > 500)
1723
        /*ok*/ printf("Pansharpen: Delay before start=" CPL_FRMT_GIB
1724
                      ", completion time=" CPL_FRMT_GIB "\n",
1725
                      start_job - launch_time, end - start_job);
1726
#endif
1727
0
}
1728
1729
/************************************************************************/
1730
/*                           PansharpenChunk()                          */
1731
/************************************************************************/
1732
1733
CPLErr GDALPansharpenOperation::PansharpenChunk(
1734
    GDALDataType eWorkDataType, GDALDataType eBufDataType,
1735
    const void *pPanBuffer, const void *pUpsampledSpectralBuffer,
1736
    void *pDataBuf, size_t nValues, size_t nBandValues, GUInt32 nMaxValue) const
1737
0
{
1738
0
    CPLErr eErr = CE_None;
1739
1740
0
    switch (eWorkDataType)
1741
0
    {
1742
0
        case GDT_Byte:
1743
0
            eErr = WeightedBrovey(
1744
0
                static_cast<const GByte *>(pPanBuffer),
1745
0
                static_cast<const GByte *>(pUpsampledSpectralBuffer), pDataBuf,
1746
0
                eBufDataType, nValues, nBandValues,
1747
0
                static_cast<GByte>(nMaxValue));
1748
0
            break;
1749
1750
0
        case GDT_UInt16:
1751
0
            eErr = WeightedBrovey(
1752
0
                static_cast<const GUInt16 *>(pPanBuffer),
1753
0
                static_cast<const GUInt16 *>(pUpsampledSpectralBuffer),
1754
0
                pDataBuf, eBufDataType, nValues, nBandValues,
1755
0
                static_cast<GUInt16>(nMaxValue));
1756
0
            break;
1757
1758
#ifndef LIMIT_TYPES
1759
        case GDT_Int8:
1760
            eErr = WeightedBrovey(
1761
                static_cast<const GInt8 *>(pPanBuffer),
1762
                static_cast<const GInt8 *>(pUpsampledSpectralBuffer), pDataBuf,
1763
                eBufDataType, nValues, nBandValues);
1764
            break;
1765
1766
        case GDT_Int16:
1767
            eErr = WeightedBrovey(
1768
                static_cast<const GInt16 *>(pPanBuffer),
1769
                static_cast<const GInt16 *>(pUpsampledSpectralBuffer), pDataBuf,
1770
                eBufDataType, nValues, nBandValues);
1771
            break;
1772
1773
        case GDT_UInt32:
1774
            eErr = WeightedBrovey(
1775
                static_cast<const GUInt32 *>(pPanBuffer),
1776
                static_cast<const GUInt32 *>(pUpsampledSpectralBuffer),
1777
                pDataBuf, eBufDataType, nValues, nBandValues, nMaxValue);
1778
            break;
1779
1780
        case GDT_Int32:
1781
            eErr = WeightedBrovey(
1782
                static_cast<const GInt32 *>(pPanBuffer),
1783
                static_cast<const GInt32 *>(pUpsampledSpectralBuffer), pDataBuf,
1784
                eBufDataType, nValues, nBandValues);
1785
            break;
1786
1787
        case GDT_UInt64:
1788
            eErr = WeightedBrovey(
1789
                static_cast<const std::uint64_t *>(pPanBuffer),
1790
                static_cast<const std::uint64_t *>(pUpsampledSpectralBuffer),
1791
                pDataBuf, eBufDataType, nValues, nBandValues, nMaxValue);
1792
            break;
1793
1794
        case GDT_Int64:
1795
            eErr = WeightedBrovey(
1796
                static_cast<const std::int64_t *>(pPanBuffer),
1797
                static_cast<const std::int64_t *>(pUpsampledSpectralBuffer),
1798
                pDataBuf, eBufDataType, nValues, nBandValues);
1799
            break;
1800
1801
        case GDT_Float16:
1802
            eErr = WeightedBrovey(
1803
                static_cast<const GFloat16 *>(pPanBuffer),
1804
                static_cast<const GFloat16 *>(pUpsampledSpectralBuffer),
1805
                pDataBuf, eBufDataType, nValues, nBandValues);
1806
            break;
1807
1808
        case GDT_Float32:
1809
            eErr = WeightedBrovey(
1810
                static_cast<const float *>(pPanBuffer),
1811
                static_cast<const float *>(pUpsampledSpectralBuffer), pDataBuf,
1812
                eBufDataType, nValues, nBandValues);
1813
            break;
1814
#endif
1815
0
        case GDT_Float64:
1816
0
            eErr = WeightedBrovey(
1817
0
                static_cast<const double *>(pPanBuffer),
1818
0
                static_cast<const double *>(pUpsampledSpectralBuffer), pDataBuf,
1819
0
                eBufDataType, nValues, nBandValues);
1820
0
            break;
1821
1822
0
        default:
1823
0
            CPLError(CE_Failure, CPLE_NotSupported,
1824
0
                     "eWorkDataType not supported");
1825
0
            eErr = CE_Failure;
1826
0
            break;
1827
0
    }
1828
1829
0
    return eErr;
1830
0
}
1831
1832
/************************************************************************/
1833
/*                             GetOptions()                             */
1834
/************************************************************************/
1835
1836
/** Return options.
1837
 * @return options.
1838
 */
1839
GDALPansharpenOptions *GDALPansharpenOperation::GetOptions()
1840
0
{
1841
0
    return psOptions;
1842
0
}
1843
1844
/************************************************************************/
1845
/*                     GDALCreatePansharpenOperation()                  */
1846
/************************************************************************/
1847
1848
/** Instantiate a pansharpening operation.
1849
 *
1850
 * The passed options are validated.
1851
 *
1852
 * @param psOptions a pansharpening option structure allocated with
1853
 * GDALCreatePansharpenOptions(). It is duplicated by this function.
1854
 * @return a valid pansharpening operation handle, or NULL in case of failure.
1855
 *
1856
 * @since GDAL 2.1
1857
 */
1858
1859
GDALPansharpenOperationH
1860
GDALCreatePansharpenOperation(const GDALPansharpenOptions *psOptions)
1861
0
{
1862
0
    GDALPansharpenOperation *psOperation = new GDALPansharpenOperation();
1863
0
    if (psOperation->Initialize(psOptions) == CE_None)
1864
0
        return reinterpret_cast<GDALPansharpenOperationH>(psOperation);
1865
0
    delete psOperation;
1866
0
    return nullptr;
1867
0
}
1868
1869
/************************************************************************/
1870
/*                     GDALDestroyPansharpenOperation()                 */
1871
/************************************************************************/
1872
1873
/** Destroy a pansharpening operation.
1874
 *
1875
 * @param hOperation a valid pansharpening operation.
1876
 *
1877
 * @since GDAL 2.1
1878
 */
1879
1880
void GDALDestroyPansharpenOperation(GDALPansharpenOperationH hOperation)
1881
0
{
1882
0
    delete reinterpret_cast<GDALPansharpenOperation *>(hOperation);
1883
0
}
1884
1885
/************************************************************************/
1886
/*                       GDALPansharpenProcessRegion()                  */
1887
/************************************************************************/
1888
1889
/** Executes a pansharpening operation on a rectangular region of the
1890
 * resulting dataset.
1891
 *
1892
 * The window is expressed with respect to the dimensions of the panchromatic
1893
 * band.
1894
 *
1895
 * Spectral bands are upsampled and merged with the panchromatic band according
1896
 * to the select algorithm and options.
1897
 *
1898
 * @param hOperation a valid pansharpening operation.
1899
 * @param nXOff pixel offset.
1900
 * @param nYOff pixel offset.
1901
 * @param nXSize width of the pansharpened region to compute.
1902
 * @param nYSize height of the pansharpened region to compute.
1903
 * @param pDataBuf output buffer. Must be nXSize * nYSize *
1904
 *                 GDALGetDataTypeSizeBytes(eBufDataType) *
1905
 *                 psOptions->nOutPansharpenedBands large.
1906
 *                 It begins with all values of the first output band, followed
1907
 *                 by values of the second output band, etc...
1908
 * @param eBufDataType data type of the output buffer
1909
 *
1910
 * @return CE_None in case of success, CE_Failure in case of failure.
1911
 *
1912
 * @since GDAL 2.1
1913
 */
1914
CPLErr GDALPansharpenProcessRegion(GDALPansharpenOperationH hOperation,
1915
                                   int nXOff, int nYOff, int nXSize, int nYSize,
1916
                                   void *pDataBuf, GDALDataType eBufDataType)
1917
0
{
1918
0
    return reinterpret_cast<GDALPansharpenOperation *>(hOperation)
1919
0
        ->ProcessRegion(nXOff, nYOff, nXSize, nYSize, pDataBuf, eBufDataType);
1920
0
}