Banuba SDK
Loading...
Searching...
No Matches
transformation.hpp
1#pragma once
2
3#include <bnb/types/base_types.hpp>
4#include <bnb/utils/event.hpp>
5#include <bnb/utils/defs.hpp>
6#include <bnb/types/pixel_rect.hpp>
9
10
11#include <memory>
12#include <array>
13#include <optional>
14
15namespace bnb
16{
17 /**
18 * @addtogroup Types
19 * @{
20 */
21
22 enum class rect_fit_mode : uint8_t
23 {
24 fit_width, //!< Always fit to width, rect_scale = w_t / w_f
25 fit_height, //!< Always fit to height, rect_scale = h_t / h_f
26 fit_inside, //!< Fit all source inside target = fit to min rect_scale of width and height modes
27 fit_outside //!< Fit to fill all target = fit to max rect_scale of width and height modes
28 };
29
30 //! Adjust rects to have the same aspect ratio as if fitting source_rect into target_rect according to mode,
31 //! return source_rect, target_rect have the same (+-rounding) aspect ratio,
32 //! and are always not exceeding corresponding input rect, preserving original centers.
33 //! May do some per-axis scale adjustments within small margin for fast, integral and/or pixel-perfect scaling between pixel rects
35
36 void fill_exterior(uint8_t* pixels, uint32_t width, uint32_t height, uint32_t channels, pixel_rect rect, uint8_t color, bool edge_repeat = false);
37
38
39 //! This class implements affine or perspective 2d transformations
40 //! Standard usage implies transformation from common basis into other(common, image or standard) basis
41 //! (e.g. written as (common -> image) in documentation)
42 //!
43 //!
44 //! Frequently used basises are:
45 //! <f ^f >f vf: direction of face-up vector left, up, right, down
46 //!
47 //! standard basis:
48 //! ^ y
49 //! | ^f
50 //! .--> x
51 //!
52 //! common basis =
53 //! image(buffer) basis:
54 //! .--> x
55 //! | ^f
56 //! v y
57 //!
59 {
60 public:
61 static const int mat_s = 3;
62
63 /// 3x3 row-maj transform matrix
64 using mat_t = std::array<float, mat_s * mat_s>;
65
66 /// Rotation is counter clockwise(only in standart basis):
67 /// - Rotating vector(1,0) (= x basis vector) by 90deg
68 /// results in vector(0,1) (= y basis vector)
69 /// - In image buffer basis(y points down) the rotation would go clockwise
70 enum class rotate_t : uint32_t
71 {
72 deg_0 = 0,
73 deg_90 = 90,
74 deg_180 = 180,
75 deg_270 = 270
76 };
77
79 {
80 float scale_x = 1.0f, scale_y = 1.0f;
81 float trans_x = 0.0f, trans_y = 0.0f;
82 rotate_t rotate = rotate_t::deg_0;
83 bool flip_x = false, flip_y = false;
84
85 // approximate comparison for float components
86 bool operator==(const affine_coeffs_t& t) const noexcept;
87 };
88
89 /// Constructs identity transform
91
92 /// Constructs from mat_t
93 explicit transformation(const mat_t& mat);
94 explicit transformation(mat_t::const_pointer mat);
95
96 /// Constructs rotate transformation
97 explicit transformation(rotate_t rotate);
98
99 /// Constructs affine transformation
100 explicit transformation(float scale_x, float scale_y = 1.f, float t_x = 0, float t_y = 0, rotate_t rotate = rotate_t::deg_0, bool flip_x = false, bool flip_y = false);
101
102 /// Constructs affine transformation
104
105 /// Constructs transformation from source to target rectangle
106 /// Rotation and flips are around rectangles' center
107 explicit transformation(pixel_rect source_rect, pixel_rect target_rect, rotate_t rotate = rotate_t::deg_0, bool flip_x = false, bool flip_y = false);
108
110
111 transformation(transformation&& t) noexcept;
112 transformation& operator=(transformation&& t) noexcept;
113
115 transformation& operator=(const transformation& t);
116
117 /// Applies transform t after this
118 /// e.g. {rotate >> translate;} rotates first: (initial -> rotated) >> (rotated -> translated) = (initial -> translated)
119 transformation operator>>(const transformation& t) const noexcept;
120
121 /// Apply transform to point
122 point2d operator*(const point2d& point) const noexcept;
123
124 bool operator==(const transformation& t) const noexcept;
125
126 /**
127 * Get the inverse of the transformation
128 * @throw std::logic_error when matrix is singular
129 */
131
132 /// Clone the transformation
133 transformation clone() const noexcept;
134
135 /// Pointer to matrix data in memory (row major)
136 mat_t::const_pointer data() const noexcept;
137
138 /// Returns 3x3 row-maj transform matrix
139 mat_t get_mat() const noexcept;
140
141 /// Returns transposed matrix data (column major, opengl)
142 mat_t transposed_data() const noexcept;
143
144 /// Cast to string for debug purposes
145 std::string to_string() const noexcept;
146
147 /// Checks if last row is [0, 0, 1] up to float precision
148 bool is_affine() const noexcept;
149
150 /// Normalizes transform to be exactly affine.
151 /// Results are invalid in case last row is not [~0, ~0, C]
152 void normalize_affine() noexcept;
153
154 /// Tries to extract affine coefficients from transformation
155 std::optional<transformation::affine_coeffs_t> extract_affine_coeffs() const;
156
157 /// Get reference to static flip-only transform
158 static const transformation& get_flip_instance(bool flip_x, bool flip_y);
159
160 // iface
161 std::shared_ptr<interfaces::transformation> chain_right(const std::shared_ptr<interfaces::transformation>& t) const override
162 {
163 return std::make_shared<transformation>(*this >> static_cast<transformation&>(*t));
164 }
165 interfaces::point2d transform_point(const interfaces::point2d& p) const override;
166 interfaces::pixel_rect transform_rect(const interfaces::pixel_rect& rect) const override;
167 bool equals(const std::shared_ptr<interfaces::transformation>& t) const override
168 {
169 return *this == static_cast<transformation&>(*t);
170 }
171 std::shared_ptr<interfaces::transformation> inverse_j() const override
172 {
173 return std::make_shared<transformation>(inverse());
174 }
175 std::shared_ptr<interfaces::transformation> clone_j() const override
176 {
177 return std::make_shared<transformation>(clone());
178 }
179 std::vector<float> get_mat_j() const override
180 {
181 auto m = get_mat();
182 return {m.begin(), m.end()};
183 }
184
185 private:
186 mat_t m_mat;
187 };
188
189 template<typename T>
191 {
192 /// (common -> some event data basis) transformation
194 /// rectangle area in common basis that encloses all valid & usable data
196 };
197
198
199 /**
200 * Transform src image to dst
201 * @param src, src_w, src_h source uint8_t image buffer, width and height
202 * @param dst, dst_w, dst_h destination uint8_t image buffer, width and height
203 * @param channels number of channels per pixel
204 * @param t transformation (src -> dst) to apply
205 */
206 void transform(const uint8_t* src, uint32_t src_w, uint32_t src_h, uint8_t* dst, uint32_t dst_w, uint32_t dst_h, uint32_t channels, const transformation& t);
207
208
209 /**
210 * Transform src image to dst
211 * @param src, src_w, src_h source 32 bit float image buffer, width and height
212 * @param dst, dst_w, dst_h destination 32 bit float image buffer, width and height
213 * @param channels number of channels per pixel
214 * @param t transformation (src -> dst) to apply
215 */
216 void transform(const float* src, uint32_t src_w, uint32_t src_h, float* dst, uint32_t dst_w, uint32_t dst_h, uint32_t channels, const transformation& t);
217
218
219 /**
220 * Transform src image to dst through common basis
221 * NOTE: both transformations should be (common -> image)
222 * @param src, src_w, src_h source image buffer, width and height
223 * @param dst, dst_w, dst_h destination image buffer, width and height
224 * @param channels number of channels per pixel
225 * @param from,to transformations (common -> image) to apply by formula (from -> common -> to)
226 */
227 inline void transform(const uint8_t* src, uint32_t src_w, uint32_t src_h, uint8_t* dst, uint32_t dst_w, uint32_t dst_h, uint32_t channels, const transformation& from, const transformation& to)
228 {
229 transform(src, src_w, src_h, dst, dst_w, dst_h, channels, from.inverse() >> to);
230 }
231
232 /**
233 * Transform src image to dst
234 * param src, dst source, destination image buffers
235 * param w, h source, destination width and height
236 * param channels number of channels per pixel
237 * param t transformation (src -> dst) to apply
238 */
239 inline void transform1x1(const uint8_t* src, uint8_t* dst, uint32_t w, uint32_t h, uint32_t channels, const transformation& t)
240 {
241 return transform(src, w, h, dst, w, h, channels, t);
242 }
243
244
245 /**
246 * Apply transformation to point
247 * @param point 2D point to transform
248 * @param t transformation to apply
249 * @return result 2D point
250 */
251 point2d transform(const point2d& point, const transformation& t);
252
253 /**
254 * Transform point through common basis
255 * Apply transformation to point from some basis to another one through common basis
256 * NOTE: both transformations should be (common -> image)
257 * param point 2D point to transform
258 * param from,to transformations (common -> image) to apply by formula (from -> common -> to)
259 * return result 2D point
260 */
261 inline point2d transform(const point2d& point, const transformation& from, const transformation& to)
262 {
263 return transform(point, from.inverse() >> to);
264 }
265
266 /**
267 * Apply transformation to rect
268 * Result is normalized wrt. flips/rotates so that w > 0 && h > 0
269 * @param rect pixel_rect to transform
270 * @param t transformation to apply
271 * @return result pixel_rect
272 */
274
275
277 {
278 auto pt = bnb::transform(point2d{{p.x, p.y}}, *this);
279 return {pt.x, pt.y};
280 }
281 inline interfaces::pixel_rect transformation::transform_rect(const interfaces::pixel_rect& rect) const
282 {
283 return bnb::transform({rect}, *this).get_iface();
284 }
285
286 /** @} */ // endgroup types
287
288} // namespace bnb
This class implements affine or perspective 2d transformations Standard usage implies transformation ...
point2d operator*(const point2d &point) const noexcept
Apply transform to point.
transformation inverse() const
Get the inverse of the transformation.
transformation clone() const noexcept
Clone the transformation.
transformation operator>>(const transformation &t) const noexcept
Applies transform t after this e.g.
transformation(const mat_t &mat)
Constructs from mat_t.
transformation(affine_coeffs_t coeffs)
Constructs affine transformation.
transformation(float scale_x, float scale_y=1.f, float t_x=0, float t_y=0, rotate_t rotate=rotate_t::deg_0, bool flip_x=false, bool flip_y=false)
Constructs affine transformation.
transformation()
Constructs identity transform.
transformation(pixel_rect source_rect, pixel_rect target_rect, rotate_t rotate=rotate_t::deg_0, bool flip_x=false, bool flip_y=false)
Constructs transformation from source to target rectangle Rotation and flips are around rectangles' c...
std::shared_ptr< interfaces::transformation > clone_j() const override
Clone the transformation.
rotate_t
Rotation is counter clockwise(only in standart basis):
std::shared_ptr< interfaces::transformation > inverse_j() const override
Get the inverse of the transformation.
std::array< float, mat_s *mat_s > mat_t
3x3 row-maj transform matrix
std::vector< float > get_mat_j() const override
Returns 3x3 row-maj transform matrix.
transformation(rotate_t rotate)
Constructs rotate transformation.
void transform1x1(const uint8_t *src, uint8_t *dst, uint32_t w, uint32_t h, uint32_t channels, const transformation &t)
Transform src image to dst param src, dst source, destination image buffers param w,...
void transform(const uint8_t *src, uint32_t src_w, uint32_t src_h, uint8_t *dst, uint32_t dst_w, uint32_t dst_h, uint32_t channels, const transformation &t)
Transform src image to dst.
interfaces::point2d transform_point(const interfaces::point2d &p) const override
Apply transform to point.
void fit_rects_aspect_ratio(pixel_rect &source_rect, pixel_rect &target_rect, rect_fit_mode mode=rect_fit_mode::fit_inside)
Adjust rects to have the same aspect ratio as if fitting source_rect into target_rect according to mo...
@ fit_inside
Fit all source inside target = fit to min rect_scale of width and height modes.
@ fit_height
Always fit to height, rect_scale = h_t / h_f.
@ fit_outside
Fit to fill all target = fit to max rect_scale of width and height modes.
@ fit_width
Always fit to width, rect_scale = w_t / w_f.
pixel_rect full_roi
rectangle area in common basis that encloses all valid & usable data
transformation basis_transform
(common -> some event data basis) transformation