1 // Copyright 2016 The Draco Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 #include "draco/compression/attributes/kd_tree_attributes_encoder.h"
16
17 #include "draco/compression/attributes/kd_tree_attributes_shared.h"
18 #include "draco/compression/attributes/point_d_vector.h"
19 #include "draco/compression/point_cloud/algorithms/dynamic_integer_points_kd_tree_encoder.h"
20 #include "draco/compression/point_cloud/algorithms/float_points_tree_encoder.h"
21 #include "draco/compression/point_cloud/point_cloud_encoder.h"
22 #include "draco/core/varint_encoding.h"
23
24 namespace draco {
25
KdTreeAttributesEncoder()26 KdTreeAttributesEncoder::KdTreeAttributesEncoder() : num_components_(0) {}
27
KdTreeAttributesEncoder(int att_id)28 KdTreeAttributesEncoder::KdTreeAttributesEncoder(int att_id)
29 : AttributesEncoder(att_id), num_components_(0) {}
30
TransformAttributesToPortableFormat()31 bool KdTreeAttributesEncoder::TransformAttributesToPortableFormat() {
32 // Convert any of the input attributes into a format that can be processed by
33 // the kd tree encoder (quantization of floating attributes for now).
34 const size_t num_points = encoder()->point_cloud()->num_points();
35 int num_components = 0;
36 for (uint32_t i = 0; i < num_attributes(); ++i) {
37 const int att_id = GetAttributeId(i);
38 const PointAttribute *const att =
39 encoder()->point_cloud()->attribute(att_id);
40 num_components += att->num_components();
41 }
42 num_components_ = num_components;
43
44 // Go over all attributes and quantize them if needed.
45 for (uint32_t i = 0; i < num_attributes(); ++i) {
46 const int att_id = GetAttributeId(i);
47 const PointAttribute *const att =
48 encoder()->point_cloud()->attribute(att_id);
49 if (att->data_type() == DT_FLOAT32) {
50 // Quantization path.
51 AttributeQuantizationTransform attribute_quantization_transform;
52 const int quantization_bits = encoder()->options()->GetAttributeInt(
53 att_id, "quantization_bits", -1);
54 if (quantization_bits < 1) {
55 return false;
56 }
57 if (encoder()->options()->IsAttributeOptionSet(att_id,
58 "quantization_origin") &&
59 encoder()->options()->IsAttributeOptionSet(att_id,
60 "quantization_range")) {
61 // Quantization settings are explicitly specified in the provided
62 // options.
63 std::vector<float> quantization_origin(att->num_components());
64 encoder()->options()->GetAttributeVector(att_id, "quantization_origin",
65 att->num_components(),
66 &quantization_origin[0]);
67 const float range = encoder()->options()->GetAttributeFloat(
68 att_id, "quantization_range", 1.f);
69 attribute_quantization_transform.SetParameters(
70 quantization_bits, quantization_origin.data(),
71 att->num_components(), range);
72 } else {
73 // Compute quantization settings from the attribute values.
74 if (!attribute_quantization_transform.ComputeParameters(
75 *att, quantization_bits)) {
76 return false;
77 }
78 }
79 attribute_quantization_transforms_.push_back(
80 attribute_quantization_transform);
81 // Store the quantized attribute in an array that will be used when we do
82 // the actual encoding of the data.
83 auto portable_att =
84 attribute_quantization_transform.InitTransformedAttribute(*att,
85 num_points);
86 attribute_quantization_transform.TransformAttribute(*att, {},
87 portable_att.get());
88 quantized_portable_attributes_.push_back(std::move(portable_att));
89 } else if (att->data_type() == DT_INT32 || att->data_type() == DT_INT16 ||
90 att->data_type() == DT_INT8) {
91 // For signed types, find the minimum value for each component. These
92 // values are going to be used to transform the attribute values to
93 // unsigned integers that can be processed by the core kd tree algorithm.
94 std::vector<int32_t> min_value(att->num_components(),
95 std::numeric_limits<int32_t>::max());
96 std::vector<int32_t> act_value(att->num_components());
97 for (AttributeValueIndex avi(0); avi < static_cast<uint32_t>(att->size());
98 ++avi) {
99 att->ConvertValue<int32_t>(avi, &act_value[0]);
100 for (int c = 0; c < att->num_components(); ++c) {
101 if (min_value[c] > act_value[c]) {
102 min_value[c] = act_value[c];
103 }
104 }
105 }
106 for (int c = 0; c < att->num_components(); ++c) {
107 min_signed_values_.push_back(min_value[c]);
108 }
109 }
110 }
111 return true;
112 }
113
EncodeDataNeededByPortableTransforms(EncoderBuffer * out_buffer)114 bool KdTreeAttributesEncoder::EncodeDataNeededByPortableTransforms(
115 EncoderBuffer *out_buffer) {
116 // Store quantization settings for all attributes that need it.
117 for (int i = 0; i < attribute_quantization_transforms_.size(); ++i) {
118 attribute_quantization_transforms_[i].EncodeParameters(out_buffer);
119 }
120
121 // Encode data needed for transforming signed integers to unsigned ones.
122 for (int i = 0; i < min_signed_values_.size(); ++i) {
123 EncodeVarint<int32_t>(min_signed_values_[i], out_buffer);
124 }
125 return true;
126 }
127
EncodePortableAttributes(EncoderBuffer * out_buffer)128 bool KdTreeAttributesEncoder::EncodePortableAttributes(
129 EncoderBuffer *out_buffer) {
130 // Encode the data using the kd tree encoder algorithm. The data is first
131 // copied to a PointDVector that provides all the API expected by the core
132 // encoding algorithm.
133
134 // We limit the maximum value of compression_level to 6 as we don't currently
135 // have viable algorithms for higher compression levels.
136 uint8_t compression_level =
137 std::min(10 - encoder()->options()->GetSpeed(), 6);
138 DRACO_DCHECK_LE(compression_level, 6);
139
140 if (compression_level == 6 && num_components_ > 15) {
141 // Don't use compression level for CL >= 6. Axis selection is currently
142 // encoded using 4 bits.
143 compression_level = 5;
144 }
145
146 out_buffer->Encode(compression_level);
147
148 // Init PointDVector. The number of dimensions is equal to the total number
149 // of dimensions across all attributes.
150 const int num_points = encoder()->point_cloud()->num_points();
151 PointDVector<uint32_t> point_vector(num_points, num_components_);
152
153 int num_processed_components = 0;
154 int num_processed_quantized_attributes = 0;
155 int num_processed_signed_components = 0;
156 // Copy data to the point vector.
157 for (uint32_t i = 0; i < num_attributes(); ++i) {
158 const int att_id = GetAttributeId(i);
159 const PointAttribute *const att =
160 encoder()->point_cloud()->attribute(att_id);
161 const PointAttribute *source_att = nullptr;
162 if (att->data_type() == DT_UINT32 || att->data_type() == DT_UINT16 ||
163 att->data_type() == DT_UINT8 || att->data_type() == DT_INT32 ||
164 att->data_type() == DT_INT16 || att->data_type() == DT_INT8) {
165 // Use the original attribute.
166 source_att = att;
167 } else if (att->data_type() == DT_FLOAT32) {
168 // Use the portable (quantized) attribute instead.
169 source_att =
170 quantized_portable_attributes_[num_processed_quantized_attributes]
171 .get();
172 num_processed_quantized_attributes++;
173 } else {
174 // Unsupported data type.
175 return false;
176 }
177
178 if (source_att == nullptr) {
179 return false;
180 }
181
182 // Copy source_att to the vector.
183 if (source_att->data_type() == DT_UINT32) {
184 // If the data type is the same as the one used by the point vector, we
185 // can directly copy individual elements.
186 for (PointIndex pi(0); pi < num_points; ++pi) {
187 const AttributeValueIndex avi = source_att->mapped_index(pi);
188 const uint8_t *const att_value_address = source_att->GetAddress(avi);
189 point_vector.CopyAttribute(source_att->num_components(),
190 num_processed_components, pi.value(),
191 att_value_address);
192 }
193 } else if (source_att->data_type() == DT_INT32 ||
194 source_att->data_type() == DT_INT16 ||
195 source_att->data_type() == DT_INT8) {
196 // Signed values need to be converted to unsigned before they are stored
197 // in the point vector.
198 std::vector<int32_t> signed_point(source_att->num_components());
199 std::vector<uint32_t> unsigned_point(source_att->num_components());
200 for (PointIndex pi(0); pi < num_points; ++pi) {
201 const AttributeValueIndex avi = source_att->mapped_index(pi);
202 source_att->ConvertValue<int32_t>(avi, &signed_point[0]);
203 for (int c = 0; c < source_att->num_components(); ++c) {
204 unsigned_point[c] =
205 signed_point[c] -
206 min_signed_values_[num_processed_signed_components + c];
207 }
208
209 point_vector.CopyAttribute(source_att->num_components(),
210 num_processed_components, pi.value(),
211 &unsigned_point[0]);
212 }
213 num_processed_signed_components += source_att->num_components();
214 } else {
215 // If the data type of the attribute is different, we have to convert the
216 // value before we put it to the point vector.
217 std::vector<uint32_t> point(source_att->num_components());
218 for (PointIndex pi(0); pi < num_points; ++pi) {
219 const AttributeValueIndex avi = source_att->mapped_index(pi);
220 source_att->ConvertValue<uint32_t>(avi, &point[0]);
221 point_vector.CopyAttribute(source_att->num_components(),
222 num_processed_components, pi.value(),
223 point.data());
224 }
225 }
226 num_processed_components += source_att->num_components();
227 }
228
229 // Compute the maximum bit length needed for the kd tree encoding.
230 int num_bits = 0;
231 const uint32_t *data = point_vector[0];
232 for (int i = 0; i < num_points * num_components_; ++i) {
233 if (data[i] > 0) {
234 const int msb = MostSignificantBit(data[i]) + 1;
235 if (msb > num_bits) {
236 num_bits = msb;
237 }
238 }
239 }
240
241 switch (compression_level) {
242 case 6: {
243 DynamicIntegerPointsKdTreeEncoder<6> points_encoder(num_components_);
244 if (!points_encoder.EncodePoints(point_vector.begin(), point_vector.end(),
245 num_bits, out_buffer)) {
246 return false;
247 }
248 break;
249 }
250 case 5: {
251 DynamicIntegerPointsKdTreeEncoder<5> points_encoder(num_components_);
252 if (!points_encoder.EncodePoints(point_vector.begin(), point_vector.end(),
253 num_bits, out_buffer)) {
254 return false;
255 }
256 break;
257 }
258 case 4: {
259 DynamicIntegerPointsKdTreeEncoder<4> points_encoder(num_components_);
260 if (!points_encoder.EncodePoints(point_vector.begin(), point_vector.end(),
261 num_bits, out_buffer)) {
262 return false;
263 }
264 break;
265 }
266 case 3: {
267 DynamicIntegerPointsKdTreeEncoder<3> points_encoder(num_components_);
268 if (!points_encoder.EncodePoints(point_vector.begin(), point_vector.end(),
269 num_bits, out_buffer)) {
270 return false;
271 }
272 break;
273 }
274 case 2: {
275 DynamicIntegerPointsKdTreeEncoder<2> points_encoder(num_components_);
276 if (!points_encoder.EncodePoints(point_vector.begin(), point_vector.end(),
277 num_bits, out_buffer)) {
278 return false;
279 }
280 break;
281 }
282 case 1: {
283 DynamicIntegerPointsKdTreeEncoder<1> points_encoder(num_components_);
284 if (!points_encoder.EncodePoints(point_vector.begin(), point_vector.end(),
285 num_bits, out_buffer)) {
286 return false;
287 }
288 break;
289 }
290 case 0: {
291 DynamicIntegerPointsKdTreeEncoder<0> points_encoder(num_components_);
292 if (!points_encoder.EncodePoints(point_vector.begin(), point_vector.end(),
293 num_bits, out_buffer)) {
294 return false;
295 }
296 break;
297 }
298 // Compression level and/or encoding speed seem wrong.
299 default:
300 return false;
301 }
302 return true;
303 }
304
305 } // namespace draco
306