您好,
会员登录 快速注册
退出 ( 条未读消息)
关于本站 意见反馈 首页

公告:小宅博客网可以开发票了,需要发票的,去群里找群主哈!!
全部文章分类
  • 人工智能 >

  • 编程语言 >

  • WPF系列 >

  • ASP.NET系列 >

  • Linux >

  • 数据库 >

  • 嵌入式 >

  • WEB技术 >

  • PLC系列 >

  • 微服务与框架 >

  • 小宅DIY >

  • 学习资料 >

OpenCv基础 ANN车牌识别 yolov5车牌识别 指针式仪表识别 ROS系列 YOLO Halcon Detectron2 昇腾AI ChatGPT在线体验 英伟达JETSON ChatGLM ChatTTS FunASR 地平线 ByteTrack 魔搭社区 LangChain
C C# C++ Python Java Go
WPF
ASP.NET小功能 GPS定位系统-MVC GPS定位系统-VUE ASP.NET WebRTC
Linux Linux内核 Shell MakeFile
MySql SqlServer Oracle
STM8 STM32 51单片机
VUE入门 HTML JavaScript CSS layui镜像网站 ElementUi中文官网 element-plus 图标
三菱 欧姆龙 西门子 施耐德 松下 台达
IOTSharp IOTGateway ABP FRAMEWORK Docker
亚克力音响 编程仙途:智驭万法
面试题与技巧 Python入门技能树 微软C#教程
首页 编程之美 工具下载 全国就业 流量地图 文心一言
OpenCv基础
内容介绍与资料分享 C# OpenCv环境搭建 C++ OpenCv环境搭建 Python OpenCv环境搭建 Java OpenCv环境搭建 OpenCv组件结构解析 OpenCv命名规范 OpenCv基本专业术语与方法 OpenCV 常用函数与构造体详细说明 创建画布 打开一张图片 利用imwrite生成透明png图像 图像打开、混合显示和输出 图像腐蚀 blur图像模糊(均值滤波) sobel边缘检测 canny边缘检测 Scharr滤波器 程序性能检测及优化 视频播放 摄像头录像与播放 双摄像头操作与图像相似度检测 颜色空间转换与物体追踪 彩色目标追踪 光流法运动目标检测 OpenCV中的稠密光流 背景减除 点追踪 人脸识别 支持向量机之SVM引导 支持向量机之处理线性不可分数据 ROI矩形截取 鼠标绘制矩形 用OpenCV进行基本绘图 绘图函数(python中文显示) 把鼠标当画笔 用滑动条做调色板 图像的基础操作 图像上的算术运算 多通道图像混合 图像的亮度、对比度调整 XML和YAML文件的写入 XML和YAML文件的读取 卷积操作 三种线性滤波 两种非线性滤波 7种图像处理形态学(1) 7种图像处理形态学(2) 漫水填充 图像缩放与图像金字塔 二值化基本阈值操作 图像阈值 Laplacian图像变换(拉普拉斯算子) 霍夫变换HoughLines边缘检测与线性矢量 霍夫变换HoughLinesP边缘检测与线性矢量 霍夫变换HoughCircles边缘检测与线性矢量 LSD快速直线检测 几何变换 remap重映射 remap实现多种重映射 仿射变换综合示例 直方图均衡化 CLAHE有限对比适应性直方图均衡化 draw最大的轮廓 轮廓的性质 点到多边形的最短距离 形状匹配 椭圆拟合与直线拟合 基础轮廓查找 查找并绘制轮廓综合示例 凸缺陷/凸包检测 凸包检测 创建包围轮廓的矩形边界 创建包围轮廓的圆形边 创建包围轮廓的矩形和圆形边界框 查找和绘制图片轮廓矩 分水岭算法 图像修补 H-S二维直方图的绘制/2D直方图 一维直方图的绘制 RGB三色直方图的绘制 直方图对比 使用掩膜绘制直方图 直方图反向投影 模板匹配 多对象模板匹配 cornerHarris角点检测 cornerHarris角点检测综合示例 Shi-Tomasi角点检测 亚像素级角点检测 角点检测的FAST算法(FAST特征检测器) 颜色识别 warpPerspective透视变换 SURF/SIFT特征点检测 SURF/SIFT特征描述 使用FLANN进行特征点匹配 FLANN结合SURF/SIFT进行关键点的描述和匹配 寻找已知物体(一) 寻找已知物体(二) 目标查找与跟踪 - Meanshift与CamShift BRIEF描述符 ORB ORB算法描述与匹配 LUT 图像灰度调整 离散傅里叶变换 双目摄像头与图像拼接 环境亮度检测 stitching 全景拼接 Maze-Solver迷宫解密 使用Haar分类器之面部检测 使用Haar分类器之行人检测 OpenCv Haar/LBP/HOG分类器-人脸识别 斑点检测 使用GrabCut算法进行交互式前景提取 对极几何 摄像机标定 姿势估计 立体图像中的深度地图 OpenCv中的KNN KNN手写数字识别 ​SVM手写数字识别(使用SVM进行手写数据OCR) 英文字母的OCR 预测手写数字(预测不准) K值聚类(一) K值聚类(二) 计算摄影学-图像去噪 高动态范围成像(HDRI或HDR) MSER区域检测 二维码、条形码识别 删除图像中的水印 OpenCv深度学习dnn Kinect-深度相机 OpenCv常用数学算法 360度旋转直线绘制 向量延长线上的像素扫描 Tools工具包-窗体分配
对极几何
姿势估计
激萌の小宅 小宅博客 OpenCv基础

文章作者:激萌の小宅

促销:¥0

价格:¥0

配送方式: 购买后立即生效(如购买异常,请联系站长)
付款之后一定要等待自动跳转结束,否则购买可能会失败
  • 0 天

    有效期

  • 0

    总销量

  • 0

    累计评价

摄像机标定

下面这段代码是 OpenCV-Python-Tutorial-中文版.pdf (P243)中的实现,

当前系列所有demo下载地址:

https://github.com/GaoRenBao/OpenCv4-Demo

https://gitee.com/fuckgrb/OpenCv4-Demo

不同编程语言对应的OpenCv版本以及开发环境信息如下: 

语言

OpenCv版本

IDE

C#

OpenCvSharp4.4.8.0.20230708

Visual Studio 2022

C++

OpenCv-4.5.5-vc14_vc15

Visual Studio 2022

Python

OpenCv-Python (4.6.0.66)

PyCharm Community Edition 2022.1.3


棋盘格下载地址:check-108.pdf

