程序流程

  1. 准备好一系列用来相机标定的图片;
  2. 对每张图片提取角点信息;
  3. 由于角点信息不够精确,进一步提取亚像素角点信息;
  4. 在图片中画出提取出的角点;
  5. 相机标定;
  6. 对标定结果评价,计算误差;
  7. 使用标定结果对原图片进行矫正;

opencv实现代码:

#include <iostream>
#include <vector>
#include <fstream>
#include <string>
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/calib3d/calib3d.hpp>using namespace std;
using namespace cv;int main()
{ifstream inImgPath("calibdata.txt");    //标定所用图像文件的路径vector<string> imgList;vector<string>::iterator p;string temp;if (!inImgPath.is_open()){cout << "没有找到文件" << endl;}//读取文件中保存的图片文件路径,并存放在数组中while (getline(inImgPath, temp)){imgList.push_back(temp);}ofstream fout("caliberation_result.txt");   //保存标定结果的文件cout << "开始提取角点......" << endl;cv::Size image_size;//保存图片大小cv::Size pattern_size = cv::Size(9, 10);//标定板上每行、每列的角点数;测试图片中的标定板上内角点数为8*6vector<cv::Point2f> corner_points_buf;//建一个数组缓存检测到的角点,通常采用Point2f形式,以图像的左上角为原点,而不是以棋盘的左上角为原点vector<cv::Point2f>::iterator corner_points_buf_ptr;vector<vector<cv::Point2f>> corner_points_of_all_imgs;   //所有图片的角点信息int image_num = 0;string filename;while(image_num < imgList.size()){filename = imgList[image_num++];cout << "image_num = " << image_num << endl;cout << filename << endl;cv::Mat imageInput = cv::imread(filename);if (image_num == 1){image_size.width = imageInput.cols;image_size.height = imageInput.rows;cout << "image_size.width = " << image_size.width << endl;cout << "image_size.height = " << image_size.height << endl;}if (findChessboardCorners(imageInput, pattern_size, corner_points_buf) == 0){cout << "can not find all chessboard corners!\n";   //找不到角点exit(1);}else{cv::Mat gray;cv::cvtColor(imageInput, gray, COLOR_RGB2GRAY);              //将原来的图片转换为灰度图片cv::find4QuadCornerSubpix(gray, corner_points_buf, cv::Size(5, 5));   //提取亚像素角点,Size(5, 5),角点搜索窗口的大小。corner_points_of_all_imgs.push_back(corner_points_buf);     cv::drawChessboardCorners(gray, pattern_size, corner_points_buf, true);   cv::imshow("camera calibration", gray);cv::waitKey(100);}}int total = corner_points_of_all_imgs.size();cout << "total=" << total << endl;int cornerNum = pattern_size.width * pattern_size.height;//每张图片上的总的角点数// cout<<cornerNum<<endl;for (int i = 0; i < total;i++){cout << "--> 第" << i + 1 << "幅图片的数据 -->:" << endl;for (int j = 0;j < cornerNum;j++){cout << "-->" << corner_points_of_all_imgs[i][j].x;cout << "-->" << corner_points_of_all_imgs[i][j].y;if ((j + 1) % 3 == 0){cout << endl;}else{cout.width(10);}}cout << endl;}cout << endl << "角点提取完成" << endl;//摄像机标定cout << "开始标定………………" << endl;cv::Mat cameraMatrix = cv::Mat(3, 3, CV_32FC1, cv::Scalar::all(0));//内外参矩阵,H——单应性矩阵cv::Mat distCoefficients = cv::Mat(1, 5, CV_32FC1, cv::Scalar::all(0));//摄像机的5个畸变系数:k1,k2,p1,p2,k3vector<cv::Mat> tvecsMat;//每幅图像的平移向量,t,若干张图片的,不是一张图像的vector<cv::Mat> rvecsMat;//每幅图像的旋转向量(罗德里格旋转向量,若干张图片的,不是一张图像的vector<vector<cv::Point3f>> objectPoints;//保存所有图片的角点的三维坐标,所有图片的//初始化每一张图片中标定板上角点的三维坐标                 //世界坐标系,以棋盘格的左上角为坐标原点int i, j, k;for (k = 0;k < image_num;k++)//遍历每一张图片{vector<cv::Point3f> tempCornerPoints;//每一幅图片对应的角点数组//遍历所有的角点for (i = 0;i < pattern_size.height;i++){for (j = 0;j < pattern_size.width;j++){cv::Point3f singleRealPoint;//一个角点的坐标,初始化三维坐标singleRealPoint.x = i * 10;     //10是长/宽,根据黑白格子的长和宽,计算出世界坐标系(x,y,z)singleRealPoint.y = j * 10;singleRealPoint.z = 0;//假设z=0tempCornerPoints.push_back(singleRealPoint);}}objectPoints.push_back(tempCornerPoints);}cv::calibrateCamera(objectPoints, corner_points_of_all_imgs, image_size, cameraMatrix, distCoefficients, rvecsMat, tvecsMat, 0);cout << "标定完成" << endl;//开始保存标定结果cout << "开始保存标定结果" << endl;cout << endl << "相机相关参数:" << endl;fout << "相机相关参数:" << endl;cout << "1.内外参数矩阵:" << endl;fout << "1.内外参数矩阵:" << endl;cout << "大小:" << cameraMatrix.size() << endl;fout << "大小:" << cameraMatrix.size() << endl;//cout<<cameraMatrix.depth()<<endl;tempCornerPointsfout << "大小:" << distCoefficients.size() << endl;cout << distCoefficients << endl;fout << distCoefficients << endl;cout << endl << "图像相关参数:" << endl;fout << endl << "图像相关参数:" << endl;cv::Mat rotation_Matrix = cv::Mat(3, 3, CV_32FC1, cv::Scalar::all(0));//旋转矩阵for (i = 0;i < image_num;i++){cout << "第" << i + 1 << "幅图像的旋转向量:" << endl;fout << "第" << i + 1 << "幅图像的旋转向量:" << endl;cout << rvecsMat[i] << endl;fout << rvecsMat[i] << endl;cout << "第" << i + 1 << "幅图像的旋转矩阵:" << endl;fout << "第" << i + 1 << "幅图像的旋转矩阵:" << endl;cv::Rodrigues(rvecsMat[i], rotation_Matrix);//将旋转向量转换为相对应的旋转矩阵cout << rotation_Matrix << endl;fout << rotation_Matrix << endl;cout << "第" << i + 1 << "幅图像的平移向量:" << endl;fout << "第" << i + 1 << "幅图像的平移向量:" << endl;cout << tvecsMat[i] << endl;fout << tvecsMat[i] << endl;}cout << "结果保存完毕" << endl;//对标定结果进行评价cout << "开始评价标定结果......" << endl;//计算每幅图像中的角点数量,假设全部角点都检测到了int corner_points_counts;corner_points_counts = pattern_size.width * pattern_size.height;cout << "每幅图像的标定误差:" << endl;fout << "每幅图像的标定误差:" << endl;double err = 0;//单张图像的误差double total_err = 0;//所有图像的平均误差for (i = 0;i < image_num;i++){vector<cv::Point2f> image_points_calculated;//存放新计算出的投影点的坐标vector<cv::Point3f> tempPointSet = objectPoints[i];cv::projectPoints(tempPointSet, rvecsMat[i], tvecsMat[i], cameraMatrix, distCoefficients, image_points_calculated);  //计算根据内外参等重投影出来的新的二维坐标,输出到image_points_calculated//计算新的投影点与旧的投影点之间的误差vector<cv::Point2f> image_points_old = corner_points_of_all_imgs[i];    //向量//将两组数据换成Mat格式cv::Mat image_points_calculated_mat = cv::Mat(1, image_points_calculated.size(), CV_32FC2);   //将mat矩阵转成1维的向量cv::Mat image_points_old_mat = cv::Mat(1, image_points_old.size(), CV_32FC2);for (j = 0;j < tempPointSet.size();j++){image_points_calculated_mat.at<cv::Vec2f>(0, j) = cv::Vec2f(image_points_calculated[j].x, image_points_calculated[j].y);  //vec2f->一个二维的向量image_points_old_mat.at<cv::Vec2f>(0, j) = cv::Vec2f(image_points_old[j].x, image_points_old[j].y);   //直接调用函数,不用定义对象}err = cv::norm(image_points_calculated_mat, image_points_old_mat, cv::NORM_L2); //输入的是矩阵err /= corner_points_counts;      //每个角点的误差total_err += err;cout << "第" << i + 1 << "幅图像的平均误差:" << err << "像素" << endl;fout << "第" << i + 1 << "幅图像的平均误差:" << err << "像素" << endl;}cout << "总体平均误差:" << total_err / image_num << "像素" << endl;fout << "总体平均误差:" << total_err / image_num << "像素" << endl;cout << "评价完成" << endl;//下面就是矫正图像的代码cv::Mat mapx = cv::Mat(image_size, CV_32FC1);  //对应坐标的重映射参数cv::Mat mapy = cv::Mat(image_size, CV_32FC1);cv::Mat R = cv::Mat::eye(3, 3, CV_32F);   //定义的对角线为1的对角矩阵cout << "保存矫正图像" << endl;string imageFileName;std::stringstream StrStm;for (int i = 0;i < image_num;i++){cout << "Frame #" << i + 1 << endl;cv::initUndistortRectifyMap(cameraMatrix, distCoefficients, R, cameraMatrix, image_size, CV_32FC1, mapx, mapy);      //输入内参,纠正后的内参,外参等,计算输出矫正的重映射参数(相片尺寸 width*height),每个像素点都需要转换cv::Mat src_image = cv::imread(imgList[i], 1);     cv::Mat new_image = src_image.clone();cv::remap(src_image, new_image, mapx, mapy, cv::INTER_LINEAR);    imshow("原始图像", src_image);imshow("矫正后图像", new_image);StrStm.clear();imageFileName.clear();StrStm << i + 1;StrStm >> imageFileName;imageFileName += "_d.jpg";cv::imwrite(imageFileName, new_image);cv::waitKey(200);}cout << "保存结束" << endl;fout.close();  //cv::waitKey(0);return 0;
}

