相机标定后得到内参和畸变系数,如何用opencv + c++实现世界坐标系转像素坐标系,代码怎么写,是有对应的函数吗
一般是世界坐标系先转成相机坐标系再都图像坐标系
原理、公式一般的鱼眼图像校正、图像拼接的论文里都有,自然校正方面的代码里也包含了。CSDN上有很多。
对于文件夹下面的每张图片都是序号.bmp格式 的图像时可以使用如下方法按顺序读取。
#include<stdio.h>
#include "opencv2/opencv.hpp"
#include <opencv2\highgui\highgui.hpp>
#include<string>
#include<iostream>
using namespace cv;
using namespace std;
void main(){
char fileName[500];
Mat pic;
for (int i = 0; i < 110; i++) {//文件夹下面一共有110张图片
printf("start deal:%d\n", i + 1);
sprintf_s(fileName, ".//picture//%d.bmp", i);//提取出文价夹下面的每张图片路径,放到fileName
pic = imread(fileName);//读取fileName路径下面的图片
imshow("tpian", pic);//显示图像
waitKey(1000);//显示延时
}
pic.release();//将Mat释放
}
使用OpenCV和C++实现世界坐标系转化为像素坐标系的步骤如下:
1.获取相机标定的内参和畸变系数,存储为相机的畸变矩阵和内参矩阵。
2.定义三维点(世界坐标系)和二维点(像素坐标系),并将三维点按照世界坐标系坐标系下的坐标存储。
std::vector<cv::Point3f> world_point;//存储世界坐标系下的三维点
std::vector<cv::Point2f> pixel_point;//存储像素坐标系下的二维点
world_point.push_back(cv::Point3f(0,0,0));//将世界坐标系下的坐标存储到vector中
pixel_point.push_back(cv::Point2f(0,0));//将相应像素坐标系下的坐标存储到vector中
3.定义相机的畸变矩阵和内参矩阵,并使用相应数据进行实例化。
Mat camera_distortion_coefficients;//相机畸变系数矩阵
Mat intrinsic_matrix;//内参矩阵
intrinsic_matrix = (Mat_<double>(3, 3) << fx, 0, cx, 0, fy, cy, 0, 0, 1);//将内参元素存入Mat矩阵
camera_distortion_coefficients = (Mat_<double>(1, 5) << k_1, k_2, p_1, p_2, k_3);//将畸变系数存入Mat矩阵
4.使用函数solvePnP将世界坐标系下的三维点和像素坐标系下的二维点进行转化。
Mat rvec, tvec;//存储旋转向量和平移向量
bool ok = solvePnP(world_point, pixel_point, intrinsic_matrix, camera_distortion_coefficients, rvec, tvec, false, cv::SOLVEPNP_IPPE);//求解转化关系
5.使用函数projectPoints将世界坐标系下的三维点转化为像素坐标系下的二维点。
vector<Point3f> objectPoint;
vector<Point2f> imagePoints;
double a = 2.0, b = 3.0, c = 10.0; // 假设一个世界坐标系中的三维点坐标为(2, 3, 10)
objectPoint.push_back(Point3f(a, b, c));//将世界坐标系下的坐标存储到vector中
projectPoints(objectPoint, rvec, tvec, intrinsic_matrix, camera_distortion_coefficients, imagePoints);//求解像素坐标系下的对应两维点
完整的代码示例如下:
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main(int argc, char* argv[])
{
// 相机内参矩阵
double fx = 1, fy = 1, cx = 1, cy = 1;//相机内参
double k_1 = 0, k_2 = 0, p_1 = 0, p_2 = 0, k_3 = 0;//畸变系数
Mat intrinsic_matrix = (Mat_<double>(3, 3) << fx, 0, cx, 0, fy, cy, 0, 0, 1);//内参矩阵
Mat camera_distortion_coefficients = (Mat_<double>(1, 5) << k_1, k_2, p_1, p_2, k_3);//相机畸变矩阵
//世界坐标系下的三维点(假设三维点坐标为(1,2,3))
vector<Point3f> objectPoint;
objectPoint.push_back(Point3f(1, 2, 3));
// 将三维点以相机坐标系下的形式存放起来(即世界坐标系转为相机坐标系)
vector<Point2f> imagePoints;
Mat rvec, tvec;
bool is_success = solvePnP(objectPoint, imagePoints, intrinsic_matrix, camera_distortion_coefficients, rvec, tvec, false, cv::SOLVEPNP_ITERATIVE);
//将相应世界坐标系下的三维点转为像素坐标系下的二维点
vector<Point2f> imagePoints2;
projectPoints(objectPoint, rvec, tvec, intrinsic_matrix, camera_distortion_coefficients, imagePoints2);
return 0;
}
需要注意的是,世界坐标系的拍摄场景应当是三维的,如拍摄物体等;如果拍摄场景为二维的,如平面图像等,则不需要进行世界坐标系到像素坐标系的转化,只需要进行像素坐标系的处理即可。