当前位置:网站首页>合工大苍穹战队视觉组培训Day9——相机标定
合工大苍穹战队视觉组培训Day9——相机标定
2022-08-05 05:59:00 【工大电科小趴菜】
目录
学习目标:
- pnp解算
- 相机标定
- 去畸变
学习内容:
直接用电脑的摄像头标定一个相机,标定完后使用cv::undistort方法去除相机的畸变。
学习时间:
- 2022年8月1日到2022年8月4日
学习产出:
一、前期准备
这次长话短说吧,网上相关资料很多,可以参考https://blog.csdn.net/LuohenYJ/article/details/104697062
标定板我用的

可以去这个网站:Camera Calibration Pattern Generator – calib.io去生成
摄像头是电脑的摄像头。
二、采集相关数据
#include "opencv2/opencv.hpp"
#include <string>
#include <iostream>
using namespace cv;
using namespace std;
int main()
{
VideoCapture inputVideo(0);
//inputVideo.set(CV_CAP_PROP_FRAME_WIDTH, 320);
//inputVideo.set(CV_CAP_PROP_FRAME_HEIGHT, 240);
if (!inputVideo.isOpened())
{
cout << "Could not open the input video " << endl;
return -1;
}
Mat frame;
string imgname;
int f = 1;
while (1) //Show the image captured in the window and repeat
{
inputVideo >> frame; // read
if (frame.empty()) break; // check if at end
imshow("Camera", frame);
char key = waitKey(1);
if (key == 27)break;
if (key == 'q' || key == 'Q')
{
imgname = to_string(f++) + ".jpg";
imwrite(imgname, frame);
}
}
cout << "Finished writing" << endl;
return 0;
}三、进行标定
//加载图片//
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
// 保存多张图片对象点列表
vector<vector<Point3f>> objectPoints;
// 保存多张图片的角点列表
vector<vector<Point2f>> cornerPoints;
int main(){
// 图片像素尺寸
Size imgSize;
// 图片路径
cv::String src_path = "./assets/camerargb_*.jpg";
std::vector<String> filenames;
cv::glob(src_path, filenames);//获取路径下所有文件名
cout << "filenames.size:" << filenames.size() << endl;
for (auto& imgName : filenames) {
// 读取图片
Mat img = imread(imgName, IMREAD_COLOR);
// 获取图片像素尺寸
imgSize = img.size();
std::cout << "name: " << imgName<< " imgSize: " << imgSize << std::endl;
//...
}
return 0;
}
//查找角点//
// 棋盘格的尺寸(宽6,高9)
const Size patternSize(6, 9);
// 黑方格的大小 20mm
const int squareSize = 20;
/**
* 在指定图片中查找角点,并将结果输出到corners中
* @param img 待检测图片
* @param corners 检测到的焦点列表
* @return 是否检测到角点(两个黑方格的交点)
*/
bool findCorners(Mat &img, vector<Point2f> &corners) {
Mat gray;
// 将图片转成灰度图
cvtColor(img, gray, COLOR_RGB2GRAY);
// 查找当前图片所有的角点
bool patternWasFound = findChessboardCorners(gray, patternSize, corners);
if (patternWasFound) { // 找到角点
// 提高角点的精确度
// 原理:https://docs.opencv.org/4.1.0/dd/d1a/group__imgproc__feature.html#ga354e0d7c86d0d9da75de9b9701a9a87e
cornerSubPix(gray, corners, Size(11, 11), Size(-1, -1),
TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 30, 0.1));
}
// 将所有的焦点在原图中绘制出来
drawChessboardCorners(img, patternSize, corners, patternWasFound);
// 绘制完角点之后,显示原图
imshow("src", img);
if (!patternWasFound){
cout << "角点检测失败!" << endl;
}
return patternWasFound;
}
// 保存多张图片对象点列表
vector<vector<Point3f>> objectPoints;
// 保存多张图片的角点列表
vector<vector<Point2f>> cornerPoints;
void calcObjectPoints(vector<Point3f> &objPoint) {
// 计算uv空间中角点对应的相机坐标系坐标值,设Z为0
for (int i = 0; i < patternSize.height; ++i)
for (int j = 0; j < patternSize.width; ++j)
objPoint.emplace_back(j * squareSize, i * squareSize, 0);
}
// 图片像素尺寸
Size imgSize;
int main(){
// 图片路径
cv::String src_path = "./assets/camerargb_*.jpg";
std::vector<String> filenames;
cv::glob(src_path, filenames);//获取路径下所有文件名
cout << "filenames.size:" << filenames.size() << endl;
for (auto& imgName : filenames) {
// 读取图片
Mat img = imread(imgName, IMREAD_COLOR);
// 获取图片像素尺寸
imgSize = img.size();
std::cout << "name: " << imgName<< " imgSize: " << imgSize << std::endl;
// 声明每张图片的角点
vector<Point2f> corners;
bool found = findCorners(img, corners);
if (found) {
vector<Point3f> objPoints;
calcObjectPoints(objPoints);
// 找到角点,证明这张图是有效的
objectPoints.push_back(objPoints);
cornerPoints.push_back(corners);
}
}
return 0;
}
//执行相机标定//
Mat cameraMatrix; // 相机参数矩阵
Mat disCoffes; // 失真系数 distortion coefficients
Mat rvecs; // 图片旋转向量
Mat tvecs; // 图片平移向量
calibrateCamera(objectPoints, cornerPoints, imgSize, cameraMatrix, disCoffes, rvecs, tvecs);
cout << "标定矩阵:" << cameraMatrix << endl;
cout << "畸变矩阵:" << disCoffes << endl;
// save2xml(cameraMatrix, distCoffes);
waitKey();
//保存标定结果//
void save2xml(const Mat &cameraMatrix, const Mat &disCoffes) {
// 获取当前时间
time_t tm;
time(&tm);
struct tm *t2 = localtime(&tm);
char buf[1024];
strftime(buf, sizeof(buf), "%c", t2);
// 写出数据
String inCailFilePath = "./inCailFilePath.xml";
FileStorage inCailFs(inCailFilePath, FileStorage::WRITE);
inCailFs << "calibration_time" << buf;
inCailFs << "cameraMatrix" << cameraMatrix;
inCailFs << "distCoffes" << disCoffes;
inCailFs.release();
}
//我最后输出了yml文件,也可以是xml文件格式//四、用cv::undistort方法去除畸变
#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc.hpp>
using namespace cv;
using namespace std;
int main(int argc, char **argv) {
// 读取相机矩阵、畸变系数
cv::FileStorage fs("你的yml文件", FileStorage::READ);
int image_width{0}, image_height{0};
fs["image_width"] >> image_width;
fs["image_height"] >> image_height;
Size image_size = Size(image_width, image_height);
Mat intrinsic_matrix, distortion_coeffs;
fs["cameraMatrix"] >> intrinsic_matrix;
fs["distCoeffs"] >> distortion_coeffs;
fs.release();
std::cout << intrinsic_matrix << std::endl;
std::cout << distortion_coeffs << std::endl;
std::cout << image_size << std::endl;
const Mat &image0 = imread("./calib_chess_img/image_0.jpg", IMREAD_COLOR);
Mat image;
undistort(image0, image, intrinsic_matrix, distortion_coeffs);
imshow("original", image0);
imshow("undistorted", image);
waitKey();
return 0;
}
PS:代码仅供参考。
五、效果

