uvgVPCCenc 1.1.0
uvgVPCCenc is an open-source real-time V-PCC encoder library written in C++ from scratch.
Loading...
Searching...
No Matches
utilsPatchGeneration.hpp
Go to the documentation of this file.
1/*****************************************************************************
2 * This file is part of uvgVPCCenc V-PCC encoder.
3 *
4 * Copyright (c) 2024-present, Tampere University, ITU/ISO/IEC, project contributors
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without modification,
8 * are permitted provided that the following conditions are met:
9 *
10 * * Redistributions of source code must retain the above copyright notice, this
11 * list of conditions and the following disclaimer.
12 *
13 * * Redistributions in binary form must reproduce the above copyright notice, this
14 * list of conditions and the following disclaimer in the documentation and/or
15 * other materials provided with the distribution.
16 *
17 * * Neither the name of the Tampere University or ITU/ISO/IEC nor the names of its
18 * contributors may be used to endorse or promote products derived from
19 * this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
25 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 * INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION HOWEVER CAUSED AND ON
28 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 * INCLUDING NEGLIGENCE OR OTHERWISE ARISING IN ANY WAY OUT OF THE USE OF THIS
31 ****************************************************************************/
32
34
35#pragma once
36
37#include <sys/types.h>
38
39#include <algorithm>
40#include <cstdint>
41#include <fstream>
42#include <vector>
43
44#include "robin_hood.h"
45#include "utils/constants.hpp"
46#include "uvgutils/utils.hpp"
47#include "uvgutils/log.hpp"
48
49
50using namespace uvgvpcc_enc;
51
52// TODO(lf): how to handle this type of lut table variable ?
53// NOLINTNEXTLINE(cert-err58-cpp)
54static const std::array<std::vector<uvgutils::VectorN<int32_t, 3>>, 9> adjacentPointsSearch = {{
55 // Adjacent shift for squared distance 1
56 {{1, 0, 0}, {-1, 0, 0}, {0, 1, 0}, {0, -1, 0}, {0, 0, 1}, {0, 0, -1}},
57 // Adjacent shift for squared distance 2
58 {{1, 1, 0},
59 {1, -1, 0},
60 {-1, 1, 0},
61 {-1, -1, 0},
62 {0, 1, 1},
63 {0, 1, -1},
64 {0, -1, 1},
65 {0, -1, -1},
66 {1, 0, 1},
67 {-1, 0, 1},
68 {1, 0, -1},
69 {-1, 0, -1}},
70 // Adjacent shift for squared distance 3
71 {{1, 1, 1}, {1, 1, -1}, {1, -1, 1}, {1, -1, -1}, {-1, 1, 1}, {-1, 1, -1}, {-1, -1, 1}, {-1, -1, -1}},
72 // Adjacent shift for squared distance 4
73 {{2, 0, 0}, {-2, 0, 0}, {0, 2, 0}, {0, -2, 0}, {0, 0, 2}, {0, 0, -2}},
74 // Adjacent shift for squared distance 5
75 {{2, 1, 0}, {2, -1, 0}, {1, 2, 0}, {1, -2, 0}, {-1, 2, 0}, {-1, -2, 0}, {-2, 1, 0}, {-2, -1, 0},
76 {0, 2, 1}, {0, 2, -1}, {0, 1, 2}, {0, 1, -2}, {0, -1, 2}, {0, -1, -2}, {0, -2, 1}, {0, -2, -1},
77 {1, 0, 2}, {-1, 0, 2}, {2, 0, 1}, {-2, 0, 1}, {2, 0, -1}, {-2, 0, -1}, {1, 0, -2}, {-1, 0, -2}},
78 // Adjacent shift for squared distance 6
79 {{2, 1, 1}, {2, 1, -1}, {2, -1, 1}, {2, -1, -1}, {1, 2, 1}, {1, 2, -1}, {1, 1, 2}, {1, 1, -2},
80 {1, -1, 2}, {1, -1, -2}, {1, -2, 1}, {1, -2, -1}, {-1, 2, 1}, {-1, 2, -1}, {-1, 1, 2}, {-1, 1, -2},
81 {-1, -1, 2}, {-1, -1, -2}, {-1, -2, 1}, {-1, -2, -1}, {-2, 1, 1}, {-2, 1, -1}, {-2, -1, 1}, {-2, -1, -1}},
82 // Adjacent shift for squared distance 7 (does not exist in an integer grid)
83 {},
84 // Adjacent shift for squared distance 8
85 {{2, 2, 0},
86 {2, -2, 0},
87 {-2, 2, 0},
88 {-2, -2, 0},
89 {0, 2, 2},
90 {0, 2, -2},
91 {0, -2, 2},
92 {0, -2, -2},
93 {2, 0, 2},
94 {-2, 0, 2},
95 {2, 0, -2},
96 {-2, 0, -2}},
97 // Adjacent shift for squared distance 9
98 {{3, 0, 0}, {-3, 0, 0}, {0, 3, 0}, {0, -3, 0}, {0, 0, 3}, {0, 0, -3}, {2, 2, 1}, {2, 2, -1}, {2, 1, 2}, {2, 1, -2},
99 {2, -1, 2}, {2, -1, -2}, {2, -2, 1}, {2, -2, -1}, {1, 2, 2}, {1, 2, -2}, {1, -2, 2}, {1, -2, -2}, {-1, 2, 2}, {-1, 2, -2},
100 {-1, -2, 2}, {-1, -2, -2}, {-2, 2, 1}, {-2, 2, -1}, {-2, 1, 2}, {-2, 1, -2}, {-2, -1, 2}, {-2, -1, -2}, {-2, -2, 1}, {-2, -2, -1}},
101}};
102
103const std::array<uvgutils::VectorN<uint8_t, 3>, 114> patchColors = {{
104 // Red color is for points not being part of a patch before the 2D projection.
105 {139, 0, 0}, {165, 42, 42}, {178, 34, 34}, {220, 20, 60}, {255, 99, 71}, {255, 127, 80}, {205, 92, 92}, {240, 128, 128},
106 {233, 150, 122}, {250, 128, 114}, {255, 160, 122}, {255, 69, 0}, {255, 140, 0}, {255, 165, 0}, {255, 215, 0}, {184, 134, 11},
107 {218, 165, 32}, {238, 232, 170}, {189, 183, 107}, {240, 230, 140}, {255, 255, 0}, {32, 178, 170}, {0, 128, 128}, {0, 139, 139},
108 {0, 255, 255}, {0, 255, 255}, {224, 255, 255}, {0, 206, 209}, {72, 209, 204}, {175, 238, 238}, {176, 224, 230}, {95, 158, 160},
109 {70, 130, 180}, {100, 149, 237}, {0, 191, 255}, {30, 144, 255}, {173, 216, 230}, {135, 206, 235}, {135, 206, 250}, {25, 25, 112},
110 {0, 0, 128}, {0, 0, 139}, {0, 0, 205}, {0, 0, 255}, {65, 105, 225}, {138, 43, 226}, {75, 0, 130}, {72, 61, 139},
111 {106, 90, 205}, {123, 104, 238}, {147, 112, 219}, {139, 0, 139}, {148, 0, 211}, {153, 50, 204}, {186, 85, 211}, {128, 0, 128},
112 {216, 191, 216}, {221, 160, 221}, {238, 130, 238}, {255, 0, 255}, {218, 112, 214}, {199, 21, 133}, {219, 112, 147}, {255, 20, 147},
113 {255, 105, 180}, {255, 182, 193}, {255, 192, 203}, {250, 235, 215}, {245, 245, 220}, {255, 228, 196}, {255, 235, 205}, {245, 222, 179},
114 {255, 248, 220}, {255, 250, 205}, {250, 250, 210}, {255, 255, 224}, {139, 69, 19}, {160, 82, 45}, {210, 105, 30}, {205, 133, 63},
115 {244, 164, 96}, {222, 184, 135}, {210, 180, 140}, {188, 143, 143}, {255, 228, 181}, {255, 222, 173}, {255, 218, 185}, {255, 228, 225},
116 {255, 240, 245}, {250, 240, 230}, {253, 245, 230}, {255, 239, 213}, {255, 245, 238}, {245, 255, 250}, {112, 128, 144}, {119, 136, 153},
117 {176, 196, 222}, {230, 230, 250}, {255, 250, 240}, {240, 248, 255}, {248, 248, 255}, {240, 255, 240}, {255, 255, 240}, {240, 255, 255},
118 {255, 250, 250}, {0, 0, 0}, {105, 105, 105}, {128, 128, 128}, {169, 169, 169}, {192, 192, 192}, {211, 211, 211}, {220, 220, 220},
119 {245, 245, 245}, {255, 255, 255},
120}};
121
122template <typename T, typename TT>
123inline double dotProduct(const std::array<T, 3>& arr1, const std::array<TT, 3>& arr2) {
124 return arr1[0] * arr2[0] + arr1[1] * arr2[1] + arr1[2] * arr2[2];
125}
126
127// Hash function for vector3
128template <typename T>
130 size_t operator()(const uvgutils::VectorN<T, 3>& vector) const {
131 std::hash<T> hasher;
132 size_t hash = 0;
133 for (const auto& elem : vector) {
134 // Use a simple hash combining algorithm
135 hash ^= hasher(elem) + 0x9e3779b9 + (hash << 6U) + (hash >> 2U);
136 }
137 return hash;
138 }
139};
140
141// The voxelization is done so to have those three vectors sharing the same order (that is sharing the same voxel index) :
142// -> A list of voxel (vector of coordinates)
143// -> A list of list of points (vector of vector of point index). This associate a voxel with the points inside it.
144// -> A list of voxel PPI (vector of PPI (int))
145//
146// Example with a voxel index i:
147// voxelizedPointsGeometry[i] stores the coordinate of the voxel i
148// voxelIdToPointsId[i] stores the index of the points inside the voxel i
149// voxelsPPIs[i] stores the PPI of the voxel i
150//
151// The use of a map is needed as several points can be inside one voxel. We want to find in a fast way if the current point resides in a voxel
152// that has already been created. For an input point j: voxelCoordToVoxelIndex[ voxelCoordsOf(j) ] = i
153//
154// This structure makes computation easier for the patch generation and for applying voxel data to points data.
155// To achieve this, we need a temporary map that interfaces the voxel coordinates with the voxel index in those three list.
156
157// voxelizedPointsGeometry -> list of the voxels. That is, a list of the coordinates of the voxels.
158// voxelIdToPointsId -> For each voxel, stores the index of the points inside. A voxel is defined by a voxel index, that is given by the
159// filling order of the vector. Thus, the third voxel to be added to this structure will have a voxel index of 2.
160// voxelCoordToVoxelIndex -> Temporary structure. Associate a voxel to its index in 'voxelIdToPointsId' (its voxel index). This structure is a
161// map whose key is a voxel coordinate and the value is a voxel index.
162//
163// For each point if the input point cloud :
164// Compute the coordinates of the voxel inside which the current point should be.
165// If those voxel coordinates are already in the map 'voxelCoordToVoxelIndex':
166// Add the current input point index to the list of points index of the found voxel.
167// That is, add the current input point index to the list of points of the voxel in 'voxelIdToPointsId'
168// If those voxel coordinates are not in the map 'voxelCoordToVoxelIndex':
169// Create a new item in the map 'voxelCoordToVoxelIndex'. This associates the voxel coordinates to its voxel index (the current size
170// of the list of voxel === the index of this voxel in the list of voxel). Add a new voxel to 'voxelIdToPointsId'. This associates the
171// voxel index (the current size of the list of voxel === the index of this voxel in the list of voxel) to an empty list of input
172// point index. Create a new voxel by adding the voxel coordinates in the voxel list 'voxelizedPointsGeometry'. Add the current input
173// point index to the list of points index of the new voxel. That is, add the current input point index to the list of points of the
174// voxel in 'voxelIdToPointsId'
175
176// Notice that in the refined segmentation, the inputPointsGeometry can be the voxelizedPointsGeometry. Indeed, when the voxelization is
177// activated, the refined segmentation is applying a second voxelization step. The created voxelized point cloud is then the result of two
178// voxelizations.
179inline void voxelization(
180 const std::vector<uvgutils::VectorN<typeGeometryInput, 3>>& inputPointsGeometry,
181 std::vector<uvgutils::VectorN<typeGeometryInput, 3>>& voxelizedPointsGeometry,
182 std::vector<size_t>& pointsIdToVoxelId,
183 const size_t inputBitResolution,
184 const size_t outputBitResolution
185)
186{
187 uvgutils::Logger::log<uvgutils::LogLevel::TRACE>("PATCH GENERATION", "Voxelization from " + std::to_string(inputBitResolution) + " to " +
188 std::to_string(outputBitResolution) + " bits of resolution.\n");
189 pointsIdToVoxelId.resize(inputPointsGeometry.size());
190
191 const size_t voxelizationShift = inputBitResolution - outputBitResolution;
192 const typeGeometryInput shift = static_cast<typeGeometryInput>(voxelizationShift);
193
194 const size_t approximateVoxelCount = 1U << (outputBitResolution * 2U);
195 voxelizedPointsGeometry.reserve(approximateVoxelCount);
196
198 voxelCoordToVoxelIndex.reserve(approximateVoxelCount);
199 size_t voxelIndex = 0;
200 for (size_t inputPointIndex = 0; inputPointIndex < inputPointsGeometry.size(); ++inputPointIndex) {
201 const uvgutils::VectorN<typeGeometryInput, 3> & inputPoint = inputPointsGeometry[inputPointIndex];
202
203 uvgutils::VectorN<typeGeometryInput, 3> voxCoord{static_cast<typeGeometryInput>(static_cast<uint32_t>(inputPoint[0]) >> shift),
204 static_cast<typeGeometryInput>(static_cast<uint32_t>(inputPoint[1]) >> shift),
205 static_cast<typeGeometryInput>(static_cast<uint32_t>(inputPoint[2]) >> shift)};
206
207 auto [it, inserted] = voxelCoordToVoxelIndex.try_emplace(voxCoord, voxelIndex);
208 if (inserted) {
209 voxelizedPointsGeometry.emplace_back(voxCoord);
210 voxelIndex++;
211 }
212 pointsIdToVoxelId[inputPointIndex] = voxelCoordToVoxelIndex[voxCoord];
213 }
214}
Definition robin_hood.h:921
std::pair< iterator, bool > try_emplace(const key_type &key, Args &&... args)
Definition robin_hood.h:1835
void reserve(size_t c)
Definition robin_hood.h:2084
Definition utils.hpp:49
Definition uvgvpcc.hpp:55
uint16_t typeGeometryInput
Definition constants.hpp:47
Definition utilsPatchGeneration.hpp:129
size_t operator()(const uvgutils::VectorN< T, 3 > &vector) const
Definition utilsPatchGeneration.hpp:130
double dotProduct(const std::array< T, 3 > &arr1, const std::array< TT, 3 > &arr2)
Definition utilsPatchGeneration.hpp:123
const std::array< uvgutils::VectorN< uint8_t, 3 >, 114 > patchColors
Definition utilsPatchGeneration.hpp:103
void voxelization(const std::vector< uvgutils::VectorN< typeGeometryInput, 3 > > &inputPointsGeometry, std::vector< uvgutils::VectorN< typeGeometryInput, 3 > > &voxelizedPointsGeometry, std::vector< size_t > &pointsIdToVoxelId, const size_t inputBitResolution, const size_t outputBitResolution)
Definition utilsPatchGeneration.hpp:179