参考博客:http://blog.csdn.net/dcrmg/article/details/52939318


        为了找到棋盘的图案我们要使用函数 cv2fndChessboardCorners()。我们还需要传入图案的类型,比如说 8x8 的格子或5x5的格子等。在本例中我们使用的是7x8的格子。(通常情况下棋盘都是 8x8 或者7x7)。它会返回角点,如果得到图像的话返回值类型(Retval)就会是True。这些角点会按顺序排列(从左到右,从上到下 )。

        patternSize:(w,h),棋盘上每一排和每一列的内角数。w=棋盘板一行上黑白块的数量-1,h=棋盘板一列上黑白块的数量-1,例如:10x6的棋盘板,则(w,h)=(9,5)


其他: 

        这个函数可能不会找出所有图像中应有的图案。所以一个好的方法是编写代码,启动摄像机并在每一帧中检查是否有应有的图案。在我们获得图案之后我们要找到角点并把它们保存成一个列表。在读取下一帧图像之前要设置一定的间隔,这样我们就有足够的时间调整棋盘的方向。继续这个过程直到我们得到足够多好的图案。就算是我们举得这个例子,在所有的 14 幅图像中也不知道有几幅是好的。所以我们要读取每一张图像从其中找到好的能用的。


其他: 

        除了使用棋盘之外,我们还可以使用环形格子,但是要使用函数cv2.findCirclesGrid来找图案。据说使用环形格子只需要很少的图像就可以了。


demo1:

QQ截图20231123090018.jpg


demo2:

经过纠正,你会发现结果图像中所有的边界变直了

calibresult1.jpg


demo3:

调用摄像头的效果:

1.gif


C#版本代码如下:

参考博客:https://blog.csdn.net/jimtien/article/details/119009460

using OpenCvSharp;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

namespace demo
{
    internal class Program
    {
        static void Main(string[] args)
        {
            //demo1();
            demo3();
        }

        static List<Point3f> GetChessboardObjectPoints(Size boardSize, float squareSize)
        {
            List<Point3f> objectPoints = new List<Point3f>() { };
            for (int i = 0; i < boardSize.Height; ++i)
            {
                for (int j = 0; j < boardSize.Width; ++j)
                {
                    objectPoints.Add(new Point3f(squareSize * j, squareSize * i, 0.0f));
                }
            }
            return objectPoints;
        }

        public static Mat[] calcBoardCornerPositions(Size BoardSize, float SquareSize, int imagesCount)
        {
            Mat[] corners = new Mat[imagesCount];
            for (int k = 0; k < imagesCount; k++)
            {
                Point3f[] p = new Point3f[BoardSize.Height * BoardSize.Width];
                for (int i = 0; i < BoardSize.Height; i++)
                {
                    for (int j = 0; j < BoardSize.Width; j++)
                    {
                        p[i * BoardSize.Width + j] = new Point3f(j * SquareSize, i * SquareSize, 0);
                    }
                }
                corners[k] = Mat.FromArray<Point3f>(p);
            }
            return corners;
        }

        static void demo1()
        {
            List<string> paths = new List<string>()
            {
                "../../../images/lefts/",
                "../../../images/rights/"
            };
            List<string> images = new List<string>();
            foreach (string path in paths)
            {
                DirectoryInfo di = new DirectoryInfo(path);
                FileInfo[] fis = di.GetFiles("*.jpg");
                Mat srcImage = new Mat();
                foreach (FileInfo fi in fis)
                {
                    images.Add(fi.FullName);
                }
            }
            TermCriteria criteria = new TermCriteria(CriteriaTypes.Eps | CriteriaTypes.MaxIter, 30, 0.001);

            // 棋盘格内角点数量(行数和列数)
            Size chessboardSize = new Size(7, 6);

            // 棋盘格尺寸(单位:米)
            float squareSize = 0.025f;

            // 存储棋盘格角点坐标的容器
            List<List<Point3f>> objpoints = new List<List<Point3f>>();
            // 存储检测到的棋盘格角点坐标的容器
            List<List<Point2f>> imgpoints = new List<List<Point2f>>();
            Mat gray = new Mat();

            foreach (var image in images)
            {
                Mat img = Cv2.ImRead(image);
                if (!img.Empty())
                {
                    Cv2.CvtColor(img, gray, ColorConversionCodes.BGR2GRAY);

                    // Find the chess board corners
                    Point2f[] corners = new Point2f[] { };
                    bool ret = Cv2.FindChessboardCorners(gray, chessboardSize, out corners);
                    // If found, add object points, image points(after refining them)
                    if (ret == true)
                    {
                        Cv2.CornerSubPix(gray, corners, new Size(11, 11), new Size(-1, -1), criteria);
                        // Draw and display the corners
                        Cv2.DrawChessboardCorners(img, chessboardSize, corners, ret);

                        objpoints.Add(GetChessboardObjectPoints(chessboardSize, squareSize));
                        imgpoints.Add(corners.ToList());

                        Cv2.ImShow("img", img);
                        Cv2.WaitKey(100);
                    }
                }
            }
        }

