added gonum stat library, moved plotResults to test file

This commit is contained in:
Russell Stanley 2022-01-10 15:11:21 +10:30
parent 33b90145f7
commit 556efa7f00
5 changed files with 38 additions and 62 deletions

1
go.mod
View File

@ -14,6 +14,7 @@ require (
github.com/pkg/errors v0.9.1 github.com/pkg/errors v0.9.1
github.com/yobert/alsa v0.0.0-20180630182551-d38d89fa843e github.com/yobert/alsa v0.0.0-20180630182551-d38d89fa843e
gocv.io/x/gocv v0.29.0 gocv.io/x/gocv v0.29.0
gonum.org/v1/gonum v0.9.3
gonum.org/v1/plot v0.10.0 gonum.org/v1/plot v0.10.0
gopkg.in/natefinch/lumberjack.v2 v2.0.0 gopkg.in/natefinch/lumberjack.v2 v2.0.0
) )

3
go.sum
View File

@ -58,10 +58,8 @@ github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+
github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
github.com/kidoman/embd v0.0.0-20170508013040-d3d8c0c5c68d h1:dPUSr0RGzXAdsUTMtiyQ/2RBLIIwkv6jGnhxrufitvQ= github.com/kidoman/embd v0.0.0-20170508013040-d3d8c0c5c68d h1:dPUSr0RGzXAdsUTMtiyQ/2RBLIIwkv6jGnhxrufitvQ=
github.com/kidoman/embd v0.0.0-20170508013040-d3d8c0c5c68d/go.mod h1:ACKj9jnzOzj1lw2ETilpFGK7L9dtJhAzT7T1OhAGtRQ= github.com/kidoman/embd v0.0.0-20170508013040-d3d8c0c5c68d/go.mod h1:ACKj9jnzOzj1lw2ETilpFGK7L9dtJhAzT7T1OhAGtRQ=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/mattetti/audio v0.0.0-20180912171649-01576cde1f21 h1:Hc1iKlyxNHp3CV59G2E/qabUkHvEwOIJxDK0CJ7CRjA= github.com/mattetti/audio v0.0.0-20180912171649-01576cde1f21 h1:Hc1iKlyxNHp3CV59G2E/qabUkHvEwOIJxDK0CJ7CRjA=
github.com/mattetti/audio v0.0.0-20180912171649-01576cde1f21/go.mod h1:LlQmBGkOuV/SKzEDXBPKauvN2UqCgzXO2XjecTGj40s= github.com/mattetti/audio v0.0.0-20180912171649-01576cde1f21/go.mod h1:LlQmBGkOuV/SKzEDXBPKauvN2UqCgzXO2XjecTGj40s=
@ -149,7 +147,6 @@ gonum.org/v1/plot v0.9.0/go.mod h1:3Pcqqmp6RHvJI72kgb8fThyUnav364FOsdDo2aGW5lY=
gonum.org/v1/plot v0.10.0 h1:ymLukg4XJlQnYUJCp+coQq5M7BsUJFk6XQE4HPflwdw= gonum.org/v1/plot v0.10.0 h1:ymLukg4XJlQnYUJCp+coQq5M7BsUJFk6XQE4HPflwdw=
gonum.org/v1/plot v0.10.0/go.mod h1:JWIHJ7U20drSQb/aDpTetJzfC1KlAPldJLpkSy88dvQ= gonum.org/v1/plot v0.10.0/go.mod h1:JWIHJ7U20drSQb/aDpTetJzfC1KlAPldJLpkSy88dvQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=

View File

@ -30,74 +30,35 @@ import (
"gonum.org/v1/plot" "gonum.org/v1/plot"
"gonum.org/v1/plot/plotter" "gonum.org/v1/plot/plotter"
"gonum.org/v1/plot/plotutil"
"gonum.org/v1/plot/vg" "gonum.org/v1/plot/vg"
) )
// standarDeviation will return the standard deviation of a float slice // normalise normalises the values in the given slice to the range [0,1] inclusive.
func standarDeviation(slice []float64) float64 { func normalize(s []float64) []float64 {
mean := average(slice)
variance := 0.0
for _, i := range slice {
variance += math.Pow(i-mean, 2.0)
}
return math.Sqrt(variance / float64(len(slice)))
}
// Normalize values in a slice between 0 and 1.
func normalize(slice []float64) []float64 {
max := -math.MaxFloat64 max := -math.MaxFloat64
min := math.MaxFloat64 min := math.MaxFloat64
out := make([]float64, len(slice)) out := make([]float64, len(s))
if len(slice) <= 1 { if len(s) <= 1 {
return slice return s
} }
// Find the max and min values of the slice. // Find the max and min values of the s.
for i := range slice { for i := range s {
if slice[i] > max { if s[i] > max {
max = slice[i] max = s[i]
} }
if slice[i] < min { if s[i] < min {
min = slice[i] min = s[i]
} }
} }
for i := range slice { for i := range s {
out[i] = (slice[i] - min) / (max - min) out[i] = (s[i] - min) / (max - min)
} }
return out return out
} }
// Return the average of a slice.
func average(slice []float64) float64 {
var out float64
for i := range slice {
out += slice[i]
}
return out / float64(len(slice))
}
func plotResults(x, sharpness, contrast []float64) error {
err := plotToFile(
"Results",
"Almond Milk (ml)",
"Score",
func(p *plot.Plot) error {
return plotutil.AddLinePoints(p,
"Contrast", plotterXY(x, contrast),
"Sharpness", plotterXY(x, sharpness),
)
},
)
if err != nil {
return fmt.Errorf("Could not plot results: %w", err)
}
return nil
}
// plotToFile creates a plot with a specified name and x&y titles using the // plotToFile creates a plot with a specified name and x&y titles using the
// provided draw function, and then saves to a PNG file with filename of name. // provided draw function, and then saves to a PNG file with filename of name.
func plotToFile(name, xTitle, yTitle string, draw func(*plot.Plot) error) error { func plotToFile(name, xTitle, yTitle string, draw func(*plot.Plot) error) error {

View File

@ -36,7 +36,7 @@ type Results struct {
Contrast []float64 Contrast []float64
} }
// NewResults returns a new Results // NewResults returns a new Results.
func NewResults(n int) (*Results, error) { func NewResults(n int) (*Results, error) {
if n <= 0 { if n <= 0 {
return nil, fmt.Errorf("invalid result size: %v", n) return nil, fmt.Errorf("invalid result size: %v", n)

View File

@ -30,12 +30,15 @@ import (
"testing" "testing"
"gocv.io/x/gocv" "gocv.io/x/gocv"
"gonum.org/v1/gonum/stat"
"gonum.org/v1/plot"
"gonum.org/v1/plot/plotutil"
) )
const ( const (
nImages = 13 // Number of images to test. (Max 13) nImages = 13 // Number of images to test. (Max 13)
nSamples = 10 // Number of samples for each image. (Max 10) nSamples = 10 // Number of samples for each image. (Max 10)
increment = 2.5 // Increment of the turbidity level increment = 2.5 // Increment of the turbidity level.
) )
func TestImages(t *testing.T) { func TestImages(t *testing.T) {
@ -45,7 +48,6 @@ func TestImages(t *testing.T) {
scale, alpha = 1.0, 1.0 scale, alpha = 1.0, 1.0
) )
// Load template and standard image.
template := gocv.IMRead("images/template.jpg", gocv.IMReadGrayScale) template := gocv.IMRead("images/template.jpg", gocv.IMReadGrayScale)
standard := gocv.IMRead("images/default.jpg", gocv.IMReadGrayScale) standard := gocv.IMRead("images/default.jpg", gocv.IMReadGrayScale)
@ -59,13 +61,11 @@ func TestImages(t *testing.T) {
} }
} }
// Create turbidity sensor.
ts, err := NewTurbiditySensor(template, standard, k1, k2, filterSize, scale, alpha) ts, err := NewTurbiditySensor(template, standard, k1, k2, filterSize, scale, alpha)
if err != nil { if err != nil {
t.Fatal("could not create turbidity sensor: %w", err) t.Fatal("could not create turbidity sensor: %w", err)
} }
// Create results.
results, err := NewResults(nImages) results, err := NewResults(nImages)
if err != nil { if err != nil {
t.Fatal("could not create results: %w", err) t.Fatal("could not create results: %w", err)
@ -80,10 +80,9 @@ func TestImages(t *testing.T) {
} }
// Add the average result from camera burst. // Add the average result from camera burst.
results.Update(average(sample_result.Sharpness), average(sample_result.Contrast), float64(i)*increment, i) results.Update(stat.Mean(sample_result.Sharpness, nil), stat.Mean(sample_result.Contrast, nil), float64(i)*increment, i)
} }
// Plot the final results.
err = plotResults(results.Turbidity, normalize(results.Sharpness), normalize(results.Contrast)) err = plotResults(results.Turbidity, normalize(results.Sharpness), normalize(results.Contrast))
if err != nil { if err != nil {
t.Fatalf("plotting Failed: %v", err) t.Fatalf("plotting Failed: %v", err)
@ -92,3 +91,21 @@ func TestImages(t *testing.T) {
t.Logf("Sharpness: %v", results.Sharpness) t.Logf("Sharpness: %v", results.Sharpness)
t.Logf("Contrast: %v", results.Contrast) t.Logf("Contrast: %v", results.Contrast)
} }
func plotResults(x, sharpness, contrast []float64) error {
err := plotToFile(
"Results",
"Almond Milk (ml)",
"Score",
func(p *plot.Plot) error {
return plotutil.AddLinePoints(p,
"Contrast", plotterXY(x, contrast),
"Sharpness", plotterXY(x, sharpness),
)
},
)
if err != nil {
return fmt.Errorf("Could not plot results: %w", err)
}
return nil
}