HoviTron Video Pipeline
opencvReading.cpp
1#include "opencvReading.h"
2
3
4/* The copyright in this software is being made available under the BSD
5* License, included below. This software may be subject to other third party
6* and contributor rights, including patent rights, and no such rights are
7* granted under this license.
8*
9* Copyright (c) 2010-2018, ITU/ISO/IEC
10* All rights reserved.
11*
12* Redistribution and use in source and binary forms, with or without
13* modification, are permitted provided that the following conditions are met:
14*
15* * Redistributions of source code must retain the above copyright notice,
16* this list of conditions and the following disclaimer.
17* * Redistributions in binary form must reproduce the above copyright notice,
18* this list of conditions and the following disclaimer in the documentation
19* and/or other materials provided with the distribution.
20* * Neither the name of the ITU/ISO/IEC nor the names of its contributors may
21* be used to endorse or promote products derived from this software without
22* specific prior written permission.
23*
24* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
28* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
34* THE POSSIBILITY OF SUCH DAMAGE.
35*/
36
37/*
38Original authors:
39
40Universite Libre de Bruxelles, Brussels, Belgium:
41 Sarah Fachada, Sarah.Fernandes.Pinto.Fachada@ulb.ac.be
42 Daniele Bonatto, Daniele.Bonatto@ulb.ac.be
43 Arnaud Schenkel, arnaud.schenkel@ulb.ac.be
44
45Koninklijke Philips N.V., Eindhoven, The Netherlands:
46 Bart Kroon, bart.kroon@philips.com
47 Bart Sonneveldt, bart.sonneveldt@philips.com
48*/
49
50
57int cvdepth_from_bit_depth(int bit_depth)
58{
59 if (bit_depth >= 1 && bit_depth <= 8)
60 return CV_8U;
61 else if (bit_depth >= 9 && bit_depth <= 16)
62 return CV_16U;
63 else if (bit_depth == 32)
64 return CV_32F;
65 else throw std::invalid_argument("invalid raw image bit depth");
66}
67
74void read_raw(std::ifstream& stream, cv::Mat image)
75{
76 CV_Assert(stream.good() && !image.empty() && image.isContinuous());
77 stream.read(reinterpret_cast<char*>(image.data), image.size().area() * image.elemSize());
78}
79
88cv::Mat read_color_YUV(std::string filepath, int frame,rvs::Parameters const& parameters) {
89 auto size = parameters.getPaddedSize();
90 auto bit_depth = parameters.getColorBitDepth();
91 auto type = CV_MAKETYPE(cvdepth_from_bit_depth(bit_depth), 1);
92 cv::Mat y_channel(size, type);
93 cv::Mat cb_channel(size / 2, type);
94 cv::Mat cr_channel(size / 2, type);
95
96 std::ifstream stream(filepath, std::ios::binary);
97 if (!stream.good()) {
98 std::ostringstream what;
99 what << "Failed to read raw YUV color file \"" << filepath << "\"";
100 throw std::runtime_error(what.str());
101 }
102 stream.seekg(size.area() * y_channel.elemSize() * 3 / 2 * frame);
103 read_raw(stream, y_channel);
104 read_raw(stream, cb_channel);
105 read_raw(stream, cr_channel);
106
107 cv::resize(cb_channel, cb_channel, size, 0, 0, cv::INTER_CUBIC);
108 cv::resize(cr_channel, cr_channel, size, 0, 0, cv::INTER_CUBIC);
109
110 cv::Mat image(size, CV_MAKETYPE(cvdepth_from_bit_depth(bit_depth), 3));
111 cv::Mat src[] = { y_channel, cr_channel, cb_channel };
112 cv::merge(src, 3, image);
113 return image;
114}
115
123cv::Mat read_color_RGB(std::string filepath, rvs::Parameters const& parameters) {
124 cv::Mat image = cv::imread(filepath, cv::IMREAD_UNCHANGED);
125
126 if (image.empty())
127 throw std::runtime_error("Failed to read color file");
128 if (image.size() != parameters.getPaddedSize())
129 throw std::runtime_error("Color file does not have the expected size");
130 if (image.depth() != cvdepth_from_bit_depth(parameters.getColorBitDepth()))
131 throw std::runtime_error("Color file has wrong bit depth");
132 if (image.channels() != 3)
133 throw std::runtime_error("Color file has wrong number of channels");
134
135 return image;
136}
137
144unsigned max_level(int bit_depth)
145{
146 assert(bit_depth > 0 && bit_depth <= 16);
147 return (1u << bit_depth) - 1u;
148}
149
157vk::Format selectFormat(cv::Mat& image, rvs::detail::ColorSpace colorSpace) {
158
159 vk::Format form = vk::Format::eUndefined;
160 if (colorSpace == rvs::detail::ColorSpace::RGB) {
161 if (image.depth() == 8) {
162 if (image.channels() == 4) {
163 form = vk::Format::eR8G8B8A8Unorm;
164 }else if (image.channels() == 3) {
165 form = vk::Format::eR8G8B8Unorm;
166 }
167 else if (image.channels() == 2) {
168 form = vk::Format::eR8G8Unorm;
169 }
170 else if (image.channels() == 1) {
171 form = vk::Format::eR8Unorm;
172 }
173 }
174 else if (image.depth() == 16 || image.depth() == 10) {
175
176 if (image.channels() == 4) {
177 form = vk::Format::eR16G16B16A16Unorm;
178 }
179 else if (image.channels() == 3) {
180 form = vk::Format::eR16G16B16Unorm;
181 }
182 else if (image.channels() == 2) {
183 form = vk::Format::eR16G16Unorm;
184 }
185 else if (image.channels() == 1) {
186 form = vk::Format::eR16Unorm;
187 }
188 }
189 else if (image.depth() == 32) {
190 if (image.channels() == 4) {
191 form = vk::Format::eR32G32B32A32Sfloat;
192 }
193 else if (image.channels() == 3) {
194 form = vk::Format::eR32G32B32Sfloat;
195 }
196 else if (image.channels() == 2) {
197 form = vk::Format::eR32G32Sfloat;
198 }
199 else if (image.channels() == 1) {
200 form = vk::Format::eR32Sfloat;
201 }
202 }
203 }
204 return form;
205}
206
215cv::Mat read_color(std::string filepath, int frame, rvs::Parameters const& parameters)
216{
217 // Load the image
218 cv::Mat image;
219 vk::Format format;
220 rvs::detail::ColorSpace color_space;
221 if (filepath.substr(filepath.size() - 4, 4) == ".yuv") {
222 image = read_color_YUV(filepath, frame, parameters);
223 color_space = rvs::detail::ColorSpace::YUV;
224 }
225 else if (frame == 0) {
226 image = read_color_RGB(filepath, parameters);
227 color_space = rvs::detail::ColorSpace::RGB;
228 }
229 else {
230 throw std::runtime_error("Readig multiple frames not (yet) supported for image files");
231 }
232
233 // Crop out padded regions
234 if (parameters.getPaddedSize() != parameters.getSize()) {
235 image = image(parameters.getCropRegion()).clone();
236 }
237
238 // Normalize to [0, 1]
239 /*
240 cv::Mat color;
241 if (image.depth() == CV_32F) {
242 color = image;
243 }
244 else {
245 image.convertTo(color, CV_32F, 1. / max_level(parameters.getColorBitDepth()));
246 }*/
247
248 cv::Mat color = image;
249
250 // Color space conversion
251 if (color_space == rvs::detail::ColorSpace::YUV && rvs::detail::g_color_space == rvs::detail::ColorSpace::RGB) {
252 if (parameters.getColorBitDepth() == 10) {
253 image.convertTo(color, CV_16U, 64);//, 1. / max_level(parameters.getColorBitDepth()));
254 }
255 cv::cvtColor(color, color, cv::COLOR_YCrCb2RGB);
256 cv::cvtColor(color, color, cv::COLOR_RGB2RGBA);
257
258 }
259 else if (color_space == rvs::detail::ColorSpace::RGB && rvs::detail::g_color_space == rvs::detail::ColorSpace::YUV) {
260 cv::cvtColor(color, color, cv::COLOR_BGR2YCrCb);
261 }
262
263
264 return color; //std::tuple<cv::Mat3f, vk::Format>();
265}
266
274cv::Mat read_depth_RGB(std::string filepath, rvs::Parameters const& parameters) {
275 cv::Mat image = cv::imread(filepath, cv::IMREAD_UNCHANGED);
276
277 if (image.empty())
278 throw std::runtime_error("Failed to read depth file");
279 if (image.size() != parameters.getPaddedSize())
280 throw std::runtime_error("Depth file does not have the expected size");
281 if (image.depth() != cvdepth_from_bit_depth(parameters.getDepthBitDepth()))
282 throw std::runtime_error("Depth file has the wrong bit depth");
283 if (image.channels() != 1)
284 throw std::runtime_error("Depth file has the wrong number of channels");
285
286 return image;
287}
288
297cv::Mat read_depth_YUV(std::string filepath, int frame, rvs::Parameters const& parameters) {
298 auto size = parameters.getPaddedSize();
299 auto bit_depth = parameters.getDepthBitDepth();
300 cv::Mat image(size, CV_MAKETYPE(cvdepth_from_bit_depth(bit_depth), 1));
301 std::ifstream stream(filepath, std::ios_base::binary);
302 if (!stream.good()) {
303 std::ostringstream what;
304 what << "Failed to read raw YUV depth file \"" << filepath << "\"";
305 throw std::runtime_error(what.str());
306 }
307
308 switch (parameters.getDepthColorFormat()) {
309 case rvs::ColorFormat::YUV420:
310 stream.seekg(size.area() * image.elemSize() * 3 / 2 * frame);
311 break;
312 case rvs::ColorFormat::YUV400:
313 stream.seekg(size.area() * image.elemSize() * frame);
314 break;
315 default:
316 throw std::logic_error("Unknown depth map color format");
317 }
318
319 read_raw(stream, image);
320 return image;
321}
322
331cv::Mat read_depth(std::string filepath, int frame, rvs::Parameters const& parameters)
332{
333 // Load the image
334 vk::Format format;
335 cv::Mat image;
336 if (filepath.substr(filepath.size() - 4, 4) == ".yuv") {
337 image = read_depth_YUV(filepath, frame, parameters);
338 }
339 else if (frame == 0) {
340 image = read_depth_RGB(filepath, parameters);
341 }
342 else {
343 throw std::runtime_error("Readig multiple frames not (yet) supported for image files");
344 }
345
346 // Crop out padded regions
347 if (parameters.getPaddedSize() != parameters.getSize()) {
348 image = image(parameters.getCropRegion()).clone();
349 }
350
351 // Do not manipulate floating-point depth maps (e.g. OpenEXR)
352 //if (image.depth() == CV_32F) {
353 // format = vk::Format::eR32Sfloat;
354 //}
355
356 //format = selectFormat(image,)
357
358 /*
359 // Normalize to [0, 1]
360
361 cv::Mat1f depth;
362 image.convertTo(depth, CV_32F, 1. / max_level(parameters.getDepthBitDepth()));
363
364 // 1000 is for 'infinitly far'
365 auto near = parameters.getDepthRange()[0];
366 auto far = parameters.getDepthRange()[1];
367 if (far >= 1000.f) {
368 depth = near / depth;
369 }
370 else {
371 depth = far * near / (near + depth * (far - near));
372 }*/
373
374 if (parameters.getColorBitDepth() == 10) {
375 image.convertTo(image, CV_16U, 64);//, 1. / max_level(parameters.getColorBitDepth()));
376 }
377
378
379 if (parameters.hasInvalidDepth()) {
380 // Level 0 is for 'invalid'
381 // Mark invalid pixels as NaN
382 auto const NaN = std::numeric_limits<float>::quiet_NaN();
383 image.setTo(NaN, image == 0);
384 }
385
386 return image;
387}
cv::Rect getCropRegion() const
Definition: Parameters.cpp:143
int getColorBitDepth() const
Definition: Parameters.cpp:148
cv::Size getSize() const
Definition: Parameters.cpp:138
bool hasInvalidDepth() const
Definition: Parameters.cpp:128
cv::Size getPaddedSize() const
Definition: Parameters.cpp:133
ColorFormat getDepthColorFormat() const
Definition: Parameters.cpp:163
int getDepthBitDepth() const
Definition: Parameters.cpp:153