kernel.go 1.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
package convolution

import (
	"fmt"
	"math"
)

// Matrix interface.
// At returns the matrix value at position x, y.
// Normalized returns a new matrix with normalized values.
// MaxX returns the horizontal length.
// MaxY returns the vertical length.
type Matrix interface {
	At(x, y int) float64
	Normalized() Matrix
	MaxX() int
	MaxY() int
}

// NewKernel returns a kernel of the provided length.
func NewKernel(width, height int) *Kernel {
	return &Kernel{make([]float64, width*height), width, height}
}

// Kernel to be used as a convolution matrix.
type Kernel struct {
	Matrix []float64
	Width  int
	Height int
}

// Normalized returns a new Kernel with normalized values.
func (k *Kernel) Normalized() Matrix {
	sum := k.Absum()
	w := k.Width
	h := k.Height
	nk := NewKernel(w, h)

	// avoid division by 0
	if sum == 0 {
		sum = 1
	}

	for i := 0; i < w*h; i++ {
		nk.Matrix[i] = k.Matrix[i] / sum
	}

	return nk
}

// MaxX returns the horizontal length.
func (k *Kernel) MaxX() int {
	return k.Width
}

// MaxY returns the vertical length.
func (k *Kernel) MaxY() int {
	return k.Height
}

// At returns the matrix value at position x, y.
func (k *Kernel) At(x, y int) float64 {
	return k.Matrix[y*k.Width+x]
}

// String returns the string representation of the matrix.
func (k *Kernel) String() string {
	result := ""
	stride := k.MaxX()
	height := k.MaxY()
	for y := 0; y < height; y++ {
		result += fmt.Sprintf("\n")
		for x := 0; x < stride; x++ {
			result += fmt.Sprintf("%-8.4f", k.At(x, y))
		}
	}
	return result
}

// Absum returns the absolute cumulative value of the kernel.
func (k *Kernel) Absum() float64 {
	var sum float64
	for _, v := range k.Matrix {
		sum += math.Abs(v)
	}
	return sum
}