1// CalibCamera 标定相机
2func CalibCamera(imgDatas [][]byte, chessboardRowCornerCount int, chessboardColCornerCount int, curImageIndex int) error {
3 // 保存各图像中的角点的二维坐标, 即像素坐标
4 imgPoints := gocv.NewPoints2fVector()
5 defer imgPoints.Close()
6 // 保存各图像中的角点的三维坐标,即世界坐标
7 objPoints := gocv.NewPoints3fVector()
8 defer objPoints.Close()
9 // 保存图片尺寸
10 imgSize := image.Point{X: 0, Y: 0}
11
12 // 为三维点定义世界坐标系
13 objectPoints := make([]gocv.Point3f, 0)
14 for i := 0; i < chessboardColCornerCount; i++ {
15 for j := 0; j < chessboardRowCornerCount; j++ {
16 objectPoints = append(objectPoints, gocv.Point3f{X: float32(j), Y: float32(i), Z: 0})
17 }
18 }
19 objPointsVector := gocv.NewPoint3fVectorFromPoints(objectPoints)
20 defer objPointsVector.Close()
21
22 // 1. 检测角点
23 for index, imgData := range imgDatas {
24 err := func() error {
25 // 读取为灰度图
26 grayImg, err := gocv.IMDecode(imgData, gocv.IMReadGrayScale)
27 if err != nil {
28 return err
29 }
30 if grayImg.Empty() {
31 return nil
32 }
33 defer grayImg.Close()
34 if index == 0 {
35 imgSize = image.Point{X: grayImg.Cols(), Y: grayImg.Rows()}
36 }
37 // 保存图像二维角点信息
38 corners := gocv.NewMat()
39 defer corners.Close()
40 // 如果在图像中找到所需数量的角点,返回true
41 if found := gocv.FindChessboardCorners(grayImg, image.Pt(chessboardRowCornerCount, chessboardColCornerCount), &corners, gocv.CalibCBAdaptiveThresh|gocv.CalibCBFastCheck|gocv.CalibCBNormalizeImage); !found {
42 return errors.New("Not Found Corner Points")
43 }
44 // 迭代算法中的终止条件(终止条件的类型、最大迭代次数、期望精度)
45 criteria := gocv.NewTermCriteria(gocv.EPS|gocv.MaxIter, 30, 0.01)
46 // 进一步提取亚像素角点,提高精度
47 gocv.CornerSubPix(grayImg, &corners, image.Pt(11, 11), image.Pt(-1, -1), criteria)
48 if corners.Cols()*corners.Rows() != chessboardColCornerCount*chessboardRowCornerCount {
49 return errors.Newr("Not Matched Number Of Corner Points")
50 }
51 imagePoints := make([]gocv.Point2f, 0)
52 // 注意corners矩阵只有一列,例如9*6的角点实际上是一个54*1的矩阵,因此不能在这里一起添加世界坐标
53 for i := 0; i < corners.Rows(); i++ {
54 for j := 0; j < corners.Cols(); j++ {
55 pixelX, pixelY := corners.GetFloatAt(i, j*2), corners.GetFloatAt(i, j*2+1)
56 imagePoints = append(imagePoints, gocv.Point2f{X: pixelX, Y: pixelY})
57 }
58 }
59 // 添加像素坐标
60 imgPointsVector := gocv.NewPoint2fVectorFromPoints(imagePoints)
61 imgPoints.Append(imgPointsVector)
62 imgPointsVector.Close()
63 // 添加世界坐标
64 objPoints.Append(objPointsVector)
65 return nil
66 }()
67 if err != nil {
68 return err
69 }
70 }
71
72 // 2. 标定
73 // 每幅图像的平移向量
74 transMat := gocv.NewMat()
75 defer transMat.Close()
76 // 每幅图像的旋转向量
77 rotMat := gocv.NewMat()
78 defer rotMat.Close()
79 // 相机内参矩阵 3*3
80 cameraMatrix := gocv.NewMatWithSize(3, 3, gocv.MatTypeCV32F)
81 defer cameraMatrix.Close()
82 // 相机的5个畸变系数:k1,k2,p1,p2,k3 1*5
83 distCoeffs := gocv.NewMat()
84 defer distCoeffs.Close()
85 res := gocv.CalibrateCamera(objPoints, imgPoints, imgSize, &cameraMatrix, &distCoeffs, &rotMat, &transMat, gocv.CalibFlag(0))
86
87 // 3. 保存标定结果
88 // 获取校正后的新相机矩阵
89 newCameramtx, _ := gocv.GetOptimalNewCameraMatrixWithParams(cameraMatrix, distCoeffs, imgSize, 1, imgSize, false)
90 defer newCameramtx.Close()
91}
Inspired by
[1] 相机畸变与标定