1、引言
自动泊车的博客小编已经写了好几篇了,但是部分都没有代码,今天我从鱼眼相机图像到鸟瞰变换之间的变换写一篇博客,以记录这段过程
首先我们看下车位的鱼眼图像
我们已经通过标定得到了内参与畸变参数,接下来我们进行矫正,由于矫正会损失好多有效信息,这里我给出两个opencv 的API,我们看下
fisheye::estimateNewCameraMatrixForUndistortRectify(cameraMatrix1,distCoeffs1,image_size,R,new_cameraMatrix,0.8,image_size,1);
fisheye::initUndistortRectifyMap(cameraMatrix1,distCoeffs1, R,new_cameraMatrix,image_size,CV_16SC2,mapx,mapy);
remap(image, dst, mapx, mapy, INTER_LINEAR);
在这里我们先求出了映射表,然后再进行remap.
另外一个API直接对图像进行矫正
cv::fisheye::undistortImage(image,UndistortImg,cameraMatrix1,distCoeffs1,new_intrinsic_mat);
后者API的速度太慢,我们这里嵌入式资源有限,不考虑。
2、图像矫正
首先我们看下矫正之后的图像
可以看出来,第二张损失了很多车位线的信息,因此在这我们只能牺牲一些图像的精度,保证图像的视野,所以采用第一张图的这种矫正方式,参数可调,具体可参考opencv官网。
https://docs.opencv.org/master/db/d58/group__calib3d__fisheye.html#ga384940fdf04c03e362e94b6eb9b673c9
3、鸟瞰图像
矫正之后我们需要做一步鸟瞰,来形成上帝视角,先看图
后面我还会通过调节RT相机的外参,来改变视角,做完这些,我们就可以来进行车位识别了,这个前面博客已经提供了思路,不在赘述。
在这给出矫正代码,代码中我做了些优化,将矩阵计算之后输入到xml,后续对视频则不需要每帧计算。
//
// Created by lenovo on 19-5-16.
//
#include
#include
using namespace cv;
using namespace std;
using namespace fisheye;
Mat image;
Mat cameraMatrix1;
cv::Mat distCoeffs1(4, 1, cv::DataType<double>::type);
Mat UndistortImg;
Mat new_intrinsic_mat;
//Mat new_intrinsic_mat(3, 3, CV_64FC1, Scalar(0))亦可,注意数据类型;
int fx_threshold_min=80;
int fy_threshold_min=80;
string winname="UndistortImg";
//TrackBar发生改变的回调函数
void onChangeTrackBar(int, void* );
int main()
{
string bar_name_1="fx";
string bar_name_2="fy";
image=imread("./saveImg.jpg");
imwrite("image.jpg",image);
Mat dst;
cameraMatrix1=Mat::eye(3, 3, cv::DataType<double>::type);
distCoeffs1.at<double>(0,0) = 0.061439051;
distCoeffs1.at<double>(1,0) = 0.03187556;
distCoeffs1.at<double>(2,0) = -0.00726151;
distCoeffs1.at<double>(3,0) = -0.00111799;
//distCoeffs1.at(4,0) = -0.00678974;
//Taken from Mastring OpenCV d
double fx = 328.61652824;
double fy = 328.56512516;
double cx = 629.80551148;
double cy = 340.5442837;
cameraMatrix1.at<double>(0, 0) = fx;
cameraMatrix1.at<double>(1, 1) = fy;
cameraMatrix1.at<double>(0, 2) = cx;
cameraMatrix1.at<double>(1, 2) = cy;
std::cout << "After calib cameraMatrix --- 1: " << cameraMatrix1 << std::endl;
std::cout << "After calib distCoeffs: --- 1" << distCoeffs1 << std::endl;
////////////////////////////////////////////////////////////////////
///// 鱼眼摄像头畸变矫正
////////////////////////////////////////////////////////////////////
Size image_size(1280,720);
Mat mapx = Mat(image_size, CV_32FC1);
Mat mapy = Mat(image_size, CV_32FC1);
Mat R = Mat::eye(3, 3, CV_32F);
Mat P = Mat::eye(3, 3, CV_32F);
Mat new_cameraMatrix=Mat::zeros(3,3,CV_32F);
//new_cameraMatrix=
fisheye::estimateNewCameraMatrixForUndistortRectify(cameraMatrix1,distCoeffs1,image_size,R,new_cameraMatrix,0.8,image_size,1);
//new_cameraMatrix=getOptimalNewCameraMatrix(cameraMatrix1, distCoeffs1, image_size, 1, image_size, 0);
cout<<"new cameraMatrix: "<<new_cameraMatrix<<endl;
// cv::fisheye::initUndistortRectifyMap()
fisheye::initUndistortRectifyMap(cameraMatrix1,distCoeffs1, R,new_cameraMatrix,image_size,CV_16SC2,mapx,mapy);
//cout<
FileStorage fs_x("../vocabulary_x.xml", FileStorage::WRITE);
FileStorage fs_y("../vocabulary_y.xml", FileStorage::WRITE);
fs_x<<"vocabulary_x"<<mapx;
fs_y<<"vocabulary_y"<<mapy;
FileStorage fs_x("../vocabulary_x.xml", FileStorage::READ);
FileStorage fs_y("../vocabulary_y.xml", FileStorage::READ);
fs_x["vocabulary_x"] >> mapx;
fs_y["vocabulary_y"] >> mapy;
double t1 = (double)getTickCount();
remap(image, dst, mapx, mapy, INTER_LINEAR);
//remap(image,dst,mapx,mapy,INTER_NEAREST);
////////////////////////////////////////////////////////////////////
///// 鱼眼摄像头畸变矫正
////////////////////////////////////////////////////////////////////
t1 = (double)getTickCount() - t1;
std::cout << "compute time :" << t1*1000.0 / cv::getTickFrequency() << " ms \n";
imshow("result",dst);
imwrite("result.jpg",dst);
//fx,fy变大(小),视场变小(大),裁剪较多(少),但细节清晰(模糊);
//new_intrinsic_mat决定输出的畸变校正图像的范围
//float max_lowThreshold=1.0;
//调整输出校正图的视场
namedWindow(winname,WINDOW_AUTOSIZE);
createTrackbar(bar_name_1, winname, &fx_threshold_min, 100,onChangeTrackBar,0);
createTrackbar(bar_name_2, winname, &fy_threshold_min, 100,onChangeTrackBar,0);
//onChangeTrackBar(0,0);
waitKey(0);
}
void onChangeTrackBar(int pos, void* )
{
cameraMatrix1.copyTo(new_intrinsic_mat);
new_intrinsic_mat.at<double>(0, 0) *= ((float)fx_threshold_min)/100.0;
//注意数据类型
new_intrinsic_mat.at<double>(1, 1) *= ((float)fy_threshold_min)/100.0;
//调整输出校正图的中心
new_intrinsic_mat.at<double>(0, 2) = 0.5*UndistortImg.cols;
new_intrinsic_mat.at<double>(1, 2) = 0.5 *UndistortImg.rows;
double t1 = (double)getTickCount();
cv::fisheye::undistortImage(image,UndistortImg,cameraMatrix1,distCoeffs1,new_intrinsic_mat);
t1 = (double)getTickCount() - t1;
std::cout << "compute time :" << t1*1000.0 / cv::getTickFrequency() << " ms \n";
cv::imshow("UndistortImg", UndistortImg);
}