图像投影模型:针孔[fx, fy, cx, cy]
图像畸变模型:切向径向畸变[k1, k2, p1, p2]
说明:用于备忘
图像来源和参考链接:https://github.com/HLearning/fisheye
因为只是一个简单验证,所以将内参、图像加载路径和保存路径都写在了代码里面
代码片段:
cv::Mat K = (cv::Mat_<double>(3, 3) << 652.8609862494474, 0.0, 1262.1021584894233,
0.0, 653.1909758659955, 928.0871455436396,
0.0, 0.0, 1.0);
cv::Mat D = (cv::Mat_<double>(4, 1) << -0.024092199861108887, 0.002745976275100771, 0.002545415522352827, -0.0014366825722748522);
cv::Mat raw_image = cv::imread("../data/pig.jpg");
cout << raw_image.cols << " " << raw_image.rows << endl;
int width = raw_image.cols;
int height = raw_image.rows;
cv::Mat map1, map2;
cv::Mat undistortImg;
cv::Size imageSize(width, height);
cv::fisheye::initUndistortRectifyMap(K, D, cv::Mat(), K, imageSize, CV_16SC2, map1, map2);
cv::remap(raw_image, undistortImg, map1, map2, cv::INTER_LINEAR, cv::BORDER_CONSTANT);
cv::imwrite("../data/dst.png", undistortImg);
原图像和结果如下,因为remap
函数要求输入与输出的图像大小一致,所以这个过程造成了信息丢失,边缘部分的小猪崽们都缺少了很多
思路很简单,既然像素丢失是因为在remap后像素坐标超出了边界,那直接对原图像进行扩边处理再去畸变就好了,图像的高和宽分别为height,width,对图像的上下边界各扩充 1 4 ⋅ h e i g h t \frac{1}{4} \cdot height 41⋅height个像素,对图像左右边界各扩充 1 4 ⋅ w i d t h \frac{1}{4} \cdot width 41⋅width个像素
图像大小改变后,投影内参也要对应的改变,主要指像素坐标远点的偏移距离cx, cy
,上下左右各增加了高和宽的1/4,所以整体上高和宽增加了1/2,即变为原来的1.5倍
扩边函数使用cv::copyMakeBorder
代码片段如下:
// 扩边处理
cv::Mat K_ = (cv::Mat_<double>(3, 3) << 652.8609862494474, 0.0, 1.5 * 1262.1021584894233,
0.0, 653.1909758659955, 1.5 * 928.0871455436396,
0.0, 0.0, 1.0);
cv::Mat D_ = (cv::Mat_<double>(4, 1) << -0.024092199861108887, 0.002745976275100771, 0.002545415522352827, -0.0014366825722748522);
int width_ = raw_image.cols + raw_image.cols/2;
int height_ = raw_image.rows + raw_image.rows/2;
cv::Mat temp(height_, width_, raw_image.type());
cv::copyMakeBorder(raw_image, temp, raw_image.rows/4, raw_image.rows/4, raw_image.cols/4, raw_image.cols/4, cv::BORDER_ISOLATED);
cout << temp.cols << " " << temp.rows << endl;
cv::imwrite("../data/src2.png", temp);
cv::Mat map3, map4;
cv::Mat undistortImg_;
cv::Size imageSize_(width_, height_);
cv::fisheye::initUndistortRectifyMap(K_, D_, cv::Mat(), K_, imageSize_, CV_16SC2, map3, map4);
cv::remap(temp, undistortImg_, map3, map4, cv::INTER_LINEAR, cv::BORDER_CONSTANT);
cv::imwrite("../data/dst2.png", undistortImg_);
但是这种思路是错误的,因为在对图像扩边处理后,进行remap的输入图像发生了变化,remap映射要对扩边后的整个图像处理,这样会影响图像中心区域的去畸变效果,如果继续增加扩便的大小,比如将增加的边界由原来高和宽的1/4变为高和宽的1/2,会很明显的发现中心区域的去畸变效果受到影响(两条栏杆变的更弯了),这不是我们想要的。
正确的做法是在remap中做文章,在函数中新建一个大的空白图像,将去畸变后的像素映射到该图像上的对应位置,在remap结束后返回这张图像
源代码文件fisheye.cpp
#include
#include
#include
#include
#include
#include
#include
using namespace std;
// using namespace cv;
int main(int argc, char **argv)
{
cv::Mat K = (cv::Mat_(3, 3) << 652.8609862494474, 0.0, 1262.1021584894233,
0.0, 653.1909758659955, 928.0871455436396,
0.0, 0.0, 1.0);
cv::Mat D = (cv::Mat_(4, 1) << -0.024092199861108887, 0.002745976275100771, 0.002545415522352827, -0.0014366825722748522);
cv::Mat raw_image = cv::imread("../data/pig.jpg");
cout << raw_image.cols << " " << raw_image.rows << endl;
int width = raw_image.cols;
int height = raw_image.rows;
cv::Mat map1, map2;
cv::Mat undistortImg;
cv::Size imageSize(width, height);
cv::fisheye::initUndistortRectifyMap(K, D, cv::Mat(), K, imageSize, CV_16SC2, map1, map2);
cv::remap(raw_image, undistortImg, map1, map2, cv::INTER_LINEAR, cv::BORDER_CONSTANT);
cv::imwrite("../data/dst.png", undistortImg);
// 扩边处理
cv::Mat K_ = (cv::Mat_(3, 3) << 652.8609862494474, 0.0, 1.5 * 1262.1021584894233,
0.0, 653.1909758659955, 1.5 * 928.0871455436396,
0.0, 0.0, 1.0);
cv::Mat D_ = (cv::Mat_(4, 1) << -0.024092199861108887, 0.002745976275100771, 0.002545415522352827, -0.0014366825722748522);
int width_ = raw_image.cols + raw_image.cols/2;
int height_ = raw_image.rows + raw_image.rows/2;
cv::Mat temp(height_, width_, raw_image.type());
cv::copyMakeBorder(raw_image, temp, raw_image.rows/4, raw_image.rows/4, raw_image.cols/4, raw_image.cols/4, cv::BORDER_ISOLATED);
cout << temp.cols << " " << temp.rows << endl;
cv::imwrite("../data/src2.png", temp);
cv::Mat map3, map4;
cv::Mat undistortImg_;
cv::Size imageSize_(width_, height_);
cv::fisheye::initUndistortRectifyMap(K_, D_, cv::Mat(), K_, imageSize_, CV_16SC2, map3, map4);
cv::remap(temp, undistortImg_, map3, map4, cv::INTER_LINEAR, cv::BORDER_CONSTANT);
cv::imwrite("../data/dst2.png", undistortImg_);
return 0;
}
CMakeLists.txt文件
cmake_minimum_required(VERSION 2.8)
project(fisheye_cali)
find_package(OpenCV REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS})
add_executable(${PROJECT_NAME} fisheye.cpp)
target_link_libraries(${PROJECT_NAME} ${OpenCV_LIBS})