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<Mat>()
         private val imagePoints = ArrayList<Mat>()
         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<Mat>()
             val translationVectors = ArrayList<Mat>()
             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,它们应该包含正确的物理世界坐标和图像坐标。

相关推荐
Kapaseker1 小时前
你不看会后悔的2025年终总结
android·kotlin
alexhilton4 小时前
务实的模块化:连接模块(wiring modules)的妙用
android·kotlin·android jetpack
ji_shuke5 小时前
opencv-mobile 和 ncnn-android 环境配置
android·前端·javascript·人工智能·opencv
sunnyday04267 小时前
Spring Boot 项目中使用 Dynamic Datasource 实现多数据源管理
android·spring boot·后端
幽络源小助理8 小时前
下载安装AndroidStudio配置Gradle运行第一个kotlin程序
android·开发语言·kotlin
inBuilder低代码平台8 小时前
浅谈安卓Webview从初级到高级应用
android·java·webview
豌豆学姐8 小时前
Sora2 短剧视频创作中如何保持人物一致性?角色创建接口教程
android·java·aigc·php·音视频·uniapp
yangpan0118 小时前
相机位姿名词澄清
数码相机
白熊小北极9 小时前
Android Jetpack Compose折叠屏感知与适配
android
HelloBan9 小时前
setHintTextColor不生效
android