六、心得
我觉得做的不是很好很对,很多东西还是得进一步弄好,等我多学点再后续更新吧。
边栏推荐
- 【内推】新相微电子
- D41_buffer pool
- 格式化代码缩进的小技巧
- 【FAQ】CCAPI Compatible EOS Camera List (Updated in August 2022)
- 自营商城提高用户留存小技巧,商城对接小游戏分享
- LaTeX笔记
- 盒子模型中过度约束问题及其解决办法
- 利用将网页项目部署到阿里云上(ngnix)
- In-depth analysis if according to data authority @datascope (annotation + AOP + dynamic sql splicing) [step by step, with analysis process]
- Pytorch distributed parallel processing
猜你喜欢

(四)旋转物体检测数据roLabelImg转DOTA格式

LaTeX使用frame制作PPT图片没有标号

LeetCode刷题记录(2)

Successful indie developers deal with failure & imposters

(2022杭电多校六)1012-Loop(单调栈+思维)

【5】Docker中部署MySQL

农场游戏果园系统+牧场养殖系统+广告联盟模式流量主游戏小程序APP V1

Tencent Internal Technology: Evolution of Server Architecture of "The Legend of Xuanyuan"

cs231n learning record

lingo入门——河北省第三届研究生建模竞赛B题
随机推荐
技术分析模式(十一)如何交易头肩形态
cs231n学习记录
开源中国活动合作说明书
格式化代码缩进的小技巧
After docker is deployed, mysql cannot connect
小程序input框不允许输入负数
Late night drinking, 50 classic SQL questions, really fragrant~
(2022杭电多校六)1010-Planar graph(最小生成树)
document.querySelector()方法
NB-IOT智能云家具项目系列实站
深夜小酌,50道经典SQL题,真香~
摆脱极域软件的限制
Come, come, let you understand how Cocos Creator reads and writes JSON files
花花省V5淘宝客APP源码无加密社交电商自营商城系统带抖音接口
golang-条件语句
Tips for formatting code indentation
NACOS Configuration Center Settings Profile
MyCat安装
vscode notes
八大排序之快速排序