chrono_batch_render/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
37 / 38
97.4%
Branches:
52 / 65
80.0%
Functions:
5 / 5, 2 excl
100.0%

io/image.h
Line Branch Exec Source
1 // SPDX-License-Identifier: BSD-3-Clause
2 #pragma once
3
4 #include <array>
5 #include <cstddef>
6 #include <cstdint>
7 #include <filesystem>
8 #include <optional>
9 #include <stdexcept>
10 #include <string_view>
11 #include <tuple>
12 #include <vector>
13
14 #include "chrono_batch_render/device/tensor.h"
15 #include "chrono_batch_render/export.h"
16 #include "chrono_batch_render/util/span.h"
17
18 namespace chrono::batch_render {
19
20 enum class ImageEncoding : uint8_t { Srgb, Linear };
21
22 struct Rgba {
23 float r = 0;
24 float g = 0;
25 float b = 0;
26 float a = 0;
27
28 24 bool operator==(const Rgba& other) const {
29
4/8
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 24 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 24 times.
24 return r == other.r && g == other.g && b == other.b && a == other.a;
30 }
31
32 bool operator!=(const Rgba& other) const {
33 return !(*this == other);
34 }
35 };
36
37
13/19
<unknown function 37>:
✓ Branch 2 taken 5 times.
✓ Branch 2 taken 9 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 time.
✓ Branch 6 taken 5 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 time.
✓ Branch 7 taken 8 times.
✓ Branch 10 taken 1 time.
✓ Branch 15 taken 1 time.
chrono::batch_render::Rgba::operator==(chrono::batch_render::Rgba const&) const:
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 time.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 time.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 time.
✓ Branch 18 taken 1 time.
73 struct CHRONO_BATCH_RENDER_API Image {
38 uint32_t width = 0;
39 uint32_t height = 0;
40 std::vector<Rgba> pixels;
41
42 Image() = default;
43
44 58 Image(uint32_t w, uint32_t h, Rgba fill = {})
45
13/14
✓ Branch 1 taken 4 times.
✓ Branch 1 taken 8 times.
✓ Branch 1 taken 1 time.
✓ Branch 1 taken 1 time.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 10 times.
✗ Branch 4 not taken.
✓ Branch 4 taken 7 times.
✓ Branch 7 taken 1 time.
✓ Branch 7 taken 1 time.
✓ Branch 10 taken 2 times.
✓ Branch 13 taken 1 time.
✓ Branch 16 taken 1 time.
✓ Branch 19 taken 1 time.
58 : width(w), height(h), pixels(size_t(w) * h, fill) {}
46
47 1835078 Rgba& Pixel(uint32_t x, uint32_t y) {
48
2/2
✓ Branch 1 taken 1 time.
✓ Branch 4 taken 1 time.
1835078 return pixels[size_t(y) * width + x];
49 }
50
51 15 const Rgba& Pixel(uint32_t x, uint32_t y) const {
52
2/2
✓ Branch 1 taken 1 time.
✓ Branch 4 taken 1 time.
15 return pixels[size_t(y) * width + x];
53 }
54
55 Rgba Mean() const;
56 };
57
58 22 struct Rgba8Image {
59 uint32_t width = 0;
60 uint32_t height = 0;
61 std::vector<uint32_t> texels;
62 };
63
64 CHRONO_BATCH_RENDER_API Image LoadImageFile(const std::filesystem::path& path,
65 ImageEncoding encoding);
66 CHRONO_BATCH_RENDER_API Image LoadImageBytes(Span<const std::byte> bytes, std::string_view name,
67 ImageEncoding encoding);
68 CHRONO_BATCH_RENDER_API bool IsPngOrJpeg(const std::filesystem::path& path);
69
70 CHRONO_BATCH_RENDER_API Rgba8Image LoadRgba8File(const std::filesystem::path& path);
71 CHRONO_BATCH_RENDER_API Rgba8Image LoadRgba8Bytes(Span<const std::byte> bytes,
72 std::string_view name);
73
74
18/20
<unknown function 74>:
✗ Branch 7 not taken.
chrono::batch_render::Rgba::operator==(chrono::batch_render::Rgba const&) const:
✓ Branch 5 taken 1 time.
✓ Branch 10 taken 1 time.
✓ Branch 15 taken 1 time.
✓ Branch 20 taken 1 time.
✓ Branch 24 taken 1 time.
✓ Branch 42 taken 1 time.
✓ Branch 51 taken 1 time.
✓ Branch 55 taken 1 time.
✓ Branch 71 taken 1 time.
✓ Branch 79 taken 1 time.
✓ Branch 85 taken 1 time.
✓ Branch 113 taken 1 time.
✓ Branch 119 taken 1 time.
✓ Branch 123 taken 1 time.
✓ Branch 138 taken 1 time.
✓ Branch 142 taken 1 time.
✗ Branch 145 not taken.
✓ Branch 146 taken 1 time.
✓ Branch 154 taken 1 time.
68 struct CHRONO_BATCH_RENDER_API Pixels {
75 int64_t rows = 0;
76 int64_t cols = 0;
77 int64_t channels = 1;
78 device::DType type = device::DType::UInt8;
79 std::vector<std::byte> bytes;
80
81 Pixels() = default;
82 Pixels(const device::Tensor& tensor);
83 Pixels(Span<const std::byte> data, device::DType elementType, int64_t rowCount,
84 int64_t colCount, int64_t channelCount = 1);
85
86 template <class T>
87 26 Pixels(Span<const T> values, int64_t rowCount, int64_t colCount, int64_t channelCount = 1)
88 26 : Pixels(Span<const std::byte>(reinterpret_cast<const std::byte*>(values.data()),
89 values.size_bytes()),
90 26 device::ElementType<T>(), rowCount, colCount, channelCount) {}
91
92 template <class T>
93 26 Pixels(const std::vector<T>& values, int64_t rowCount, int64_t colCount,
94 int64_t channelCount = 1)
95 26 : Pixels(Span<const T>(values), rowCount, colCount, channelCount) {}
96
97 88 template <class T> Span<const T> Values() const {
98 88 if (device::ElementType<T>() != type) {
99 1 throw std::invalid_argument("Values of a type unlike the pixels' elements");
100 }
101 87 return {reinterpret_cast<const T*>(bytes.data()), bytes.size() / sizeof(T)};
102 }
103 };
104
105 CHRONO_BATCH_RENDER_API Image ImageFromTensor(const device::Tensor& tensor, ImageEncoding encoding);
106 CHRONO_BATCH_RENDER_API std::vector<uint8_t> ToRgba8(const Image& image, ImageEncoding encoding);
107
108 CHRONO_BATCH_RENDER_API void WritePng(const std::filesystem::path& path, const Image& image);
109 CHRONO_BATCH_RENDER_API void WritePng(const std::filesystem::path& path, const Pixels& image);
110 CHRONO_BATCH_RENDER_API void WriteJpeg(const std::filesystem::path& path, const Image& image,
111 int quality = 92);
112 CHRONO_BATCH_RENDER_API void WriteJpeg(const std::filesystem::path& path, const Pixels& image,
113 int quality = 92);
114 CHRONO_BATCH_RENDER_API void WriteExr(const std::filesystem::path& path, const Image& image);
115 CHRONO_BATCH_RENDER_API void WriteExr(const std::filesystem::path& path, const Pixels& image);
116 CHRONO_BATCH_RENDER_API std::filesystem::path WriteImage(std::filesystem::path path,
117 const Pixels& image);
118
119 enum class Colormap : uint8_t { Grayscale, Turbo, Viridis };
120
121 struct ColorizeOptions {
122 Colormap colormap = Colormap::Grayscale;
123 std::optional<float> minimum;
124 std::optional<float> maximum;
125 bool logarithmic = false;
126 bool reversed = false;
127 bool centered = false;
128 uint32_t channel = 0;
129
130 bool operator==(const ColorizeOptions& other) const {
131 return std::tie(colormap, minimum, maximum, logarithmic, reversed, centered, channel) ==
132 std::tie(other.colormap, other.minimum, other.maximum, other.logarithmic,
133 other.reversed, other.centered, other.channel);
134 }
135 };
136
137 inline constexpr ColorizeOptions kDepthColors{Colormap::Grayscale, std::nullopt, std::nullopt, true,
138 true};
139
140 CHRONO_BATCH_RENDER_API std::array<uint8_t, 4> ColormapColor(Colormap colormap, float position);
141
142 CHRONO_BATCH_RENDER_API Pixels ColorizeScalars(const Pixels& values,
143 const ColorizeOptions& options = {});
144 CHRONO_BATCH_RENDER_API Pixels ColorizeHdr(const Pixels& color, float exposure = 0);
145 CHRONO_BATCH_RENDER_API Pixels ColorizeNormals(const Pixels& normals);
146 CHRONO_BATCH_RENDER_API Pixels ColorizeIds(const Pixels& ids);
147 CHRONO_BATCH_RENDER_API std::array<uint8_t, 4> IdColor(Span<const uint32_t> words);
148 CHRONO_BATCH_RENDER_API device::Tensor ColorizeScalars(const device::Tensor& values,
149 const ColorizeOptions& options = {});
150 CHRONO_BATCH_RENDER_API device::Tensor ColorizeScalars(const device::Tensor& values,
151 const ColorizeOptions& options,
152 device::Tensor& bounds);
153 CHRONO_BATCH_RENDER_API device::Tensor ColorizeHdr(const device::Tensor& color, float exposure = 0);
154 CHRONO_BATCH_RENDER_API device::Tensor ColorizeNormals(const device::Tensor& normals);
155 CHRONO_BATCH_RENDER_API device::Tensor ColorizeIds(const device::Tensor& ids);
156
157 }
158