Coverage Report

Created: 2025-06-13 06:18

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