Coverage Report

Created: 2026-02-14 06:52

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