3

How do I apply a function to corresponding pixels of two images of the same resolution? Like Photoshop does when covering one layer with another one. What about more than two images?

If it was Wolfram Mathematica I would take a List of those images and transpose them to get a single "image" where each "pixel" would be an array of N pixels -- there I would apply a Mean[] function to them.

But how do I do that with vips? There are so many Vips::Image methods and only here I could find some minimal description on what do they all mean. So for example:

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

I wanted it to mean "calculating an average image" but I'm not sure what I've done here.

4

1 に答える 1

2

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 使用率が良好であることがわかります。

于 2016-05-03T09:12:20.967 に答える