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()
对数组求和,然后使用vips_linear()
进行除法运算,最后使用vips_cast()
将其转换回uchar。
当调用write_to_file
时,您的计算机上的每个核心都将获得管道的副本,并排队处理来自解压器的源图像瓦片。每次完成一行输出瓦片时,后台线程将使用所选的图像写入库(在我的示例中为libtiff)将这些扫描线发送回磁盘。
您应该看到低内存使用和良好的CPU利用率。
my_custom_function(pixel1, pixel2, ..., pixelN)
。 - Nakilon