        static void demo3()
        {
            List<string> paths = new List<string>()
            {
                "../../../images/lefts/",
                "../../../images/rights/"
            };
            List<string> imagesList = new List<string>();
            foreach (string path in paths)
            {
                DirectoryInfo di = new DirectoryInfo(path);
                FileInfo[] fis = di.GetFiles("*.jpg");
                Mat srcImage = new Mat();
                foreach (FileInfo fi in fis)
                {
                    imagesList.Add(fi.FullName);
                }
            }

            TermCriteria criteria = new TermCriteria(CriteriaTypes.Eps | CriteriaTypes.MaxIter, 30, 0.001);

            Size BoardSize = new Size(9, 6);
            int SquareSize = 25; //每格的宽度应设置为实际的毫米数

            Mat img = new Mat();
            Mat gray = new Mat();

            List<Mat> imagesPointsM = new List<Mat>();
            List<Point2f[]> imgpoints = new List<Point2f[]>();

            for (int i = 0; i < imagesList.Count; i++)
            {
                img = new Mat(imagesList[i]);
                if (!img.Empty())
                {
                    Cv2.CvtColor(img, gray, ColorConversionCodes.BGR2GRAY);

                    Point2f[] pointBuf;
                    bool found = Cv2.FindChessboardCorners(img, BoardSize, out pointBuf);
                    if (found == true)
                    {
                        Mat viewGray = new Mat();
                        Cv2.CvtColor(img, viewGray, ColorConversionCodes.BGR2GRAY);
                        Cv2.CornerSubPix(viewGray, pointBuf, new Size(11, 11), new Size(-1, -1), criteria);
                        imgpoints.Add(pointBuf);
                        imagesPointsM.Add(Mat.FromArray<Point2f>(pointBuf));

                        Cv2.DrawChessboardCorners(img, BoardSize, pointBuf, found);
                        Cv2.ImShow("img", img);
                        Cv2.WaitKey(10);
                    }
                }
            }

            // 执行相机标定
            Mat[] rvecs = new Mat[] { };
            Mat[] tvecs = new Mat[] { };
            Mat mtx = new Mat();
            Mat dist = new Mat();
            Mat[] objpoints = calcBoardCornerPositions(BoardSize, SquareSize, imagesList.Count);
            Cv2.CalibrateCamera(objpoints, imagesPointsM.ToArray(), new Size(gray.Cols, gray.Rows), mtx, dist, out rvecs, out tvecs, CalibrationFlags.None);

            // 畸变校正
            img = Cv2.ImRead("../../../images/lefts/left12.jpg");
            int h = img.Rows;
            int w = img.Cols;
            Mat mapx = new Mat();
            Mat mapy = new Mat();
            Rect roi = new Rect();
            Mat newcameramtx = Cv2.GetOptimalNewCameraMatrix(mtx, dist, new Size(w, h), 1, new Size(w, h), out roi);

            // undistort
            Mat dst = new Mat();
            Cv2.Undistort(img, dst, mtx, dist, newcameramtx);

            // crop the image
            dst = new Mat(dst, roi);
            Cv2.ImShow("calibresult1.png", dst);

            Cv2.InitUndistortRectifyMap(mtx, dist, new Mat(), newcameramtx, new Size(w, h), 5, mapx, mapy);
            Cv2.Remap(img, dst, mapx, mapy, InterpolationFlags.Linear);

            // crop the image
            dst = new Mat(dst, roi);
            Cv2.ImShow("calibresult2.png", dst);

            double mean_error = 0;
            for (int i = 0; i < objpoints.Length; ++i)
            {
                Mat imagePoints2 = new Mat();
                Cv2.ProjectPoints(objpoints[i], rvecs[i], tvecs[i], mtx, dist, imagePoints2);
                double error = Cv2.Norm(imagesPointsM[i], imagePoints2, NormTypes.L2);
                Console.WriteLine($"total error :{mean_error / objpoints.Count()}");
            }

            Cv2.WaitKey();
        }
    }
}


C++版本代码如下:

#include <opencv2/opencv.hpp>
#include <opencv2/ml.hpp>
#include <opencv2/cvconfig.h>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>    

#include <io.h>
#include <string>
#include <iostream>
#include <ctime>

using namespace cv;
using namespace std;

std::vector<cv::Point3f> GetChessboardObjectPoints(const cv::Size& boardSize, float squareSize) {
    std::vector<cv::Point3f> objectPoints;
    for (int i = 0; i < boardSize.height; ++i) {
        for (int j = 0; j < boardSize.width; ++j) {
            objectPoints.push_back(Point3f(squareSize * j, squareSize * i, 0.0f));
        }
    }
    return objectPoints;
}

void demo1()
{
    // 获取图片目录
    std::string inPath1 = "..\\images\\lefts\\left*.jpg";
    std::string inPath2 = "..\\images\\rights\\right*.jpg";
    intptr_t handle1, handle2;
    struct _finddata_t fileinfo1, fileinfo2;
    handle1 = _findfirst(inPath1.c_str(), &fileinfo1);
    handle2 = _findfirst(inPath2.c_str(), &fileinfo2);

    vector<string> images;
    do {
        string Name = fileinfo1.name;
        images.push_back("..\\images\\lefts\\" + Name);
    } while (!_findnext(handle1, &fileinfo1));

    do {
        string Name = fileinfo2.name;
        images.push_back("..\\images\\lefts\\" + Name);
    } while (!_findnext(handle2, &fileinfo2));

    TermCriteria criteria = TermCriteria(TermCriteria::EPS | TermCriteria::MAX_ITER, 30, 0.001);

    // 棋盘格内角点数量(行数和列数)
    cv::Size chessboardSize(7, 6);

    // 棋盘格尺寸(单位:米)
    float squareSize = 0.025f;

    // 存储棋盘格角点坐标的容器
    std::vector<std::vector<cv::Point3f>> objpoints;
    // 存储检测到的棋盘格角点坐标的容器
    std::vector<std::vector<cv::Point2f>> imgpoints;
    Mat gray;

    for (int i = 0; i < images.size(); i++)
    {
        Mat img = imread(images[i]);
        if (!img.empty())
        {
            cvtColor(img, gray, COLOR_BGR2GRAY);

            // Find the chess board corners
            std::vector<cv::Point2f> corners;
            bool ret = findChessboardCorners(gray, chessboardSize, corners);

            // If found, add object points, image points(after refining them)
            if (ret == true)
            {
                cornerSubPix(gray, corners, Size(11, 11), Size(-1, -1), criteria);
                // Draw and display the corners
                drawChessboardCorners(img, chessboardSize, corners, ret);

                objpoints.push_back(GetChessboardObjectPoints(chessboardSize, squareSize));
                imgpoints.push_back(corners);

                imshow("img", img);
                waitKey(100);
            }
        }
    }
}

