mirror of https://bitbucket.org/ausocean/av.git
revid: add transfrom matrix variable
This commit is contained in:
parent
ee6fc3ca44
commit
3047704ca0
cmd/rv
revid/config
turbidity
|
@ -146,7 +146,7 @@ func main() {
|
||||||
p *turbidityProbe
|
p *turbidityProbe
|
||||||
)
|
)
|
||||||
|
|
||||||
p, err := NewTurbidityProbe(*log, 60*time.Second)
|
p, err := NewTurbidityProbe(*log, 60*time.Second, rv.Config().TransformMatrix)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Log(logger.Fatal, "could not create new turbidity probe", "error", err.Error())
|
log.Log(logger.Fatal, "could not create new turbidity probe", "error", err.Error())
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,16 +68,18 @@ type turbidityProbe struct {
|
||||||
ts *turbidity.TurbiditySensor
|
ts *turbidity.TurbiditySensor
|
||||||
log logger.Logger
|
log logger.Logger
|
||||||
buffer *bytes.Buffer
|
buffer *bytes.Buffer
|
||||||
|
transform []float64
|
||||||
trimCounter int
|
trimCounter int
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewTurbidityProbe returns a new turbidity probe.
|
// NewTurbidityProbe returns a new turbidity probe.
|
||||||
func NewTurbidityProbe(log logger.Logger, delay time.Duration) (*turbidityProbe, error) {
|
func NewTurbidityProbe(log logger.Logger, delay time.Duration, transformMatrix []float64) (*turbidityProbe, error) {
|
||||||
tp := new(turbidityProbe)
|
tp := new(turbidityProbe)
|
||||||
tp.log = log
|
tp.log = log
|
||||||
tp.delay = delay
|
tp.delay = delay
|
||||||
tp.ticker = *time.NewTicker(delay)
|
tp.ticker = *time.NewTicker(delay)
|
||||||
tp.buffer = bytes.NewBuffer(*new([]byte))
|
tp.buffer = bytes.NewBuffer(*new([]byte))
|
||||||
|
tp.transform = transformMatrix
|
||||||
|
|
||||||
// Create the turbidity sensor.
|
// Create the turbidity sensor.
|
||||||
standard := gocv.IMRead("../../turbidity/images/default.jpg", gocv.IMReadGrayScale)
|
standard := gocv.IMRead("../../turbidity/images/default.jpg", gocv.IMReadGrayScale)
|
||||||
|
@ -125,6 +127,7 @@ func (tp *turbidityProbe) Write(p []byte) (int, error) {
|
||||||
select {
|
select {
|
||||||
case <-tp.ticker.C:
|
case <-tp.ticker.C:
|
||||||
tp.log.Log(logger.Debug, "beginning turbidity calculation")
|
tp.log.Log(logger.Debug, "beginning turbidity calculation")
|
||||||
|
tp.log.Log(logger.Debug, "transformation matrix", tp.transform[0])
|
||||||
startTime := time.Now()
|
startTime := time.Now()
|
||||||
err := tp.turbidityCalculation()
|
err := tp.turbidityCalculation()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -44,8 +44,9 @@ func TestProbe(t *testing.T) {
|
||||||
MaxAge: logMaxAge,
|
MaxAge: logMaxAge,
|
||||||
}
|
}
|
||||||
log := logger.New(logVerbosity, io.MultiWriter(fileLog), logSuppress)
|
log := logger.New(logVerbosity, io.MultiWriter(fileLog), logSuppress)
|
||||||
|
transformMatrix := []float64{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}
|
||||||
|
|
||||||
ts, err := NewTurbidityProbe(*log, time.Microsecond)
|
ts, err := NewTurbidityProbe(*log, time.Microsecond, transformMatrix)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create turbidity probe")
|
t.Fatalf("failed to create turbidity probe")
|
||||||
}
|
}
|
||||||
|
|
|
@ -273,6 +273,8 @@ type Config struct {
|
||||||
|
|
||||||
VerticalFlip bool // VerticalFlip flips video vertically for Raspivid input.
|
VerticalFlip bool // VerticalFlip flips video vertically for Raspivid input.
|
||||||
Width uint // Width defines the input video width Raspivid input.
|
Width uint // Width defines the input video width Raspivid input.
|
||||||
|
|
||||||
|
TransformMatrix []float64 // Describes the transformation matrix to extract the target.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate checks for any errors in the config fields and defaults settings
|
// Validate checks for any errors in the config fields and defaults settings
|
||||||
|
|
|
@ -99,6 +99,7 @@ const (
|
||||||
KeyVBRQuality = "VBRQuality"
|
KeyVBRQuality = "VBRQuality"
|
||||||
KeyVerticalFlip = "VerticalFlip"
|
KeyVerticalFlip = "VerticalFlip"
|
||||||
KeyWidth = "Width"
|
KeyWidth = "Width"
|
||||||
|
KeyTransformMatrix = "TransformMatrix"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Config map parameter types.
|
// Config map parameter types.
|
||||||
|
@ -144,6 +145,23 @@ var Variables = []struct {
|
||||||
Update func(*Config, string)
|
Update func(*Config, string)
|
||||||
Validate func(*Config)
|
Validate func(*Config)
|
||||||
}{
|
}{
|
||||||
|
{
|
||||||
|
Name: KeyTransformMatrix,
|
||||||
|
Type: typeString,
|
||||||
|
Update: func(c *Config, v string) {
|
||||||
|
v = strings.Replace(v, " ", "", 0)
|
||||||
|
elements := strings.Split(v, ",")
|
||||||
|
vals := make([]float64, len(elements))
|
||||||
|
for _, i := range elements {
|
||||||
|
vFloat, err := strconv.ParseFloat(i, 64)
|
||||||
|
if err != nil {
|
||||||
|
c.Logger.Log(logger.Warning, "invalid TransformMatrix param", "value", i)
|
||||||
|
}
|
||||||
|
vals = append(vals, vFloat)
|
||||||
|
}
|
||||||
|
c.TransformMatrix = vals
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Name: KeyAutoWhiteBalance,
|
Name: KeyAutoWhiteBalance,
|
||||||
Type: "enum:off,auto,sun,cloud,shade,tungsten,fluorescent,incandescent,flash,horizon",
|
Type: "enum:off,auto,sun,cloud,shade,tungsten,fluorescent,incandescent,flash,horizon",
|
||||||
|
|
|
@ -41,11 +41,19 @@ import (
|
||||||
"gocv.io/x/gocv"
|
"gocv.io/x/gocv"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Homography constants
|
||||||
|
const (
|
||||||
|
ransacThreshold = 3.0 // Maximum allowed reprojection error to treat a point pair as an inlier.
|
||||||
|
maxIter = 2000 // The maximum number of RANSAC iterations.
|
||||||
|
confidence = 0.995 // Confidence level, between 0 and 1.
|
||||||
|
)
|
||||||
|
|
||||||
// TurbiditySensor is a software based turbidity sensor that uses CV to determine sharpness and constrast level
|
// TurbiditySensor is a software based turbidity sensor that uses CV to determine sharpness 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, templateCorners gocv.Mat
|
template, templateCorners gocv.Mat
|
||||||
standard, standardCorners gocv.Mat
|
standard, standardCorners gocv.Mat
|
||||||
|
H gocv.Mat
|
||||||
k1, k2, sobelFilterSize int
|
k1, k2, sobelFilterSize int
|
||||||
scale, alpha float64
|
scale, alpha float64
|
||||||
log logger.Logger
|
log logger.Logger
|
||||||
|
@ -56,6 +64,7 @@ func NewTurbiditySensor(template, standard gocv.Mat, k1, k2, sobelFilterSize int
|
||||||
ts := new(TurbiditySensor)
|
ts := new(TurbiditySensor)
|
||||||
templateCorners := gocv.NewMat()
|
templateCorners := gocv.NewMat()
|
||||||
standardCorners := gocv.NewMat()
|
standardCorners := gocv.NewMat()
|
||||||
|
mask := gocv.NewMat()
|
||||||
|
|
||||||
// Validate template image is not empty and has valid corners.
|
// Validate template image is not empty and has valid corners.
|
||||||
if template.Empty() {
|
if template.Empty() {
|
||||||
|
@ -74,8 +83,10 @@ func NewTurbiditySensor(template, standard gocv.Mat, k1, k2, sobelFilterSize int
|
||||||
if !gocv.FindChessboardCorners(standard, image.Pt(3, 3), &standardCorners, gocv.CalibCBNormalizeImage) {
|
if !gocv.FindChessboardCorners(standard, image.Pt(3, 3), &standardCorners, gocv.CalibCBNormalizeImage) {
|
||||||
return nil, errors.New("could not find corners in standard image")
|
return nil, errors.New("could not find corners in standard image")
|
||||||
}
|
}
|
||||||
|
|
||||||
ts.standard = standard
|
ts.standard = standard
|
||||||
ts.standardCorners = standardCorners
|
ts.standardCorners = standardCorners
|
||||||
|
ts.H = gocv.FindHomography(ts.standardCorners, &ts.templateCorners, gocv.HomograpyMethodRANSAC, ransacThreshold, &mask, maxIter, confidence)
|
||||||
|
|
||||||
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
|
||||||
|
@ -191,13 +202,6 @@ func (ts TurbiditySensor) evaluateBlockAMEE(img gocv.Mat, xStart, yStart, xEnd,
|
||||||
// transform will search img for matching template. Returns the transformed image which best match the template.
|
// transform will search img for matching template. Returns the transformed image which best match the template.
|
||||||
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()
|
|
||||||
imgCorners := ts.standardCorners
|
|
||||||
const (
|
|
||||||
ransacThreshold = 3.0 // Maximum allowed reprojection error to treat a point pair as an inlier.
|
|
||||||
maxIter = 2000 // The maximum number of RANSAC iterations.
|
|
||||||
confidence = 0.995 // Confidence level, between 0 and 1.
|
|
||||||
)
|
|
||||||
|
|
||||||
if img.Empty() {
|
if img.Empty() {
|
||||||
return out, errors.New("image is empty, cannot transform")
|
return out, errors.New("image is empty, cannot transform")
|
||||||
|
@ -206,8 +210,7 @@ func (ts TurbiditySensor) transform(img gocv.Mat) (gocv.Mat, error) {
|
||||||
// if !gocv.FindChessboardCorners(img, image.Pt(3, 3), &imgCorners, gocv.CalibCBFastCheck) {}
|
// if !gocv.FindChessboardCorners(img, image.Pt(3, 3), &imgCorners, gocv.CalibCBFastCheck) {}
|
||||||
|
|
||||||
// Find and apply transformation.
|
// Find and apply transformation.
|
||||||
H := gocv.FindHomography(imgCorners, &ts.templateCorners, gocv.HomograpyMethodRANSAC, ransacThreshold, &mask, maxIter, confidence)
|
gocv.WarpPerspective(img, &out, ts.H, image.Pt(ts.template.Rows(), ts.template.Cols()))
|
||||||
gocv.WarpPerspective(img, &out, H, image.Pt(ts.template.Rows(), ts.template.Cols()))
|
|
||||||
gocv.CvtColor(out, &out, gocv.ColorRGBToGray)
|
gocv.CvtColor(out, &out, gocv.ColorRGBToGray)
|
||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,8 +42,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
nImages = 10 // Number of images to test. (Max 13)
|
nImages = 12 // Number of images to test. (Max 13)
|
||||||
nSamples = 1 // 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.
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ const (
|
||||||
func TestImages(t *testing.T) {
|
func TestImages(t *testing.T) {
|
||||||
|
|
||||||
const (
|
const (
|
||||||
k1, k2 = 8, 8
|
k1, k2 = 4, 4
|
||||||
filterSize = 3
|
filterSize = 3
|
||||||
scale, alpha = 1.0, 1.0
|
scale, alpha = 1.0, 1.0
|
||||||
)
|
)
|
||||||
|
@ -85,7 +85,7 @@ func TestImages(t *testing.T) {
|
||||||
for i := range imgs {
|
for i := range imgs {
|
||||||
imgs[i] = make([]gocv.Mat, nSamples)
|
imgs[i] = make([]gocv.Mat, nSamples)
|
||||||
for j := range imgs[i] {
|
for j := range imgs[i] {
|
||||||
imgs[i][j] = gocv.IMRead(fmt.Sprintf("images/t-%v/000%v.jpg", i, j), gocv.IMReadGrayScale)
|
imgs[i][j] = gocv.IMRead(fmt.Sprintf("images/t-%v/000%v.jpg", i, j), gocv.IMReadColor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,6 +94,13 @@ func TestImages(t *testing.T) {
|
||||||
t.Fatalf("could not create turbidity sensor: %v", err)
|
t.Fatalf("could not create turbidity sensor: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for i := 0; i < ts.H.Rows(); i++ {
|
||||||
|
for j := 0; j < ts.H.Cols(); j++ {
|
||||||
|
fmt.Printf(" %v,\t", ts.H.GetDoubleAt(i, j))
|
||||||
|
}
|
||||||
|
fmt.Println()
|
||||||
|
}
|
||||||
|
|
||||||
results, err := NewResults(nImages)
|
results, err := NewResults(nImages)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("could not create results: %v", err)
|
t.Fatalf("could not create results: %v", err)
|
||||||
|
@ -111,7 +118,7 @@ func TestImages(t *testing.T) {
|
||||||
results.Update(stat.Mean(sample_result.Sharpness, nil), stat.Mean(sample_result.Contrast, nil), float64(i)*increment, i)
|
results.Update(stat.Mean(sample_result.Sharpness, nil), stat.Mean(sample_result.Contrast, nil), float64(i)*increment, i)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = plotResults(results.Turbidity, results.Sharpness, 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)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue