diff options
Diffstat (limited to 'integral_test.go')
-rw-r--r-- | integral_test.go | 185 |
1 files changed, 185 insertions, 0 deletions
diff --git a/integral_test.go b/integral_test.go new file mode 100644 index 0000000..513c7c4 --- /dev/null +++ b/integral_test.go @@ -0,0 +1,185 @@ +// Copyright 2020 Nick White. +// Use of this source code is governed by the GPLv3 +// license that can be found in the LICENSE file. + +package integral + +import ( + "image" + "image/draw" + _ "image/png" + "os" + "testing" +) + +func TestFromPNG(t *testing.T) { + f, err := os.Open("testdata/in.png") + if err != nil { + t.Fatalf("Could not open file %s: %v\n", "testdata/in.png", err) + } + defer f.Close() + img, _, err := image.Decode(f) + if err != nil { + t.Fatalf("Could not decode image: %v\n", err) + } + b := img.Bounds() + + integral := NewImage(b) + draw.Draw(integral, b, img, b.Min, draw.Src) + + if !imgsequal(img, integral) { + t.Errorf("Read png image differs to integral image\n") + } +} + +func TestSqFromPNG(t *testing.T) { + f, err := os.Open("testdata/in.png") + if err != nil { + t.Fatalf("Could not open file %s: %v\n", "testdata/in.png", err) + } + defer f.Close() + img, _, err := image.Decode(f) + if err != nil { + t.Fatalf("Could not decode image: %v\n", err) + } + b := img.Bounds() + + integral := NewSqImage(b) + draw.Draw(integral, b, img, b.Min, draw.Src) + + if !imgsequal(img, integral) { + t.Errorf("Read png image differs to square integral image\n") + } +} + +func TestSum(t *testing.T) { + f, err := os.Open("testdata/in.png") + if err != nil { + t.Fatalf("Could not open file %s: %v\n", "testdata/in.png", err) + } + defer f.Close() + img, _, err := image.Decode(f) + if err != nil { + t.Fatalf("Could not decode image: %v\n", err) + } + b := img.Bounds() + + imgplus := newGray16Plus(b) + integral := NewImage(b) + + draw.Draw(imgplus, b, img, b.Min, draw.Src) + draw.Draw(integral, b, img, b.Min, draw.Src) + + cases := []struct { + name string + r image.Rectangle + }{ + {"fullimage", b}, + {"small", image.Rect(1, 1, 5, 5)}, + {"toobig", image.Rect(0, 0, 2000, b.Dy())}, + {"toosmall", image.Rect(-1, -1, 4, 5)}, + {"small2", image.Rect(0, 0, 4, 4)}, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + sumimg := imgplus.sum(c.r) + sumint := integral.Sum(c.r) + if sumimg != sumint { + t.Errorf("Sum of integral image differs to regular image: regular: %d, integral: %d\n", sumimg, sumint) + } + }) + } +} + +func TestMean(t *testing.T) { + f, err := os.Open("testdata/in.png") + if err != nil { + t.Fatalf("Could not open file %s: %v\n", "testdata/in.png", err) + } + defer f.Close() + img, _, err := image.Decode(f) + if err != nil { + t.Fatalf("Could not decode image: %v\n", err) + } + b := img.Bounds() + + imgplus := newGray16Plus(b) + integral := NewImage(b) + + draw.Draw(imgplus, b, img, b.Min, draw.Src) + draw.Draw(integral, b, img, b.Min, draw.Src) + + cases := []struct { + name string + r image.Rectangle + }{ + {"fullimage", b}, + {"small", image.Rect(1, 1, 5, 5)}, + {"toobig", image.Rect(0, 0, 2000, b.Dy())}, + {"toosmall", image.Rect(-1, -1, 4, 5)}, + {"small2", image.Rect(0, 0, 4, 4)}, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + meanimg := imgplus.mean(c.r) + meanint := integral.Mean(c.r) + if meanimg != meanint { + t.Errorf("Mean of integral image differs to regular image: regular: %f, integral: %f\n", meanimg, meanint) + } + }) + } +} + +func imgsequal(img1, img2 image.Image) bool { + b := img1.Bounds() + if !b.Eq(img2.Bounds()) { + return false + } + for y := b.Min.Y; y < b.Max.Y; y++ { + for x := b.Min.X; x < b.Max.X; x++ { + r0, g0, b0, a0 := img1.At(x, y).RGBA() + r1, g1, b1, a1 := img2.At(x, y).RGBA() + if r0 != r1 { + return false + } + if g0 != g1 { + return false + } + if b0 != b1 { + return false + } + if a0 != a1 { + return false + } + } + } + return true +} + +type grayPlus struct { + image.Gray16 +} + +func newGray16Plus(r image.Rectangle) *grayPlus { + var g grayPlus + g.Gray16 = *image.NewGray16(r) + return &g +} + +func (i grayPlus) sum(r image.Rectangle) uint64 { + var sum uint64 + for y := r.Min.Y; y < r.Max.Y; y++ { + for x := r.Min.X; x < r.Max.X; x++ { + c := i.Gray16At(x, y).Y + sum += uint64(c) + } + } + return sum +} + +func (i grayPlus) mean(r image.Rectangle) float64 { + in := r.Intersect(i.Bounds()) + return float64(i.sum(r)) / float64(in.Dx()*in.Dy()) +} |