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#include "utils/utils.hpp"
39#include "uvgvpcc/log.hpp"
40#include <cstdint>
41#include <fstream>
42#include <vector>
43#include <algorithm>
44#include "robin_hood.h"
45
46using namespace uvgvpcc_enc;
47
48
49// TODO(lf): how to handle this type of lut table variable ?
50// NOLINTNEXTLINE(cert-err58-cpp)
51static const std::array<std::vector<Vector3<int32_t>>, 9> adjacentPointsSearch = {{
52 // Adjacent shift for squared distance 1
53 {{1, 0, 0}, {-1, 0, 0}, {0, 1, 0}, {0, -1, 0}, {0, 0, 1}, {0, 0, -1}},
54 // Adjacent shift for squared distance 2
55 {{1, 1, 0},
56 {1, -1, 0},
57 {-1, 1, 0},
58 {-1, -1, 0},
59 {0, 1, 1},
60 {0, 1, -1},
61 {0, -1, 1},
62 {0, -1, -1},
63 {1, 0, 1},
64 {-1, 0, 1},
65 {1, 0, -1},
66 {-1, 0, -1}},
67 // Adjacent shift for squared distance 3
68 {{1, 1, 1}, {1, 1, -1}, {1, -1, 1}, {1, -1, -1}, {-1, 1, 1}, {-1, 1, -1}, {-1, -1, 1}, {-1, -1, -1}},
69 // Adjacent shift for squared distance 4
70 {{2, 0, 0}, {-2, 0, 0}, {0, 2, 0}, {0, -2, 0}, {0, 0, 2}, {0, 0, -2}},
71 // Adjacent shift for squared distance 5
72 {{2, 1, 0}, {2, -1, 0}, {1, 2, 0}, {1, -2, 0}, {-1, 2, 0}, {-1, -2, 0}, {-2, 1, 0}, {-2, -1, 0},
73 {0, 2, 1}, {0, 2, -1}, {0, 1, 2}, {0, 1, -2}, {0, -1, 2}, {0, -1, -2}, {0, -2, 1}, {0, -2, -1},
74 {1, 0, 2}, {-1, 0, 2}, {2, 0, 1}, {-2, 0, 1}, {2, 0, -1}, {-2, 0, -1}, {1, 0, -2}, {-1, 0, -2}},
75 // Adjacent shift for squared distance 6
76 {{2, 1, 1}, {2, 1, -1}, {2, -1, 1}, {2, -1, -1}, {1, 2, 1}, {1, 2, -1}, {1, 1, 2}, {1, 1, -2},
77 {1, -1, 2}, {1, -1, -2}, {1, -2, 1}, {1, -2, -1}, {-1, 2, 1}, {-1, 2, -1}, {-1, 1, 2}, {-1, 1, -2},
78 {-1, -1, 2}, {-1, -1, -2}, {-1, -2, 1}, {-1, -2, -1}, {-2, 1, 1}, {-2, 1, -1}, {-2, -1, 1}, {-2, -1, -1}},
79 // Adjacent shift for squared distance 7 (does not exist in an integer grid)
80 {},
81 // Adjacent shift for squared distance 8
82 {{2, 2, 0},
83 {2, -2, 0},
84 {-2, 2, 0},
85 {-2, -2, 0},
86 {0, 2, 2},
87 {0, 2, -2},
88 {0, -2, 2},
89 {0, -2, -2},
90 {2, 0, 2},
91 {-2, 0, 2},
92 {2, 0, -2},
93 {-2, 0, -2}},
94 // Adjacent shift for squared distance 9
95 {{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},
96 {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},
97 {-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}},
98}};
99
100const std::array<Vector3<uint8_t>, 114> patchColors = {{
101 // Red color is for points not being part of a patch before the 2D projection.
102{139,0,0},{165,42,42},{178,34,34},{220,20,60},{255,99,71},{255,127,80},{205,92,92},{240,128,128},{233,150,122},{250,128,114},{255,160,122},{255,69,0},{255,140,0},{255,165,0},{255,215,0},{184,134,11},{218,165,32},{238,232,170},{189,183,107},{240,230,140},{255,255,0},{32,178,170},{0,128,128},{0,139,139},{0,255,255},{0,255,255},{224,255,255},{0,206,209},{72,209,204},{175,238,238},{176,224,230},{95,158,160},{70,130,180},{100,149,237},{0,191,255},{30,144,255},{173,216,230},{135,206,235},{135,206,250},{25,25,112},{0,0,128},{0,0,139},{0,0,205},{0,0,255},{65,105,225},{138,43,226},{75,0,130},{72,61,139},{106,90,205},{123,104,238},{147,112,219},{139,0,139},{148,0,211},{153,50,204},{186,85,211},{128,0,128},{216,191,216},{221,160,221},{238,130,238},{255,0,255},{218,112,214},{199,21,133},{219,112,147},{255,20,147},{255,105,180},{255,182,193},{255,192,203},{250,235,215},{245,245,220},{255,228,196},{255,235,205},{245,222,179},{255,248,220},{255,250,205},{250,250,210},{255,255,224},{139,69,19},{160,82,45},{210,105,30},{205,133,63},{244,164,96},{222,184,135},{210,180,140},{188,143,143},{255,228,181},{255,222,173},{255,218,185},{255,228,225},{255,240,245},{250,240,230},{253,245,230},{255,239,213},{255,245,238},{245,255,250},{112,128,144},{119,136,153},{176,196,222},{230,230,250},{255,250,240},{240,248,255},{248,248,255},{240,255,240},{255,255,240},{240,255,255},{255,250,250},{0,0,0},{105,105,105},{128,128,128},{169,169,169},{192,192,192},{211,211,211},{220,220,220},{245,245,245},{255,255,255},
103}};
104
105template <typename T, typename TT>
106inline double dotProduct(const std::array<T, 3>& arr1, const std::array<TT, 3>& arr2) {
107 return arr1[0] * arr2[0] + arr1[1] * arr2[1] + arr1[2] * arr2[2];
108}
109
110
111// Hash function for vector3
112template <typename T>
114 size_t operator()(const Vector3<T>& vector) const {
115 std::hash<T> hasher;
116 size_t hash = 0;
117 for (const auto& elem : vector) {
118 // Use a simple hash combining algorithm
119 hash ^= hasher(elem) + 0x9e3779b9 + (hash << 6U) + (hash >> 2U);
120 }
121 return hash;
122 }
123};
124
125
126// The voxelization is done so to have those three vectors sharing the same order (that is sharing the same voxel index) :
127// -> A list of voxel (vector of coordinates)
128// -> A list of list of points (vector of vector of point index). This associate a voxel with the points inside it.
129// -> A list of voxel PPI (vector of PPI (int))
130//
131// Example with a voxel index i:
132// voxelizedPointsGeometry[i] stores the coordinate of the voxel i
133// voxelIdToPointsId[i] stores the index of the points inside the voxel i
134// voxelsPPIs[i] stores the PPI of the voxel i
135//
136// 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
137// that has already been created. For an input point j: voxelCoordToVoxelIndex[ voxelCoordsOf(j) ] = i
138//
139// This structure makes computation easier for the patch generation and for applying voxel data to points data.
140// To achieve this, we need a temporary map that interfaces the voxel coordinates with the voxel index in those three list.
141
142// voxelizedPointsGeometry -> list of the voxels. That is, a list of the coordinates of the voxels.
143// voxelIdToPointsId -> For each voxel, stores the index of the points inside. A voxel is defined by a voxel index, that is given by the
144// filling order of the vector. Thus, the third voxel to be added to this structure will have a voxel index of 2.
145// voxelCoordToVoxelIndex -> Temporary structure. Associate a voxel to its index in 'voxelIdToPointsId' (its voxel index). This structure is a
146// map whose key is a voxel coordinate and the value is a voxel index.
147//
148// For each point if the input point cloud :
149// Compute the coordinates of the voxel inside which the current point should be.
150// If those voxel coordinates are already in the map 'voxelCoordToVoxelIndex':
151// Add the current input point index to the list of points index of the found voxel.
152// That is, add the current input point index to the list of points of the voxel in 'voxelIdToPointsId'
153// If those voxel coordinates are not in the map 'voxelCoordToVoxelIndex':
154// Create a new item in the map 'voxelCoordToVoxelIndex'. This associates the voxel coordinates to its voxel index (the current size
155// of the list of voxel === the index of this voxel in the list of voxel). Add a new voxel to 'voxelIdToPointsId'. This associates the
156// 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
157// point index. Create a new voxel by adding the voxel coordinates in the voxel list 'voxelizedPointsGeometry'. Add the current input
158// 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
159// voxel in 'voxelIdToPointsId'
160
161
162// Notice that in the refined segmentation, the inputPointsGeometry can be the voxelizedPointsGeometry. Indeed, when the voxelization is
163// activated, the refined segmentation is applying a second voxelization step. The created voxelized point cloud is then the result of two
164// voxelizations.
165inline void voxelization(
166 const std::vector<Vector3<typeGeometryInput>>& inputPointsGeometry,
167 std::vector<Vector3<typeGeometryInput>>& voxelizedPointsGeometry,
168 std::vector<std::vector<size_t>>& voxelIdToPointsId,
169 const size_t inputBitResolution,
170 const size_t outputBitResolution)
171{
172 Logger::log<LogLevel::TRACE>("PATCH GENERATION",
173 "Voxelization from " + std::to_string(inputBitResolution) + " to " + std::to_string(outputBitResolution) + " bits of resolution.\n");
174
175 const size_t voxelizationShift = inputBitResolution - outputBitResolution;
176 const typeGeometryInput shift = static_cast<typeGeometryInput>(voxelizationShift);
177
178 const size_t approximateVoxelCount = 1U << (outputBitResolution * 2U);
179 voxelizedPointsGeometry.reserve(approximateVoxelCount);
180 voxelIdToPointsId.reserve(approximateVoxelCount);
181
183 voxelCoordToVoxelIndex.reserve(approximateVoxelCount);
184
185 const size_t inputSize = inputPointsGeometry.size();
186 for (size_t inputPointIndex = 0; inputPointIndex < inputSize; ++inputPointIndex) {
187 const Vector3<typeGeometryInput> & inputPoint = inputPointsGeometry[inputPointIndex];
188
190 static_cast<typeGeometryInput>(static_cast<uint32_t>(inputPoint[0]) >> shift),
191 static_cast<typeGeometryInput>(static_cast<uint32_t>(inputPoint[1]) >> shift),
192 static_cast<typeGeometryInput>(static_cast<uint32_t>(inputPoint[2]) >> shift)
193 };
194
195 size_t voxelIndex = voxelizedPointsGeometry.size();
196 auto [it, inserted] = voxelCoordToVoxelIndex.try_emplace(voxCoord, voxelIndex);
197 if (inserted) {
198 voxelizedPointsGeometry.emplace_back(voxCoord);
199 voxelIdToPointsId.emplace_back();
200 voxelIdToPointsId.back().reserve(16);
201 }
202
203 voxelIdToPointsId[it->second].push_back(inputPointIndex);
204 }
205}
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:60
Definition log.hpp:48
uint16_t typeGeometryInput
Definition utils.hpp:46
Definition utilsPatchGeneration.hpp:113
size_t operator()(const Vector3< T > &vector) const
Definition utilsPatchGeneration.hpp:114
void voxelization(const std::vector< Vector3< typeGeometryInput > > &inputPointsGeometry, std::vector< Vector3< typeGeometryInput > > &voxelizedPointsGeometry, std::vector< std::vector< size_t > > &voxelIdToPointsId, const size_t inputBitResolution, const size_t outputBitResolution)
Definition utilsPatchGeneration.hpp:165
double dotProduct(const std::array< T, 3 > &arr1, const std::array< TT, 3 > &arr2)
Definition utilsPatchGeneration.hpp:106
const std::array< Vector3< uint8_t >, 114 > patchColors
Definition utilsPatchGeneration.hpp:100