相关文章:三维重建学习(4):张正友相机标定程序实现(OpenCV)_hongbin_xu的博客-CSDN博客_标定程序

opencv c++实现棋盘格标定相关推荐

  1. 利用opencv棋盘格标定法对鱼眼图像校正分析

    利用opencv棋盘格标定法对鱼眼图像校正分析 一.开发环境 PC端.vs2013+opencv3.0.摄像头为淘宝购置的鱼眼摄像头外设+iphone6 二.镜头标定 1.  输入畸变的棋盘格图以及棋 ...

  2. 利用OpenCv程序生成棋盘格标定板,并且实现像素单位与米制单位的转换

    /********************************************************************************************* 程序功能: ...

  3. 相机标定与棋盘格标定

    文章目录 1.相机标定 1.1 相机标定介绍 1.2 相机标定的意义 1.3 相机标定方法 1.4 相机标定的用途 2.相机参数 2.1 内参 2.2 外参 2.3 畸变参数 3.棋盘格标定 3.1 ...

  4. OpenCV+C++面阵相机标定函数的使用

    OpenCV+C++面阵相机标定函数的使用 1. FindChessboardCorners 找到标定板内角点位置(角点是指黑白色相接的方块定点部分:内角点是不与标定板边缘接触的内部角点) 函数试图确 ...

  5. 【ZED】从零开始使用ZED相机(五):Opencv+Python实现相机标定(双目)

    引言 同样Opencv+Python实现双目相机的标定,单目标定详见[ZED]从零开始使用ZED相机(五):Opencv+Python实现相机标定(单目) 1 cv2.stereoCalibrate ...

  6. Python OpenCV实践,相机标定

    Python OpenCV实践,相机标定 前言 准备棋盘格 标定相机 图像去畸变 前言 本篇主要是使用python opencv标定相机内参和畸变参数的记录,主要参考opencv官方文档中的示例. 本 ...

  7. python棋盘格标定程序

    根据棋盘格标定板的尺寸和格子数量.大小修改程序 #标定命令 python3 cal.py --image_size 1280x720 --corner 11x8 --square 30import o ...

  8. 计算机视觉——棋盘格标定法获取相机内参外参

    计算机视觉--棋盘格标定法获取相机内参外参 一.原理 相机标定目的 相机标定的输入 相机标定的输出 相机标定策略 相机拍摄图像变换过程 相机内参 相机外参 二.环境 三.数据集 四.运行结果与分析 角 ...

  9. 基于python的opencv相机标定(采用黑白棋盘格标定板)

    基于python的相机标定(采用黑白棋盘格图片) 系列文章目录 [第一章 基于python的相机标定(采用黑白棋盘格图片)](https://blog.csdn.net/HWHXXX/article/ ...

最新文章

  1. 算法--------俄罗斯套娃信封问题(Java版本)
  2. 关于MySQL 5.6 中文乱码的问题(尤其是windows的gbk编码)
  3. mongodb中分页显示数据集的学习
  4. 前端学习(2976):路由钩子函数
  5. angualr 单选全选方法(适用购物车/各种列表删除等)
  6. iOS-项目常见文件
  7. APP设计灵感|仪表盘这样设计,所有信息一目了然!
  8. 随机初始化(代码实现)
  9. Linux 命令(2)—— od 命令
  10. python读音Python怎么读
  11. MySQL - 查询今天的数据(以及昨天、本月、上个月、今年...)
  12. struts响应用户请求的工作流程
  13. java源码社团管理系统_基于jsp的社团管理系统-JavaEE实现社团管理系统 - java项目源码...
  14. 未来教育计算机二级2016版,20163未来教育计算机二级题库(操作题).docx
  15. 中华第一考----系统架构设计师考试
  16. 自然语言处理 | (4)英文文本处理与NLTK
  17. 《自然语言处理入门》何晗阅读笔记—第1章:自然语言处理基础概念
  18. 【修真院“善良”系列之十七】请拿好这支时间之箭
  19. 二建机电实务视频教程
  20. linux系统提升硬盘写速度的方法

热门文章

  1. 对于青少年编程等级考试的认识
  2. ios 开发中遇到的一些问题
  3. win10内存占用率过高怎么办_DNF:WIN10玩DNF卡顿,内存占用过高的解决方法
  4. 跟 John Ousterhout 学 Raft 算法
  5. 两点之间最短距离:贪心算法 (DIJKSTRA算法)
  6. html在一行内横向排列并排同行同时显示两个多个div盒子的方法(CSS浮动清除float-clear/inline)/办法
  7. (29)Verilog实现倍频【方法二】
  8. python适合做网页吗_python是否适合网页编程详解
  9. 电机远计算机控制,电机控制器
  10. 如何关闭WPS烦人的广告推送