使用vips组合多个图像(ruby-vips8)

时间:2016-05-01 22:18:22

标签: ruby image-processing vips

如何将函数应用于相同分辨率的两个图像的相应像素?像Photoshop一样用另一层覆盖一层。两张以上的图片怎么样?

如果是Wolfram Mathematica我将获取这些图像的列表并转置它们以获得单个“图像”,其中每个“像素”将是N个像素的数组 - 在那里我将应用Mean[]对他们有用。

但我怎么用vips做到这一点?有很多Vips::Image方法,只有here我可以找到一些关于它们的含义的最小描述。例如:

images = Dir["shots/*"].map{ |i| Vips::Image.new_from_file(i) }
ims = images.map(&:bandmean)
(ims.inject(:+) / ims.size).write_to_file "temp.png"

我希望它的意思是“计算平均图像”,但我不确定我在这里做了什么。

1 个答案:

答案 0 :(得分:2)

ruby​​-vips8附带complete set of operator overloads,因此您可以对图像进行算术运算。它还可以自动进行常见的子表达式消除,因此您无需过于谨慎地进行排序或分组,您只需编写一个等式就可以正常工作。

在你的例子中:

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利用率高。