Lagrange
Loading...
Searching...
No Matches
ImageType.h
1/*
2 * Copyright 2020 Adobe. All rights reserved.
3 * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License. You may obtain a copy
5 * of the License at http://www.apache.org/licenses/LICENSE-2.0
6 *
7 * Unless required by applicable law or agreed to in writing, software distributed under
8 * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9 * OF ANY KIND, either express or implied. See the License for the specific language
10 * governing permissions and limitations under the License.
11 */
12#pragma once
13
14#include <Eigen/Eigen>
15
16#include <algorithm>
17#include <type_traits>
18
19namespace lagrange {
20namespace image {
21
22enum class ImagePrecision : unsigned int {
23 uint8,
24 int8,
25 uint16,
26 uint32,
27 int32,
28 float32,
29 float64,
30 float16,
31 unknown,
32};
33enum class ImageChannel : unsigned int {
34 one = 1,
35 three = 3,
36 four = 4,
37 unknown,
38};
39
40template <typename T>
41struct ImageTraits;
42
43// to convert the value of image, included in ImagePrecision,
44// it is not the same as static_cast:
45// * unsigned char <==> float/double : [0, 255] <==> [-1.0, 1.0]
46// * others : clamp to avoid overflow
47template <typename VALUE_SRC, typename VALUE_DST>
48inline VALUE_DST convert_channel_value(VALUE_SRC val);
49
50template <typename PIX_SRC, typename PIX_DST>
52{
53 void operator()(const PIX_SRC& src, PIX_DST& dst) const;
54};
55
56
57template <typename TYPE>
59{
60 static constexpr ImagePrecision precision = ImagePrecision::unknown;
61 static constexpr ImageChannel channel = ImageChannel::unknown;
62};
63
64#ifdef LAGRANGE_IMAGE_TRAITS
65static_assert(false, "LAGRANGE_IMAGE_TRAITS was defined somewhere else")
66#elif LAGRANGE_IMAGE_COMMA
67static_assert(false, "LAGRANGE_IMAGE_COMMA was defined somewhere else")
68#else
69
70 #define LAGRANGE_IMAGE_TRAITS(TYPE, VALUE, SIZE_OF_VALUE, PRECISION, CHANNEL) \
71 template <> \
72 struct ImageTraits<TYPE> \
73 { \
74 typedef VALUE TValue; \
75 static constexpr size_t value_size = SIZE_OF_VALUE; \
76 static constexpr ImagePrecision precision = ImagePrecision::PRECISION; \
77 static constexpr ImageChannel channel = ImageChannel::CHANNEL; \
78 };
79
80 #define LAGRANGE_IMAGE_COMMA ,
81LAGRANGE_IMAGE_TRAITS(uint16_t, uint16_t, 1, uint16, one)
82LAGRANGE_IMAGE_TRAITS(
83 Eigen::Matrix<uint16_t LAGRANGE_IMAGE_COMMA 3 LAGRANGE_IMAGE_COMMA 1>,
84 uint16_t,
85 3,
86 uint16,
87 three)
88LAGRANGE_IMAGE_TRAITS(
89 Eigen::Matrix<uint16_t LAGRANGE_IMAGE_COMMA 4 LAGRANGE_IMAGE_COMMA 1>,
90 uint16_t,
91 4,
92 uint16,
93 four)
94LAGRANGE_IMAGE_TRAITS(unsigned char, unsigned char, 1, uint8, one)
95LAGRANGE_IMAGE_TRAITS(
96 Eigen::Matrix<unsigned char LAGRANGE_IMAGE_COMMA 3 LAGRANGE_IMAGE_COMMA 1>,
97 unsigned char,
98 3,
99 uint8,
100 three)
101LAGRANGE_IMAGE_TRAITS(
102 Eigen::Matrix<unsigned char LAGRANGE_IMAGE_COMMA 4 LAGRANGE_IMAGE_COMMA 1>,
103 unsigned char,
104 4,
105 uint8,
106 four)
107LAGRANGE_IMAGE_TRAITS(char, char, 1, int8, one)
108LAGRANGE_IMAGE_TRAITS(
109 Eigen::Matrix<char LAGRANGE_IMAGE_COMMA 3 LAGRANGE_IMAGE_COMMA 1>,
110 char,
111 3,
112 int8,
113 three)
114LAGRANGE_IMAGE_TRAITS(
115 Eigen::Matrix<char LAGRANGE_IMAGE_COMMA 4 LAGRANGE_IMAGE_COMMA 1>,
116 char,
117 4,
118 int8,
119 four)
120LAGRANGE_IMAGE_TRAITS(unsigned int, unsigned int, 1, uint32, one)
121LAGRANGE_IMAGE_TRAITS(
122 Eigen::Matrix<unsigned int LAGRANGE_IMAGE_COMMA 3 LAGRANGE_IMAGE_COMMA 1>,
123 unsigned int,
124 3,
125 uint32,
126 three)
127LAGRANGE_IMAGE_TRAITS(
128 Eigen::Matrix<unsigned int LAGRANGE_IMAGE_COMMA 4 LAGRANGE_IMAGE_COMMA 1>,
129 unsigned int,
130 4,
131 uint32,
132 four)
133LAGRANGE_IMAGE_TRAITS(int, int, 1, int32, one)
134LAGRANGE_IMAGE_TRAITS(Eigen::Vector3i, int, 3, int32, three)
135LAGRANGE_IMAGE_TRAITS(Eigen::Vector4i, int, 4, int32, four)
136LAGRANGE_IMAGE_TRAITS(float, float, 1, float32, one)
137LAGRANGE_IMAGE_TRAITS(Eigen::Vector3f, float, 3, float32, three)
138LAGRANGE_IMAGE_TRAITS(Eigen::Vector4f, float, 4, float32, four)
139LAGRANGE_IMAGE_TRAITS(double, double, 1, float64, one)
140LAGRANGE_IMAGE_TRAITS(Eigen::Vector3d, double, 3, float64, three)
141LAGRANGE_IMAGE_TRAITS(Eigen::Vector4d, double, 4, float64, four)
142LAGRANGE_IMAGE_TRAITS(Eigen::half, Eigen::half, 1, float16, one)
143LAGRANGE_IMAGE_TRAITS(
144 Eigen::Matrix<Eigen::half LAGRANGE_IMAGE_COMMA 3 LAGRANGE_IMAGE_COMMA 1>,
145 Eigen::half,
146 3,
147 float16,
148 three)
149LAGRANGE_IMAGE_TRAITS(
150 Eigen::Matrix<Eigen::half LAGRANGE_IMAGE_COMMA 4 LAGRANGE_IMAGE_COMMA 1>,
151 Eigen::half,
152 4,
153 float16,
154 four)
155
156 #undef LAGRANGE_IMAGE_TRAITS
157 #undef LAGRANGE_IMAGE_COMMA
158#endif
159
160 template <typename VALUE_SRC, typename VALUE_DST>
161 inline VALUE_DST convert_channel_value(VALUE_SRC val)
162{
163 // convert between same type
164 if constexpr (std::is_same<VALUE_SRC, VALUE_DST>::value) {
165 return val;
166 }
167 // convert from unsigned char and float/double
168 else if constexpr (
169 std::is_same<VALUE_SRC, unsigned char>::value && std::is_floating_point<VALUE_DST>::value) {
170 return static_cast<VALUE_DST>(val) /
171 static_cast<VALUE_DST>(std::numeric_limits<unsigned char>::max());
172 }
173 // convert from float/double to unsigned char
174 else if constexpr (
175 std::is_floating_point<VALUE_SRC>::value && std::is_same<VALUE_DST, unsigned char>::value) {
176 return static_cast<unsigned char>(
177 std::clamp(val, static_cast<VALUE_SRC>(0), static_cast<VALUE_SRC>(1)) *
178 static_cast<VALUE_SRC>(std::numeric_limits<unsigned char>::max()));
179 }
180 // convert from uint16_t to float/double: normalize [0, 65535] -> [0, 1]
181 else if constexpr (
182 std::is_same<VALUE_SRC, uint16_t>::value && std::is_floating_point<VALUE_DST>::value) {
183 return static_cast<VALUE_DST>(val) /
184 static_cast<VALUE_DST>(std::numeric_limits<uint16_t>::max());
185 }
186 // convert from float/double to uint16_t: [0, 1] -> [0, 65535]
187 else if constexpr (
188 std::is_floating_point<VALUE_SRC>::value && std::is_same<VALUE_DST, uint16_t>::value) {
189 return static_cast<uint16_t>(
190 std::clamp(val, static_cast<VALUE_SRC>(0), static_cast<VALUE_SRC>(1)) *
191 static_cast<VALUE_SRC>(std::numeric_limits<uint16_t>::max()));
192 } else {
193 // clamping, prepare to convert from signed to unsigned
194 if constexpr (std::is_signed<VALUE_SRC>::value && !std::is_signed<VALUE_DST>::value) {
195 val = std::max(val, static_cast<VALUE_SRC>(0));
196 }
197 // convert between integral types, and it may overflow
198 if constexpr (
199 (std::is_integral<VALUE_SRC>::value && std::is_integral<VALUE_DST>::value) &&
200 (sizeof(VALUE_SRC) > sizeof(VALUE_DST) ||
201 (sizeof(VALUE_SRC) == sizeof(VALUE_DST) && std::is_signed<VALUE_DST>::value))) {
202 return static_cast<VALUE_DST>(
203 std::min(val, static_cast<VALUE_SRC>(std::numeric_limits<VALUE_DST>::max())));
204 }
205 // the rest
206 else {
207 return static_cast<VALUE_DST>(val);
208 }
209 }
210}
211
212template <typename PIX_SRC, typename PIX_DST>
213inline void convert_image_pixel<PIX_SRC, PIX_DST>::operator()(const PIX_SRC& src, PIX_DST& dst)
214 const
215{
216 using V_SRC = typename ImageTraits<PIX_SRC>::TValue;
217 using V_DST = typename ImageTraits<PIX_DST>::TValue;
218 constexpr size_t L_SRC = static_cast<size_t>(ImageTraits<PIX_SRC>::channel);
219 constexpr size_t L_DST = static_cast<size_t>(ImageTraits<PIX_DST>::channel);
220 // convert [1] to [1]
221 if constexpr (1 == L_SRC && 1 == L_DST) {
222 dst = convert_channel_value<V_SRC, V_DST>(src);
223 }
224 // convert [1] to [n]
225 else if constexpr (1 == L_SRC) {
226 dst(0) = convert_channel_value<V_SRC, V_DST>(src);
227 for (size_t i = 1; i < L_DST; ++i) {
228 dst(i) = static_cast<V_DST>(0);
229 }
230 if constexpr (3 <= L_DST) {
231 dst(1) = dst(0);
232 dst(2) = dst(0);
233 }
234 if constexpr (4 == L_DST) {
235 if constexpr (std::is_floating_point<V_DST>::value) {
236 dst(3) = static_cast<V_DST>(1);
237 } else if constexpr (!std::is_signed<V_DST>::value && 1 == sizeof(V_DST)) {
238 dst(3) = std::numeric_limits<V_DST>::max();
239 } else {
240 dst(3) = static_cast<V_DST>(0);
241 }
242 }
243 }
244 // convert [n] to [1]
245 else if constexpr (1 == L_DST) {
246 dst = convert_channel_value<V_SRC, V_DST>(src(0));
247 }
248 // convert [m] to [n]
249 else {
250 constexpr size_t L_MIN = std::min(L_SRC, L_DST);
251 for (size_t i = 0; i < L_MIN; ++i) {
252 dst(i) = convert_channel_value<V_SRC, V_DST>(src(i));
253 }
254 if constexpr (3 == L_MIN && 4 == L_DST) {
255 if constexpr (std::is_floating_point<V_DST>::value) {
256 dst(3) = static_cast<V_DST>(1);
257 } else if constexpr (!std::is_signed<V_DST>::value && 1 == sizeof(V_DST)) {
258 dst(3) = std::numeric_limits<V_DST>::max();
259 } else {
260 dst(3) = static_cast<V_DST>(0);
261 }
262 } else {
263 for (size_t i = L_MIN; i < L_DST; ++i) {
264 dst(i) = static_cast<V_DST>(0);
265 }
266 }
267 }
268}
269} // namespace image
270} // namespace lagrange
Basic image data structure.
Main namespace for Lagrange.
Definition ImageType.h:59
Definition ImageType.h:52