VSE: bilinear upscaling no longer adds transparent border around the image #117717

Merged
Aras Pranckevicius merged 8 commits from aras_p/blender:vse_filter_aa into main 2024-02-02 16:29:01 +01:00
14 changed files with 67 additions and 62 deletions
Showing only changes of commit c178460a76 - Show all commits

View File

@ -1316,7 +1316,7 @@ static void tracking_stabilize_frame_interpolation_cb(void *__restrict userdata,
for (int x = 0; x < tmpibuf->x; x++, dst++) {
vec[0] = float(x);
mul_v3_m4v3(rvec, mat, vec);
*dst = imbuf::interpolate_bilinear_fl(ibuf, rvec[0], rvec[1]);
*dst = imbuf::interpolate_bilinear_border_fl(ibuf, rvec[0], rvec[1]);
}
}
else if (data->tracking_filter == TRACKING_FILTER_BICUBIC) {
@ -1342,7 +1342,7 @@ static void tracking_stabilize_frame_interpolation_cb(void *__restrict userdata,
for (int x = 0; x < tmpibuf->x; x++, dst++) {
vec[0] = float(x);
mul_v3_m4v3(rvec, mat, vec);
*dst = imbuf::interpolate_bilinear_byte(ibuf, rvec[0], rvec[1]);
*dst = imbuf::interpolate_bilinear_border_byte(ibuf, rvec[0], rvec[1]);
}
}
else if (data->tracking_filter == TRACKING_FILTER_BICUBIC) {

View File

@ -152,13 +152,13 @@ inline void interpolate_nearest_wrap_fl(
* to get proper filtering.
*/
[[nodiscard]] uchar4 interpolate_bilinear_byte(
[[nodiscard]] uchar4 interpolate_bilinear_border_byte(
const uchar *buffer, int width, int height, float u, float v);
[[nodiscard]] float4 interpolate_bilinear_fl(
[[nodiscard]] float4 interpolate_bilinear_border_fl(
const float *buffer, int width, int height, float u, float v);
void interpolate_bilinear_fl(
void interpolate_bilinear_border_fl(
const float *buffer, float *output, int width, int height, int components, float u, float v);
/**

View File

@ -357,7 +357,8 @@ BLI_INLINE void bilinear_fl_impl(const float *buffer,
namespace blender::math {
uchar4 interpolate_bilinear_byte(const uchar *buffer, int width, int height, float u, float v)
uchar4 interpolate_bilinear_border_byte(
const uchar *buffer, int width, int height, float u, float v)
{
BLI_assert(buffer);
uchar4 res;
@ -502,14 +503,14 @@ uchar4 interpolate_bilinear_byte(const uchar *buffer, int width, int height, flo
return res;
}
float4 interpolate_bilinear_fl(const float *buffer, int width, int height, float u, float v)
float4 interpolate_bilinear_border_fl(const float *buffer, int width, int height, float u, float v)
{
float4 res;
bilinear_fl_impl(buffer, res, width, height, 4, u, v);
return res;
}
void interpolate_bilinear_fl(
void interpolate_bilinear_border_fl(
const float *buffer, float *output, int width, int height, int components, float u, float v)
{
bilinear_fl_impl(buffer, output, width, height, components, u, v);

View File

@ -28,10 +28,10 @@ TEST(math_interp, BilinearCharExactSamples)
{
uchar4 res;
uchar4 exp1 = {73, 108, 153, 251};
res = interpolate_bilinear_byte(image_char[0][0], image_width, image_height, 1.0f, 2.0f);
res = interpolate_bilinear_border_byte(image_char[0][0], image_width, image_height, 1.0f, 2.0f);
EXPECT_EQ(exp1, res);
uchar4 exp2 = {240, 160, 90, 20};
res = interpolate_bilinear_byte(image_char[0][0], image_width, image_height, 2.0f, 0.0f);
res = interpolate_bilinear_border_byte(image_char[0][0], image_width, image_height, 2.0f, 0.0f);
EXPECT_EQ(exp2, res);
}
@ -39,10 +39,10 @@ TEST(math_interp, BilinearCharHalfwayUSamples)
{
uchar4 res;
uchar4 exp1 = {31, 37, 42, 48};
res = interpolate_bilinear_byte(image_char[0][0], image_width, image_height, 0.5f, 1.0f);
res = interpolate_bilinear_border_byte(image_char[0][0], image_width, image_height, 0.5f, 1.0f);
EXPECT_EQ(exp1, res);
uchar4 exp2 = {243, 242, 224, 223};
res = interpolate_bilinear_byte(image_char[0][0], image_width, image_height, 0.5f, 0.0f);
res = interpolate_bilinear_border_byte(image_char[0][0], image_width, image_height, 0.5f, 0.0f);
EXPECT_EQ(exp2, res);
}
@ -50,10 +50,10 @@ TEST(math_interp, BilinearCharHalfwayVSamples)
{
uchar4 res;
uchar4 exp1 = {1, 2, 3, 4};
res = interpolate_bilinear_byte(image_char[0][0], image_width, image_height, 0.0f, 1.5f);
res = interpolate_bilinear_border_byte(image_char[0][0], image_width, image_height, 0.0f, 1.5f);
EXPECT_EQ(exp1, res);
uchar4 exp2 = {127, 128, 129, 130};
res = interpolate_bilinear_byte(image_char[0][0], image_width, image_height, 2.0f, 1.5f);
res = interpolate_bilinear_border_byte(image_char[0][0], image_width, image_height, 2.0f, 1.5f);
EXPECT_EQ(exp2, res);
}
@ -61,10 +61,11 @@ TEST(math_interp, BilinearCharSamples)
{
uchar4 res;
uchar4 exp1 = {136, 133, 132, 130};
res = interpolate_bilinear_byte(image_char[0][0], image_width, image_height, 1.25f, 0.625f);
res = interpolate_bilinear_border_byte(
image_char[0][0], image_width, image_height, 1.25f, 0.625f);
EXPECT_EQ(exp1, res);
uchar4 exp2 = {219, 191, 167, 142};
res = interpolate_bilinear_byte(image_char[0][0], image_width, image_height, 1.4f, 0.1f);
res = interpolate_bilinear_border_byte(image_char[0][0], image_width, image_height, 1.4f, 0.1f);
EXPECT_EQ(exp2, res);
}
@ -72,10 +73,10 @@ TEST(math_interp, BilinearFloatSamples)
{
float4 res;
float4 exp1 = {135.9375f, 133.28125f, 131.5625f, 129.84375f};
res = interpolate_bilinear_fl(image_fl[0][0], image_width, image_height, 1.25f, 0.625f);
res = interpolate_bilinear_border_fl(image_fl[0][0], image_width, image_height, 1.25f, 0.625f);
EXPECT_V4_NEAR(exp1, res, float_tolerance);
float4 exp2 = {219.36f, 191.2f, 166.64f, 142.08f};
res = interpolate_bilinear_fl(image_fl[0][0], image_width, image_height, 1.4f, 0.1f);
res = interpolate_bilinear_border_fl(image_fl[0][0], image_width, image_height, 1.4f, 0.1f);
EXPECT_V4_NEAR(exp2, res, float_tolerance);
}
@ -83,13 +84,13 @@ TEST(math_interp, BilinearCharPartiallyOutsideImage)
{
uchar4 res;
uchar4 exp1 = {1, 1, 2, 2};
res = interpolate_bilinear_byte(image_char[0][0], image_width, image_height, -0.5f, 2.0f);
res = interpolate_bilinear_border_byte(image_char[0][0], image_width, image_height, -0.5f, 2.0f);
EXPECT_EQ(exp1, res);
uchar4 exp2 = {9, 11, 15, 22};
res = interpolate_bilinear_byte(image_char[0][0], image_width, image_height, 1.25f, 2.9f);
res = interpolate_bilinear_border_byte(image_char[0][0], image_width, image_height, 1.25f, 2.9f);
EXPECT_EQ(exp2, res);
uchar4 exp3 = {173, 115, 65, 14};
res = interpolate_bilinear_byte(image_char[0][0], image_width, image_height, 2.2f, -0.1f);
res = interpolate_bilinear_border_byte(image_char[0][0], image_width, image_height, 2.2f, -0.1f);
EXPECT_EQ(exp3, res);
}
@ -111,13 +112,13 @@ TEST(math_interp, BilinearFloatPartiallyOutsideImage)
{
float4 res;
float4 exp1 = {0.5f, 1, 1.5f, 2};
res = interpolate_bilinear_fl(image_fl[0][0], image_width, image_height, -0.5f, 2.0f);
res = interpolate_bilinear_border_fl(image_fl[0][0], image_width, image_height, -0.5f, 2.0f);
EXPECT_V4_NEAR(exp1, res, float_tolerance);
float4 exp2 = {8.675f, 11.325f, 14.725f, 22.1f};
res = interpolate_bilinear_fl(image_fl[0][0], image_width, image_height, 1.25f, 2.9f);
res = interpolate_bilinear_border_fl(image_fl[0][0], image_width, image_height, 1.25f, 2.9f);
EXPECT_V4_NEAR(exp2, res, float_tolerance);
float4 exp3 = {172.8f, 115.2f, 64.8f, 14.4f};
res = interpolate_bilinear_fl(image_fl[0][0], image_width, image_height, 2.2f, -0.1f);
res = interpolate_bilinear_border_fl(image_fl[0][0], image_width, image_height, 2.2f, -0.1f);
EXPECT_V4_NEAR(exp3, res, float_tolerance);
}
@ -151,23 +152,23 @@ TEST(math_interp, BilinearCharFullyOutsideImage)
uchar4 res;
uchar4 exp = {0, 0, 0, 0};
/* Out of range on U */
res = interpolate_bilinear_byte(image_char[0][0], image_width, image_height, -1.5f, 0);
res = interpolate_bilinear_border_byte(image_char[0][0], image_width, image_height, -1.5f, 0);
EXPECT_EQ(exp, res);
res = interpolate_bilinear_byte(image_char[0][0], image_width, image_height, -1.1f, 0);
res = interpolate_bilinear_border_byte(image_char[0][0], image_width, image_height, -1.1f, 0);
EXPECT_EQ(exp, res);
res = interpolate_bilinear_byte(image_char[0][0], image_width, image_height, 3, 0);
res = interpolate_bilinear_border_byte(image_char[0][0], image_width, image_height, 3, 0);
EXPECT_EQ(exp, res);
res = interpolate_bilinear_byte(image_char[0][0], image_width, image_height, 5, 0);
res = interpolate_bilinear_border_byte(image_char[0][0], image_width, image_height, 5, 0);
EXPECT_EQ(exp, res);
/* Out of range on V */
res = interpolate_bilinear_byte(image_char[0][0], image_width, image_height, 0, -3.2f);
res = interpolate_bilinear_border_byte(image_char[0][0], image_width, image_height, 0, -3.2f);
EXPECT_EQ(exp, res);
res = interpolate_bilinear_byte(image_char[0][0], image_width, image_height, 0, -1.5f);
res = interpolate_bilinear_border_byte(image_char[0][0], image_width, image_height, 0, -1.5f);
EXPECT_EQ(exp, res);
res = interpolate_bilinear_byte(image_char[0][0], image_width, image_height, 0, 3.1f);
res = interpolate_bilinear_border_byte(image_char[0][0], image_width, image_height, 0, 3.1f);
EXPECT_EQ(exp, res);
res = interpolate_bilinear_byte(image_char[0][0], image_width, image_height, 0, 500.0f);
res = interpolate_bilinear_border_byte(image_char[0][0], image_width, image_height, 0, 500.0f);
EXPECT_EQ(exp, res);
}

View File

@ -249,17 +249,17 @@ class MemoryBuffer {
single_y = rel_y - last_y;
}
math::interpolate_bilinear_fl(buffer_, out, 1, 1, num_channels_, single_x, single_y);
math::interpolate_bilinear_border_fl(buffer_, out, 1, 1, num_channels_, single_x, single_y);
return;
}
math::interpolate_bilinear_fl(buffer_,
out,
get_width(),
get_height(),
num_channels_,
get_relative_x(x),
get_relative_y(y));
math::interpolate_bilinear_border_fl(buffer_,
out,
get_width(),
get_height(),
num_channels_,
get_relative_x(x),
get_relative_y(y));
}
void read_elem_sampled(float x, float y, PixelSampler sampler, float *out) const

View File

@ -104,7 +104,7 @@ static void sample_image_at_location(ImBuf *ibuf,
imbuf::interpolate_nearest_fl(ibuf, color, x, y);
break;
case PixelSampler::Bilinear:
imbuf::interpolate_bilinear_fl(ibuf, color, x, y);
imbuf::interpolate_bilinear_border_fl(ibuf, color, x, y);
break;
case PixelSampler::Bicubic:
imbuf::interpolate_cubic_bspline_fl(ibuf, color, x, y);
@ -118,7 +118,7 @@ static void sample_image_at_location(ImBuf *ibuf,
byte_color = imbuf::interpolate_nearest_byte(ibuf, x, y);
break;
case PixelSampler::Bilinear:
byte_color = imbuf::interpolate_bilinear_byte(ibuf, x, y);
byte_color = imbuf::interpolate_bilinear_border_byte(ibuf, x, y);
break;
case PixelSampler::Bicubic:
byte_color = imbuf::interpolate_cubic_bspline_byte(ibuf, x, y);

View File

@ -85,7 +85,7 @@ void MovieClipBaseOperation::execute_pixel_sampled(float output[4],
imbuf::interpolate_nearest_fl(ibuf, output, x, y);
break;
case PixelSampler::Bilinear:
imbuf::interpolate_bilinear_fl(ibuf, output, x, y);
imbuf::interpolate_bilinear_border_fl(ibuf, output, x, y);
break;
case PixelSampler::Bicubic:
imbuf::interpolate_cubic_bspline_fl(ibuf, output, x, y);

View File

@ -91,7 +91,7 @@ void MultilayerColorOperation::execute_pixel_sampled(float output[4],
imbuf::interpolate_nearest_fl(buffer_, output, x, y);
break;
case PixelSampler::Bilinear:
imbuf::interpolate_bilinear_fl(buffer_, output, x, y);
imbuf::interpolate_bilinear_border_fl(buffer_, output, x, y);
break;
case PixelSampler::Bicubic:
imbuf::interpolate_cubic_bspline_fl(buffer_, output, x, y);

View File

@ -77,7 +77,8 @@ void RenderLayersProg::do_interpolation(float output[4], float x, float y, Pixel
math::interpolate_nearest_fl(input_buffer_, output, width, height, elementsize_, x, y);
break;
case PixelSampler::Bilinear:
math::interpolate_bilinear_fl(input_buffer_, output, width, height, elementsize_, x, y);
math::interpolate_bilinear_border_fl(
input_buffer_, output, width, height, elementsize_, x, y);
break;
case PixelSampler::Bicubic:
math::interpolate_cubic_bspline_fl(input_buffer_, output, width, height, elementsize_, x, y);

View File

@ -44,22 +44,22 @@ inline void interpolate_nearest_fl(const ImBuf *in, float output[4], float u, fl
return math::interpolate_nearest_wrap_fl(in->float_buffer.data, in->x, in->y, u, v);
}
[[nodiscard]] inline uchar4 interpolate_bilinear_byte(const ImBuf *in, float u, float v)
[[nodiscard]] inline uchar4 interpolate_bilinear_border_byte(const ImBuf *in, float u, float v)
{
return math::interpolate_bilinear_byte(in->byte_buffer.data, in->x, in->y, u, v);
return math::interpolate_bilinear_border_byte(in->byte_buffer.data, in->x, in->y, u, v);
}
[[nodiscard]] inline float4 interpolate_bilinear_fl(const ImBuf *in, float u, float v)
[[nodiscard]] inline float4 interpolate_bilinear_border_fl(const ImBuf *in, float u, float v)
{
return math::interpolate_bilinear_fl(in->float_buffer.data, in->x, in->y, u, v);
return math::interpolate_bilinear_border_fl(in->float_buffer.data, in->x, in->y, u, v);
}
inline void interpolate_bilinear_byte(const ImBuf *in, uchar output[4], float u, float v)
inline void interpolate_bilinear_border_byte(const ImBuf *in, uchar output[4], float u, float v)
{
uchar4 col = math::interpolate_bilinear_byte(in->byte_buffer.data, in->x, in->y, u, v);
uchar4 col = math::interpolate_bilinear_border_byte(in->byte_buffer.data, in->x, in->y, u, v);
memcpy(output, &col, sizeof(col));
}
inline void interpolate_bilinear_fl(const ImBuf *in, float output[4], float u, float v)
inline void interpolate_bilinear_border_fl(const ImBuf *in, float output[4], float u, float v)
{
float4 col = math::interpolate_bilinear_fl(in->float_buffer.data, in->x, in->y, u, v);
float4 col = math::interpolate_bilinear_border_fl(in->float_buffer.data, in->x, in->y, u, v);
memcpy(output, &col, sizeof(col));
}

View File

@ -1761,12 +1761,12 @@ static void *do_scale_thread(void *data_v)
int offset = y * data->newx + x;
if (data->byte_buffer) {
interpolate_bilinear_byte(ibuf, data->byte_buffer + 4 * offset, u, v);
interpolate_bilinear_border_byte(ibuf, data->byte_buffer + 4 * offset, u, v);
}
if (data->float_buffer) {
float *pixel = data->float_buffer + ibuf->channels * offset;
blender::math::interpolate_bilinear_fl(
blender::math::interpolate_bilinear_border_fl(
ibuf->float_buffer.data, pixel, ibuf->x, ibuf->y, ibuf->channels, u, v);
}
}

View File

@ -136,7 +136,7 @@ static void sample_image(const ImBuf *source, float u, float v, T *r_sample)
v -= 0.5f;
}
if constexpr (Filter == IMB_FILTER_BILINEAR && std::is_same_v<T, float> && NumChannels == 4) {
interpolate_bilinear_fl(source, r_sample, u, v);
interpolate_bilinear_border_fl(source, r_sample, u, v);
}
else if constexpr (Filter == IMB_FILTER_NEAREST && std::is_same_v<T, uchar> && NumChannels == 4)
{
@ -144,7 +144,7 @@ static void sample_image(const ImBuf *source, float u, float v, T *r_sample)
}
else if constexpr (Filter == IMB_FILTER_BILINEAR && std::is_same_v<T, uchar> && NumChannels == 4)
{
interpolate_bilinear_byte(source, r_sample, u, v);
interpolate_bilinear_border_byte(source, r_sample, u, v);
}
else if constexpr (Filter == IMB_FILTER_BILINEAR && std::is_same_v<T, float>) {
if constexpr (WrapUV) {
@ -159,7 +159,7 @@ static void sample_image(const ImBuf *source, float u, float v, T *r_sample)
true);
}
else {
math::interpolate_bilinear_fl(
math::interpolate_bilinear_border_fl(
source->float_buffer.data, r_sample, source->x, source->y, NumChannels, u, v);
}
}

View File

@ -274,10 +274,12 @@ class TextureMarginMap {
if (found_pixel_in_polygon) {
if (ibuf_ptr_fl) {
ibuf_ptr_fl[pixel_index] = imbuf::interpolate_bilinear_fl(ibuf, destX, destY);
ibuf_ptr_fl[pixel_index] = imbuf::interpolate_bilinear_border_fl(
ibuf, destX, destY);
}
if (ibuf_ptr_ch) {
ibuf_ptr_ch[pixel_index] = imbuf::interpolate_bilinear_byte(ibuf, destX, destY);
ibuf_ptr_ch[pixel_index] = imbuf::interpolate_bilinear_border_byte(
ibuf, destX, destY);
}
/* Add our new pixels to the assigned pixel map. */
mask[pixel_index] = 1;

View File

@ -1584,10 +1584,10 @@ static void transform_image(int x,
break;
case 1:
if (dst_fl) {
dst_fl[offset] = imbuf::interpolate_bilinear_fl(ibuf, xt, yt);
dst_fl[offset] = imbuf::interpolate_bilinear_border_fl(ibuf, xt, yt);
}
else {
dst_ch[offset] = imbuf::interpolate_bilinear_byte(ibuf, xt, yt);
dst_ch[offset] = imbuf::interpolate_bilinear_border_byte(ibuf, xt, yt);
}
break;
case 2: