AttributeDecoder.cpp 21.4 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/* The copyright in this software is being made available under the BSD
 * Licence, included below.  This software may be subject to other third
 * party and contributor rights, including patent rights, and no such
 * rights are granted under this licence.
 *
 * Copyright (c) 2017-2018, ISO/IEC
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 *
 * * Neither the name of the ISO/IEC nor the names of its contributors
 *   may be used to endorse or promote products derived from this
 *   software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "AttributeDecoder.h"
37

38
#include "DualLutCoder.h"
39
#include "constants.h"
40
#include "entropy.h"
41
#include "io_hls.h"
42
#include "RAHT.h"
43
#include "FixedPoint.h"
44
45
46
47
48
49
50

namespace pcc {

//============================================================================
// An encapsulation of the entropy decoding methods used in attribute coding

struct PCCResidualsDecoder {
51
52
53
54
  EntropyDecoder arithmeticDecoder;
  StaticBitModel binaryModel0;
  AdaptiveBitModel binaryModelDiff[7];
  AdaptiveBitModel binaryModelIsZero[7];
55
  AdaptiveBitModel ctxPredMode[2];
56
  DualLutCoder<false> symbolCoder[2];
57

58
  void start(const char* buf, int buf_len);
59
  void stop();
60
  int decodePredMode(int max);
61
62
63
  uint32_t decodeSymbol(int k1, int k2);
  void decode(uint32_t values[3]);
  uint32_t decode();
64
65
66
67
};

//----------------------------------------------------------------------------

68
void
69
PCCResidualsDecoder::start(const char* buf, int buf_len)
70
{
71
72
  arithmeticDecoder.setBuffer(buf_len, buf);
  arithmeticDecoder.start();
73
74
75
76
}

//----------------------------------------------------------------------------

77
78
79
void
PCCResidualsDecoder::stop()
{
80
  arithmeticDecoder.stop();
81
82
83
84
}

//----------------------------------------------------------------------------

85
86
int
PCCResidualsDecoder::decodePredMode(int maxMode)
87
{
88
89
90
91
92
93
94
95
96
97
98
99
100
101
  int mode = 0;

  if (maxMode == 0)
    return mode;

  int ctxIdx = 0;
  while (arithmeticDecoder.decode(ctxPredMode[ctxIdx])) {
    ctxIdx = 1;
    mode++;
    if (mode == maxMode)
      break;
  }

  return mode;
102
103
104
105
}

//----------------------------------------------------------------------------

106
uint32_t
107
PCCResidualsDecoder::decodeSymbol(int k1, int k2)
108
{
109
110
111
112
113
  if (arithmeticDecoder.decode(binaryModelIsZero[k1])) {
    return 0u;
  }

  uint32_t value = symbolCoder[k2].decode(&arithmeticDecoder);
114
  if (value == kAttributeResidualAlphabetSize) {
115
    value +=
116
      arithmeticDecoder.decodeExpGolomb(0, binaryModel0, binaryModelDiff[k1]);
117
  }
118
119
  ++value;

120
121
122
123
124
  return value;
}

//----------------------------------------------------------------------------

125
126
127
128
129
130
131
132
133
134
135
136
void
PCCResidualsDecoder::decode(uint32_t value[3])
{
  value[0] = decodeSymbol(0, 0);
  int b0 = value[0] == 0;
  value[1] = decodeSymbol(1 + b0, 1);
  int b1 = value[1] == 0;
  value[2] = decodeSymbol(3 + (b0 << 1) + b1, 1);
}

//----------------------------------------------------------------------------

137
uint32_t
138
PCCResidualsDecoder::decode()
139
{
140
  return decodeSymbol(0, 0);
141
142
143
144
145
}

//============================================================================
// AttributeDecoder Members

146
void
147
148
149
150
151
AttributeDecoder::decode(
  const AttributeDescription& attr_desc,
  const AttributeParameterSet& attr_aps,
  const PayloadBuffer& payload,
  PCCPointSet3& pointCloud)
152
{
153
  int abhSize;
154
  AttributeBrickHeader abh = parseAbh(attr_aps, payload, &abhSize);
155
  Quantizers qstep = deriveQuantSteps(attr_aps, abh);
156

157
  PCCResidualsDecoder decoder;
158
  decoder.start(payload.data() + abhSize, payload.size() - abhSize);
159

160
  if (attr_desc.attr_num_dimensions == 1) {
161
162
    switch (attr_aps.attr_encoding) {
    case AttributeEncoding::kRAHTransform:
163
      decodeReflectancesRaht(attr_desc, attr_aps, qstep, decoder, pointCloud);
164
      break;
165

166
    case AttributeEncoding::kPredictingTransform:
167
      decodeReflectancesPred(attr_desc, attr_aps, qstep, decoder, pointCloud);
168
      break;
169

170
    case AttributeEncoding::kLiftingTransform:
171
      decodeReflectancesLift(attr_desc, attr_aps, qstep, decoder, pointCloud);
172
173
      break;
    }
174
  } else if (attr_desc.attr_num_dimensions == 3) {
175
176
    switch (attr_aps.attr_encoding) {
    case AttributeEncoding::kRAHTransform:
177
      decodeColorsRaht(attr_desc, attr_aps, qstep, decoder, pointCloud);
178
179
180
      break;

    case AttributeEncoding::kPredictingTransform:
181
      decodeColorsPred(attr_desc, attr_aps, qstep, decoder, pointCloud);
182
183
184
      break;

    case AttributeEncoding::kLiftingTransform:
185
      decodeColorsLift(attr_desc, attr_aps, qstep, decoder, pointCloud);
186
187
188
      break;
    }
  } else {
189
190
191
    assert(
      attr_desc.attr_num_dimensions == 1
      || attr_desc.attr_num_dimensions == 3);
192
  }
193
194
195
196
197
198

  decoder.stop();
}

//----------------------------------------------------------------------------

199
void
200
AttributeDecoder::computeReflectancePredictionWeights(
201
  const AttributeParameterSet& aps,
202
  const PCCPointSet3& pointCloud,
203
  const std::vector<uint32_t>& indexes,
204
205
206
207
208
209
210
  PCCPredictor& predictor,
  PCCResidualsDecoder& decoder)
{
  predictor.computeWeights();
  if (predictor.neighborCount > 1) {
    int64_t minValue = 0;
    int64_t maxValue = 0;
211
212
213
    for (int i = 0; i < predictor.neighborCount; ++i) {
      const uint16_t reflectanceNeighbor = pointCloud.getReflectance(
        indexes[predictor.neighbors[i].predictorIndex]);
214
215
216
217
218
219
220
221
      if (i == 0 || reflectanceNeighbor < minValue) {
        minValue = reflectanceNeighbor;
      }
      if (i == 0 || reflectanceNeighbor > maxValue) {
        maxValue = reflectanceNeighbor;
      }
    }
    const int64_t maxDiff = maxValue - minValue;
222
    if (maxDiff > aps.adaptive_prediction_threshold) {
223
224
      predictor.predMode =
        decoder.decodePredMode(aps.max_num_direct_predictors);
225
226
227
228
229
230
    }
  }
}

//----------------------------------------------------------------------------

231
void
232
AttributeDecoder::decodeReflectancesPred(
233
  const AttributeDescription& desc,
234
  const AttributeParameterSet& aps,
235
  const Quantizers& qstep,
236
237
  PCCResidualsDecoder& decoder,
  PCCPointSet3& pointCloud)
238
{
239
  const size_t pointCount = pointCloud.getPointCount();
240
241
242
  std::vector<PCCPredictor> predictors;
  std::vector<uint32_t> numberOfPointsPerLOD;
  std::vector<uint32_t> indexesLOD;
243
244
245
246
247
248
249
250
251
252
253
254

  if (!aps.lod_binary_tree_enabled_flag) {
    if (aps.num_detail_levels <= 1) {
      buildPredictorsFastNoLod(
        pointCloud, aps.num_pred_nearest_neighbours, aps.search_range,
        predictors, indexesLOD);
    } else {
      buildPredictorsFast(
        pointCloud, aps.dist2, aps.num_detail_levels,
        aps.num_pred_nearest_neighbours, aps.search_range, aps.search_range,
        predictors, numberOfPointsPerLOD, indexesLOD);
    }
255
  } else {
256
257
258
259
    buildLevelOfDetailBinaryTree(pointCloud, numberOfPointsPerLOD, indexesLOD);
    computePredictors(
      pointCloud, numberOfPointsPerLOD, indexesLOD,
      aps.num_pred_nearest_neighbours, predictors);
260
  }
261

262
  const int64_t maxReflectance = (1ll << desc.attr_bitdepth) - 1;
263
264
265
  for (size_t predictorIndex = 0; predictorIndex < pointCount;
       ++predictorIndex) {
    auto& predictor = predictors[predictorIndex];
266
    const int64_t qs = qstep[0];
267
268
269
270
    computeReflectancePredictionWeights(
      aps, pointCloud, indexesLOD, predictor, decoder);
    const uint32_t pointIndex = indexesLOD[predictorIndex];
    uint16_t& reflectance = pointCloud.getReflectance(pointIndex);
271
    const uint32_t attValue0 = decoder.decode();
272
273
    const int64_t quantPredAttValue =
      predictor.predictReflectance(pointCloud, indexesLOD);
274
275
    const int64_t delta =
      PCCInverseQuantization(UIntToInt(attValue0), qs, true);
276
    const int64_t reconstructedQuantAttValue = quantPredAttValue + delta;
277
278
279
280
281
282
283
284
285
    reflectance = uint16_t(
      PCCClip(reconstructedQuantAttValue, int64_t(0), maxReflectance));
  }
}

//----------------------------------------------------------------------------

void
AttributeDecoder::computeColorPredictionWeights(
286
  const AttributeParameterSet& aps,
287
  const PCCPointSet3& pointCloud,
288
  const std::vector<uint32_t>& indexes,
289
290
291
292
293
294
295
  PCCPredictor& predictor,
  PCCResidualsDecoder& decoder)
{
  predictor.computeWeights();
  if (predictor.neighborCount > 1) {
    int64_t minValue[3] = {0, 0, 0};
    int64_t maxValue[3] = {0, 0, 0};
296
    for (int i = 0; i < predictor.neighborCount; ++i) {
297
      const Vec3<uint8_t> colorNeighbor =
298
        pointCloud.getColor(indexes[predictor.neighbors[i].predictorIndex]);
299
300
301
302
303
304
305
306
307
308
309
310
      for (size_t k = 0; k < 3; ++k) {
        if (i == 0 || colorNeighbor[k] < minValue[k]) {
          minValue[k] = colorNeighbor[k];
        }
        if (i == 0 || colorNeighbor[k] > maxValue[k]) {
          maxValue[k] = colorNeighbor[k];
        }
      }
    }
    const int64_t maxDiff = (std::max)(
      maxValue[2] - minValue[2],
      (std::max)(maxValue[0] - minValue[0], maxValue[1] - minValue[1]));
311
    if (maxDiff > aps.adaptive_prediction_threshold) {
312
313
      predictor.predMode =
        decoder.decodePredMode(aps.max_num_direct_predictors);
314
    }
315
316
317
318
319
  }
}

//----------------------------------------------------------------------------

320
void
321
AttributeDecoder::decodeColorsPred(
322
  const AttributeDescription& desc,
323
  const AttributeParameterSet& aps,
324
  const Quantizers& qstep,
325
326
  PCCResidualsDecoder& decoder,
  PCCPointSet3& pointCloud)
327
{
328
  const size_t pointCount = pointCloud.getPointCount();
329
330
331
  std::vector<PCCPredictor> predictors;
  std::vector<uint32_t> numberOfPointsPerLOD;
  std::vector<uint32_t> indexesLOD;
332
333
334
335
336
337
338
339
340
341
342
343

  if (!aps.lod_binary_tree_enabled_flag) {
    if (aps.num_detail_levels <= 1) {
      buildPredictorsFastNoLod(
        pointCloud, aps.num_pred_nearest_neighbours, aps.search_range,
        predictors, indexesLOD);
    } else {
      buildPredictorsFast(
        pointCloud, aps.dist2, aps.num_detail_levels,
        aps.num_pred_nearest_neighbours, aps.search_range, aps.search_range,
        predictors, numberOfPointsPerLOD, indexesLOD);
    }
344
  } else {
345
346
347
348
    buildLevelOfDetailBinaryTree(pointCloud, numberOfPointsPerLOD, indexesLOD);
    computePredictors(
      pointCloud, numberOfPointsPerLOD, indexesLOD,
      aps.num_pred_nearest_neighbours, predictors);
349
  }
350

351
  uint32_t values[3];
352
353
354
  for (size_t predictorIndex = 0; predictorIndex < pointCount;
       ++predictorIndex) {
    auto& predictor = predictors[predictorIndex];
355
356
    const int64_t qs = qstep[0];
    const int64_t qs2 = qstep[1];
357
358
    computeColorPredictionWeights(
      aps, pointCloud, indexesLOD, predictor, decoder);
359
    decoder.decode(values);
360
    const uint32_t pointIndex = indexesLOD[predictorIndex];
361
362
    Vec3<uint8_t>& color = pointCloud.getColor(pointIndex);
    const Vec3<uint8_t> predictedColor =
363
      predictor.predictColor(pointCloud, indexesLOD);
364
    const int64_t quantPredAttValue = predictedColor[0];
365
366
    const int64_t delta =
      PCCInverseQuantization(UIntToInt(values[0]), qs, true);
367
    const int64_t reconstructedQuantAttValue = quantPredAttValue + delta;
368
    int64_t clipMax = (1 << desc.attr_bitdepth) - 1;
369
    color[0] =
370
      uint8_t(PCCClip(reconstructedQuantAttValue, int64_t(0), clipMax));
371
372
    for (size_t k = 1; k < 3; ++k) {
      const int64_t quantPredAttValue = predictedColor[k];
373
374
      const int64_t delta =
        PCCInverseQuantization(UIntToInt(values[k]), qs2, true);
375
      const int64_t reconstructedQuantAttValue = quantPredAttValue + delta;
376
      color[k] =
377
        uint8_t(PCCClip(reconstructedQuantAttValue, int64_t(0), clipMax));
378
379
380
381
    }
  }
}

382
383
//----------------------------------------------------------------------------

384
385
void
AttributeDecoder::decodeReflectancesRaht(
386
  const AttributeDescription& desc,
387
  const AttributeParameterSet& aps,
388
  const Quantizers& qstep,
389
390
  PCCResidualsDecoder& decoder,
  PCCPointSet3& pointCloud)
391
{
392
  const int voxelCount = int(pointCloud.getPointCount());
393
394
  uint64_t* weight = new uint64_t[voxelCount];
  int* binaryLayer = new int[voxelCount];
395
396
  std::vector<MortonCodeWithIndex> packedVoxel(voxelCount);
  for (int n = 0; n < voxelCount; n++) {
397
    weight[n] = 1;
398
    packedVoxel[n].mortonCode = mortonAddr(pointCloud[n], 0);
399
400
401
402
    packedVoxel[n].index = n;
  }
  sort(packedVoxel.begin(), packedVoxel.end());

403
  // Morton codes
404
  uint64_t* mortonCode = new uint64_t[voxelCount];
405
406
407
408
409
  for (int n = 0; n < voxelCount; n++) {
    mortonCode[n] = packedVoxel[n].mortonCode;
  }

  // Entropy decode
410
411
412
  const int attribCount = 1;
  uint32_t value;
  int* integerizedAttributes = new int[attribCount * voxelCount];
413
  for (int n = 0; n < voxelCount; ++n) {
414
415
    value = decoder.decode();
    integerizedAttributes[n] = UIntToInt(value);
416
417
  }

418
  FixedPoint* attributes = new FixedPoint[attribCount * voxelCount];
419
420

  regionAdaptiveHierarchicalInverseTransform(
421
422
    FixedPoint(qstep[0]), mortonCode, attributes, weight, attribCount,
    voxelCount, integerizedAttributes);
423

424
425
  const int64_t maxReflectance = (1 << desc.attr_bitdepth) - 1;
  const int64_t minReflectance = 0;
426
  for (int n = 0; n < voxelCount; n++) {
427
428
429
430
    int64_t val = attributes[attribCount * n].round();
    const uint16_t reflectance =
      (uint16_t)PCCClip(val, minReflectance, maxReflectance);
    pointCloud.setReflectance(packedVoxel[n].index, reflectance);
431
432
433
  }

  // De-allocate arrays.
434
  delete[] binaryLayer;
435
436
437
438
439
440
441
442
  delete[] mortonCode;
  delete[] attributes;
  delete[] integerizedAttributes;
  delete[] weight;
}

//----------------------------------------------------------------------------

443
444
void
AttributeDecoder::decodeColorsRaht(
445
  const AttributeDescription& desc,
446
  const AttributeParameterSet& aps,
447
  const Quantizers& qstep,
448
449
  PCCResidualsDecoder& decoder,
  PCCPointSet3& pointCloud)
450
{
451
  const int voxelCount = int(pointCloud.getPointCount());
452
453
  uint64_t* weight = new uint64_t[voxelCount];
  int* binaryLayer = new int[voxelCount];
454
455
  std::vector<MortonCodeWithIndex> packedVoxel(voxelCount);
  for (int n = 0; n < voxelCount; n++) {
456
    weight[n] = 1;
457
    packedVoxel[n].mortonCode = mortonAddr(pointCloud[n], 0);
458
459
460
461
    packedVoxel[n].index = n;
  }
  sort(packedVoxel.begin(), packedVoxel.end());

462
  // Morton codes
463
  uint64_t* mortonCode = new uint64_t[voxelCount];
464
465
466
467
468
469
  for (int n = 0; n < voxelCount; n++) {
    mortonCode[n] = packedVoxel[n].mortonCode;
  }

  // Entropy decode
  const int attribCount = 3;
470
  uint32_t values[3];
471
  int* integerizedAttributes = new int[attribCount * voxelCount];
472

473
474
475
476
  for (int n = 0; n < voxelCount; ++n) {
    decoder.decode(values);
    for (int d = 0; d < attribCount; ++d) {
      integerizedAttributes[voxelCount * d + n] = UIntToInt(values[d]);
477
478
479
    }
  }

480
481
  FixedPoint* attributes = new FixedPoint[attribCount * voxelCount];

482
  regionAdaptiveHierarchicalInverseTransform(
483
484
    FixedPoint(qstep[0]), mortonCode, attributes, weight, attribCount,
    voxelCount, integerizedAttributes);
485

486
  const int clipMax = (1 << desc.attr_bitdepth) - 1;
487
  for (int n = 0; n < voxelCount; n++) {
488
489
490
    const int r = attributes[attribCount * n].round();
    const int g = attributes[attribCount * n + 1].round();
    const int b = attributes[attribCount * n + 2].round();
491
    Vec3<uint8_t> color;
492
493
494
    color[0] = uint8_t(PCCClip(r, 0, clipMax));
    color[1] = uint8_t(PCCClip(g, 0, clipMax));
    color[2] = uint8_t(PCCClip(b, 0, clipMax));
495
496
497
498
    pointCloud.setColor(packedVoxel[n].index, color);
  }

  // De-allocate arrays.
499
  delete[] binaryLayer;
500
501
502
503
504
505
  delete[] mortonCode;
  delete[] attributes;
  delete[] integerizedAttributes;
  delete[] weight;
}

506
507
508
509
//----------------------------------------------------------------------------

void
AttributeDecoder::decodeColorsLift(
510
  const AttributeDescription& desc,
511
  const AttributeParameterSet& aps,
512
  const Quantizers& qstep,
513
514
  PCCResidualsDecoder& decoder,
  PCCPointSet3& pointCloud)
515
516
{
  const size_t pointCount = pointCloud.getPointCount();
517
  std::vector<PCCPredictor> predictors;
518
519
  std::vector<uint32_t> numberOfPointsPerLOD;
  std::vector<uint32_t> indexesLOD;
520
521
522
523
524
525
526
527
528
529
530
531
532

  if (!aps.lod_binary_tree_enabled_flag) {
    buildPredictorsFast(
      pointCloud, aps.dist2, aps.num_detail_levels,
      aps.num_pred_nearest_neighbours, aps.search_range, aps.search_range,
      predictors, numberOfPointsPerLOD, indexesLOD);
  } else {
    buildLevelOfDetailBinaryTree(pointCloud, numberOfPointsPerLOD, indexesLOD);
    computePredictors(
      pointCloud, numberOfPointsPerLOD, indexesLOD,
      aps.num_pred_nearest_neighbours, predictors);
  }

533
534
535
536
  for (size_t predictorIndex = 0; predictorIndex < pointCount;
       ++predictorIndex) {
    predictors[predictorIndex].computeWeights();
  }
537
  std::vector<uint64_t> weights;
538
  PCCComputeQuantizationWeights(predictors, weights);
539
  const size_t lodCount = numberOfPointsPerLOD.size();
540
  std::vector<Vec3<int64_t>> colors;
541
  colors.resize(pointCount);
542
543
544
545
  // decompress
  for (size_t predictorIndex = 0; predictorIndex < pointCount;
       ++predictorIndex) {
    uint32_t values[3];
546
    decoder.decode(values);
547
548
549
    const int64_t qs = qstep[0] << (kFixedPointWeightShift / 2);
    const int64_t qs2 = qstep[1] << (kFixedPointWeightShift / 2);
    // + kFixedPointAttributeShift ???
550
    const int64_t quantWeight = weights[predictorIndex];
551
    auto& color = colors[predictorIndex];
552
    const int64_t delta = UIntToInt(values[0]);
553
    const int64_t reconstructedDelta = PCCInverseQuantization(delta, qs);
554
555
    color[0] = reconstructedDelta / quantWeight;
    for (size_t d = 1; d < 3; ++d) {
556
      const int64_t delta = UIntToInt(values[d]);
557
      const int64_t reconstructedDelta = PCCInverseQuantization(delta, qs2);
558
559
560
561
562
563
564
565
566
567
568
      color[d] = reconstructedDelta / quantWeight;
    }
  }

  // reconstruct
  for (size_t lodIndex = 1; lodIndex < lodCount; ++lodIndex) {
    const size_t startIndex = numberOfPointsPerLOD[lodIndex - 1];
    const size_t endIndex = numberOfPointsPerLOD[lodIndex];
    PCCLiftUpdate(predictors, weights, startIndex, endIndex, false, colors);
    PCCLiftPredict(predictors, startIndex, endIndex, false, colors);
  }
569

570
  const int64_t clipMax = (1 << desc.attr_bitdepth) - 1;
571
  for (size_t f = 0; f < pointCount; ++f) {
572
573
    const auto color0 =
      divExp2RoundHalfInf(colors[f], kFixedPointAttributeShift);
574
    Vec3<uint8_t> color;
575
    for (size_t d = 0; d < 3; ++d) {
576
      color[d] = uint8_t(PCCClip(color0[d], int64_t(0), clipMax));
577
    }
578
    pointCloud.setColor(indexesLOD[f], color);
579
580
581
582
583
584
585
  }
}

//----------------------------------------------------------------------------

void
AttributeDecoder::decodeReflectancesLift(
586
  const AttributeDescription& desc,
587
  const AttributeParameterSet& aps,
588
  const Quantizers& qstep,
589
590
  PCCResidualsDecoder& decoder,
  PCCPointSet3& pointCloud)
591
{
592
  const size_t pointCount = pointCloud.getPointCount();
593
  std::vector<PCCPredictor> predictors;
594
595
  std::vector<uint32_t> numberOfPointsPerLOD;
  std::vector<uint32_t> indexesLOD;
596
597
598
599
600
601
602
603
604
605
606
607
608

  if (!aps.lod_binary_tree_enabled_flag) {
    buildPredictorsFast(
      pointCloud, aps.dist2, aps.num_detail_levels,
      aps.num_pred_nearest_neighbours, aps.search_range, aps.search_range,
      predictors, numberOfPointsPerLOD, indexesLOD);
  } else {
    buildLevelOfDetailBinaryTree(pointCloud, numberOfPointsPerLOD, indexesLOD);
    computePredictors(
      pointCloud, numberOfPointsPerLOD, indexesLOD,
      aps.num_pred_nearest_neighbours, predictors);
  }

609
610
611
612
  for (size_t predictorIndex = 0; predictorIndex < pointCount;
       ++predictorIndex) {
    predictors[predictorIndex].computeWeights();
  }
613
  std::vector<uint64_t> weights;
614
  PCCComputeQuantizationWeights(predictors, weights);
615
  const size_t lodCount = numberOfPointsPerLOD.size();
616
  std::vector<int64_t> reflectances;
617
  reflectances.resize(pointCount);
618
619
620
621

  // decompress
  for (size_t predictorIndex = 0; predictorIndex < pointCount;
       ++predictorIndex) {
622
    const int64_t detail = decoder.decode();
623
    const int64_t qs = qstep[0] << (kFixedPointWeightShift / 2);
624
    const int64_t quantWeight = weights[predictorIndex];
625
    auto& reflectance = reflectances[predictorIndex];
626
    const int64_t delta = UIntToInt(detail);
627
    const int64_t reconstructedDelta = PCCInverseQuantization(delta, qs);
628
629
630
631
632
633
634
635
636
637
638
    reflectance = reconstructedDelta / quantWeight;
  }

  // reconstruct
  for (size_t lodIndex = 1; lodIndex < lodCount; ++lodIndex) {
    const size_t startIndex = numberOfPointsPerLOD[lodIndex - 1];
    const size_t endIndex = numberOfPointsPerLOD[lodIndex];
    PCCLiftUpdate(
      predictors, weights, startIndex, endIndex, false, reflectances);
    PCCLiftPredict(predictors, startIndex, endIndex, false, reflectances);
  }
639
  const int64_t maxReflectance = (1 << desc.attr_bitdepth) - 1;
640
  for (size_t f = 0; f < pointCount; ++f) {
641
642
    const auto refl =
      divExp2RoundHalfInf(reflectances[f], kFixedPointAttributeShift);
643
    pointCloud.setReflectance(
644
      indexesLOD[f], uint16_t(PCCClip(refl, int64_t(0), maxReflectance)));
645
646
647
  }
}

648
649
//============================================================================

650
} /* namespace pcc */