関数の相関・畳み込み・フーリエ変換・画像処理・処理フィルタ

  • こちらで時系列データの相関についてコメントしている
  • 関数の似ている程度の評価方法
    • \int_{-\infty}^{\infty} f(\tau)g(\tau) d\tauである
      • ベクトルの内積の無限長版である
  • 拡張すると相互相関関数(Cross correlation(Wiki))というものがある
    • (f\star g)(t)=\int_{-\infty}^{\infty} f(\tau)g(\tau+t) d\tau
    • タイムラグtが入って、tの関数になった
    • これが相互相関関数
  • 相互相関関数は畳み込み(Convolution)と呼ばれる計算である(\tauの正負に注意)
    • 自己相関(Wiki)
      • g(\tau)の代わりにf(\tau)とすると、(f\star f)(t)=\int_{-\infty}^{\infty} f(\tau)f(\tau+t) d\tauとなる
      • f(\tau)が周期的であると、あるタイムラグtを持って相互相関関数の値は大きくなる
      • Rで自己相関
  • 処理フィルタのこと
    • \int f(t)g(t)dttの定義域全体に渡る処理であるが、この世の中の出来事は、(tを位置とすると)、同じ場所でのf(t),g(t)の間には関係があり、そのごく近傍(g(t+\delta t)も少し関係があり、それより遠いと関係がない、というようなものが多い
    • 画像処理で、ぼやかしたり、くっきりさせたりさせる(こちらでやっているような処理)という処理はまさにこれ(関連記事)
    • このようにオリジナルの値を少し改変するような処理において、「フィルターをかける」と呼ぶとき、g(t)関数は「フィルター」そのものなので、フィルタリングと言うこともある
  • 畳み込み・相互相関関数とフーリエ変換の関係
  • 数列のフーリエ変換は「離散フーリエ変換」(こちら)
  • さて、Rを使ってみることにする
    • 1次元データにフィルタをかけてみる
      • フィルタはc(1,2,1)/4 である(フィルタの要素の和は1になっている)
      • これは、自身そのものとその前後とに2:1の重みづけをするフィルタで、結果として、「平滑化」している
        • 平滑化は補間とかとも関係がある(補間についてはこちら)
n <- length(x <- -20:24)
y <- (x-10)^2/1000 + rnorm(x)/8
# c(1,2,1)/4でフィルタをかけている
Han <- function(y) # Hanning
       convolve(y, c(1,2,1)/4, type = "filter")

plot(x,y, main="Using  convolve(.) for Hanning filters")
# x[-c(1,n)]はベクトルxの末端要素を除く処理
lines(x[-c(1  , n)      ], Han(y), col="red")
lines(x[-c(1:2, (n-1):n)], Han(Han(y)), lwd=2, col="dark blue")
> convolve
function (x, y, conj = TRUE, type = c("circular", "open", "filter")) 
{
    type <- match.arg(type)
    n <- length(x)
    ny <- length(y)
    Real <- is.numeric(x) && is.numeric(y)
    if (type == "circular") {
        if (ny != n) 
            stop("length mismatch in convolution")
    }
    else {
        n1 <- ny - 1
        x <- c(rep.int(0, n1), x)
        n <- length(y <- c(y, rep.int(0, n - 1)))
    }
    x <- fft(fft(x) * (if (conj) 
        Conj(fft(y))
    else fft(y)), inverse = TRUE)
    if (type == "filter") 
        (if (Real) 
            Re(x)
        else x)[-c(1L:n1, (n - n1 + 1L):n)]/n
    else (if (Real) 
        Re(x)
    else x)/n
}
    • この関数ソースは自分にとって読みにくいので、書き方を変えてみる
my.convolve <- function(x,y,conj=TRUE,type=c("circular", "open", "filter")){
	type <- match.arg(type)
	n <- length(x)
	ny <- length(y)
	Real <- is.numeric(x) && is.numeric(y)
	if(type == "circular"){
		if(ny !=n){
			stop("length mismatch in convolution")
		}
	}else{
		n1 <- ny-1
		x <- c(rep.int(0,n1),x)
		n <- length(y <- c(y, rep.int(0,n-1)))
	}
	if(conj){
		tmp <- Conj(fft(y))
	}else{
		tmp <- fft(y)
	}
	tmp2 <- fft(x) * tmp
	x <- fft(tmp2,inverse = TRUE)
	ret <- NULL
	if(type == "filter"){
		if(Real){
			ret <- Re(x)[-c(1L:n1, (n - n1 + 1L):n)]/n
		}else{
			ret <- x[-c(1L:n1, (n - n1 + 1L):n)]/n
		}
	}else{
		if(Real){
			ret <- Re(x)/n
		}else{
			ret <- x/n
		}
	}
	ret
}
  • 多項式の畳み込み
    • 多項式の掛け算の結果の係数列は、元の多項式の係数列の線形畳み込みになる(Wiki)
    • conv()関数で、畳み込んだ多項式がconv.polyに入った
library(pracma)
# c(1,1,1) は x^2 + x + 1 を表し、c(-0.5,1,-1)は-0.5 x^2 + x -1を表す
poly1<-c(1,1,1)
poly2<-c(-0.5,1,-1)
conv.poly<-conv(poly1,poly2)
conv.poly
conv.v<-polyval(conv.poly,3)
conv.v