Blender V4.3
IMB_transform_test.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2024 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "testing/testing.h"
6
7#include "BLI_color.hh"
8#include "BLI_math_matrix.hh"
10#include "IMB_imbuf.hh"
11
12namespace blender::imbuf::tests {
13
15{
16 ImBuf *img = IMB_allocImBuf(6, 2, 32, IB_rect);
17 ColorTheme4b *col = reinterpret_cast<ColorTheme4b *>(img->byte_buffer.data);
18
19 /* Source pixels are spelled out in 2x2 blocks below:
20 * nearest filter results in corner pixel from each block, bilinear
21 * is average of each block. */
22 col[0] = ColorTheme4b(0, 0, 0, 255);
23 col[1] = ColorTheme4b(255, 0, 0, 255);
24 col[6] = ColorTheme4b(255, 255, 0, 255);
25 col[7] = ColorTheme4b(255, 255, 255, 255);
26
27 col[2] = ColorTheme4b(133, 55, 31, 13);
28 col[3] = ColorTheme4b(133, 55, 31, 15);
29 col[8] = ColorTheme4b(133, 55, 31, 17);
30 col[9] = ColorTheme4b(133, 55, 31, 19);
31
32 col[4] = ColorTheme4b(50, 200, 0, 255);
33 col[5] = ColorTheme4b(55, 0, 32, 254);
34 col[10] = ColorTheme4b(56, 0, 64, 253);
35 col[11] = ColorTheme4b(57, 0, 96, 252);
36
37 return img;
38}
39
41{
43 ImBuf *dst = IMB_allocImBuf(3, 1, 32, IB_rect);
45 IMB_transform(src, dst, IMB_TRANSFORM_MODE_REGULAR, filter, matrix.ptr(), nullptr);
46 IMB_freeImBuf(src);
47 return dst;
48}
49
51{
53 ImBuf *dst = IMB_allocImBuf(9, 7, 32, IB_rect);
54 float4x4 matrix = math::from_scale<float4x4>(float4(6.0f / 9.0f, 2.0f / 7.0f, 1.0f, 1.0f));
55 IMB_transform(src, dst, IMB_TRANSFORM_MODE_REGULAR, filter, matrix.ptr(), nullptr);
56 IMB_freeImBuf(src);
57 return dst;
58}
59
60TEST(imbuf_transform, nearest_2x_smaller)
61{
63 const ColorTheme4b *got = reinterpret_cast<ColorTheme4b *>(res->byte_buffer.data);
64 EXPECT_EQ(got[0], ColorTheme4b(255, 255, 255, 255));
65 EXPECT_EQ(got[1], ColorTheme4b(133, 55, 31, 19));
66 EXPECT_EQ(got[2], ColorTheme4b(57, 0, 96, 252));
67 IMB_freeImBuf(res);
68}
69
70TEST(imbuf_transform, box_2x_smaller)
71{
73 const ColorTheme4b *got = reinterpret_cast<ColorTheme4b *>(res->byte_buffer.data);
74 /* At 2x reduction should be same as bilinear, save for some rounding errors. */
75 EXPECT_EQ(got[0], ColorTheme4b(191, 128, 64, 255));
76 EXPECT_EQ(got[1], ColorTheme4b(133, 55, 31, 16));
77 EXPECT_EQ(got[2], ColorTheme4b(54, 50, 48, 254));
78 IMB_freeImBuf(res);
79}
80
81TEST(imbuf_transform, bilinear_2x_smaller)
82{
84 const ColorTheme4b *got = reinterpret_cast<ColorTheme4b *>(res->byte_buffer.data);
85 EXPECT_EQ(got[0], ColorTheme4b(191, 128, 64, 255));
86 EXPECT_EQ(got[1], ColorTheme4b(133, 55, 31, 16));
87 EXPECT_EQ(got[2], ColorTheme4b(55, 50, 48, 254));
88 IMB_freeImBuf(res);
89}
90
91TEST(imbuf_transform, cubic_bspline_2x_smaller)
92{
94 const ColorTheme4b *got = reinterpret_cast<ColorTheme4b *>(res->byte_buffer.data);
95 EXPECT_EQ(got[0], ColorTheme4b(189, 126, 62, 250));
96 EXPECT_EQ(got[1], ColorTheme4b(134, 57, 33, 26));
97 EXPECT_EQ(got[2], ColorTheme4b(56, 49, 48, 249));
98 IMB_freeImBuf(res);
99}
100
101TEST(imbuf_transform, cubic_mitchell_2x_smaller)
102{
104 const ColorTheme4b *got = reinterpret_cast<ColorTheme4b *>(res->byte_buffer.data);
105 EXPECT_EQ(got[0], ColorTheme4b(195, 130, 67, 255));
106 EXPECT_EQ(got[1], ColorTheme4b(132, 51, 28, 0));
107 EXPECT_EQ(got[2], ColorTheme4b(52, 52, 48, 255));
108 IMB_freeImBuf(res);
109}
110
111TEST(imbuf_transform, cubic_mitchell_fractional_larger)
112{
114 const ColorTheme4b *got = reinterpret_cast<ColorTheme4b *>(res->byte_buffer.data);
115 EXPECT_EQ(got[0 + 0 * res->x], ColorTheme4b(0, 0, 0, 255));
116 EXPECT_EQ(got[1 + 0 * res->x], ColorTheme4b(127, 0, 0, 255));
117 EXPECT_EQ(got[7 + 0 * res->x], ColorTheme4b(49, 109, 13, 255));
118 EXPECT_EQ(got[2 + 2 * res->x], ColorTheme4b(236, 53, 50, 215));
119 EXPECT_EQ(got[3 + 2 * res->x], ColorTheme4b(155, 55, 35, 54));
120 EXPECT_EQ(got[8 + 6 * res->x], ColorTheme4b(57, 0, 98, 252));
121 IMB_freeImBuf(res);
122}
123
124TEST(imbuf_transform, nearest_very_large_scale)
125{
126 /* Create 511x1 black image, with three middle pixels being red/green/blue. */
127 ImBuf *src = IMB_allocImBuf(511, 1, 32, IB_rect);
128 ColorTheme4b col_r = ColorTheme4b(255, 0, 0, 255);
129 ColorTheme4b col_g = ColorTheme4b(0, 255, 0, 255);
130 ColorTheme4b col_b = ColorTheme4b(0, 0, 255, 255);
131 ColorTheme4b col_0 = ColorTheme4b(0, 0, 0, 0);
132 ColorTheme4b *src_col = reinterpret_cast<ColorTheme4b *>(src->byte_buffer.data);
133 src_col[254] = col_r;
134 src_col[255] = col_g;
135 src_col[256] = col_b;
136
137 /* Create 3841x1 image, and scale the input image so that the three middle
138 * pixels cover almost all of it, except the rightmost pixel. */
139 ImBuf *res = IMB_allocImBuf(3841, 1, 32, IB_rect);
141 float3(254, 0, 0), math::Quaternion::identity(), float3(3.0f / 3840.0f, 1, 1));
142 IMB_transform(src, res, IMB_TRANSFORM_MODE_REGULAR, IMB_FILTER_NEAREST, matrix.ptr(), nullptr);
143
144 /* Check result: leftmost red, middle green, two rightmost pixels blue and black.
145 * If the transform code internally does not have enough precision while stepping
146 * through the scan-line, the rightmost side will not come out correctly. */
147 const ColorTheme4b *got = reinterpret_cast<ColorTheme4b *>(res->byte_buffer.data);
148 EXPECT_EQ(got[0], col_r);
149 EXPECT_EQ(got[res->x / 2], col_g);
150 EXPECT_EQ(got[res->x - 2], col_b);
151 EXPECT_EQ(got[res->x - 1], col_0);
152 IMB_freeImBuf(src);
153 IMB_freeImBuf(res);
154}
155
156} // namespace blender::imbuf::tests
EXPECT_EQ(BLI_expr_pylike_eval(expr, nullptr, 0, &result), EXPR_PYLIKE_INVALID)
@ IMB_TRANSFORM_MODE_REGULAR
Do not crop or repeat.
Definition IMB_imbuf.hh:678
void IMB_transform(const ImBuf *src, ImBuf *dst, eIMBTransformMode mode, eIMBInterpolationFilterMode filter, const float transform_matrix[4][4], const rctf *src_crop)
Transform source image buffer onto destination image buffer using a transform matrix.
eIMBInterpolationFilterMode
Definition IMB_imbuf.hh:288
@ IMB_FILTER_NEAREST
Definition IMB_imbuf.hh:289
@ IMB_FILTER_CUBIC_BSPLINE
Definition IMB_imbuf.hh:291
@ IMB_FILTER_CUBIC_MITCHELL
Definition IMB_imbuf.hh:292
@ IMB_FILTER_BILINEAR
Definition IMB_imbuf.hh:290
@ IMB_FILTER_BOX
Definition IMB_imbuf.hh:293
@ IB_rect
uint col
struct ImBuf * IMB_allocImBuf(unsigned int, unsigned int, unsigned char, unsigned int)
void IMB_freeImBuf(ImBuf *)
TEST(imbuf_scaling, nearest_2x_smaller)
static ImBuf * create_6x2_test_image()
static ImBuf * transform_2x_smaller(eIMBInterpolationFilterMode filter)
static ImBuf * transform_fractional_larger(eIMBInterpolationFilterMode filter)
MatT from_scale(const VecBase< typename MatT::base_type, ScaleDim > &scale)
MatT from_loc_rot_scale(const typename MatT::loc_type &location, const RotationT &rotation, const VecBase< typename MatT::base_type, ScaleDim > &scale)
ColorTheme4< uint8_t > ColorTheme4b
Definition BLI_color.hh:286
VecBase< float, 4 > float4
VecBase< float, 3 > float3
ImBufByteBuffer byte_buffer