void demo2()
{
    // 获取图片目录
    std::string inPath1 = "..\\images\\lefts\\left*.jpg";
    std::string inPath2 = "..\\images\\rights\\right*.jpg";
    intptr_t handle1, handle2;
    struct _finddata_t fileinfo1, fileinfo2;
    handle1 = _findfirst(inPath1.c_str(), &fileinfo1);
    handle2 = _findfirst(inPath2.c_str(), &fileinfo2);

    vector<string> images;
    do {
        string Name = fileinfo1.name;
        images.push_back("..\\images\\lefts\\" + Name);
    } while (!_findnext(handle1, &fileinfo1));

    do {
        string Name = fileinfo2.name;
        images.push_back("..\\images\\lefts\\" + Name);
    } while (!_findnext(handle2, &fileinfo2));

    TermCriteria criteria = TermCriteria(TermCriteria::EPS | TermCriteria::MAX_ITER, 30, 0.001);

    // 棋盘格内角点数量(行数和列数)
    cv::Size chessboardSize(7, 6);

    // 棋盘格尺寸(单位:米)
    float squareSize = 0.025f;

    // 存储棋盘格角点坐标的容器
    std::vector<std::vector<cv::Point3f>> objpoints;
    // 存储检测到的棋盘格角点坐标的容器
    std::vector<std::vector<cv::Point2f>> imgpoints;
    Mat gray;

    for (int i = 0; i < images.size(); i++)
    {
        Mat img = imread(images[i]);
        if (!img.empty())
        {
            cvtColor(img, gray, COLOR_BGR2GRAY);

            // Find the chess board corners
            std::vector<cv::Point2f> corners;
            bool ret = findChessboardCorners(gray, chessboardSize, corners);

            // If found, add object points, image points(after refining them)
            if (ret == true)
            {
                cornerSubPix(gray, corners, Size(11, 11), Size(-1, -1), criteria);
                // Draw and display the corners
                drawChessboardCorners(img, chessboardSize, corners, ret);

                objpoints.push_back(GetChessboardObjectPoints(chessboardSize, squareSize));
                imgpoints.push_back(corners);

                imshow("img", img);
                waitKey(10);
            }
        }
    }

    // 执行相机标定
    cv::Mat mtx, dist;
    std::vector<cv::Mat> rvecs, tvecs;
    cv::calibrateCamera(objpoints, imgpoints, cv::Size(gray.cols, gray.rows), mtx, dist, rvecs, tvecs);

    // 畸变校正
    Mat img = imread("../images/lefts/left12.jpg");
    int h = img.rows;
    int w = img.cols;
    cv::Mat mapx, mapy;
    Rect roi;
    cv::Mat newcameramtx = getOptimalNewCameraMatrix(mtx, dist, Size(w,h), 1, Size(w, h), &roi);

    // undistort
    Mat dst;
    undistort(img, dst, mtx, dist, newcameramtx);

    // crop the image
    dst = dst(roi);
    imshow("calibresult1.png", dst);

    initUndistortRectifyMap(mtx, dist, cv::Mat(), newcameramtx, Size(w, h), 5, mapx, mapy);
    remap(img, dst, mapx, mapy, INTER_LINEAR);

    // crop the image
    dst = dst(roi);
    imshow("calibresult2.png", dst);
   // 你会发现结果图像中所有的边界变直了

    // 反向投影误差
    // 我们可以利用反向投影误差对我们找到的参数的准确性进行估计。得到的结果越接近 0越好。
    // 有了内部参数,畸变参数和旋转变换矩阵,我们就可以使用cv2.projectPoints()将对象点转换到图像点。
    // 然后就可以计算变换得到图像与角点检测算法的绝对差了。
    // 然后我们计算所有标定图像的误差平均值。
    int mean_error = 0;
    for (int i = 0; i < objpoints.size(); i++)
    {
        vector<Point2f> imgpoints2;
        projectPoints(objpoints[i], rvecs[i], tvecs[i], mtx, dist, imgpoints2);
       int error = norm(imgpoints[i], imgpoints2, NORM_L2) / imgpoints2.size();
       mean_error += error;
       cout << "total error :" << mean_error / objpoints.size() << endl;
    }
    waitKey(0);
}

int main()
{
    //demo1();
    demo2();
}


Python版本代码如下:

demo1:

import numpy as np
import cv2
import glob

# termination criteria
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
# prepare object points, like (0,0,0), (1,0,0), (2,0,0) ....,(6,5,0)
objp = np.zeros((6 * 7, 3), np.float32)
objp[:, :2] = np.mgrid[0:7, 0:6].T.reshape(-1, 2)
# Arrays to store object points and image points from all the images.
objpoints = []  # 3d point in real world space
imgpoints = []  # 2d points in image plane.
images = glob.glob('../images/lefts/left*.jpg')
images += glob.glob('../images/rights/right*.jpg')

for fname in images:
    img = cv2.imread(fname)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    # Find the chess board corners
    ret, corners = cv2.findChessboardCorners(gray, (7, 6), None)
    # If found, add object points, image points (after refining them)
    if ret == True:
        objpoints.append(objp)
        corners2 = cv2.cornerSubPix(gray, corners, (11, 11), (-1, -1), criteria)
        imgpoints.append(corners)
        # Draw and display the corners
        cv2.drawChessboardCorners(img, (7, 6), corners2, ret)
        cv2.imshow('img', img)
        cv2.waitKey(0)
cv2.destroyAllWindows()


demo2:

import numpy as np
import cv2
import glob

# termination criteria
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
# prepare object points, like (0,0,0), (1,0,0), (2,0,0) ....,(6,5,0)
objp = np.zeros((6 * 7, 3), np.float32)
objp[:, :2] = np.mgrid[0:7, 0:6].T.reshape(-1, 2)
# Arrays to store object points and image points from all the images.
objpoints = []  # 3d point in real world space
imgpoints = []  # 2d points in image plane.
images = glob.glob('../images/lefts/left*.jpg')
images += glob.glob('../images/rights/right*.jpg')

for fname in images:
    img = cv2.imread(fname)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    # Find the chess board corners
    ret, corners = cv2.findChessboardCorners(gray, (7, 6), None)
    # If found, add object points, image points (after refining them)
    if ret == True:
        objpoints.append(objp)
        corners2 = cv2.cornerSubPix(gray, corners, (11, 11), (-1, -1), criteria)
        imgpoints.append(corners)
        # Draw and display the corners
        cv2.drawChessboardCorners(img, (7, 6), corners2, ret)
        cv2.imshow('img', img)
        cv2.waitKey(10)
cv2.destroyAllWindows()

##################### 标定  #####################
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None)

# 畸变校正
img = cv2.imread('../images/lefts/left12.jpg')
h, w = img.shape[:2]
newcameramtx, roi = cv2.getOptimalNewCameraMatrix(mtx, dist, (w, h), 1, (w, h))

# 使用 cv2.undistort()  是最简单的方法。只 使用这个函数和上面得到 的 ROI 对结果进行裁剪。

# undistort
dst = cv2.undistort(img, mtx, dist, None, newcameramtx)
# crop the image
x, y, w, h = roi
dst = dst[y:y + h, x:x + w]
cv2.imshow('calibresult1.png', dst)

# 使用 remapping  应 属于 曲线救国 了。 先我们 找到从畸变图像到畸变图像的映射方程。再使用 重映射方程
# undistort
mapx, mapy = cv2.initUndistortRectifyMap(mtx, dist, None, newcameramtx, (w, h), 5)
dst = cv2.remap(img, mapx, mapy, cv2.INTER_LINEAR)
# crop the image
x, y, w, h = roi
dst = dst[y:y + h, x:x + w]
cv2.imshow('calibresult2.png', dst)
# 你会发现结果图像中所有的边界变直了

