av/turbidity/turbidity_test.go

168 lines
4.7 KiB
Go

//go:build !nocv
// +build !nocv
/*
DESCRIPTION
Testing functions for the turbidity sensor using images from
previous experiment.
AUTHORS
Russell Stanley <russell@ausocean.org>
LICENSE
Copyright (C) 2021-2022 the Australian Ocean Lab (AusOcean)
It is free software: you can redistribute it and/or modify them
under the terms of the GNU General Public License as published by the
Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
It is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
in gpl.txt. If not, see http://www.gnu.org/licenses.
*/
package turbidity
import (
"fmt"
"io"
"testing"
"bitbucket.org/ausocean/utils/logger"
"gocv.io/x/gocv"
"gonum.org/v1/gonum/stat"
"gonum.org/v1/plot"
"gonum.org/v1/plot/plotutil"
"gopkg.in/natefinch/lumberjack.v2"
)
const (
nImages = 27 // Number of images to test. (Max 13)
nSamples = 9 // Number of samples for each image. (Max 10)
increment = 1 // Increment of the turbidity level.
)
// Logging configuration.
const (
logPath = "/var/log/netsender/netsender.log"
logMaxSize = 500 // MB
logMaxBackup = 10
logMaxAge = 28 // days
logVerbosity = logger.Info
logSuppress = true
)
// TestImages will read a library of test images and calculate the sharpness and contrast scores.
// A plot of the results will be generated and stored in the plots directory.
func TestImages(t *testing.T) {
const (
k1, k2 = 4, 4
filterSize = 3
scale, alpha = 1.0, 1.0
)
// Create lumberjack logger.
fileLog := &lumberjack.Logger{
Filename: logPath,
MaxSize: logMaxSize,
MaxBackups: logMaxBackup,
MaxAge: logMaxAge,
}
log := *logger.New(logVerbosity, io.MultiWriter(fileLog), logSuppress)
imgs := make([][]gocv.Mat, nImages)
// Load test images.
for i := range imgs {
imgs[i] = make([]gocv.Mat, nSamples)
for j := range imgs[i] {
imgs[i][j] = gocv.IMRead(fmt.Sprintf("images/test/t-%v/000%v.jpg", i, j), gocv.IMReadColor)
}
}
boardSizes := []int{1, 2, 3, 4}
allResults := make([]Results, len(boardSizes))
for n, boardSize := range boardSizes {
template := gocv.IMRead("images/template.jpg", gocv.IMReadGrayScale)
transformMatrix, err := FindTransform(fmt.Sprintf("images/default_%v.jpg", boardSize), "images/template.jpg", 3)
if err != nil {
t.Fatalf("could not find transformation: %v", err)
}
t.Log(formatMat(transformMatrix))
ts, err := NewTurbiditySensor(template, transformMatrix, k1, k2, filterSize, scale, alpha, log)
if err != nil {
t.Fatalf("could not create turbidity sensor: %v", err)
}
results, err := NewResults(nImages)
if err != nil {
t.Fatalf("could not create results: %v", err)
}
// Score each image by calculating the average score from camera burst.
for i := range imgs {
// Evaluate camera burst.
sample_result, err := ts.Evaluate(imgs[i])
if err != nil {
t.Fatalf("evaluation Failed: %v", err)
}
// Add the average result from camera burst.
results.Update(stat.Mean(sample_result.Sharpness, nil), stat.Mean(sample_result.Contrast, nil), float64(i)*increment, i)
}
allResults[n] = *results
}
err := plotResults(allResults[0].Turbidity, normalize(allResults[0].Contrast), normalize(allResults[1].Contrast), normalize(allResults[2].Contrast), normalize(allResults[3].Contrast), "Contrast")
if err != nil {
t.Fatalf("plotting Failed: %v", err)
}
err = plotResults(allResults[0].Turbidity, normalize(allResults[0].Sharpness), normalize(allResults[1].Sharpness), normalize(allResults[2].Sharpness), normalize(allResults[3].Sharpness), "Sharpness")
if err != nil {
t.Fatalf("plotting Failed: %v", err)
}
}
// plotResults plots sharpness and contrast scores against the level of almond milk in the container
func plotResults(x, l1, l2, l3, l4 []float64, name string) error {
err := plotToFile(
name,
"Almond Milk (ml)",
"Score",
func(p *plot.Plot) error {
return plotutil.AddLinePoints(p,
"50cm", plotterXY(x, l1),
"40cm", plotterXY(x, l2),
"30cm", plotterXY(x, l3),
"20cm", plotterXY(x, l4),
)
},
)
if err != nil {
return fmt.Errorf("Could not plot results: %w", err)
}
return nil
}
// formatMat creates a formatted transformation matrix string for use in vidgrind.
func formatMat(transformMatrix gocv.Mat) string {
var out string
for i := 0; i < transformMatrix.Rows(); i++ {
for j := 0; j < transformMatrix.Cols(); j++ {
out += fmt.Sprintf(" %.10f", transformMatrix.GetDoubleAt(i, j))
if i < 2 || j < 2 {
out += ","
}
}
}
return out
}