improved corner detection in transform function, fixed some comments

This commit is contained in:
Russell Stanley 2022-01-06 14:41:35 +10:30
parent 2ec62db850
commit 77c803e4bd
3 changed files with 29 additions and 25 deletions

View File

@ -29,14 +29,14 @@ package main
import "fmt" import "fmt"
// Struct to hold the results of the turbidity sensor. // Results holds the results of the turbidity sensor.
type Results struct { type Results struct {
Turbidity []float64 Turbidity []float64
Saturation []float64 Saturation []float64
Contrast []float64 Contrast []float64
} }
// Results constructor // NewResults constructs the results object.
func NewResults(n int) (*Results, error) { func NewResults(n int) (*Results, error) {
if n <= 0 { if n <= 0 {
@ -51,7 +51,7 @@ func NewResults(n int) (*Results, error) {
return r, nil return r, nil
} }
// Update results to add new values at specified index. // Update adds new values to slice at specified index.
func (r *Results) Update(newSat, newCont, newTurb float64, index int) { func (r *Results) Update(newSat, newCont, newTurb float64, index int) {
r.Saturation[index] = newSat r.Saturation[index] = newSat
r.Contrast[index] = newCont r.Contrast[index] = newCont

View File

@ -40,24 +40,37 @@ import (
// TurbiditySensor is a software based turbidity sensor that uses CV to determine saturation and constrast level // TurbiditySensor is a software based turbidity sensor that uses CV to determine saturation and constrast level
// of a chessboard-like target submerged in water that can be correlated to turbidity/visibility values. // of a chessboard-like target submerged in water that can be correlated to turbidity/visibility values.
type TurbiditySensor struct { type TurbiditySensor struct {
template, standard gocv.Mat template, templateCorners gocv.Mat
k1, k2, sobelFilterSize int standard, standardCorners gocv.Mat
scale, alpha float64 k1, k2, sobelFilterSize int
scale, alpha float64
} }
// Turbidity sensor constructor. // NewTurbiditySensor constructor for a turbidity sensor.
func NewTurbiditySensor(template, standard gocv.Mat, k1, k2, sobelFilterSize int, scale, alpha float64) (*TurbiditySensor, error) { func NewTurbiditySensor(template, standard gocv.Mat, k1, k2, sobelFilterSize int, scale, alpha float64) (*TurbiditySensor, error) {
ts := new(TurbiditySensor) ts := new(TurbiditySensor)
templateCorners := gocv.NewMat()
standardCorners := gocv.NewMat()
// Validate template image is not empty and has valid corners.
if template.Empty() { if template.Empty() {
return nil, errors.New("template image is empty.") return nil, errors.New("template image is empty.")
} }
if !gocv.FindChessboardCorners(template, image.Pt(3, 3), &templateCorners, gocv.CalibCBNormalizeImage) {
return nil, errors.New("could not find corners in template image")
}
ts.template = template ts.template = template
ts.templateCorners = templateCorners
// Validate standard image is not empty and has valid corners.
if standard.Empty() { if standard.Empty() {
return nil, errors.New("standard image is empty.") return nil, errors.New("standard image is empty.")
} }
if !gocv.FindChessboardCorners(standard, image.Pt(3, 3), &standardCorners, gocv.CalibCBNormalizeImage) {
return nil, errors.New("could not find corners in standard image")
}
ts.standard = standard ts.standard = standard
ts.standardCorners = standardCorners
ts.k1, ts.k2, ts.sobelFilterSize = k1, k2, sobelFilterSize ts.k1, ts.k2, ts.sobelFilterSize = k1, k2, sobelFilterSize
ts.alpha, ts.scale = alpha, scale ts.alpha, ts.scale = alpha, scale
@ -127,6 +140,7 @@ func (ts TurbiditySensor) EvaluateImage(img, edge gocv.Mat) (float64, float64, e
return sharpness, contrast, nil return sharpness, contrast, nil
} }
// minMax returns the max and min pixel values of an image block.
func (ts TurbiditySensor) minMax(img gocv.Mat, xStart, yStart, xEnd, yEnd int) (float64, float64) { func (ts TurbiditySensor) minMax(img gocv.Mat, xStart, yStart, xEnd, yEnd int) (float64, float64) {
max := -math.MaxFloat64 max := -math.MaxFloat64
min := math.MaxFloat64 min := math.MaxFloat64
@ -147,7 +161,7 @@ func (ts TurbiditySensor) minMax(img gocv.Mat, xStart, yStart, xEnd, yEnd int) (
return max, min return max, min
} }
// Evaluate a block within an image and return the value to be added to the sharpness result. // evaluateBlockEME will evaluate an image block and return the value to be added to the sharpness result.
func (ts TurbiditySensor) evaluateBlockEME(img gocv.Mat, xStart, yStart, xEnd, yEnd int) float64 { func (ts TurbiditySensor) evaluateBlockEME(img gocv.Mat, xStart, yStart, xEnd, yEnd int) float64 {
max, min := ts.minMax(img, xStart, yStart, xEnd, yEnd) max, min := ts.minMax(img, xStart, yStart, xEnd, yEnd)
@ -158,7 +172,7 @@ func (ts TurbiditySensor) evaluateBlockEME(img gocv.Mat, xStart, yStart, xEnd, y
return 0.0 return 0.0
} }
// Evaluate a block within an image and return the value to be added to the contrast result. // evaluateBlockAMEE will evaluate an image block and return the value to be added to the contrast result.
func (ts TurbiditySensor) evaluateBlockAMEE(img gocv.Mat, xStart, yStart, xEnd, yEnd int) float64 { func (ts TurbiditySensor) evaluateBlockAMEE(img gocv.Mat, xStart, yStart, xEnd, yEnd int) float64 {
max, min := ts.minMax(img, xStart, yStart, xEnd, yEnd) max, min := ts.minMax(img, xStart, yStart, xEnd, yEnd)
@ -174,29 +188,19 @@ func (ts TurbiditySensor) evaluateBlockAMEE(img gocv.Mat, xStart, yStart, xEnd,
func (ts TurbiditySensor) transform(img gocv.Mat) (gocv.Mat, error) { func (ts TurbiditySensor) transform(img gocv.Mat) (gocv.Mat, error) {
out := gocv.NewMat() out := gocv.NewMat()
mask := gocv.NewMat() mask := gocv.NewMat()
corners_img := gocv.NewMat() imgCorners := gocv.NewMat()
corners_template := gocv.NewMat()
// Check image is valid. // Check image is valid.
if img.Empty() { if img.Empty() {
return out, errors.New("image is empty, cannot transform") return out, errors.New("image is empty, cannot transform")
} }
// Check image for corners, if non can be found corners will be set to default value.
// Find corners in image. if !gocv.FindChessboardCorners(img, image.Pt(3, 3), &imgCorners, gocv.CalibCBFastCheck) {
if !gocv.FindChessboardCorners(img, image.Pt(3, 3), &corners_img, gocv.CalibCBNormalizeImage) { imgCorners = ts.standardCorners
// Apply default if transformation fails.
if !gocv.FindChessboardCorners(ts.standard, image.Pt(3, 3), &corners_img, gocv.CalibCBNormalizeImage) {
return out, errors.New("Could not find corners in default image")
}
}
// Find corners in template.
if !gocv.FindChessboardCorners(ts.template, image.Pt(3, 3), &corners_template, gocv.CalibCBNormalizeImage) {
return out, errors.New("Could not find corners in template")
} }
// Find and apply transformation. // Find and apply transformation.
H := gocv.FindHomography(corners_img, &corners_template, gocv.HomograpyMethodRANSAC, 3.0, &mask, 2000, 0.995) H := gocv.FindHomography(imgCorners, &ts.templateCorners, gocv.HomograpyMethodRANSAC, 3.0, &mask, 2000, 0.995)
gocv.WarpPerspective(img, &out, H, image.Pt(ts.template.Rows(), ts.template.Cols())) gocv.WarpPerspective(img, &out, H, image.Pt(ts.template.Rows(), ts.template.Cols()))
return out, nil return out, nil

View File

@ -59,7 +59,7 @@ func TestImages(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
// Create results // Create results.
results, err := NewResults(nImages) results, err := NewResults(nImages)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)