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