mirror of
https://github.com/hybridgroup/gocv
synced 2025-08-25 08:41:04 +08:00
1073 lines
26 KiB
Go
1073 lines
26 KiB
Go
//go:build !gocv_specific_modules || (gocv_specific_modules && gocv_calib3d)
|
|
|
|
package gocv
|
|
|
|
import (
|
|
"fmt"
|
|
"image"
|
|
"image/color"
|
|
"math"
|
|
"testing"
|
|
)
|
|
|
|
func TestFisheyeCalibrate(t *testing.T) {
|
|
img := IMRead("images/chessboard_4x6_distort.png", IMReadGrayScale)
|
|
if img.Empty() {
|
|
t.Error("Invalid read of chessboard image")
|
|
return
|
|
}
|
|
defer img.Close()
|
|
|
|
corners := NewMat()
|
|
defer corners.Close()
|
|
|
|
size := image.Pt(4, 6)
|
|
found := FindChessboardCorners(img, size, &corners, 0)
|
|
if !found {
|
|
t.Error("chessboard pattern not found")
|
|
return
|
|
}
|
|
if corners.Empty() {
|
|
t.Error("chessboard pattern not found")
|
|
return
|
|
}
|
|
|
|
imagePoints := NewPoint2fVectorFromMat(corners)
|
|
defer imagePoints.Close()
|
|
|
|
objectPoints := NewPoint3fVector()
|
|
defer objectPoints.Close()
|
|
|
|
for j := 0; j < size.Y; j++ {
|
|
for i := 0; i < size.X; i++ {
|
|
objectPoints.Append(Point3f{
|
|
X: float32(100 * i),
|
|
Y: float32(100 * j),
|
|
Z: 0,
|
|
})
|
|
}
|
|
}
|
|
|
|
k := NewMat()
|
|
defer k.Close()
|
|
d := NewMat()
|
|
defer d.Close()
|
|
rvecs := NewMat()
|
|
defer rvecs.Close()
|
|
tvecs := NewMat()
|
|
defer tvecs.Close()
|
|
|
|
objectPointsVector := NewPoints3fVector()
|
|
objectPointsVector.Append(objectPoints)
|
|
defer objectPointsVector.Close()
|
|
|
|
imagePointsVector := NewPoints2fVector()
|
|
imagePointsVector.Append(imagePoints)
|
|
defer imagePointsVector.Close()
|
|
|
|
FisheyeCalibrate(
|
|
objectPointsVector, imagePointsVector, image.Pt(img.Cols(), img.Rows()),
|
|
&k, &d, &rvecs, &tvecs, 0,
|
|
)
|
|
|
|
if rvecs.Empty() {
|
|
t.Error("rvecs result is empty")
|
|
return
|
|
}
|
|
|
|
if tvecs.Empty() {
|
|
t.Error("tvecs result is empty")
|
|
return
|
|
}
|
|
}
|
|
|
|
func TestFisheyeDistortPoints(t *testing.T) {
|
|
k := NewMatWithSize(3, 3, MatTypeCV64F)
|
|
defer k.Close()
|
|
|
|
k.SetDoubleAt(0, 0, 1094.7249578198823)
|
|
k.SetDoubleAt(0, 1, 0)
|
|
k.SetDoubleAt(0, 2, 959.4907612030962)
|
|
|
|
k.SetDoubleAt(1, 0, 0)
|
|
k.SetDoubleAt(1, 1, 1094.9945708128778)
|
|
k.SetDoubleAt(1, 2, 536.4566143451868)
|
|
|
|
k.SetDoubleAt(2, 0, 0)
|
|
k.SetDoubleAt(2, 1, 0)
|
|
k.SetDoubleAt(2, 2, 1)
|
|
|
|
d := NewMatWithSize(1, 4, MatTypeCV64F)
|
|
defer d.Close()
|
|
|
|
d.SetDoubleAt(0, 0, -0.05207412392075069)
|
|
d.SetDoubleAt(0, 1, -0.089168300192224)
|
|
d.SetDoubleAt(0, 2, 0.10465607695792184)
|
|
d.SetDoubleAt(0, 3, -0.045693446831115585)
|
|
|
|
// transform 3 points in one go (X and Y values of points go in each channel)
|
|
src := NewMatWithSize(3, 1, MatTypeCV64FC2)
|
|
defer src.Close()
|
|
|
|
dst := NewMat()
|
|
defer dst.Close()
|
|
|
|
// This camera matrix is 1920x1080. Points where x < 960 and y < 540 should move toward the top left (x and y get smaller)
|
|
// The centre point should be mostly unchanged
|
|
// Points where x > 960 and y > 540 should move toward the bottom right (x and y get bigger)
|
|
|
|
// The index being used for col here is actually the channel (i.e. the point's x/y dimensions)
|
|
// (since there's only 1 column so the formula: (colNumber * numChannels + channelNumber) reduces to
|
|
// (0 * 2) + channelNumber
|
|
// so col = 0 is the x coordinate and col = 1 is the y coordinate
|
|
|
|
src.SetDoubleAt(0, 0, 480)
|
|
src.SetDoubleAt(0, 1, 270)
|
|
|
|
src.SetDoubleAt(1, 0, 960)
|
|
src.SetDoubleAt(1, 1, 540)
|
|
|
|
src.SetDoubleAt(2, 0, 1440)
|
|
src.SetDoubleAt(2, 1, 810)
|
|
|
|
FisheyeDistortPoints(src, &dst, k, d)
|
|
|
|
if dst.Empty() {
|
|
t.Error("final image is empty")
|
|
return
|
|
}
|
|
}
|
|
|
|
func TestFisheyeUndistorImage(t *testing.T) {
|
|
img := IMRead("images/fisheye_sample.jpg", IMReadUnchanged)
|
|
if img.Empty() {
|
|
t.Error("Invalid read of Mat test")
|
|
return
|
|
}
|
|
defer img.Close()
|
|
|
|
dest := NewMat()
|
|
defer dest.Close()
|
|
|
|
k := NewMatWithSize(3, 3, MatTypeCV64F)
|
|
defer k.Close()
|
|
|
|
k.SetDoubleAt(0, 0, 689.21)
|
|
k.SetDoubleAt(0, 1, 0)
|
|
k.SetDoubleAt(0, 2, 1295.56)
|
|
|
|
k.SetDoubleAt(1, 0, 0)
|
|
k.SetDoubleAt(1, 1, 690.48)
|
|
k.SetDoubleAt(1, 2, 942.17)
|
|
|
|
k.SetDoubleAt(2, 0, 0)
|
|
k.SetDoubleAt(2, 1, 0)
|
|
k.SetDoubleAt(2, 2, 1)
|
|
|
|
d := NewMatWithSize(1, 4, MatTypeCV64F)
|
|
defer d.Close()
|
|
|
|
d.SetDoubleAt(0, 0, 0)
|
|
d.SetDoubleAt(0, 1, 0)
|
|
d.SetDoubleAt(0, 2, 0)
|
|
d.SetDoubleAt(0, 3, 0)
|
|
|
|
FisheyeUndistortImage(img, &dest, k, d)
|
|
|
|
if dest.Empty() {
|
|
t.Error("final image is empty")
|
|
return
|
|
}
|
|
}
|
|
|
|
func TestFisheyeUndistorImageWithParams(t *testing.T) {
|
|
img := IMRead("images/fisheye_sample.jpg", IMReadUnchanged)
|
|
if img.Empty() {
|
|
t.Error("Invalid read of Mat test")
|
|
return
|
|
}
|
|
defer img.Close()
|
|
|
|
dest := NewMat()
|
|
defer dest.Close()
|
|
|
|
k := NewMatWithSize(3, 3, MatTypeCV64F)
|
|
defer k.Close()
|
|
|
|
k.SetDoubleAt(0, 0, 689.21)
|
|
k.SetDoubleAt(0, 1, 0)
|
|
k.SetDoubleAt(0, 2, 1295.56)
|
|
|
|
k.SetDoubleAt(1, 0, 0)
|
|
k.SetDoubleAt(1, 1, 690.48)
|
|
k.SetDoubleAt(1, 2, 942.17)
|
|
|
|
k.SetDoubleAt(2, 0, 0)
|
|
k.SetDoubleAt(2, 1, 0)
|
|
k.SetDoubleAt(2, 2, 1)
|
|
|
|
d := NewMatWithSize(1, 4, MatTypeCV64F)
|
|
defer d.Close()
|
|
|
|
d.SetDoubleAt(0, 0, 0)
|
|
d.SetDoubleAt(0, 1, 0)
|
|
d.SetDoubleAt(0, 2, 0)
|
|
d.SetDoubleAt(0, 3, 0)
|
|
|
|
knew := NewMat()
|
|
defer knew.Close()
|
|
|
|
k.CopyTo(&knew)
|
|
|
|
knew.SetDoubleAt(0, 0, 0.4*k.GetDoubleAt(0, 0))
|
|
knew.SetDoubleAt(1, 1, 0.4*k.GetDoubleAt(1, 1))
|
|
|
|
size := image.Point{dest.Rows(), dest.Cols()}
|
|
FisheyeUndistortImageWithParams(img, &dest, k, d, knew, size)
|
|
|
|
if dest.Empty() {
|
|
t.Error("final image is empty")
|
|
return
|
|
}
|
|
}
|
|
|
|
func TestInitUndistortRectifyMap(t *testing.T) {
|
|
img := IMRead("images/distortion.jpg", IMReadUnchanged)
|
|
if img.Empty() {
|
|
t.Error("Invalid read of Mat test")
|
|
return
|
|
}
|
|
defer img.Close()
|
|
|
|
dest := NewMat()
|
|
defer dest.Close()
|
|
|
|
k := NewMatWithSize(3, 3, MatTypeCV64F)
|
|
defer k.Close()
|
|
|
|
k.SetDoubleAt(0, 0, 842.0261028)
|
|
k.SetDoubleAt(0, 1, 0)
|
|
k.SetDoubleAt(0, 2, 667.7569792)
|
|
|
|
k.SetDoubleAt(1, 0, 0)
|
|
k.SetDoubleAt(1, 1, 707.3668897)
|
|
k.SetDoubleAt(1, 2, 385.56476464)
|
|
|
|
k.SetDoubleAt(2, 0, 0)
|
|
k.SetDoubleAt(2, 1, 0)
|
|
k.SetDoubleAt(2, 2, 1)
|
|
|
|
d := NewMatWithSize(1, 5, MatTypeCV64F)
|
|
defer d.Close()
|
|
|
|
d.SetDoubleAt(0, 0, -3.65584802e-01)
|
|
d.SetDoubleAt(0, 1, 1.41555815e-01)
|
|
d.SetDoubleAt(0, 2, -2.62985819e-03)
|
|
d.SetDoubleAt(0, 3, 2.05841873e-04)
|
|
d.SetDoubleAt(0, 4, -2.35021914e-02)
|
|
|
|
newC, roi := GetOptimalNewCameraMatrixWithParams(k, d, image.Point{X: img.Cols(), Y: img.Rows()}, (float64)(1), image.Point{X: img.Cols(), Y: img.Rows()}, false)
|
|
if newC.Empty() {
|
|
t.Error("final image is empty")
|
|
return
|
|
}
|
|
fmt.Printf("roi:%+v\n", roi)
|
|
defer newC.Close()
|
|
r := NewMat()
|
|
defer r.Close()
|
|
mapx := NewMat()
|
|
defer mapx.Close()
|
|
mapy := NewMat()
|
|
defer mapy.Close()
|
|
|
|
InitUndistortRectifyMap(k, d, r, newC, image.Point{X: img.Cols(), Y: img.Rows()}, 5, mapx, mapy)
|
|
|
|
Remap(img, &dest, &mapx, &mapy, InterpolationDefault, BorderConstant, color.RGBA{0, 0, 0, 0})
|
|
flg := IMWrite("images/distortion-correct.jpg", dest)
|
|
if !flg {
|
|
t.Error("IMWrite failed")
|
|
}
|
|
}
|
|
|
|
func TestUndistort(t *testing.T) {
|
|
img := IMRead("images/distortion.jpg", IMReadUnchanged)
|
|
if img.Empty() {
|
|
t.Error("Invalid read of Mat test")
|
|
return
|
|
}
|
|
defer img.Close()
|
|
|
|
dest := img.Clone()
|
|
defer dest.Close()
|
|
|
|
k := NewMatWithSize(3, 3, MatTypeCV64F)
|
|
defer k.Close()
|
|
|
|
k.SetDoubleAt(0, 0, 689.21)
|
|
k.SetDoubleAt(0, 1, 0)
|
|
k.SetDoubleAt(0, 2, 1295.56)
|
|
|
|
k.SetDoubleAt(1, 0, 0)
|
|
k.SetDoubleAt(1, 1, 690.48)
|
|
k.SetDoubleAt(1, 2, 942.17)
|
|
|
|
k.SetDoubleAt(2, 0, 0)
|
|
k.SetDoubleAt(2, 1, 0)
|
|
k.SetDoubleAt(2, 2, 1)
|
|
|
|
d := NewMatWithSize(1, 4, MatTypeCV64F)
|
|
defer d.Close()
|
|
|
|
d.SetDoubleAt(0, 0, 0)
|
|
d.SetDoubleAt(0, 1, 0)
|
|
d.SetDoubleAt(0, 2, 0)
|
|
d.SetDoubleAt(0, 3, 0)
|
|
|
|
knew := NewMat()
|
|
defer knew.Close()
|
|
|
|
k.CopyTo(&knew)
|
|
|
|
knew.SetDoubleAt(0, 0, 0.5*k.GetDoubleAt(0, 0))
|
|
knew.SetDoubleAt(1, 1, 0.5*k.GetDoubleAt(1, 1))
|
|
|
|
Undistort(img, &dest, k, d, knew)
|
|
|
|
if dest.Empty() {
|
|
t.Error("final image is empty")
|
|
return
|
|
}
|
|
}
|
|
|
|
func TestUndistortPoint(t *testing.T) {
|
|
k := NewMatWithSize(3, 3, MatTypeCV64F)
|
|
defer k.Close()
|
|
|
|
k.SetDoubleAt(0, 0, 1094.7249578198823)
|
|
k.SetDoubleAt(0, 1, 0)
|
|
k.SetDoubleAt(0, 2, 959.4907612030962)
|
|
|
|
k.SetDoubleAt(1, 0, 0)
|
|
k.SetDoubleAt(1, 1, 1094.9945708128778)
|
|
k.SetDoubleAt(1, 2, 536.4566143451868)
|
|
|
|
k.SetDoubleAt(2, 0, 0)
|
|
k.SetDoubleAt(2, 1, 0)
|
|
k.SetDoubleAt(2, 2, 1)
|
|
|
|
d := NewMatWithSize(1, 4, MatTypeCV64F)
|
|
defer d.Close()
|
|
|
|
d.SetDoubleAt(0, 0, -0.05207412392075069)
|
|
d.SetDoubleAt(0, 1, -0.089168300192224)
|
|
d.SetDoubleAt(0, 2, 0.10465607695792184)
|
|
d.SetDoubleAt(0, 3, -0.045693446831115585)
|
|
|
|
r := NewMat()
|
|
defer r.Close()
|
|
|
|
// transform 3 points in one go
|
|
src := NewMatWithSize(3, 1, MatTypeCV64FC2)
|
|
defer src.Close()
|
|
dst := NewMatWithSize(3, 1, MatTypeCV64FC2)
|
|
defer dst.Close()
|
|
|
|
// This camera matrix is 1920x1080. Points where x < 960 and y < 540 should move toward the top left (x and y get smaller)
|
|
// The centre point should be mostly unchanged
|
|
// Points where x > 960 and y > 540 should move toward the bottom right (x and y get bigger)
|
|
|
|
// The index being used for col here is actually the channel (i.e. the point's x/y dimensions)
|
|
// (since there's only 1 column so the formula: (colNumber * numChannels + channelNumber) reduces to
|
|
// (0 * 2) + channelNumber
|
|
// so col = 0 is the x coordinate and col = 1 is the y coordinate
|
|
|
|
src.SetDoubleAt(0, 0, 480)
|
|
src.SetDoubleAt(0, 1, 270)
|
|
|
|
src.SetDoubleAt(1, 0, 960)
|
|
src.SetDoubleAt(1, 1, 540)
|
|
|
|
src.SetDoubleAt(2, 0, 1920)
|
|
src.SetDoubleAt(2, 1, 1080)
|
|
|
|
UndistortPoints(src, &dst, k, d, r, k)
|
|
|
|
if dst.GetDoubleAt(0, 0) >= 480 || dst.GetDoubleAt(0, 1) >= 270 {
|
|
t.Error("undistortion expected top left point to move further up and left")
|
|
return
|
|
}
|
|
|
|
if math.Round(dst.GetDoubleAt(1, 0)) != 960 || math.Round(dst.GetDoubleAt(1, 1)) != 540 {
|
|
t.Error("undistortion expected centre point to be nearly unchanged")
|
|
return
|
|
}
|
|
|
|
if dst.GetDoubleAt(2, 0) != 1920 || dst.GetDoubleAt(2, 1) != 1080 {
|
|
t.Error("undistortion expected bottom right corner to be unchanged")
|
|
return
|
|
}
|
|
|
|
}
|
|
|
|
func TestFisheyeUndistortPoint(t *testing.T) {
|
|
k := NewMatWithSize(3, 3, MatTypeCV64F)
|
|
defer k.Close()
|
|
|
|
k.SetDoubleAt(0, 0, 1094.7249578198823)
|
|
k.SetDoubleAt(0, 1, 0)
|
|
k.SetDoubleAt(0, 2, 959.4907612030962)
|
|
|
|
k.SetDoubleAt(1, 0, 0)
|
|
k.SetDoubleAt(1, 1, 1094.9945708128778)
|
|
k.SetDoubleAt(1, 2, 536.4566143451868)
|
|
|
|
k.SetDoubleAt(2, 0, 0)
|
|
k.SetDoubleAt(2, 1, 0)
|
|
k.SetDoubleAt(2, 2, 1)
|
|
|
|
d := NewMatWithSize(1, 4, MatTypeCV64F)
|
|
defer d.Close()
|
|
|
|
d.SetDoubleAt(0, 0, -0.05207412392075069)
|
|
d.SetDoubleAt(0, 1, -0.089168300192224)
|
|
d.SetDoubleAt(0, 2, 0.10465607695792184)
|
|
d.SetDoubleAt(0, 3, -0.045693446831115585)
|
|
|
|
r := NewMat()
|
|
defer r.Close()
|
|
|
|
// transform 3 points in one go (X and Y values of points go in each channel)
|
|
src := NewMatWithSize(3, 1, MatTypeCV64FC2)
|
|
defer src.Close()
|
|
dst := NewMatWithSize(3, 1, MatTypeCV64FC2)
|
|
defer dst.Close()
|
|
|
|
// This camera matrix is 1920x1080. Points where x < 960 and y < 540 should move toward the top left (x and y get smaller)
|
|
// The centre point should be mostly unchanged
|
|
// Points where x > 960 and y > 540 should move toward the bottom right (x and y get bigger)
|
|
|
|
// The index being used for col here is actually the channel (i.e. the point's x/y dimensions)
|
|
// (since there's only 1 column so the formula: (colNumber * numChannels + channelNumber) reduces to
|
|
// (0 * 2) + channelNumber
|
|
// so col = 0 is the x coordinate and col = 1 is the y coordinate
|
|
|
|
src.SetDoubleAt(0, 0, 480)
|
|
src.SetDoubleAt(0, 1, 270)
|
|
|
|
src.SetDoubleAt(1, 0, 960)
|
|
src.SetDoubleAt(1, 1, 540)
|
|
|
|
src.SetDoubleAt(2, 0, 1440)
|
|
src.SetDoubleAt(2, 1, 810)
|
|
|
|
kNew := NewMat()
|
|
defer kNew.Close()
|
|
|
|
k.CopyTo(&kNew)
|
|
|
|
kNew.SetDoubleAt(0, 0, 0.4*k.GetDoubleAt(0, 0))
|
|
kNew.SetDoubleAt(1, 1, 0.4*k.GetDoubleAt(1, 1))
|
|
|
|
imgSize := image.Point{X: 1920, Y: 1080}
|
|
|
|
EstimateNewCameraMatrixForUndistortRectify(k, d, imgSize, r, &kNew, 1, imgSize, 1)
|
|
|
|
FisheyeUndistortPoints(src, &dst, k, d, r, kNew)
|
|
|
|
if dst.GetDoubleAt(0, 0) == 0 {
|
|
t.Error("expected destination Mat to be populated")
|
|
}
|
|
}
|
|
|
|
func TestCheckChessboard(t *testing.T) {
|
|
img := IMRead("images/chessboard_4x6.png", IMReadGrayScale)
|
|
if img.Empty() {
|
|
t.Error("Invalid read of chessboard image")
|
|
return
|
|
}
|
|
defer img.Close()
|
|
|
|
if !CheckChessboard(img, image.Point{X: 4, Y: 6}) {
|
|
t.Error("chessboard pattern not found")
|
|
return
|
|
}
|
|
}
|
|
|
|
func TestFindAndDrawChessboard(t *testing.T) {
|
|
img := IMRead("images/chessboard_4x6.png", IMReadUnchanged)
|
|
if img.Empty() {
|
|
t.Error("Invalid read of chessboard image")
|
|
return
|
|
}
|
|
defer img.Close()
|
|
|
|
corners := NewMat()
|
|
defer corners.Close()
|
|
|
|
found := FindChessboardCorners(img, image.Point{X: 4, Y: 6}, &corners, 0)
|
|
if found == false {
|
|
t.Error("chessboard pattern not found")
|
|
return
|
|
}
|
|
if corners.Empty() {
|
|
t.Error("chessboard pattern not found")
|
|
return
|
|
}
|
|
|
|
img2 := NewMatWithSize(150, 150, MatTypeCV8U)
|
|
defer img2.Close()
|
|
|
|
DrawChessboardCorners(&img2, image.Pt(4, 6), corners, true)
|
|
if img2.Empty() {
|
|
t.Error("Error in DrawChessboardCorners test")
|
|
}
|
|
}
|
|
|
|
func TestFindAndDrawChessboardSB(t *testing.T) {
|
|
img := IMRead("images/chessboard_4x6.png", IMReadUnchanged)
|
|
if img.Empty() {
|
|
t.Error("Invalid read of chessboard image")
|
|
return
|
|
}
|
|
defer img.Close()
|
|
|
|
corners := NewMat()
|
|
defer corners.Close()
|
|
|
|
found := FindChessboardCornersSB(img, image.Point{X: 4, Y: 6}, &corners, 0)
|
|
if found == false {
|
|
t.Error("chessboard pattern not found")
|
|
return
|
|
}
|
|
if corners.Empty() {
|
|
t.Error("chessboard pattern not found")
|
|
return
|
|
}
|
|
|
|
img2 := NewMatWithSize(150, 150, MatTypeCV8U)
|
|
defer img2.Close()
|
|
|
|
DrawChessboardCorners(&img2, image.Pt(4, 6), corners, true)
|
|
if img2.Empty() {
|
|
t.Error("Error in DrawChessboardCorners test")
|
|
}
|
|
}
|
|
|
|
func TestFindChessboardCornersSBWithMeta(t *testing.T) {
|
|
img := IMRead("images/chessboard_4x6.png", IMReadUnchanged)
|
|
if img.Empty() {
|
|
t.Error("Invalid read of chessboard image")
|
|
return
|
|
}
|
|
defer img.Close()
|
|
|
|
corners := NewMat()
|
|
defer corners.Close()
|
|
|
|
meta := NewMat()
|
|
defer meta.Close()
|
|
|
|
found := FindChessboardCornersSBWithMeta(img, image.Point{X: 4, Y: 6}, &corners, 0, &meta)
|
|
if found == false {
|
|
t.Error("chessboard pattern not found")
|
|
return
|
|
}
|
|
if corners.Empty() {
|
|
t.Error("chessboard pattern not found")
|
|
return
|
|
}
|
|
|
|
img2 := NewMatWithSize(150, 150, MatTypeCV8U)
|
|
defer img2.Close()
|
|
|
|
DrawChessboardCorners(&img2, image.Pt(4, 6), corners, true)
|
|
if img2.Empty() {
|
|
t.Error("Error in DrawChessboardCorners test")
|
|
}
|
|
}
|
|
|
|
func TestCalibrateCamera(t *testing.T) {
|
|
img := IMRead("images/chessboard_4x6_distort.png", IMReadGrayScale)
|
|
if img.Empty() {
|
|
t.Error("Invalid read of chessboard image")
|
|
return
|
|
}
|
|
defer img.Close()
|
|
|
|
corners := NewMat()
|
|
defer corners.Close()
|
|
|
|
size := image.Pt(4, 6)
|
|
found := FindChessboardCorners(img, size, &corners, 0)
|
|
if !found {
|
|
t.Error("chessboard pattern not found")
|
|
return
|
|
}
|
|
if corners.Empty() {
|
|
t.Error("chessboard pattern not found")
|
|
return
|
|
}
|
|
|
|
imagePoints := NewPoint2fVectorFromMat(corners)
|
|
defer imagePoints.Close()
|
|
|
|
objectPoints := NewPoint3fVector()
|
|
defer objectPoints.Close()
|
|
|
|
for j := 0; j < size.Y; j++ {
|
|
for i := 0; i < size.X; i++ {
|
|
objectPoints.Append(Point3f{
|
|
X: float32(100 * i),
|
|
Y: float32(100 * j),
|
|
Z: 0,
|
|
})
|
|
}
|
|
}
|
|
|
|
cameraMatrix := NewMat()
|
|
defer cameraMatrix.Close()
|
|
distCoeffs := NewMat()
|
|
defer distCoeffs.Close()
|
|
rvecs := NewMat()
|
|
defer rvecs.Close()
|
|
tvecs := NewMat()
|
|
defer tvecs.Close()
|
|
|
|
objectPointsVector := NewPoints3fVector()
|
|
objectPointsVector.Append(objectPoints)
|
|
defer objectPointsVector.Close()
|
|
|
|
imagePointsVector := NewPoints2fVector()
|
|
imagePointsVector.Append(imagePoints)
|
|
defer imagePointsVector.Close()
|
|
|
|
CalibrateCamera(
|
|
objectPointsVector, imagePointsVector, image.Pt(img.Cols(), img.Rows()),
|
|
&cameraMatrix, &distCoeffs, &rvecs, &tvecs, 0,
|
|
)
|
|
|
|
dest := NewMat()
|
|
defer dest.Close()
|
|
Undistort(img, &dest, cameraMatrix, distCoeffs, cameraMatrix)
|
|
|
|
target := IMRead("images/chessboard_4x6_distort_correct.png", IMReadGrayScale)
|
|
defer target.Close()
|
|
|
|
xor := NewMat()
|
|
defer xor.Close()
|
|
|
|
// The method for compare is ugly : different pix number < 0.5%
|
|
BitwiseXor(dest, target, &xor)
|
|
differentPixelsNumber := xor.Sum().Val1
|
|
maxDifferentPixelsNumber := float64(img.Cols()*img.Rows()) * 0.005
|
|
if differentPixelsNumber > maxDifferentPixelsNumber {
|
|
t.Error("the undisorted image not equal the target one:", differentPixelsNumber, "bigger than", maxDifferentPixelsNumber)
|
|
}
|
|
}
|
|
|
|
func TestEstimateAffinePartial2D(t *testing.T) {
|
|
src := []Point2f{
|
|
{0, 0},
|
|
{10, 5},
|
|
{10, 10},
|
|
{5, 10},
|
|
}
|
|
|
|
dst := []Point2f{
|
|
{0, 0},
|
|
{10, 0},
|
|
{10, 10},
|
|
{0, 10},
|
|
}
|
|
|
|
pvsrc := NewPoint2fVectorFromPoints(src)
|
|
defer pvsrc.Close()
|
|
|
|
pvdst := NewPoint2fVectorFromPoints(dst)
|
|
defer pvdst.Close()
|
|
|
|
m := EstimateAffinePartial2D(pvsrc, pvdst)
|
|
defer m.Close()
|
|
|
|
if m.Cols() != 3 {
|
|
t.Errorf("TestEstimateAffinePartial2D(): unexpected cols = %v, want = %v", m.Cols(), 3)
|
|
}
|
|
if m.Rows() != 2 {
|
|
t.Errorf("TestEstimateAffinePartial2D(): unexpected rows = %v, want = %v", m.Rows(), 2)
|
|
}
|
|
}
|
|
|
|
func TestEstimateAffinePartial2DWithParams(t *testing.T) {
|
|
src := []Point2f{
|
|
{0, 0},
|
|
{10, 5},
|
|
{10, 10},
|
|
{5, 10},
|
|
}
|
|
|
|
dst := []Point2f{
|
|
{0, 0},
|
|
{10, 0},
|
|
{10, 10},
|
|
{0, 10},
|
|
}
|
|
|
|
pvsrc := NewPoint2fVectorFromPoints(src)
|
|
defer pvsrc.Close()
|
|
|
|
pvdst := NewPoint2fVectorFromPoints(dst)
|
|
defer pvdst.Close()
|
|
|
|
inliers := NewMat()
|
|
defer inliers.Close()
|
|
method := 8
|
|
ransacProjThreshold := 3.0
|
|
maxiters := uint(2000)
|
|
confidence := 0.99
|
|
refineIters := uint(10)
|
|
|
|
m := EstimateAffinePartial2DWithParams(pvsrc, pvdst, inliers, method, ransacProjThreshold, maxiters, confidence, refineIters)
|
|
defer m.Close()
|
|
|
|
if m.Cols() != 3 {
|
|
t.Errorf("TestEstimateAffinePartial2D(): unexpected cols = %v, want = %v", m.Cols(), 3)
|
|
}
|
|
if m.Rows() != 2 {
|
|
t.Errorf("TestEstimateAffinePartial2D(): unexpected rows = %v, want = %v", m.Rows(), 2)
|
|
}
|
|
}
|
|
|
|
func TestEstimateAffine2D(t *testing.T) {
|
|
src := []Point2f{
|
|
{0, 0},
|
|
{10, 5},
|
|
{10, 10},
|
|
{5, 10},
|
|
}
|
|
|
|
dst := []Point2f{
|
|
{0, 0},
|
|
{10, 0},
|
|
{10, 10},
|
|
{0, 10},
|
|
}
|
|
|
|
pvsrc := NewPoint2fVectorFromPoints(src)
|
|
defer pvsrc.Close()
|
|
|
|
pvdst := NewPoint2fVectorFromPoints(dst)
|
|
defer pvdst.Close()
|
|
|
|
m := EstimateAffine2D(pvsrc, pvdst)
|
|
defer m.Close()
|
|
|
|
if m.Cols() != 3 {
|
|
t.Errorf("TestEstimateAffine2D(): unexpected cols = %v, want = %v", m.Cols(), 3)
|
|
}
|
|
if m.Rows() != 2 {
|
|
t.Errorf("TestEstimateAffine2D(): unexpected rows = %v, want = %v", m.Rows(), 2)
|
|
}
|
|
}
|
|
|
|
func TestEstimateAffine2DWithParams(t *testing.T) {
|
|
src := []Point2f{
|
|
{0, 0},
|
|
{10, 5},
|
|
{10, 10},
|
|
{5, 10},
|
|
}
|
|
|
|
dst := []Point2f{
|
|
{0, 0},
|
|
{10, 0},
|
|
{10, 10},
|
|
{0, 10},
|
|
}
|
|
|
|
pvsrc := NewPoint2fVectorFromPoints(src)
|
|
defer pvsrc.Close()
|
|
|
|
pvdst := NewPoint2fVectorFromPoints(dst)
|
|
defer pvdst.Close()
|
|
|
|
inliers := NewMat()
|
|
defer inliers.Close()
|
|
method := 8
|
|
ransacProjThreshold := 3.0
|
|
maxiters := uint(2000)
|
|
confidence := 0.99
|
|
refineIters := uint(10)
|
|
|
|
m := EstimateAffine2DWithParams(pvsrc, pvdst, inliers, method, ransacProjThreshold, maxiters, confidence, refineIters)
|
|
defer m.Close()
|
|
|
|
if m.Cols() != 3 {
|
|
t.Errorf("TestEstimateAffine2DWithParams(): unexpected cols = %v, want = %v", m.Cols(), 3)
|
|
}
|
|
if m.Rows() != 2 {
|
|
t.Errorf("TestEstimateAffine2DWithParams(): unexpected rows = %v, want = %v", m.Rows(), 2)
|
|
}
|
|
}
|
|
|
|
func TestTriangulatePoints(t *testing.T) {
|
|
projMat1, projMat2 := NewMatWithSize(3, 4, MatTypeCV64F), NewMatWithSize(3, 4, MatTypeCV64F)
|
|
defer projMat1.Close()
|
|
defer projMat2.Close()
|
|
projPoints1, projPoints2 := NewPoint2fVectorFromPoints([]Point2f{{Y: 1.0, X: 2.0}}), NewPoint2fVectorFromPoints([]Point2f{{Y: 3.0, X: 4.0}})
|
|
defer projPoints1.Close()
|
|
defer projPoints2.Close()
|
|
homogeneous := NewMat()
|
|
defer homogeneous.Close()
|
|
TriangulatePoints(projMat1, projMat2, projPoints1, projPoints2, &homogeneous)
|
|
if homogeneous.Empty() {
|
|
t.Errorf("TriangulatePoints(): output homogeneous mat is empty")
|
|
}
|
|
}
|
|
|
|
func TestConvertPointsFromHomogeneous(t *testing.T) {
|
|
homogeneous := NewMatWithSize(1, 4, MatTypeCV32F)
|
|
defer homogeneous.Close()
|
|
homogeneous.SetFloatAt(0, 0, 1)
|
|
homogeneous.SetFloatAt(0, 1, 2)
|
|
homogeneous.SetFloatAt(0, 2, 4)
|
|
homogeneous.SetFloatAt(0, 3, 2)
|
|
euclidean := NewMat()
|
|
defer euclidean.Close()
|
|
ConvertPointsFromHomogeneous(homogeneous, &euclidean)
|
|
if euclidean.Empty() {
|
|
t.Fatalf("ConvertPointsFromHomogeneous(): output euclidean mat is empty")
|
|
}
|
|
ptsVector := NewPoint3fVectorFromMat(euclidean)
|
|
defer ptsVector.Close()
|
|
pts := ptsVector.ToPoints()
|
|
if len(pts) != 1 {
|
|
t.Fatalf("ConvertPointsFromHomogeneous(): euclidean mat converted to points is empty")
|
|
}
|
|
if pts[0].X != 0.5 {
|
|
t.Errorf("ConvertPointsFromHomogeneous(): euclidean X - got %v, want %v", pts[0].X, 0.5)
|
|
}
|
|
if pts[0].Y != 1 {
|
|
t.Errorf("ConvertPointsFromHomogeneous(): euclidean Y - got %v, want %v", pts[0].Y, 1)
|
|
}
|
|
if pts[0].Z != 2 {
|
|
t.Errorf("ConvertPointsFromHomogeneous(): euclidean Z - got %v, want %v", pts[0].Z, 2)
|
|
}
|
|
}
|
|
|
|
func TestRodrigues(t *testing.T) {
|
|
k := NewMatWithSize(3, 3, MatTypeCV64F)
|
|
defer k.Close()
|
|
|
|
k.SetDoubleAt(0, 0, 689.21)
|
|
k.SetDoubleAt(0, 1, 0)
|
|
k.SetDoubleAt(0, 2, 1295.56)
|
|
|
|
k.SetDoubleAt(1, 0, 0)
|
|
k.SetDoubleAt(1, 1, 690.48)
|
|
k.SetDoubleAt(1, 2, 942.17)
|
|
|
|
k.SetDoubleAt(2, 0, 0)
|
|
k.SetDoubleAt(2, 1, 0)
|
|
k.SetDoubleAt(2, 2, 1)
|
|
|
|
dest := NewMat()
|
|
defer dest.Close()
|
|
|
|
Rodrigues(k, &dest)
|
|
|
|
if dest.Empty() {
|
|
t.Error("final result is empty")
|
|
return
|
|
}
|
|
}
|
|
|
|
func TestSolvePnP(t *testing.T) {
|
|
pts := []Point3f{
|
|
{10.0, 10.0, 0.1},
|
|
{10.0, 20.0, 1.0},
|
|
{20.5, 21.5, 2.0},
|
|
{10.0, 20.0, 1.0},
|
|
}
|
|
|
|
objectPointsVector := NewPoint3fVectorFromPoints(pts)
|
|
defer objectPointsVector.Close()
|
|
|
|
pts2 := []Point2f{
|
|
{10.0, 10.0},
|
|
{10.0, 20.0},
|
|
{20.5, 21.5},
|
|
{25.5, 30.5},
|
|
}
|
|
|
|
imagePointsVector := NewPoint2fVectorFromPoints(pts2)
|
|
defer imagePointsVector.Close()
|
|
|
|
cameraMatrix := Eye(3, 3, MatTypeCV64F)
|
|
defer cameraMatrix.Close()
|
|
distCoeffs := NewMat()
|
|
defer distCoeffs.Close()
|
|
rvecs := NewMat()
|
|
defer rvecs.Close()
|
|
tvecs := NewMat()
|
|
defer tvecs.Close()
|
|
|
|
SolvePnP(objectPointsVector, imagePointsVector, cameraMatrix, distCoeffs,
|
|
&rvecs, &tvecs, false, 0)
|
|
|
|
if rvecs.Empty() {
|
|
t.Error("rvecs result is empty")
|
|
return
|
|
}
|
|
|
|
if tvecs.Empty() {
|
|
t.Error("tvecs result is empty")
|
|
return
|
|
}
|
|
}
|
|
|
|
func TestStereoRectify(t *testing.T) {
|
|
cameraMatrix1 := NewMatWithSize(3, 3, MatTypeCV64F)
|
|
defer cameraMatrix1.Close()
|
|
cameraMatrix1.SetDoubleAt(0, 0, 1679.861998224759)
|
|
cameraMatrix1.SetDoubleAt(0, 1, 0)
|
|
cameraMatrix1.SetDoubleAt(0, 2, 1231.158426771668)
|
|
cameraMatrix1.SetDoubleAt(1, 0, 0)
|
|
cameraMatrix1.SetDoubleAt(1, 1, 1679.6751024982132)
|
|
cameraMatrix1.SetDoubleAt(1, 2, 998.4768157307255)
|
|
cameraMatrix1.SetDoubleAt(2, 0, 0)
|
|
cameraMatrix1.SetDoubleAt(2, 1, 0)
|
|
cameraMatrix1.SetDoubleAt(2, 2, 1)
|
|
|
|
distCoeffs1 := NewMatWithSize(1, 5, MatTypeCV64F)
|
|
defer distCoeffs1.Close()
|
|
distCoeffs1.SetDoubleAt(0, 0, -0.13657891044008158)
|
|
distCoeffs1.SetDoubleAt(0, 1, 0.08861314898314139)
|
|
distCoeffs1.SetDoubleAt(0, 2, -0.0006100429198910993)
|
|
distCoeffs1.SetDoubleAt(0, 3, -0.000146035714553745)
|
|
distCoeffs1.SetDoubleAt(0, 4, -0.0223854079208295)
|
|
|
|
cameraMatrix2 := NewMatWithSize(3, 3, MatTypeCV64F)
|
|
defer cameraMatrix2.Close()
|
|
cameraMatrix2.SetDoubleAt(0, 0, 1678.7797594660801)
|
|
cameraMatrix2.SetDoubleAt(0, 1, 0)
|
|
cameraMatrix2.SetDoubleAt(0, 2, 1233.9647439048256)
|
|
cameraMatrix2.SetDoubleAt(1, 0, 0)
|
|
cameraMatrix2.SetDoubleAt(1, 1, 1679.0176277206788)
|
|
cameraMatrix2.SetDoubleAt(1, 2, 964.4565768594671)
|
|
cameraMatrix2.SetDoubleAt(2, 0, 0)
|
|
cameraMatrix2.SetDoubleAt(2, 1, 0)
|
|
cameraMatrix2.SetDoubleAt(2, 2, 1)
|
|
|
|
distCoeffs2 := NewMatWithSize(1, 5, MatTypeCV64F)
|
|
defer distCoeffs2.Close()
|
|
distCoeffs2.SetDoubleAt(0, 0, -0.13690489442431938)
|
|
distCoeffs2.SetDoubleAt(0, 1, 0.08705821688253863)
|
|
distCoeffs2.SetDoubleAt(0, 2, 0.001288895752441417)
|
|
distCoeffs2.SetDoubleAt(0, 3, -5.508164903909865e-05)
|
|
distCoeffs2.SetDoubleAt(0, 4, -0.02092107478701842)
|
|
|
|
R := NewMatWithSize(3, 3, MatTypeCV64F)
|
|
defer R.Close()
|
|
R.SetDoubleAt(0, 0, 0.9978384271270464)
|
|
R.SetDoubleAt(0, 1, 0.06567174227009016)
|
|
R.SetDoubleAt(0, 2, -0.0023865489378896566)
|
|
R.SetDoubleAt(1, 0, -0.06567842187628788)
|
|
R.SetDoubleAt(1, 1, 0.9978368073955511)
|
|
R.SetDoubleAt(1, 2, -0.002837376692327134)
|
|
R.SetDoubleAt(2, 0, 0.0021950509020153912)
|
|
R.SetDoubleAt(2, 1, 0.0029879882638097722)
|
|
R.SetDoubleAt(2, 2, 0.9999931268152161)
|
|
|
|
T := NewMatWithSize(3, 1, MatTypeCV64F)
|
|
defer T.Close()
|
|
T.SetDoubleAt(0, 0, -0.1600062730246643)
|
|
T.SetDoubleAt(1, 0, 0.007804854680409705)
|
|
T.SetDoubleAt(2, 0, 9.242933249524358e-05)
|
|
|
|
R1 := NewMat()
|
|
defer R1.Close()
|
|
R2 := NewMat()
|
|
defer R2.Close()
|
|
P1 := NewMat()
|
|
defer P1.Close()
|
|
P2 := NewMat()
|
|
defer P2.Close()
|
|
Q := NewMat()
|
|
defer Q.Close()
|
|
|
|
imageSize := image.Point{X: 2448, Y: 2048}
|
|
err := StereoRectify(cameraMatrix1, distCoeffs1, cameraMatrix2, distCoeffs2, imageSize, R, T, &R1, &R2, &P1, &P2, &Q, CalibFlagPinholeZeroDisparity)
|
|
if err != nil {
|
|
t.Errorf("StereoRectify failed: %v", err)
|
|
}
|
|
|
|
if R1.Empty() {
|
|
t.Error("R1 result is empty")
|
|
}
|
|
if R2.Empty() {
|
|
t.Error("R2 result is empty")
|
|
}
|
|
if P1.Empty() {
|
|
t.Error("P1 result is empty")
|
|
}
|
|
if P2.Empty() {
|
|
t.Error("P2 result is empty")
|
|
}
|
|
if Q.Empty() {
|
|
t.Error("Q result is empty")
|
|
}
|
|
}
|
|
|
|
func TestFindHomography(t *testing.T) {
|
|
src := NewMatWithSize(4, 1, MatTypeCV64FC2)
|
|
defer src.Close()
|
|
target := NewMatWithSize(4, 1, MatTypeCV64FC2)
|
|
defer target.Close()
|
|
|
|
srcPoints := []Point2f{
|
|
{193, 932},
|
|
{191, 378},
|
|
{1497, 183},
|
|
{1889, 681},
|
|
}
|
|
targetPoints := []Point2f{
|
|
{51.51206544281359, -0.10425475260813055},
|
|
{51.51211051314331, -0.10437947532732306},
|
|
{51.512222354139325, -0.10437679311830816},
|
|
{51.51214828037607, -0.1042212249954444},
|
|
}
|
|
|
|
for i, point := range srcPoints {
|
|
src.SetDoubleAt(i, 0, float64(point.X))
|
|
src.SetDoubleAt(i, 1, float64(point.Y))
|
|
}
|
|
|
|
for i, point := range targetPoints {
|
|
target.SetDoubleAt(i, 0, float64(point.X))
|
|
target.SetDoubleAt(i, 1, float64(point.Y))
|
|
}
|
|
|
|
mask := NewMat()
|
|
defer mask.Close()
|
|
|
|
m := FindHomography(src, target, HomographyMethodAllPoints, 3, &mask, 2000, 0.995)
|
|
defer m.Close()
|
|
|
|
pvsrc := NewPoint2fVectorFromPoints(srcPoints)
|
|
defer pvsrc.Close()
|
|
|
|
pvdst := NewPoint2fVectorFromPoints(targetPoints)
|
|
defer pvdst.Close()
|
|
|
|
m2 := GetPerspectiveTransform2f(pvsrc, pvdst)
|
|
defer m2.Close()
|
|
|
|
for row := 0; row < 3; row++ {
|
|
for col := 0; col < 3; col++ {
|
|
if math.Abs(m.GetDoubleAt(row, col)-m2.GetDoubleAt(row, col)) > 0.002 {
|
|
t.Errorf("expected little difference between GetPerspectiveTransform2f and FindHomography results, got %f for row %d col %d", math.Abs(m.GetDoubleAt(row, col)-m2.GetDoubleAt(row, col)), row, col)
|
|
}
|
|
}
|
|
}
|
|
}
|