# 反向投影误差
# 我们可以利用反向投影误差对我们找到的参数的准确性进行估计。得到的结果越接近 0越好。
# 有了内部参数,畸变参数和旋转变换矩阵,我们就可以使用cv2.projectPoints()将对象点转换到图像点。
# 然后就可以计算变换得到图像与角点检测算法的绝对差了。
# 然后我们计算所有标定图像的误差平均值。
mean_error = 0
for i in range(len(objpoints)):
    imgpoints2, _ = cv2.projectPoints(objpoints[i], rvecs[i], tvecs[i], mtx, dist)
    error = cv2.norm(imgpoints[i], imgpoints2, cv2.NORM_L2) / len(imgpoints2)
    mean_error += error
print("total error: ", mean_error / len(objpoints))
cv2.waitKey(0)


demo3:

import numpy as np
import cv2

criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
cap = cv2.VideoCapture(0)

# 等比缩放
# frame_height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT)
# frame_width = cap.get(cv2.CAP_PROP_FRAME_WIDTH)
#
# frame_height = int(480 / frame_width * frame_height)
# ret = cap.set(cv2.CAP_PROP_FRAME_HEIGHT, frame_height)
# ret = cap.set(cv2.CAP_PROP_FRAME_WIDTH, 480)

while cap.isOpened():
    # img = cv2.imread(fname)
    ret, img = cap.read()
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    ret, corners = cv2.findChessboardCorners(image=gray, patternSize=(8, 6), corners=None)
    '''
    第一个参数Image,传入拍摄的棋盘图Mat图像,必须是8位的灰度或者彩色图像;
    第二个参数patternSize,每个棋盘图上内角点的行列数,一般情况下,行列数不要相同,便于后续标定程序识别标定板的方向;
    第三个参数corners,用于存储检测到的内角点图像坐标位置,一般用元素是Point2f的向量来表示:vector<Point2f> image_points_buf;
    第四个参数flage:用于定义棋盘图上内角点查找的不同处理方式,有默认值。
    '''
    print(corners)
    print('---------')
    if ret == True:
        # objpoints.append(objp)
        corners2 = cv2.cornerSubPix(gray, corners, (11, 11), (-1, -1), criteria)
        # imgpoints.append(corners)
        # Draw and display the corners
        cv2.drawChessboardCorners(img, (8, 6), corners2, ret)

    cv2.imshow('img', img)
    key = cv2.waitKey(delay=10)
    if key == ord("q"):
        break

cv2.destroyAllWindows()


对极几何
姿势估计

友情链接: CSDN激萌の小宅 95知识库 自考题库 罗分明个人网络博客 精益编程leanboot

小宅博客  www.bilibili996.com All Rights Reserved. 备案号: 闽ICP备2024034575号

网站经营许可证  福建省福州市 Copyright©2021-2025 版权所有

小宅博客
首页 智能家居 地图定位
公告:小宅博客网可以开发票了,需要发票的,去群里找群主哈!!

文章作者:激萌の小宅

促销:¥0

价格:¥0

配送方式: 购买后立即生效(如购买异常,请联系站长)
付款之后一定要等待自动跳转结束,否则购买可能会失败
  • 0 天

    有效期

  • 0

    总销量

  • 0

    累计评价

摄像机标定

下面这段代码是 OpenCV-Python-Tutorial-中文版.pdf (P243)中的实现,

当前系列所有demo下载地址:

https://github.com/GaoRenBao/OpenCv4-Demo

https://gitee.com/fuckgrb/OpenCv4-Demo

不同编程语言对应的OpenCv版本以及开发环境信息如下: 

语言

OpenCv版本

IDE

C#

OpenCvSharp4.4.8.0.20230708

Visual Studio 2022

C++

OpenCv-4.5.5-vc14_vc15

Visual Studio 2022

Python

OpenCv-Python (4.6.0.66)

PyCharm Community Edition 2022.1.3


棋盘格下载地址:check-108.pdf

参考博客:http://blog.csdn.net/dcrmg/article/details/52939318


        为了找到棋盘的图案我们要使用函数 cv2fndChessboardCorners()。我们还需要传入图案的类型,比如说 8x8 的格子或5x5的格子等。在本例中我们使用的是7x8的格子。(通常情况下棋盘都是 8x8 或者7x7)。它会返回角点,如果得到图像的话返回值类型(Retval)就会是True。这些角点会按顺序排列(从左到右,从上到下 )。

        patternSize:(w,h),棋盘上每一排和每一列的内角数。w=棋盘板一行上黑白块的数量-1,h=棋盘板一列上黑白块的数量-1,例如:10x6的棋盘板,则(w,h)=(9,5)


其他: 

        这个函数可能不会找出所有图像中应有的图案。所以一个好的方法是编写代码,启动摄像机并在每一帧中检查是否有应有的图案。在我们获得图案之后我们要找到角点并把它们保存成一个列表。在读取下一帧图像之前要设置一定的间隔,这样我们就有足够的时间调整棋盘的方向。继续这个过程直到我们得到足够多好的图案。就算是我们举得这个例子,在所有的 14 幅图像中也不知道有几幅是好的。所以我们要读取每一张图像从其中找到好的能用的。


其他: 

        除了使用棋盘之外,我们还可以使用环形格子,但是要使用函数cv2.findCirclesGrid来找图案。据说使用环形格子只需要很少的图像就可以了。


demo1:

QQ截图20231123090018.jpg


demo2:

经过纠正,你会发现结果图像中所有的边界变直了

calibresult1.jpg


demo3:

调用摄像头的效果:

1.gif


C#版本代码如下:

参考博客:https://blog.csdn.net/jimtien/article/details/119009460

using OpenCvSharp;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

namespace demo
{
    internal class Program
    {
        static void Main(string[] args)
        {
            //demo1();
            demo3();
        }

        static List<Point3f> GetChessboardObjectPoints(Size boardSize, float squareSize)
        {
            List<Point3f> objectPoints = new List<Point3f>() { };
            for (int i = 0; i < boardSize.Height; ++i)
            {
                for (int j = 0; j < boardSize.Width; ++j)
                {
                    objectPoints.Add(new Point3f(squareSize * j, squareSize * i, 0.0f));
                }
            }
            return objectPoints;
        }

