Android通过OpenCV实现相机标定

在 Android 中使用 OpenCV 实现相机标定,你可以按照以下步骤进行操作:

  1. 首先,确保你已经在项目中引入了 OpenCV 库的依赖。

  2. 创建一个 CameraCalibrator 类,用于执行相机标定。

     import org.opencv.calib3d.Calib3d
     import org.opencv.core.CvType.CV_32F
     import org.opencv.core.CvType.CV_64F
     import org.opencv.core.Mat
     import org.opencv.core.MatOfPoint2f
     import org.opencv.core.MatOfPoint3f
     import org.opencv.core.Size
     
    
     class CameraCalibrator {
         private val objectPoints = ArrayList()
         private val imagePoints = ArrayList()
         private var imageSize = Size()
         var cameraMatrix = Mat(3, 3, CV_64F)
         private var distortionCoefficients = Mat(5, 1, CV_64F)
         // 添加一组图像点和对应的物理世界点
         fun addObjectPoint(objectPoint: Mat) {
             objectPoints.add(objectPoint)
         }
     
         fun addImagePoint(imagePoint: Mat) {
             imagePoints.add(imagePoint)
         }
          执行相机标定
         fun calibrate(): Mat? {
             val rotationVectors = ArrayList()
             val translationVectors = ArrayList()
             val rms = Calib3d.calibrateCamera(
                 objectPoints,
                 imagePoints,
                 imageSize,
                 cameraMatrix,
                 distortionCoefficients,
                 rotationVectors,
                 translationVectors
             )
     
             if (rms < 1.0) {
                 return cameraMatrix
             }
     
             return null
         }
          // 获取相机矩阵
         fun getCameraMatrix(): Mat {
             return cameraMatrix
         }
    
     	 // 获取畸变系数
         fun getDistortionCoefficients(): Mat {
             return distortionCoefficients
         }
     
         fun setImageSize(width: Int, height: Int) {
             imageSize = Size(width.toDouble(), height.toDouble())
         }
     }
    
  3. 通过Camera2获取到帧数据后转成灰度图Mat,创建一个 CameraCalibrator 对象,添加物理世界点和图像点

     fun startCalib(){
     	calibrator = CameraCalibrator()
         GlobalScope.launch(Dispatchers.IO) {
                 var grayMat = Mat(CameraUtil.cameraH, CameraUtil.cameraW, CvType.CV_8UC1);
                 grayMat.put(0,0,data)
                 addPoint(grayMat)
         }
     }
    
     fun addPoint(grayImage:Mat){
         Log.i(TAG,"addPointstart")
         val corners = MatOfPoint2f()
         val patternSize = Size(11.0, 8.0) // 棋盘格的内角点数目
         val found = Calib3d.findChessboardCorners(
             grayImage, patternSize, corners,
             Calib3d.CALIB_CB_ADAPTIVE_THRESH or Calib3d.CALIB_CB_NORMALIZE_IMAGE
         )
         if (found) {
             Log.i(TAG,"addPointend found")
             // 添加图像点和物理世界点
             val objectPoints = MatOfPoint3f()
             for (i in 0 until patternSize.height.toInt()) {
                 for (j in 0 until patternSize.width.toInt()) {
                     objectPoints.push_back(MatOfPoint3f(Point3(j.toDouble(), i.toDouble(), 0.0)))
                 }
             }
             calibrator?.addObjectPoint(objectPoints)
             calibrator?.addImagePoint(corners)
         }
         Log.i(TAG,"addPointend")
         stopCabin()
     }
    
  4. 执行相机标定,并获取相机矩阵和畸变系数

     fun stopCabin(){
             Log.i(TAG,"stopCabin")
             calibrator?.setImageSize(1920, 1080)
             val cameraMatrix = calibrator?.calibrate()
             val distortionCoefficients = calibrator?.getDistortionCoefficients()
             if (cameraMatrix != null) {
                 // 标定成功,可以使用相机矩阵进行后续处理
                 //查看相机的内参(相机矩阵),你可以获取 cameraMatrix 输出的 Mat 对象,并使用 OpenCV 提供的函数来解析和显示其内容
                 //将 cameraMatrix 转换为双精度数组
                 val cameraMatrixArray = DoubleArray(9)
                 cameraMatrix.get(0, 0, cameraMatrixArray)
                 Log.i(TAG,"相机内参 = "+cameraMatrixArray.contentToString())
             } else {
                 // 标定失败,请检查标定图像和参数设置
             }
         }
    
  5. Calib3d.calibrateCamera() 方法用于相机标定,它接受多个参数来执行标定过程。下面是各个参数的含义:
    objectPoints:一个 ArrayList 对象,存储了多个棋盘格的物理世界坐标点。每个 Mat 对象表示一个图像对应的物理世界坐标点。该参数用于指定棋盘格的内角点在物理世界中的坐标。
    imagePoints:一个 ArrayList 对象,存储了多个棋盘格的图像坐标点。每个 Mat 对象表示一个图像中检测到的棋盘格的内角点坐标。该参数用于指定棋盘格的内角点在图像中的坐标。
    imageSize:一个 Size 对象,指定图像的大小(宽度和高度)。该参数用于指定输入图像的尺寸。
    cameraMatrix:一个 Mat 对象,用于存储输出的相机矩阵。相机矩阵包含了相机的内参,如焦距和光心坐标等信息。
    distortionCoefficients:一个 Mat 对象,用于存储输出的畸变系数。畸变系数描述了相机的畸变情况,包括径向畸变和切向畸变等。
    rotationVectors:一个 ArrayList 对象,用于存储输出的旋转向量。每个旋转向量表示了相机在捕获每张图像时的姿态信息。
    translationVectors:一个 ArrayList 对象,用于存储输出的平移向量。每个平移向量表示了相机在捕获每张图像时的位置信息。
    返回值是一个浮点数,表示标定的均方根误差(RMSE),用于评估标定结果的准确度。
    请注意,为了将参数传递到 Calib3d.calibrateCamera() 方法中,你需要正确地创建和填充这些参数。特别是 objectPoints 和 imagePoints,它们应该包含正确的物理世界坐标和图像坐标。

你可能感兴趣的:(数码相机,android,opencv,相机标定)