1 /*
2 ===============================================================================
3
4 FILE: field_rgb14.cpp
5
6 CONTENTS:
7
8
9 PROGRAMMERS:
10
11 martin.isenburg@rapidlasso.com - http://rapidlasso.com
12 uday.karan@gmail.com - Hobu, Inc.
13
14 COPYRIGHT:
15
16 (c) 2007-2014, martin isenburg, rapidlasso - tools to catch reality
17 (c) 2014, Uday Verma, Hobu, Inc.
18
19 This is free software; you can redistribute and/or modify it under the
20 terms of the GNU Lesser General Licence as published by the Free Software
21 Foundation. See the COPYING file for more information.
22
23 This software is distributed WITHOUT ANY WARRANTY and without even the
24 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
25
26 CHANGE HISTORY:
27
28 ===============================================================================
29 */
30
31 #include "../las.hpp"
32
33 namespace lazperf
34 {
35 namespace detail
36 {
37
38 namespace
39 {
40
color_diff_bits_1_4(const las::rgb14 & color,const las::rgb14 & last)41 unsigned int color_diff_bits_1_4(const las::rgb14& color, const las::rgb14& last)
42 {
43 const las::rgb14& a = last;
44 const las::rgb14& b = color;
45
46 auto flag_diff = [](unsigned short c1, unsigned short c2, int mask) -> bool
47 {
48 return ((c1 ^ c2) & mask);
49 };
50
51 unsigned int r =
52 (flag_diff(a.r, b.r, 0x00FF) << 0) |
53 (flag_diff(a.r, b.r, 0xFF00) << 1) |
54 (flag_diff(a.g, b.g, 0x00FF) << 2) |
55 (flag_diff(a.g, b.g, 0xFF00) << 3) |
56 (flag_diff(a.b, b.b, 0x00FF) << 4) |
57 (flag_diff(a.b, b.b, 0xFF00) << 5) |
58 ((flag_diff(b.r, b.g, 0x00FF) |
59 flag_diff(b.r, b.b, 0x00FF) |
60 flag_diff(b.r, b.g, 0xFF00) |
61 flag_diff(b.r, b.b, 0xFF00)) << 6);
62 return r;
63 }
64
65 } // unnamed namespace
66
67
writeSizes()68 void Rgb14Compressor::writeSizes()
69 {
70 rgb_enc_.done();
71 stream_ << rgb_enc_.num_encoded();
72 }
73
writeData()74 void Rgb14Compressor::writeData()
75 {
76 LAZDEBUG(std::cerr << "RGB : " <<
77 utils::sum(rgb_enc_.encoded_bytes(), rgb_enc_.num_encoded()) << "\n");
78
79 if (rgb_enc_.num_encoded())
80 stream_.putBytes(rgb_enc_.encoded_bytes(), rgb_enc_.num_encoded());
81 }
82
compress(const char * buf,int & sc)83 const char *Rgb14Compressor::compress(const char *buf, int& sc)
84 {
85 const las::rgb14 color(buf);
86
87 // don't have the first data yet, just push it to our
88 // have last stuff and move on
89 if (last_channel_ == -1)
90 {
91 ChannelCtx& c = chan_ctxs_[sc];
92 stream_.putBytes((const unsigned char*)&color, sizeof(las::rgb));
93 c.last_ = color;
94 c.have_last_ = true;
95 last_channel_ = sc;
96 return buf + sizeof(las::rgb);
97 }
98
99 ChannelCtx& c = chan_ctxs_[sc];
100 las::rgb14 *pLastColor = &chan_ctxs_[last_channel_].last_;
101 if (!c.have_last_)
102 {
103 c.have_last_ = true;
104 c.last_ = *pLastColor;
105 pLastColor = &c.last_;
106 }
107 // This mess is because of the broken-ness of the handling for last in v3, where
108 // 'last_point' only gets updated on the first context switch in the LASzip code.
109 las::rgb& lastColor = *pLastColor;
110
111 // compress color
112 int diff_l = 0;
113 int diff_h = 0;
114
115 unsigned int sym = detail::color_diff_bits_1_4(color, lastColor);
116 if (sym)
117 rgb_enc_.makeValid();
118 rgb_enc_.encodeSymbol(c.used_model_, sym);
119
120 // high and low R
121 if (sym & (1 << 0))
122 {
123 diff_l = (color.r & 0xFF) - (lastColor.r & 0xFF);
124 rgb_enc_.encodeSymbol(c.diff_model_[0], uint8_t(diff_l));
125 }
126 if (sym & (1 << 1))
127 {
128 diff_h = static_cast<int>(color.r >> 8) - (lastColor.r >> 8);
129 rgb_enc_.encodeSymbol(c.diff_model_[1], uint8_t(diff_h));
130 }
131
132 // Only encode green and blue if they are different from red.
133 if (sym & (1 << 6))
134 {
135 if (sym & (1 << 2))
136 {
137 int corr = static_cast<int>(color.g & 0xFF) -
138 utils::clamp<uint8_t>(diff_l + (lastColor.g & 0xFF));
139 rgb_enc_.encodeSymbol(c.diff_model_[2], uint8_t(corr));
140 }
141
142 if (sym & (1 << 4))
143 {
144 diff_l = (diff_l + (color.g & 0xFF) - (lastColor.g & 0xFF)) / 2;
145 int corr = static_cast<int>(color.b & 0xFF) -
146 utils::clamp<uint8_t>(diff_l + (lastColor.b & 0xFF));
147 rgb_enc_.encodeSymbol(c.diff_model_[4], uint8_t(corr));
148 }
149
150 if (sym & (1 << 3))
151 {
152 int corr = static_cast<int>(color.g >> 8) -
153 utils::clamp<uint8_t>(diff_h + (lastColor.g >> 8));
154 rgb_enc_.encodeSymbol(c.diff_model_[3], uint8_t(corr));
155 }
156
157 if (sym & (1 << 5))
158 {
159 diff_h = (diff_h + ((color.g >> 8)) - (lastColor.g >> 8)) / 2;
160 int corr = static_cast<int>(color.b >> 8) -
161 utils::clamp<uint8_t>(diff_h + (lastColor.b >> 8));
162 rgb_enc_.encodeSymbol(c.diff_model_[5], uint8_t(corr));
163 }
164 }
165
166 lastColor = color;
167 last_channel_ = sc;
168 return buf + sizeof(las::rgb14);
169 }
170
171 // DECOMPRESSOR
172
dumpSums()173 void Rgb14Decompressor::dumpSums()
174 {
175 std::cout << "RGB : " << sumRgb.value() << "\n";
176 }
177
readSizes()178 void Rgb14Decompressor::readSizes()
179 {
180 stream_ >> rgb_cnt_;
181 }
182
readData()183 void Rgb14Decompressor::readData()
184 {
185 rgb_dec_.initStream(stream_, rgb_cnt_);
186 }
187
decompress(char * buf,int & sc)188 char *Rgb14Decompressor::decompress(char *buf, int& sc)
189 {
190 if (last_channel_ == -1)
191 {
192 ChannelCtx& c = chan_ctxs_[sc];
193 stream_.getBytes((unsigned char*)buf, sizeof(las::rgb));
194 c.last_.unpack(buf);
195 c.have_last_ = true;
196 last_channel_ = sc;
197 return buf + sizeof(las::rgb14);
198 }
199 if (rgb_cnt_ == 0)
200 {
201 las::rgb14 *color = reinterpret_cast<las::rgb14 *>(buf);
202 *color = chan_ctxs_[last_channel_].last_;
203 return buf + sizeof(las::rgb14);
204 }
205
206 ChannelCtx& c = chan_ctxs_[sc];
207 las::rgb14 *pLastColor = &chan_ctxs_[last_channel_].last_;
208 if (sc != last_channel_)
209 {
210 last_channel_ = sc;
211 if (!c.have_last_)
212 {
213 c.have_last_ = true;
214 c.last_ = *pLastColor;
215 pLastColor = &chan_ctxs_[last_channel_].last_;
216 }
217 }
218 las::rgb14& lastColor = *pLastColor;
219
220 uint32_t sym = rgb_dec_.decodeSymbol(c.used_model_);
221
222 las::rgb14 color;
223
224 if (sym & (1 << 0))
225 {
226 uint8_t corr = (uint8_t)rgb_dec_.decodeSymbol(c.diff_model_[0]);
227 color.r = static_cast<unsigned short>(uint8_t(corr + (lastColor.r & 0xFF)));
228 }
229 else
230 color.r = lastColor.r & 0xFF;
231
232 if (sym & (1 << 1))
233 {
234 uint8_t corr = (uint8_t)rgb_dec_.decodeSymbol(c.diff_model_[1]);
235 color.r |= (static_cast<unsigned short>(uint8_t(corr + (lastColor.r >> 8))) << 8);
236 }
237 else
238 color.r |= lastColor.r & 0xFF00;
239
240 if (sym & (1 << 6))
241 {
242 int diff = (color.r & 0xFF) - (lastColor.r & 0xFF);
243
244 if (sym & (1 << 2))
245 {
246 uint8_t corr = (uint8_t)rgb_dec_.decodeSymbol(c.diff_model_[2]);
247 color.g = static_cast<unsigned short>(uint8_t(corr +
248 utils::clamp<uint8_t>(diff + (lastColor.g & 0xFF))));
249 }
250 else
251 color.g = lastColor.g & 0xFF;
252
253 if (sym & (1 << 4))
254 {
255 uint8_t corr = (uint8_t)rgb_dec_.decodeSymbol(c.diff_model_[4]);
256 diff = (diff + ((color.g & 0xFF) - (lastColor.g & 0xFF))) / 2;
257 color.b = static_cast<unsigned short>(uint8_t(corr +
258 utils::clamp<uint8_t>(diff + (lastColor.b & 0xFF))));
259 }
260 else
261 color.b = lastColor.b & 0xFF;
262
263 diff = (color.r >> 8) - (lastColor.r >> 8);
264 if (sym & (1 << 3))
265 {
266 uint8_t corr = (uint8_t)rgb_dec_.decodeSymbol(c.diff_model_[3]);
267 color.g |= (static_cast<unsigned short>(uint8_t(corr +
268 utils::clamp<uint8_t>(diff + (lastColor.g >> 8))))) << 8;
269 }
270 else
271 color.g |= lastColor.g & 0xFF00;
272
273 if (sym & (1 << 5))
274 {
275 uint8_t corr = (uint8_t)rgb_dec_.decodeSymbol(c.diff_model_[5]);
276 diff = (diff + (color.g >> 8) - (lastColor.g >> 8)) / 2;
277 color.b |= (static_cast<unsigned short>(uint8_t(corr +
278 utils::clamp<uint8_t>(diff + (lastColor.b >> 8))))) << 8;
279 }
280 else
281 color.b |= (lastColor.b & 0xFF00);
282 }
283 else
284 {
285 color.g = color.r;
286 color.b = color.r;
287 }
288
289 LAZDEBUG(sumRgb.add(color));
290 lastColor = color;
291 color.pack(buf);
292 return buf + sizeof(las::rgb14);
293 }
294
295 } // namespace detail
296 } // namespace lazperf
297