【问题标题】:Fast image scale down?快速缩小图像?
【发布时间】:2023-03-25 01:10:02
【问题描述】:

我正在为视频文件编写“电视滤镜”(你知道那种,RGB 条放大),我一直在研究一些缩小图像的方法,以保留尽可能多的细节尽可能。

为了进行测试,我将采样图像绘制回屏幕以查看质量 - 在实际过滤器中,我将仅采样像素并获取所得计算颜色的 RGB 值。

我试过三个,Hermite滤镜看起来不错,但与速度“硬件”最近邻版本相比,它不适合处理视频。

JavaScript 中是否有任何“技巧”可用于加速图像缩小,如 2,但质量如 1 或 3?

1:蛮力:http://codepen.io/SarahC/pen/VpvWvb?editors=1010

2:内部最近邻:http://codepen.io/SarahC/pen/ryeQgN?editors=1010

3:Hermite 过滤器:http://codepen.io/SarahC/pen/ryMNWZ?editors=1010

这里是“硬件”?版本:

function processResize(percent) {
  var size = percent * 0.01;
  var sw = canvas.width * size;
  var sh = canvas.height * size;
  ctx.drawImage(canvas2, 0, 0, sw, sh);
  ctx.drawImage(canvas, 0, 0, sw, sh, 0, 0, w, h);
}

【问题讨论】:

  • 在你的蛮力上,似乎有一个无限循环+你在一个循环中调用 getImageData ,而这个操作真的很慢并且消耗内存(因为浏览器必须对画布进行反乘' 像素)。为了避免它,调用它一次,然后从你得到的 arrayBuffer 生成你的图块逻辑。第二种方法应该是最快的,并且至少对于视频来说足够快,并且在我的组合中似乎还可以。没有花时间阅读第三种方法,我不确定实际问题是什么。
  • PS:为了加速动画内容(如视频)的图像处理,您可以首先检查您是否没有在同一帧处理两次无用的处理(使用您的视频元素的currentTime 属性),并使用硬件收缩方法,对较小版本的图像数据进行处理。

标签: javascript performance canvas graphics


【解决方案1】:

从描述中我不完全确定您尝试实现什么,但从代码笔看来,当您尝试创建马赛克效果时。

您可以使用画布上下文的内置插值设置,通过关闭图像平滑来使用最近邻,然后将图像绘制为表示您想要多少“块”的小尺寸。然后再次将该版本拉回全尺寸:

// blocks = initial number of pixels (video aspect is usually 16:9 so you may want
// to calculate a separate values for height.
var blocks = 24;

// draw initial size representing "blocks"
ctx.drawImage(video, 0, 0, blocks, blocks);

// turn off image smoothing (see below for prefixing)
// This uses nearest neighbor
ctx.imageSmoothingEnabled = false;

// enlarge the mosaic back to full size
ctx.drawImage(c, 0, 0, blocks, blocks, 0, 0, c.width, c.height);

视频示例

(视频可能需要几秒钟才能加载...)

var ctx = null;
var blocks = 24;
var video = document.createElement("video");
video.preload = "auto"; video.muted = video.autoplay = video.loop = true;
video.oncanplay = function() {  // initialize for demo
  if (!ctx) {
    c.width = this.videoWidth;
    c.height = this.videoHeight;
    ctx = c.getContext("2d");

    document.querySelector("input").oninput = function() {blocks = +this.value};
    requestAnimationFrame(loop);
  }
}
video.src = "//media.w3.org/2010/05/sintel/trailer.mp4";

function smoothing(state) {
  ctx.oImageSmoothingEnabled = ctx.msImageSmoothingEnabled =
  ctx.mozImageSmoothingEnabled = ctx.webkitImageSmoothingEnabled =
  ctx.imageSmoothingEnabled = state;
}

function loop() {
  smoothing(true);  // improve quality of first step
  ctx.drawImage(video, 0, 0, blocks, blocks);

  smoothing(false); // mosaic step
  ctx.drawImage(c, 0, 0, blocks, blocks, 0, 0, c.width, c.height);
  
  // loop and throttle to 30 fps
  requestAnimationFrame(function() {requestAnimationFrame(loop)});
}
<label>Blocks: <input type=range min=8 max=128 value=24></label><br>
<canvas id=c></canvas>

【讨论】:

  • 谢谢你的例子!我的问题是图像的下采样丢弃了像素而不是平均它们 - 所以像线条这样的细节大部分会消失,剩下的会出现混叠(我的代码中的示例 2 显示,当你增加块大小时,一条白色的对角线会混叠) . DIY 缩小效果要好得多——随着块大小的增加,白线仍然可见,但速度太慢了。根据您在此处演示的内容,无法实时进行更好的下采样。
  • @SarahC 啊,在这种情况下,您可以通过在第一次缩小时打开平滑并在最终马赛克时关闭来稍微提高质量(我会更新答案)。
  • @SarahC 未来可能会有一个用于平滑的质量 type 选项(目前在规范中定义为 imageSmoothingQuality),但目前仅在 Chrome/歌剧。这允许您将质量设置为“高”(Lanczos 或类似的东西),并将保留更多细节。目前我们只有双线性,所以如果您需要比这更高的质量,您需要逐步缩小(参见here 示例)。浏览器通常足够快,可以实时处理这些额外的步骤。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-08-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多