ruby-vips8 带有一套完整的运算符重载,因此您可以对图像进行算术运算。它还可以自动消除公共子表达式,因此您无需对排序或分组过于小心,您只需编写一个方程,它应该可以正常工作。
在您的示例中:
require 'vips8'
images = Dir["shots/*"].map{ |i| Vips::Image.new_from_file(i) }
sum = images.reduce (:+)
avg = sum / images.length
avg.write_to_file "out.tif"
带有常量的 +-*/ 始终会生成浮动图像,因此您可能希望在保存之前将结果转换为 uchar(或者可能是 ushort?),否则您将获得巨大的输出 tiff。你可以写:
avg = sum / images.length
avg.cast("uchar").write_to_file "out.tif"
默认情况下,new_from_file
打开图像以进行随机访问。如果您的源图像是 JPG 或 PNG,这将涉及在开始处理之前将它们完全解压缩到内存(如果它们非常大,则解压缩到磁盘温度)。
在这种情况下,您只需要在编写结果时从上到下扫描输入图像,这样您就可以通过系统流式传输图像。更改new_from_file
为:
images = Dir["shots/*"].map { |i| Vips::Image.new_from_file(i, :access => "sequential") }
暗示您将仅按顺序使用图像像素,并且您应该会看到内存和 CPU 使用率大幅下降。
PNG 是一种非常慢的格式,如果可能的话,我会使用 tiff。
您可以尝试使用bandrank
这对一组图像进行中值过滤器之类的操作:您给它一个图像数组,并在每个像素位置按像素值对图像进行排序并选择第 N 个图像。这是去除暂时性伪影的一种非常有效的方法。
您可以用来计算更复杂的函数。例如,要将大于其局部平均值的所有像素设置为等于局部平均值,您可以编写:condition
.ifthenelse
(then, else)
(image > image.gaussblur(1)).ifthenelse(image.gaussblur(1), image)
你可能很好奇 vips 将如何执行上面的程序。编码:
(images.reduce(:+) / images.length).cast("uchar")
将构造一个图像处理操作的管道:一系列对vips_add()
数组求和,然后 avips_linear()
进行除法,最后 avips_cast()
将其敲回 uchar。
当您调用 时write_to_file
,您机器上的每个核心都将获得管道的副本,并且当它们从解压缩器到达时,它们将排队处理来自源图像的切片。每次完成一行输出图块时,后台线程将使用选定的图像写入库(在我的示例中为 libtiff)将这些扫描线发送回磁盘。
您应该看到低内存使用和良好的 CPU 利用率。