예제 #1
0
파일: bank.go 프로젝트: jvlmdr/go-cv
// CorrBankFFT computes the correlation of an image with a bank of filters.
// 	h_p[u, v] = (f corr g_p)[u, v]
func CorrBankFFT(f *rimg64.Image, g *Bank) (*rimg64.Multi, error) {
	out := ValidSize(f.Size(), g.Size())
	if out.X <= 0 || out.Y <= 0 {
		return nil, nil
	}
	// Determine optimal size for FFT.
	work, _ := FFT2Size(f.Size())
	// Re-use FFT of image.
	fhat := fftw.NewArray2(work.X, work.Y)
	copyImageTo(fhat, f)
	fftw.FFT2To(fhat, fhat)
	// Transform of each filter.
	curr := fftw.NewArray2(work.X, work.Y)
	fwd := fftw.NewPlan2(curr, curr, fftw.Forward, fftw.Estimate)
	defer fwd.Destroy()
	bwd := fftw.NewPlan2(curr, curr, fftw.Backward, fftw.Estimate)
	defer bwd.Destroy()

	h := rimg64.NewMulti(out.X, out.Y, len(g.Filters))
	alpha := complex(1/float64(work.X*work.Y), 0)
	// For each output channel.
	for p, gp := range g.Filters {
		// Take FFT.
		copyImageTo(curr, gp)
		fwd.Execute()
		// h_p[x] = (G_p corr F)[x]
		// H_p[x] = conj(G_p[x]) F[x]
		scaleMul(curr, alpha, curr, fhat)
		bwd.Execute()
		copyRealToChannel(h, p, curr)
	}
	return h, nil
}
예제 #2
0
파일: corr.go 프로젝트: jvlmdr/go-cv
// CorrFFT computes the correlation of an image with a filter.
// 	h[u, v] = (f corr g)[u, v]
func CorrFFT(f, g *rimg64.Image) (*rimg64.Image, error) {
	out := ValidSize(f.Size(), g.Size())
	if out.X <= 0 || out.Y <= 0 {
		return nil, nil
	}
	// Determine optimal size for FFT.
	work, _ := FFT2Size(f.Size())
	fhat := fftw.NewArray2(work.X, work.Y)
	ghat := fftw.NewArray2(work.X, work.Y)
	// Take forward transforms.
	copyImageTo(fhat, f)
	fftw.FFT2To(fhat, fhat)
	copyImageTo(ghat, g)
	fftw.FFT2To(ghat, ghat)
	// Scale such that convolution theorem holds.
	n := float64(work.X * work.Y)
	scaleMul(fhat, complex(1/n, 0), ghat, fhat)
	// Take inverse transform.
	h := rimg64.New(out.X, out.Y)
	fftw.IFFT2To(fhat, fhat)
	copyRealTo(h, fhat)
	return h, nil
}
예제 #3
0
파일: multi_bank.go 프로젝트: jvlmdr/go-cv
// CorrMultiBankFFT computes the correlation of
// a multi-channel image with a bank of multi-channel filters.
// 	h_p[u, v] = sum_q (f_q corr g_pq)[u, v]
func CorrMultiBankFFT(f *rimg64.Multi, g *MultiBank) (*rimg64.Multi, error) {
	out := ValidSize(f.Size(), g.Size())
	if out.X <= 0 || out.Y <= 0 {
		return nil, nil
	}
	// Determine optimal size for FFT.
	work, _ := FFT2Size(f.Size())
	// Cache FFT of each channel of image.
	fhat := make([]*fftw.Array2, f.Channels)
	for i := range fhat {
		fhat[i] = fftw.NewArray2(work.X, work.Y)
		copyChannelTo(fhat[i], f, i)
		fftw.FFT2To(fhat[i], fhat[i])
	}

	curr := fftw.NewArray2(work.X, work.Y)
	fwd := fftw.NewPlan2(curr, curr, fftw.Forward, fftw.Estimate)
	defer fwd.Destroy()
	sum := fftw.NewArray2(work.X, work.Y)
	bwd := fftw.NewPlan2(sum, sum, fftw.Backward, fftw.Estimate)
	defer bwd.Destroy()

	h := rimg64.NewMulti(out.X, out.Y, len(g.Filters))
	alpha := complex(1/float64(work.X*work.Y), 0)
	// For each output channel.
	for p, gp := range g.Filters {
		zero(sum)
		// For each input channel.
		for q := 0; q < f.Channels; q++ {
			// Take FFT of this input channel.
			copyChannelTo(curr, gp, q)
			fwd.Execute()
			// h_p[x] = (G_qp corr F_p)[x]
			// H_p[x] = conj(G_qp[x]) F_p[x]
			addScaleMul(sum, alpha, curr, fhat[q])
		}
		bwd.Execute()
		copyRealToChannel(h, p, sum)
	}
	return h, nil
}