        public static Mat[] calcBoardCornerPositions(Size BoardSize, float SquareSize, int imagesCount)
        {
            Mat[] corners = new Mat[imagesCount];
            for (int k = 0; k < imagesCount; k++)
            {
                Point3f[] p = new Point3f[BoardSize.Height * BoardSize.Width];
                for (int i = 0; i < BoardSize.Height; i++)
                {
                    for (int j = 0; j < BoardSize.Width; j++)
                    {
                        p[i * BoardSize.Width + j] = new Point3f(j * SquareSize, i * SquareSize, 0);
                    }
                }
                corners[k] = Mat.FromArray<Point3f>(p);
            }
            return corners;
        }

        static void demo1()
        {
            List<string> paths = new List<string>()
            {
                "../../../images/lefts/",
                "../../../images/rights/"
            };
            List<string> images = new List<string>();
            foreach (string path in paths)
            {
                DirectoryInfo di = new DirectoryInfo(path);
                FileInfo[] fis = di.GetFiles("*.jpg");
                Mat srcImage = new Mat();
                foreach (FileInfo fi in fis)
                {
                    images.Add(fi.FullName);
                }
            }
            TermCriteria criteria = new TermCriteria(CriteriaTypes.Eps | CriteriaTypes.MaxIter, 30, 0.001);

            // 棋盘格内角点数量(行数和列数)
            Size chessboardSize = new Size(7, 6);

            // 棋盘格尺寸(单位:米)
            float squareSize = 0.025f;

            // 存储棋盘格角点坐标的容器
            List<List<Point3f>> objpoints = new List<List<Point3f>>();
            // 存储检测到的棋盘格角点坐标的容器
            List<List<Point2f>> imgpoints = new List<List<Point2f>>();
            Mat gray = new Mat();

            foreach (var image in images)
            {
                Mat img = Cv2.ImRead(image);
                if (!img.Empty())
                {
                    Cv2.CvtColor(img, gray, ColorConversionCodes.BGR2GRAY);

                    // Find the chess board corners
                    Point2f[] corners = new Point2f[] { };
                    bool ret = Cv2.FindChessboardCorners(gray, chessboardSize, out corners);
                    // If found, add object points, image points(after refining them)
                    if (ret == true)
                    {
                        Cv2.CornerSubPix(gray, corners, new Size(11, 11), new Size(-1, -1), criteria);
                        // Draw and display the corners
                        Cv2.DrawChessboardCorners(img, chessboardSize, corners, ret);

                        objpoints.Add(GetChessboardObjectPoints(chessboardSize, squareSize));
                        imgpoints.Add(corners.ToList());

                        Cv2.ImShow("img", img);
                        Cv2.WaitKey(100);
                    }
                }
            }
        }

        static void demo3()
        {
            List<string> paths = new List<string>()
            {
                "../../../images/lefts/",
                "../../../images/rights/"
            };
            List<string> imagesList = new List<string>();
            foreach (string path in paths)
            {
                DirectoryInfo di = new DirectoryInfo(path);
                FileInfo[] fis = di.GetFiles("*.jpg");
                Mat srcImage = new Mat();
                foreach (FileInfo fi in fis)
                {
                    imagesList.Add(fi.FullName);
                }
            }

            TermCriteria criteria = new TermCriteria(CriteriaTypes.Eps | CriteriaTypes.MaxIter, 30, 0.001);

            Size BoardSize = new Size(9, 6);
            int SquareSize = 25; //每格的宽度应设置为实际的毫米数

            Mat img = new Mat();
            Mat gray = new Mat();

            List<Mat> imagesPointsM = new List<Mat>();
            List<Point2f[]> imgpoints = new List<Point2f[]>();

            for (int i = 0; i < imagesList.Count; i++)
            {
                img = new Mat(imagesList[i]);
                if (!img.Empty())
                {
                    Cv2.CvtColor(img, gray, ColorConversionCodes.BGR2GRAY);

                    Point2f[] pointBuf;
                    bool found = Cv2.FindChessboardCorners(img, BoardSize, out pointBuf);
                    if (found == true)
                    {
                        Mat viewGray = new Mat();
                        Cv2.CvtColor(img, viewGray, ColorConversionCodes.BGR2GRAY);
                        Cv2.CornerSubPix(viewGray, pointBuf, new Size(11, 11), new Size(-1, -1), criteria);
                        imgpoints.Add(pointBuf);
                        imagesPointsM.Add(Mat.FromArray<Point2f>(pointBuf));

                        Cv2.DrawChessboardCorners(img, BoardSize, pointBuf, found);
                        Cv2.ImShow("img", img);
                        Cv2.WaitKey(10);
                    }
                }
            }

            // 执行相机标定
            Mat[] rvecs = new Mat[] { };
            Mat[] tvecs = new Mat[] { };
            Mat mtx = new Mat();
            Mat dist = new Mat();
            Mat[] objpoints = calcBoardCornerPositions(BoardSize, SquareSize, imagesList.Count);
            Cv2.CalibrateCamera(objpoints, imagesPointsM.ToArray(), new Size(gray.Cols, gray.Rows), mtx, dist, out rvecs, out tvecs, CalibrationFlags.None);

            // 畸变校正
            img = Cv2.ImRead("../../../images/lefts/left12.jpg");
            int h = img.Rows;
            int w = img.Cols;
            Mat mapx = new Mat();
            Mat mapy = new Mat();
            Rect roi = new Rect();
            Mat newcameramtx = Cv2.GetOptimalNewCameraMatrix(mtx, dist, new Size(w, h), 1, new Size(w, h), out roi);

            // undistort
            Mat dst = new Mat();
            Cv2.Undistort(img, dst, mtx, dist, newcameramtx);

            // crop the image
            dst = new Mat(dst, roi);
            Cv2.ImShow("calibresult1.png", dst);

            Cv2.InitUndistortRectifyMap(mtx, dist, new Mat(), newcameramtx, new Size(w, h), 5, mapx, mapy);
            Cv2.Remap(img, dst, mapx, mapy, InterpolationFlags.Linear);

            // crop the image
            dst = new Mat(dst, roi);
            Cv2.ImShow("calibresult2.png", dst);

            double mean_error = 0;
            for (int i = 0; i < objpoints.Length; ++i)
            {
                Mat imagePoints2 = new Mat();
                Cv2.ProjectPoints(objpoints[i], rvecs[i], tvecs[i], mtx, dist, imagePoints2);
                double error = Cv2.Norm(imagesPointsM[i], imagePoints2, NormTypes.L2);
                Console.WriteLine($"total error :{mean_error / objpoints.Count()}");
            }

            Cv2.WaitKey();
        }
    }
}


C++版本代码如下:

