Coverage Report

Created: 2025-11-16 06:25

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