【Android开发】OpenCV相机标定,获取内参和畸变参数

本文介绍了如何在Android应用中使用OpenCV进行摄像头标定,包括初始化OpenCV库,检测并标定标准7x7棋盘格,获取内参和畸变参数的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先导入依赖库

implementation 'com.quickbirdstudios:opencv:3.4.4-contrib'

使用相关方法前需要先对opencv进行初始化,初始化之后才能调用其内部函数

//初始化结果    
private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this)
    {
        @Override
        public void onManagerConnected(int status)
        {
            super.onManagerConnected(status);
            if (status == LoaderCallbackInterface.SUCCESS)
            {
                Log.d("控制台调试1", "OpenCV library init success");
            }
        }
    };

//开始初始化
private void initOpenCV()
    {
        if (!OpenCVLoader.initDebug())
        {
            Log.d("控制台调试1", "Internal OpenCV library not found. Using OpenCV Manager for initialization");
            OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION, this, mLoaderCallback);
        }
        else
        {
            Log.d("控制台调试1", "OpenCV library found inside package. Using it!");
            mLoaderCallback.onManagerConnected(LoaderCallbackInterface.SUCCESS);
        }
    }

标定棋盘格,标准象棋棋盘cvSize是(7,7)

相机标定部分代码,开始校准前需要先将棋盘格打印出来,并在各个角度对其进行拍摄(拍摄20张左右)。

 /**
     * 内参、畸变参数获取
     */
    public void getCalibratorParams()
    {

       //内参
        Mat mCameraMatrix = new Mat();
        //畸变参数
        Mat mDistortionCoefficients = new Mat();
        Log.i("视觉识别测试", "calibarator: 发现与绘制棋盘格");
        //标定文件位置(拍摄好的棋盘格图片放置到特定位置)
        String path = GlobalConstant.BLOCK_CHECK_MEDIA_SAVE_LOCAL_PATH;
        File resourceFile = new File(path);
        File dir = new File(path + "处理后/");
        if (!dir.exists())
        {
            dir.mkdirs();
        }
        if (!resourceFile.exists() || resourceFile.length() == 0)
        {
            ToastUtils.show("文件不存在!");
            return;
        }
        //校准棋盘格 内角点数量(横向)
        int numCornersHor = 7;
        //校准棋盘格 内角点数量(纵向)
        int numCornersVer = 7;
        //校准棋盘格 正方形边长(厘米)
        float mSquareSize = 2.2f;
        File[] files = resourceFile.listFiles();
        ArrayList<Mat> objectPoints = new ArrayList<>();    //角点位于物体坐标平面
        ArrayList<Mat> imagePoints = new ArrayList<>();
        MatOfPoint3f obj = new MatOfPoint3f();
        try
        {
            for (int i = 1; i <= numCornersHor; i++)
            {
                for (int j = 1; j <= numCornersVer; j++)
                {
                    //厘米度量
                    obj.push_back(new MatOfPoint3f(new Point3((double) j * mSquareSize, (double) i * mSquareSize, 0.0)));
                }
            }

        }
        catch (Exception e)
        {
            Log.i("视觉识别测试", "calibarator崩溃点1: " + e.getMessage());
        }

        List<Mat> mCornersBuffer = new ArrayList<>();
        // 发现棋盘格与绘制
        Size s = new Size();
        try
        {
            for (File file : files)
            {
                if (file.isFile())
                {
                    Log.i("视觉识别测试", "calibarator: image file:" + file.getName());
                    Mat image = Imgcodecs.imread(path + file.getName());
                    s = image.size();
                    Mat gray = new Mat();
                    Imgproc.cvtColor(image, gray, Imgproc.COLOR_BGRA2GRAY);  //灰度处理
                    Imgproc.threshold(gray, gray, 100, 255, Imgproc.THRESH_TOZERO);
                    Imgcodecs.imwrite(path + "处理后/" + "二值化" + file.getName(), gray);
                    MatOfPoint2f corners = new MatOfPoint2f(); //角向量已经检测到的标记角。对于每个标记,它的四个角被提供
                    /*
                     * gray 灰度图
                     * size 每行每列内角点,正常7*7
                     * corners 存储角点位置的数组指针
                     * 定义额外滤波步长以帮助寻找角点
                     */
                    boolean ret = Calib3d.findChessboardCorners(gray, new Size(numCornersHor, numCornersVer), corners, Calib3d.CALIB_CB_ADAPTIVE_THRESH | Calib3d.CALIB_CB_FILTER_QUADS);
                    Log.i("视觉识别测试", "calibrator1");
                    if (ret)
                    {
                        Imgproc.cornerSubPix(gray, corners, new Size(11, 11), new Size(-1, -1), new TermCriteria(TermCriteria.EPS + TermCriteria.MAX_ITER, 30, 0.1));
                        Log.i("视觉识别测试", "calibrator2");
                        /*
                         * image 欲绘制的图像,彩色
                         * size 每行每列内角点,正常7*7
                         * corners 存储角点位置的数组指针
                         * ret 是否成功找到角点
                         */
                        Calib3d.drawChessboardCorners(gray, new Size(numCornersHor, numCornersVer), corners, ret);
                        Log.i("视觉识别测试", "calibrator3");
                        imagePoints.add(corners);
                        objectPoints.add(obj);
                        mCornersBuffer.add(corners.clone());
                        Log.i("视觉识别测试", "calibrator4");
                        Imgcodecs.imwrite(path + "处理后/" + "棋盘绘制" + file.getName(), gray);
                        Log.i("视觉识别测试", "calibrator5");
                    }
                }
            }
        }
        catch (Exception e)
        {
            Log.i("视觉识别测试", "calibarator崩溃点2: " + e.getMessage());
        }

        try
        {
            Log.i("视觉识别测试", "calibarator: 相机矫正");
            // 相机校正
            Mat.eye(3, 3, CvType.CV_64FC1).copyTo(mCameraMatrix);
            mCameraMatrix.put(0, 0, 1.0);
            mCameraMatrix.put(1, 1, 1.0);
            ArrayList<Mat> rvecs = new ArrayList<>();
            ArrayList<Mat> tvecs = new ArrayList<>();
            /*
             * objects: 棋盘格坐标系,由棋盘格真是坐标生成,以左上角为顶点建立,Z为0。
             * imagePoints: 图片识别到的角点坐标,与objectPoints中的值一一对应。
             * cameraMatrix: 相机内参
             * distCoeffs: 相机畸变
             * rvec: 标定板坐标系到相机坐标系的旋转向量,可用cv::Rodrigues()变为旋转矩阵
             * tvec: 标定板坐标系到相机坐标系的旋转矩阵
             * */
            Calib3d.calibrateCamera(objectPoints, mCornersBuffer, s, mCameraMatrix, mDistortionCoefficients, rvecs, tvecs, 0);
            Log.i("视觉识别测试", "calibarator内参: " + mCameraMatrix.dump());
            Log.i("视觉识别测试", "calibarator畸变参: " + mDistortionCoefficients.dump());
            ToastUtils.show("镜头参数获取完成!");
        }
        catch (Exception e)
        {
            Log.i("视觉识别测试", "calibarator崩溃点3: " + e.getMessage());
        }
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值