#include <opencv2/opencv.hpp>
#include <opencv2/ml.hpp>
#include <opencv2/cvconfig.h>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>    

#include <io.h>
#include <string>
#include <iostream>
#include <ctime>

using namespace cv;
using namespace std;

std::vector<cv::Point3f> GetChessboardObjectPoints(const cv::Size& boardSize, float squareSize) {
    std::vector<cv::Point3f> objectPoints;
    for (int i = 0; i < boardSize.height; ++i) {
        for (int j = 0; j < boardSize.width; ++j) {
            objectPoints.push_back(Point3f(squareSize * j, squareSize * i, 0.0f));
        }
    }
    return objectPoints;
}

void demo1()
{
    // 获取图片目录
    std::string inPath1 = "..\\images\\lefts\\left*.jpg";
    std::string inPath2 = "..\\images\\rights\\right*.jpg";
    intptr_t handle1, handle2;
    struct _finddata_t fileinfo1, fileinfo2;
    handle1 = _findfirst(inPath1.c_str(), &fileinfo1);
    handle2 = _findfirst(inPath2.c_str(), &fileinfo2);

    vector<string> images;
    do {
        string Name = fileinfo1.name;
        images.push_back("..\\images\\lefts\\" + Name);
    } while (!_findnext(handle1, &fileinfo1));

    do {
        string Name = fileinfo2.name;
        images.push_back("..\\images\\lefts\\" + Name);
    } while (!_findnext(handle2, &fileinfo2));

    TermCriteria criteria = TermCriteria(TermCriteria::EPS | TermCriteria::MAX_ITER, 30, 0.001);

    // 棋盘格内角点数量(行数和列数)
    cv::Size chessboardSize(7, 6);

    // 棋盘格尺寸(单位:米)
    float squareSize = 0.025f;

    // 存储棋盘格角点坐标的容器
    std::vector<std::vector<cv::Point3f>> objpoints;
    // 存储检测到的棋盘格角点坐标的容器
    std::vector<std::vector<cv::Point2f>> imgpoints;
    Mat gray;

    for (int i = 0; i < images.size(); i++)
    {
        Mat img = imread(images[i]);
        if (!img.empty())
        {
            cvtColor(img, gray, COLOR_BGR2GRAY);

            // Find the chess board corners
            std::vector<cv::Point2f> corners;
            bool ret = findChessboardCorners(gray, chessboardSize, corners);

            // If found, add object points, image points(after refining them)
            if (ret == true)
            {
                cornerSubPix(gray, corners, Size(11, 11), Size(-1, -1), criteria);
                // Draw and display the corners
                drawChessboardCorners(img, chessboardSize, corners, ret);

                objpoints.push_back(GetChessboardObjectPoints(chessboardSize, squareSize));
                imgpoints.push_back(corners);

                imshow("img", img);
                waitKey(100);
            }
        }
    }
}

void demo2()
{
    // 获取图片目录
    std::string inPath1 = "..\\images\\lefts\\left*.jpg";
    std::string inPath2 = "..\\images\\rights\\right*.jpg";
    intptr_t handle1, handle2;
    struct _finddata_t fileinfo1, fileinfo2;
    handle1 = _findfirst(inPath1.c_str(), &fileinfo1);
    handle2 = _findfirst(inPath2.c_str(), &fileinfo2);

    vector<string> images;
    do {
        string Name = fileinfo1.name;
        images.push_back("..\\images\\lefts\\" + Name);
    } while (!_findnext(handle1, &fileinfo1));

    do {
        string Name = fileinfo2.name;
        images.push_back("..\\images\\lefts\\" + Name);
    } while (!_findnext(handle2, &fileinfo2));

    TermCriteria criteria = TermCriteria(TermCriteria::EPS | TermCriteria::MAX_ITER, 30, 0.001);

    // 棋盘格内角点数量(行数和列数)
    cv::Size chessboardSize(7, 6);

    // 棋盘格尺寸(单位:米)
    float squareSize = 0.025f;

    // 存储棋盘格角点坐标的容器
    std::vector<std::vector<cv::Point3f>> objpoints;
    // 存储检测到的棋盘格角点坐标的容器
    std::vector<std::vector<cv::Point2f>> imgpoints;
    Mat gray;

    for (int i = 0; i < images.size(); i++)
    {
        Mat img = imread(images[i]);
        if (!img.empty())
        {
            cvtColor(img, gray, COLOR_BGR2GRAY);

            // Find the chess board corners
            std::vector<cv::Point2f> corners;
            bool ret = findChessboardCorners(gray, chessboardSize, corners);

            // If found, add object points, image points(after refining them)
            if (ret == true)
            {
                cornerSubPix(gray, corners, Size(11, 11), Size(-1, -1), criteria);
                // Draw and display the corners
                drawChessboardCorners(img, chessboardSize, corners, ret);

                objpoints.push_back(GetChessboardObjectPoints(chessboardSize, squareSize));
                imgpoints.push_back(corners);

                imshow("img", img);
                waitKey(10);
            }
        }
    }

    // 执行相机标定
    cv::Mat mtx, dist;
    std::vector<cv::Mat> rvecs, tvecs;
    cv::calibrateCamera(objpoints, imgpoints, cv::Size(gray.cols, gray.rows), mtx, dist, rvecs, tvecs);

    // 畸变校正
    Mat img = imread("../images/lefts/left12.jpg");
    int h = img.rows;
    int w = img.cols;
    cv::Mat mapx, mapy;
    Rect roi;
    cv::Mat newcameramtx = getOptimalNewCameraMatrix(mtx, dist, Size(w,h), 1, Size(w, h), &roi);

    // undistort
    Mat dst;
    undistort(img, dst, mtx, dist, newcameramtx);

    // crop the image
    dst = dst(roi);
    imshow("calibresult1.png", dst);

    initUndistortRectifyMap(mtx, dist, cv::Mat(), newcameramtx, Size(w, h), 5, mapx, mapy);
    remap(img, dst, mapx, mapy, INTER_LINEAR);

    // crop the image
    dst = dst(roi);
    imshow("calibresult2.png", dst);
   // 你会发现结果图像中所有的边界变直了

    // 反向投影误差
    // 我们可以利用反向投影误差对我们找到的参数的准确性进行估计。得到的结果越接近 0越好。
    // 有了内部参数,畸变参数和旋转变换矩阵,我们就可以使用cv2.projectPoints()将对象点转换到图像点。
    // 然后就可以计算变换得到图像与角点检测算法的绝对差了。
    // 然后我们计算所有标定图像的误差平均值。
    int mean_error = 0;
    for (int i = 0; i < objpoints.size(); i++)
    {
        vector<Point2f> imgpoints2;
        projectPoints(objpoints[i], rvecs[i], tvecs[i], mtx, dist, imgpoints2);
       int error = norm(imgpoints[i], imgpoints2, NORM_L2) / imgpoints2.size();
       mean_error += error;
       cout << "total error :" << mean_error / objpoints.size() << endl;
    }
    waitKey(0);
}

