LoginSignup
1
1

More than 5 years have passed since last update.

JuliaImagesの備忘録その3

Last updated at Posted at 2018-09-23

ImageFiltering.jl

この記事はImageFilteringのページを参考に試した内容です。Factored kernel(詳細は次回)の部分は勉強になりました。

ImageFiltering(Imagesパッケージの一つ)は配列に対する線形および非線形フィルタリングをサポートします。imfilterという関数と、共通カーネル(フィルタ)を提供するKernelモジュールとKernelFactorsモジュールから構成されています。

デモ

using Images, ImageFiltering
using TestImages

img = testimage("cameraman")

imgg = imfilter(img, Kernel.gaussian(3))
imgl = imfilter(img, Kernel.Laplacian())
imgl_ = (imgl .+ 1.0) ./ 2.0
images = hcat(img, imgg, imgl_)

save("demo.png", images)

demo.png

線形フィルタリング

畳み込みではなく、相関

(原文だと「Correlation, not convolution」なのですが、どう訳すのがいいんでしょう。)

ImageFilteringでは、入力画像AをカーネルKでフィルタリングした画像Fは次の式で計算されます。

F[I] = \sum_J A[I+J]K[J]

畳み込みを計算したければ、カーネルに対してreflectを作用させればよいとのこと。

カーネルのインデックス

カーネルのインデックスにはOffsetArrayが使われています。

julia> kernel = Kernel.gaussian(1)
OffsetArray(::Array{Float64,2}, -2:2, -2:2) with eltype Float64 with indices -2:2×-2:2:
 0.00296902  0.0133062  0.0219382  0.0133062  0.00296902
 0.0133062   0.0596343  0.0983203  0.0596343  0.0133062
 0.0219382   0.0983203  0.162103   0.0983203  0.0219382
 0.0133062   0.0596343  0.0983203  0.0596343  0.0133062
 0.00296902  0.0133062  0.0219382  0.0133062  0.00296902

上記の場合、インデックスは各軸に対して-2:2となっており、[0, 0]がカーネルの中心に来るようになっています。このおかげで、フィルタリングによって画像がシフトしなくなります。

自分で作成したカーネルには、centered関数を通せばOffsetArrayになります。

julia> centered([1 0 1; 0 1 0; 1 0 1])
OffsetArrays.OffsetArray{Int64,2,Array{Int64,2}} with indices -1:1×-1:1:
 1  0  1
 0  1  0
 1  0  1

Factored kernels

ガウシアンカーネルなどのよく使われるカーネルはseparableという性質を持ちます。separableなカーネルとは、$K[j_1, j_2, ...]$が$K_1[j_1]K_2[j_2]$と書けるカーネルのことです。このとき、相関の式

F[i_1, i_2] = \sum_{j_1, j_2}A[i_1+j_1, i_2+j_2] K[j_1, j_2]

F[i_1, i_2] = \sum_{j_2} \left( \sum_{j_1}A[i_1+j_1, i_2+j_2] K_1[j_1]
\right) K_2[j_2]

と書けます。例えば、カーネルサイズがmxnの場合、元の式だと各点でmn回の演算が必要なのに対して、変形した式だとm+n回の演算で済みます。

この性質を利用してseparableなカーネルで効率的にフィルタリングするための補助関数として、Kernelfactor.kernelfactorsが用意されています。

julia> kern1 = centered([1/3, 1/3, 1/3])
OffsetArrays.OffsetArray{Float64,1,Array{Float64,1}} with indices -1:1:
 0.333333
 0.333333
 0.333333

julia> kernf = kernelfactors((kern1, kern1))
(ImageFiltering.KernelFactors.ReshapedOneD{Float64,2,0,OffsetArrays.OffsetArray{Float64,1,Array{Float64,1}}}([0.333333,0.333333,0.333333]),ImageFiltering.KernelFactors.ReshapedOneD{Float64,2,1,OffsetArrays.OffsetArray{Float64,1,Array{Float64,1}}}([0.333333,0.333333,0.333333]))

ここから2次元カーネルに変形するにはbroadcast(*, kernf...)を用います。

julia> kernp = broadcast(*, kernf...)
OffsetArrays.OffsetArray{Float64,2,Array{Float64,2}} with indices -1:1×-1:1:
 0.111111  0.111111  0.111111
 0.111111  0.111111  0.111111
 0.111111  0.111111  0.111111

julia> imfilter(img, kernf)  imfilter(img, kernp)
true

今回はここまで。
次回は、Factored kernelsで簡単な比較実験をしてみます。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1