mirror of
https://github.com/hybridgroup/gocv
synced 2025-08-25 08:41:04 +08:00
446 lines
10 KiB
Go
446 lines
10 KiB
Go
//go:build !gocv_specific_modules || (gocv_specific_modules && gocv_video)
|
|
|
|
package gocv
|
|
|
|
import (
|
|
"image"
|
|
"image/color"
|
|
"math"
|
|
"os"
|
|
"testing"
|
|
)
|
|
|
|
func TestMOG2(t *testing.T) {
|
|
img := IMRead("images/face.jpg", IMReadColor)
|
|
if img.Empty() {
|
|
t.Error("Invalid Mat in MOG2 test")
|
|
}
|
|
defer img.Close()
|
|
|
|
dst := NewMat()
|
|
defer dst.Close()
|
|
|
|
mog2 := NewBackgroundSubtractorMOG2()
|
|
defer mog2.Close()
|
|
|
|
mog2.Apply(img, &dst)
|
|
|
|
if dst.Empty() {
|
|
t.Error("Error in TestMOG2 test")
|
|
}
|
|
}
|
|
|
|
func TestMOG2ApplyWithParams(t *testing.T) {
|
|
img := IMRead("images/face.jpg", IMReadColor)
|
|
if img.Empty() {
|
|
t.Error("Invalid Mat in MOG2 test")
|
|
}
|
|
defer img.Close()
|
|
|
|
dst := NewMat()
|
|
defer dst.Close()
|
|
|
|
mog2 := NewBackgroundSubtractorMOG2()
|
|
defer mog2.Close()
|
|
|
|
mog2.ApplyWithLearningRate(img, &dst, 0.01)
|
|
|
|
if dst.Empty() {
|
|
t.Error("Error in TestMOG2 test")
|
|
}
|
|
}
|
|
|
|
func TestMOG2WithParams(t *testing.T) {
|
|
img := IMRead("images/face.jpg", IMReadColor)
|
|
if img.Empty() {
|
|
t.Error("Invalid Mat in MOG2 test")
|
|
}
|
|
defer img.Close()
|
|
|
|
dst := NewMat()
|
|
defer dst.Close()
|
|
|
|
mog2 := NewBackgroundSubtractorMOG2WithParams(250, 8, false)
|
|
defer mog2.Close()
|
|
|
|
mog2.Apply(img, &dst)
|
|
|
|
if dst.Empty() {
|
|
t.Error("Error in TestMOG2WithParams test")
|
|
}
|
|
}
|
|
|
|
func TestMOG2WithParamsWithLR(t *testing.T) {
|
|
img := IMRead("images/face.jpg", IMReadColor)
|
|
if img.Empty() {
|
|
t.Error("Invalid Mat in MOG2 test")
|
|
}
|
|
defer img.Close()
|
|
|
|
dst := NewMat()
|
|
defer dst.Close()
|
|
|
|
mog2 := NewBackgroundSubtractorMOG2WithParams(250, 8, false)
|
|
defer mog2.Close()
|
|
|
|
mog2.ApplyWithLearningRate(img, &dst, 0.0)
|
|
|
|
if dst.Empty() {
|
|
t.Error("Error in TestMOG2WithParams test")
|
|
}
|
|
}
|
|
|
|
func TestKNN(t *testing.T) {
|
|
img := IMRead("images/face.jpg", IMReadColor)
|
|
if img.Empty() {
|
|
t.Error("Invalid Mat in KNN test")
|
|
}
|
|
defer img.Close()
|
|
|
|
dst := NewMat()
|
|
defer dst.Close()
|
|
|
|
knn := NewBackgroundSubtractorKNN()
|
|
defer knn.Close()
|
|
|
|
knn.Apply(img, &dst)
|
|
|
|
if dst.Empty() {
|
|
t.Error("Error in TestKNN test")
|
|
}
|
|
}
|
|
|
|
func TestKNNWithParams(t *testing.T) {
|
|
img := IMRead("images/face.jpg", IMReadColor)
|
|
if img.Empty() {
|
|
t.Error("Invalid Mat in KNN test")
|
|
}
|
|
defer img.Close()
|
|
|
|
dst := NewMat()
|
|
defer dst.Close()
|
|
|
|
knn := NewBackgroundSubtractorKNNWithParams(250, 200, false)
|
|
defer knn.Close()
|
|
|
|
knn.Apply(img, &dst)
|
|
|
|
if dst.Empty() {
|
|
t.Error("Error in TestKNNWithParams test")
|
|
}
|
|
}
|
|
|
|
func TestCalcOpticalFlowFarneback(t *testing.T) {
|
|
img1 := IMRead("images/face.jpg", IMReadColor)
|
|
if img1.Empty() {
|
|
t.Error("Invalid Mat in CalcOpticalFlowFarneback test")
|
|
}
|
|
defer img1.Close()
|
|
|
|
dest := NewMat()
|
|
defer dest.Close()
|
|
|
|
CvtColor(img1, &dest, ColorBGRAToGray)
|
|
|
|
img2 := dest.Clone()
|
|
defer img2.Close()
|
|
|
|
flow := NewMat()
|
|
defer flow.Close()
|
|
|
|
CalcOpticalFlowFarneback(dest, img2, &flow, 0.4, 1, 12, 2, 8, 1.2, 0)
|
|
|
|
if flow.Empty() {
|
|
t.Error("Error in CalcOpticalFlowFarneback test")
|
|
}
|
|
if flow.Rows() != 480 {
|
|
t.Errorf("Invalid CalcOpticalFlowFarneback test rows: %v", flow.Rows())
|
|
}
|
|
if flow.Cols() != 640 {
|
|
t.Errorf("Invalid CalcOpticalFlowFarneback test cols: %v", flow.Cols())
|
|
}
|
|
}
|
|
|
|
func TestCalcOpticalFlowPyrLK(t *testing.T) {
|
|
img1 := IMRead("images/face.jpg", IMReadColor)
|
|
if img1.Empty() {
|
|
t.Error("Invalid Mat in CalcOpticalFlowPyrLK test")
|
|
}
|
|
defer img1.Close()
|
|
|
|
dest := NewMat()
|
|
defer dest.Close()
|
|
|
|
CvtColor(img1, &dest, ColorBGRAToGray)
|
|
|
|
img2 := dest.Clone()
|
|
defer img2.Close()
|
|
|
|
prevPts := NewMat()
|
|
defer prevPts.Close()
|
|
|
|
nextPts := NewMat()
|
|
defer nextPts.Close()
|
|
|
|
status := NewMat()
|
|
defer status.Close()
|
|
|
|
err := NewMat()
|
|
defer err.Close()
|
|
|
|
corners := NewMat()
|
|
defer corners.Close()
|
|
|
|
GoodFeaturesToTrack(dest, &corners, 500, 0.01, 10)
|
|
tc := NewTermCriteria(Count|EPS, 20, 0.03)
|
|
CornerSubPix(dest, &corners, image.Pt(10, 10), image.Pt(-1, -1), tc)
|
|
|
|
CalcOpticalFlowPyrLK(dest, img2, corners, nextPts, &status, &err)
|
|
|
|
if status.Empty() {
|
|
t.Error("Error in CalcOpticalFlowPyrLK test")
|
|
}
|
|
if status.Rows() != 323 {
|
|
t.Errorf("Invalid CalcOpticalFlowPyrLK test rows: %v", status.Rows())
|
|
}
|
|
if status.Cols() != 1 {
|
|
t.Errorf("Invalid CalcOpticalFlowPyrLK test cols: %v", status.Cols())
|
|
}
|
|
}
|
|
|
|
func TestCalcOpticalFlowPyrLKWithParams(t *testing.T) {
|
|
img1 := IMRead("images/face.jpg", IMReadColor)
|
|
if img1.Empty() {
|
|
t.Error("Invalid Mat in CalcOpticalFlowPyrLK test")
|
|
}
|
|
defer img1.Close()
|
|
|
|
dest := NewMat()
|
|
defer dest.Close()
|
|
|
|
CvtColor(img1, &dest, ColorBGRAToGray)
|
|
|
|
img2 := dest.Clone()
|
|
defer img2.Close()
|
|
|
|
prevPts := NewMat()
|
|
defer prevPts.Close()
|
|
|
|
nextPts := NewMat()
|
|
defer nextPts.Close()
|
|
|
|
status := NewMat()
|
|
defer status.Close()
|
|
|
|
err := NewMat()
|
|
defer err.Close()
|
|
|
|
corners := NewMat()
|
|
defer corners.Close()
|
|
|
|
GoodFeaturesToTrack(dest, &corners, 500, 0.01, 10)
|
|
tc := NewTermCriteria(Count|EPS, 30, 0.03)
|
|
CornerSubPix(dest, &corners, image.Pt(10, 10), image.Pt(-1, -1), tc)
|
|
|
|
CalcOpticalFlowPyrLKWithParams(dest, img2, corners, nextPts, &status, &err, image.Pt(21, 21), 3, tc, 0, 0.0001)
|
|
|
|
if status.Empty() {
|
|
t.Error("Error in CalcOpticalFlowPyrLK test")
|
|
}
|
|
if status.Rows() != 323 {
|
|
t.Errorf("Invalid CalcOpticalFlowPyrLK test rows: %v", status.Rows())
|
|
}
|
|
if status.Cols() != 1 {
|
|
t.Errorf("Invalid CalcOpticalFlowPyrLK test cols: %v", status.Cols())
|
|
}
|
|
}
|
|
|
|
func computeRMS(mat1 Mat, mat2 Mat) float64 {
|
|
var rms float64
|
|
for y := 0; y < mat1.Rows(); y++ {
|
|
for x := 0; x < mat1.Cols(); x++ {
|
|
diff := float64(mat1.GetFloatAt(y, x) - mat2.GetFloatAt(y, x))
|
|
rms += diff * diff
|
|
}
|
|
}
|
|
|
|
rms /= float64(mat1.Rows() * mat1.Cols())
|
|
return math.Sqrt(rms)
|
|
}
|
|
|
|
func TestFindTransformECC(t *testing.T) {
|
|
img := IMRead("images/face.jpg", IMReadGrayScale)
|
|
if img.Empty() {
|
|
t.Error("Invalid Mat in FindTransformECC test")
|
|
}
|
|
defer img.Close()
|
|
testImg := NewMat()
|
|
defer testImg.Close()
|
|
Resize(img, &testImg, image.Point{216, 216}, 0, 0, InterpolationLinear)
|
|
|
|
translationGround := Eye(2, 3, MatTypeCV32F)
|
|
defer translationGround.Close()
|
|
translationGround.SetFloatAt(0, 2, 11.4159)
|
|
translationGround.SetFloatAt(1, 2, 17.1828)
|
|
|
|
warpedImage := NewMat()
|
|
defer warpedImage.Close()
|
|
WarpAffineWithParams(testImg, &warpedImage, translationGround, image.Point{200, 200}, InterpolationLinear+WarpInverseMap, BorderConstant, color.RGBA{})
|
|
|
|
mapTranslation := Eye(2, 3, MatTypeCV32F)
|
|
defer mapTranslation.Close()
|
|
eecIterations := 50
|
|
// Negative value means that ECC_Iterations will be executed.
|
|
var eecEpsilon float64 = -1
|
|
criteria := NewTermCriteria(Count+EPS, eecIterations, eecEpsilon)
|
|
inputMask := NewMat()
|
|
defer inputMask.Close()
|
|
gaussFiltSize := 5
|
|
FindTransformECC(warpedImage, testImg, &mapTranslation, MotionTranslation, criteria, inputMask, gaussFiltSize)
|
|
|
|
maxRMSECC := 0.1
|
|
rms := computeRMS(mapTranslation, translationGround)
|
|
if rms > maxRMSECC {
|
|
t.Errorf("FindTransformECC RMS = %f", rms)
|
|
}
|
|
}
|
|
|
|
func BaseTestTracker(t *testing.T, tracker Tracker, name string) {
|
|
if tracker == nil {
|
|
t.Error("TestTracker " + name + " should not be nil")
|
|
}
|
|
|
|
img := IMRead("./images/face.jpg", 1)
|
|
if img.Empty() {
|
|
t.Error("TestTracker " + name + " input img failed to load")
|
|
}
|
|
defer img.Close()
|
|
|
|
rect := image.Rect(250, 150, 250+200, 150+250)
|
|
init := tracker.Init(img, rect)
|
|
if !init {
|
|
t.Error("TestTracker " + name + " failed in Init")
|
|
}
|
|
|
|
_, ok := tracker.Update(img)
|
|
if !ok {
|
|
t.Error("TestTracker " + name + " lost object in Update")
|
|
}
|
|
}
|
|
|
|
func TestSingleTrackers(t *testing.T) {
|
|
goturnPath := os.Getenv("GOCV_TRACKER_GOTURN_TEST_FILES")
|
|
if goturnPath == "" {
|
|
goturnPath = "./testdata"
|
|
}
|
|
|
|
vitPath := os.Getenv("GOCV_ONNX_TEST_FILES")
|
|
if vitPath == "" {
|
|
vitPath = "./testdata"
|
|
}
|
|
|
|
tab := []struct {
|
|
name string
|
|
tracker Tracker
|
|
}{
|
|
{"MIL", NewTrackerMIL()},
|
|
{"GOTURN", NewTrackerGOTURNWithParams(goturnPath+"/goturn.caffemodel", goturnPath+"/goturn.prototxt")},
|
|
{"Vit", NewTrackerVitWithParams(vitPath + "/object_tracking_vittrack_2023sep.onnx")},
|
|
}
|
|
|
|
for _, test := range tab {
|
|
func() {
|
|
defer test.tracker.Close()
|
|
BaseTestTracker(t, test.tracker, test.name)
|
|
}()
|
|
}
|
|
}
|
|
|
|
func TestKalmanFilter(t *testing.T) {
|
|
// Basic test with default constructor.
|
|
kf := NewKalmanFilter(2, 1)
|
|
kf.Init(2, 1)
|
|
measurement := Zeros(1, 1, MatTypeCV32F)
|
|
prediction := kf.Predict()
|
|
statePost := kf.Correct(measurement)
|
|
statePost.Close()
|
|
prediction.Close()
|
|
measurement.Close()
|
|
kf.Close()
|
|
|
|
// Basic test with param constructor.
|
|
kf = NewKalmanFilterWithParams(2, 1, 1, MatTypeCV32F)
|
|
control := Ones(1, 1, MatTypeCV32F)
|
|
measurement = Ones(1, 1, MatTypeCV32F)
|
|
prediction = kf.PredictWithParams(control)
|
|
statePost = kf.Correct(measurement)
|
|
statePost.Close()
|
|
prediction.Close()
|
|
measurement.Close()
|
|
control.Close()
|
|
kf.Close()
|
|
}
|
|
|
|
func TestKalmanFilter_Getters(t *testing.T) {
|
|
kf := NewKalmanFilterWithParams(2, 1, 1, MatTypeCV32F)
|
|
getterTests := []struct {
|
|
desc string
|
|
f func() Mat
|
|
}{
|
|
{desc: "GetStatePre()", f: kf.GetStatePre},
|
|
{desc: "GetStatePost()", f: kf.GetStatePost},
|
|
{desc: "GetTransitionMatrix()", f: kf.GetTransitionMatrix},
|
|
{desc: "GetControlMatrix()", f: kf.GetControlMatrix},
|
|
{desc: "GetMeasurementMatrix()", f: kf.GetMeasurementMatrix},
|
|
{desc: "GetProcessNoiseCov()", f: kf.GetProcessNoiseCov},
|
|
{desc: "GetMeasurementNoiseCov()", f: kf.GetMeasurementNoiseCov},
|
|
{desc: "GetErrorCovPre()", f: kf.GetErrorCovPre},
|
|
{desc: "GetGain()", f: kf.GetGain},
|
|
{desc: "GetErrorCovPost()", f: kf.GetErrorCovPost},
|
|
{desc: "GetTemp1()", f: kf.GetTemp1},
|
|
{desc: "GetTemp2()", f: kf.GetTemp2},
|
|
{desc: "GetTemp3()", f: kf.GetTemp3},
|
|
{desc: "GetTemp4()", f: kf.GetTemp4},
|
|
{desc: "GetTemp5()", f: kf.GetTemp5},
|
|
}
|
|
for _, test := range getterTests {
|
|
t.Run(test.desc, func(t *testing.T) {
|
|
if got := test.f(); got.Empty() {
|
|
t.Errorf("%v: returned empty, want non-Empty", test.desc)
|
|
} else {
|
|
got.Close()
|
|
}
|
|
|
|
})
|
|
}
|
|
kf.Close()
|
|
}
|
|
|
|
func TestKalmanFilter_Setters(t *testing.T) {
|
|
kf := NewKalmanFilter(2, 1)
|
|
tests := []struct {
|
|
desc string
|
|
f func(Mat)
|
|
}{
|
|
{desc: "SetStatePre()", f: kf.SetStatePre},
|
|
{desc: "SetStatePost()", f: kf.SetStatePost},
|
|
{desc: "SetTransitionMatrix()", f: kf.SetTransitionMatrix},
|
|
{desc: "SetControlMatrix()", f: kf.SetControlMatrix},
|
|
{desc: "SetMeasurementMatrix()", f: kf.SetMeasurementMatrix},
|
|
{desc: "SetProcessNoiseCov()", f: kf.SetProcessNoiseCov},
|
|
{desc: "SetMeasurementNoiseCov()", f: kf.SetMeasurementNoiseCov},
|
|
{desc: "SetErrorCovPre()", f: kf.SetErrorCovPre},
|
|
{desc: "SetGain()", f: kf.SetGain},
|
|
{desc: "SetErrorCovPost()", f: kf.SetErrorCovPost},
|
|
}
|
|
for _, test := range tests {
|
|
t.Run(test.desc, func(t *testing.T) {
|
|
testMat := Ones(2, 1, MatTypeCV32F)
|
|
// Just run this to make sure the execution doesn't fail.
|
|
test.f(testMat)
|
|
testMat.Close()
|
|
})
|
|
}
|
|
kf.Close()
|
|
}
|