int main()
{
    //demo1();
    demo2();
}


Python版本代码如下:

demo1:

import numpy as np
import cv2
import glob

# termination criteria
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
# prepare object points, like (0,0,0), (1,0,0), (2,0,0) ....,(6,5,0)
objp = np.zeros((6 * 7, 3), np.float32)
objp[:, :2] = np.mgrid[0:7, 0:6].T.reshape(-1, 2)
# Arrays to store object points and image points from all the images.
objpoints = []  # 3d point in real world space
imgpoints = []  # 2d points in image plane.
images = glob.glob('../images/lefts/left*.jpg')
images += glob.glob('../images/rights/right*.jpg')

for fname in images:
    img = cv2.imread(fname)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    # Find the chess board corners
    ret, corners = cv2.findChessboardCorners(gray, (7, 6), None)
    # If found, add object points, image points (after refining them)
    if ret == True:
        objpoints.append(objp)
        corners2 = cv2.cornerSubPix(gray, corners, (11, 11), (-1, -1), criteria)
        imgpoints.append(corners)
        # Draw and display the corners
        cv2.drawChessboardCorners(img, (7, 6), corners2, ret)
        cv2.imshow('img', img)
        cv2.waitKey(0)
cv2.destroyAllWindows()


demo2:

import numpy as np
import cv2
import glob

# termination criteria
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
# prepare object points, like (0,0,0), (1,0,0), (2,0,0) ....,(6,5,0)
objp = np.zeros((6 * 7, 3), np.float32)
objp[:, :2] = np.mgrid[0:7, 0:6].T.reshape(-1, 2)
# Arrays to store object points and image points from all the images.
objpoints = []  # 3d point in real world space
imgpoints = []  # 2d points in image plane.
images = glob.glob('../images/lefts/left*.jpg')
images += glob.glob('../images/rights/right*.jpg')

for fname in images:
    img = cv2.imread(fname)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    # Find the chess board corners
    ret, corners = cv2.findChessboardCorners(gray, (7, 6), None)
    # If found, add object points, image points (after refining them)
    if ret == True:
        objpoints.append(objp)
        corners2 = cv2.cornerSubPix(gray, corners, (11, 11), (-1, -1), criteria)
        imgpoints.append(corners)
        # Draw and display the corners
        cv2.drawChessboardCorners(img, (7, 6), corners2, ret)
        cv2.imshow('img', img)
        cv2.waitKey(10)
cv2.destroyAllWindows()

##################### 标定  #####################
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None)

# 畸变校正
img = cv2.imread('../images/lefts/left12.jpg')
h, w = img.shape[:2]
newcameramtx, roi = cv2.getOptimalNewCameraMatrix(mtx, dist, (w, h), 1, (w, h))

# 使用 cv2.undistort()  是最简单的方法。只 使用这个函数和上面得到 的 ROI 对结果进行裁剪。

# undistort
dst = cv2.undistort(img, mtx, dist, None, newcameramtx)
# crop the image
x, y, w, h = roi
dst = dst[y:y + h, x:x + w]
cv2.imshow('calibresult1.png', dst)

# 使用 remapping  应 属于 曲线救国 了。 先我们 找到从畸变图像到畸变图像的映射方程。再使用 重映射方程
# undistort
mapx, mapy = cv2.initUndistortRectifyMap(mtx, dist, None, newcameramtx, (w, h), 5)
dst = cv2.remap(img, mapx, mapy, cv2.INTER_LINEAR)
# crop the image
x, y, w, h = roi
dst = dst[y:y + h, x:x + w]
cv2.imshow('calibresult2.png', dst)
# 你会发现结果图像中所有的边界变直了

# 反向投影误差
# 我们可以利用反向投影误差对我们找到的参数的准确性进行估计。得到的结果越接近 0越好。
# 有了内部参数,畸变参数和旋转变换矩阵,我们就可以使用cv2.projectPoints()将对象点转换到图像点。
# 然后就可以计算变换得到图像与角点检测算法的绝对差了。
# 然后我们计算所有标定图像的误差平均值。
mean_error = 0
for i in range(len(objpoints)):
    imgpoints2, _ = cv2.projectPoints(objpoints[i], rvecs[i], tvecs[i], mtx, dist)
    error = cv2.norm(imgpoints[i], imgpoints2, cv2.NORM_L2) / len(imgpoints2)
    mean_error += error
print("total error: ", mean_error / len(objpoints))
cv2.waitKey(0)


demo3:

import numpy as np
import cv2

criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
cap = cv2.VideoCapture(0)

# 等比缩放
# frame_height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT)
# frame_width = cap.get(cv2.CAP_PROP_FRAME_WIDTH)
#
# frame_height = int(480 / frame_width * frame_height)
# ret = cap.set(cv2.CAP_PROP_FRAME_HEIGHT, frame_height)
# ret = cap.set(cv2.CAP_PROP_FRAME_WIDTH, 480)

while cap.isOpened():
    # img = cv2.imread(fname)
    ret, img = cap.read()
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    ret, corners = cv2.findChessboardCorners(image=gray, patternSize=(8, 6), corners=None)
    '''
    第一个参数Image,传入拍摄的棋盘图Mat图像,必须是8位的灰度或者彩色图像;
    第二个参数patternSize,每个棋盘图上内角点的行列数,一般情况下,行列数不要相同,便于后续标定程序识别标定板的方向;
    第三个参数corners,用于存储检测到的内角点图像坐标位置,一般用元素是Point2f的向量来表示:vector<Point2f> image_points_buf;
    第四个参数flage:用于定义棋盘图上内角点查找的不同处理方式,有默认值。
    '''
    print(corners)
    print('---------')
    if ret == True:
        # objpoints.append(objp)
        corners2 = cv2.cornerSubPix(gray, corners, (11, 11), (-1, -1), criteria)
        # imgpoints.append(corners)
        # Draw and display the corners
        cv2.drawChessboardCorners(img, (8, 6), corners2, ret)

    cv2.imshow('img', img)
    key = cv2.waitKey(delay=10)
    if key == ord("q"):
        break

cv2.destroyAllWindows()