[Bf-blender-cvs] [d20f3992392] blender-v2.93-release: VSE: Fix colorbleed on scaled images

Richard Antalik noreply at git.blender.org
Wed Apr 28 17:21:37 CEST 2021


Commit: d20f3992392a7fb308f85fd4a920aaf99230b227
Author: Richard Antalik
Date:   Wed Apr 28 17:11:12 2021 +0200
Branches: blender-v2.93-release
https://developer.blender.org/rBd20f3992392a7fb308f85fd4a920aaf99230b227

VSE: Fix colorbleed on scaled images

When frame is rendered to file, bilinear interpolation on scaled images
caused blurred edges.

This is fixed by not doing interpolation with pixels outside of source
buffer.

Such fix doesn't cover cropped images which are currently cropped by
filling area of image with black transparent color, because image buffer
has bigger size than visible image area.

This is fixed by offsetting range used in previous fix by amount, that
would correspond to crop distance. Because of this, image area doesn't
even need to be filled with transparency.

Reviewed By: sergey

Differential Revision: https://developer.blender.org/D11058

===================================================================

M	source/blender/sequencer/intern/render.c

===================================================================

diff --git a/source/blender/sequencer/intern/render.c b/source/blender/sequencer/intern/render.c
index 96c881c9c5f..f892f1c1b41 100644
--- a/source/blender/sequencer/intern/render.c
+++ b/source/blender/sequencer/intern/render.c
@@ -459,50 +459,81 @@ static bool seq_input_have_to_preprocess(const SeqRenderData *context,
 typedef struct ImageTransformThreadInitData {
   ImBuf *ibuf_source;
   ImBuf *ibuf_out;
-  StripTransform *transform;
-  float scale_to_fit;
-  float image_scale_factor;
+  Sequence *seq;
   float preview_scale_factor;
+  bool is_proxy_image;
   bool for_render;
 } ImageTransformThreadInitData;
 
 typedef struct ImageTransformThreadData {
   ImBuf *ibuf_source;
   ImBuf *ibuf_out;
-  StripTransform *transform;
-  float scale_to_fit;
+  Sequence *seq;
   /* image_scale_factor is used to scale proxies to correct preview size. */
   float image_scale_factor;
   /* Preview scale factor is needed to correct translation to match preview size. */
   float preview_scale_factor;
+  float crop_scale_factor;
   bool for_render;
   int start_line;
   int tot_line;
 } ImageTransformThreadData;
 
-static void sequencer_image_transform_init(void *handle_v,
-                                           int start_line,
-                                           int tot_line,
-                                           void *init_data_v)
+/**
+ * Effect, mask and scene in strip input strips are rendered in preview resolution.
+ * They are already down-scaled. #input_preprocess() does not expect this to happen.
+ * Other strip types are rendered with original media resolution, unless proxies are
+ * enabled for them. With proxies `is_proxy_image` will be set correctly to true.
+ */
+static bool seq_need_scale_to_render_size(const Sequence *seq, bool is_proxy_image)
+{
+  if (is_proxy_image) {
+    return true;
+  }
+  if ((seq->type & SEQ_TYPE_EFFECT) != 0 || seq->type == SEQ_TYPE_MASK ||
+      seq->type == SEQ_TYPE_META ||
+      (seq->type == SEQ_TYPE_SCENE && ((seq->flag & SEQ_SCENE_STRIPS) != 0))) {
+    return true;
+  }
+  return false;
+}
+
+static void sequencer_image_crop_transform_init(void *handle_v,
+                                                int start_line,
+                                                int tot_line,
+                                                void *init_data_v)
 {
   ImageTransformThreadData *handle = (ImageTransformThreadData *)handle_v;
   const ImageTransformThreadInitData *init_data = (ImageTransformThreadInitData *)init_data_v;
 
   handle->ibuf_source = init_data->ibuf_source;
   handle->ibuf_out = init_data->ibuf_out;
-  handle->transform = init_data->transform;
-  handle->image_scale_factor = init_data->image_scale_factor;
+  handle->seq = init_data->seq;
+
   handle->preview_scale_factor = init_data->preview_scale_factor;
-  handle->for_render = init_data->for_render;
+  if (seq_need_scale_to_render_size(init_data->seq, init_data->is_proxy_image)) {
+    handle->image_scale_factor = 1.0f;
+  }
+  else {
+    handle->image_scale_factor = handle->preview_scale_factor;
+  }
+
+  /* Proxy image is smaller, so crop values must be corrected by proxy scale factor.
+   * Proxy scale factor always matches preview_scale_factor. */
+  handle->crop_scale_factor = seq_need_scale_to_render_size(init_data->seq,
+                                                            init_data->is_proxy_image) ?
+                                  init_data->preview_scale_factor :
+                                  1.0f;
 
+  handle->for_render = init_data->for_render;
   handle->start_line = start_line;
   handle->tot_line = tot_line;
 }
 
-static void *sequencer_image_transform_do_thread(void *data_v)
+static void *sequencer_image_crop_transform_do_thread(void *data_v)
 {
   const ImageTransformThreadData *data = (ImageTransformThreadData *)data_v;
-  const StripTransform *transform = data->transform;
+  const StripTransform *transform = data->seq->strip->transform;
   const float scale_x = transform->scale_x * data->image_scale_factor;
   const float scale_y = transform->scale_y * data->image_scale_factor;
   const float image_center_offs_x = (data->ibuf_out->x - data->ibuf_source->x) / 2;
@@ -515,8 +546,19 @@ static void *sequencer_image_transform_do_thread(void *data_v)
                        (const float[]){translate_x, translate_y},
                        transform->rotation,
                        (const float[]){scale_x, scale_y});
-  invert_m3(transform_matrix);
   transform_pivot_set_m3(transform_matrix, pivot);
+  invert_m3(transform_matrix);
+
+  /* Image crop is done by offsetting image boundary limits. */
+  const StripCrop *c = data->seq->strip->crop;
+  const int left = c->left * data->crop_scale_factor;
+  const int right = c->right * data->crop_scale_factor;
+  const int top = c->top * data->crop_scale_factor;
+  const int bottom = c->bottom * data->crop_scale_factor;
+
+  const float source_pixel_range_max[2] = {data->ibuf_source->x - right,
+                                           data->ibuf_source->y - top};
+  const float source_pixel_range_min[2] = {left, bottom};
 
   const int width = data->ibuf_out->x;
   for (int yi = data->start_line; yi < data->start_line + data->tot_line; yi++) {
@@ -524,6 +566,11 @@ static void *sequencer_image_transform_do_thread(void *data_v)
       float uv[2] = {xi, yi};
       mul_v2_m3v2(uv, transform_matrix, uv);
 
+      if (source_pixel_range_min[0] >= uv[0] || uv[0] >= source_pixel_range_max[0] ||
+          source_pixel_range_min[1] >= uv[1] || uv[1] >= source_pixel_range_max[1]) {
+        continue;
+      }
+
       if (data->for_render) {
         bilinear_interpolation(data->ibuf_source, data->ibuf_out, uv[0], uv[1], xi, yi);
       }
@@ -571,25 +618,6 @@ static void multibuf(ImBuf *ibuf, const float fmul)
   }
 }
 
-/**
- * Effect, mask and scene in strip input strips are rendered in preview resolution.
- * They are already down-scaled. #input_preprocess() does not expect this to happen.
- * Other strip types are rendered with original media resolution, unless proxies are
- * enabled for them. With proxies `is_proxy_image` will be set correctly to true.
- */
-static bool seq_need_scale_to_render_size(const Sequence *seq, bool is_proxy_image)
-{
-  if (is_proxy_image) {
-    return true;
-  }
-  if ((seq->type & SEQ_TYPE_EFFECT) != 0 || seq->type == SEQ_TYPE_MASK ||
-      seq->type == SEQ_TYPE_META ||
-      (seq->type == SEQ_TYPE_SCENE && ((seq->flag & SEQ_SCENE_STRIPS) != 0))) {
-    return true;
-  }
-  return false;
-}
-
 static ImBuf *input_preprocess(const SeqRenderData *context,
                                Sequence *seq,
                                float timeline_frame,
@@ -608,46 +636,8 @@ static ImBuf *input_preprocess(const SeqRenderData *context,
     IMB_filtery(preprocessed_ibuf);
   }
 
-  /* Get scale factor if preview resolution doesn't match project resolution. */
-  float preview_scale_factor;
-  if (context->preview_render_size == SEQ_RENDER_SIZE_SCENE) {
-    preview_scale_factor = (float)scene->r.size / 100;
-  }
-  else {
-    preview_scale_factor = SEQ_rendersize_to_scale_factor(context->preview_render_size);
-  }
-
-  if (sequencer_use_crop(seq)) {
-    /* Change original image pointer to avoid another duplication in SEQ_USE_TRANSFORM. */
-    preprocessed_ibuf = IMB_makeSingleUser(ibuf);
-    ibuf = preprocessed_ibuf;
-
-    const int width = ibuf->x;
-    const int height = ibuf->y;
-    const StripCrop *c = seq->strip->crop;
-
-    /* Proxy image is smaller, so crop values must be corrected by proxy scale factor.
-     * Proxy scale factor always matches preview_scale_factor. */
-    const float crop_scale_factor = seq_need_scale_to_render_size(seq, is_proxy_image) ?
-                                        preview_scale_factor :
-                                        1.0f;
-    const int left = c->left * crop_scale_factor;
-    const int right = c->right * crop_scale_factor;
-    const int top = c->top * crop_scale_factor;
-    const int bottom = c->bottom * crop_scale_factor;
-    const float col[4] = {0.0f, 0.0f, 0.0f, 0.0f};
-
-    /* Left. */
-    IMB_rectfill_area_replace(preprocessed_ibuf, col, 0, 0, left, height);
-    /* Bottom. */
-    IMB_rectfill_area_replace(preprocessed_ibuf, col, left, 0, width, bottom);
-    /* Right. */
-    IMB_rectfill_area_replace(preprocessed_ibuf, col, width - right, bottom, width, height);
-    /* Top. */
-    IMB_rectfill_area_replace(preprocessed_ibuf, col, left, height - top, width - right, height);
-  }
-
-  if (sequencer_use_transform(seq) || context->rectx != ibuf->x || context->recty != ibuf->y) {
+  if (sequencer_use_crop(seq) || sequencer_use_transform(seq) || context->rectx != ibuf->x ||
+      context->recty != ibuf->y) {
     const int x = context->rectx;
     const int y = context->recty;
     preprocessed_ibuf = IMB_allocImBuf(x, y, 32, ibuf->rect_float ? IB_rectfloat : IB_rect);
@@ -655,20 +645,24 @@ static ImBuf *input_preprocess(const SeqRenderData *context,
     ImageTransformThreadInitData init_data = {NULL};
     init_data.ibuf_source = ibuf;
     init_data.ibuf_out = preprocessed_ibuf;
-    init_data.transform = seq->strip->transform;
-    if (seq_need_scale_to_render_size(seq, is_proxy_image)) {
-      init_data.image_scale_factor = 1.0f;
+    init_data.seq = seq;
+    init_data.is_proxy_image = is_proxy_image;
+
+    /* Get scale factor if preview resolution doesn't match project resolution. */
+    if (context->preview_render_size == SEQ_RENDER_SIZE_SCENE) {
+      init_data.preview_scale_factor = (float)scene->r.size / 100;
     }
     else {
-      init_data.image_scale_factor = preview_scale_factor;
+      init_data.preview_scale_factor = SEQ_rendersize_to_scale_factor(
+          context->preview_render_size);
     }
-    init_data.preview_scale_factor = preview_scale_factor;
+
     init_data.for_render = context->for_render;
     IMB_processor_apply_threaded(context->recty,
                                  sizeof(ImageTransformThreadData),
                                  &init_data,
-                                 sequencer_image_transform_init,
-                                 sequencer_image_transform_do_thread);
+                           

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list