相机模型和标定 —— 图像去畸变

 本示例是关于图像去畸变的,采用的是投影模型是最一般的针孔相机模型。

不要试图去全面的掌握多个不同抽象层级之间的复杂繁复的细节,理清每一个抽象层级内的逻辑,以及相关抽象层级之间的联系。

—— 著名计算机科学家 达丛明

原理:

本示例中,有原图image,这个cv::Mat我们作为是畸变之后的图像,也就是我们平常用相机实际采集到的图像。

同时我们还有空图像image_undistorted,也就是去畸变之后的图像,我们的目标就是找到去畸变之后的图像和原图图像中像素点的一一对应关系。

注意,像素坐标u和v都是整数,没有浮点数。

怎么找到这种一一对应关系呢,就要利用到相机的畸变原理。

相机畸变分为多种类型,主要有以下几种畸变形式:

1. 径向畸变

又可分为枕型畸变(下图左)和桶型畸变(下图右)。

径向畸变的矫正公式如下:

2. 切向畸变

切向畸变通常是由于制造工艺缺陷导致的镜头与成像平面不平行造成的。

切向畸变根据和上面径向畸变的对比也能发现是和径向垂直的方向上发生的畸变。如下图所示:

切向畸变的公式如下:

综上,畸变依赖k1, k2, k3, p1, p2等个参数。

 

有了畸变原理,就可以获得未畸变的图像和畸变图像之间逐个像素的对应关系。

这里的实际效果也要考虑是何种畸变类型,因为畸变也伴随着未畸变图像的放大或者缩小,这意味着,去畸变后的图像会比原图的尺寸扩大或者缩小以及部分像素的损失。

下面的例子,只是作为一个例子,演示如何找到上文所述的去畸变之后的图像和畸变图像(也就是原图)中的像素一一对应的关系,所采用的去畸变之后的图像尺寸和原图一致。

// Created by ouyangzizhou on 2019/04/28.
// For pinhole cameras

#include <opencv2/opencv.hpp>

#include <iostream>
#include <string>

using namespace std;

int main(int argc, char** argv)
{
    // 相机的内参和畸变参数
	double k1 = -0.0454286, k2 = 0.00676248, p1 = -0.00931325, p2 = 0.00221027;
	double fx = 678.0467841929283, fy = 677.2937841093414, cx = 961.1753112084883, cy = 640.059204416268;

    // 原图,从输入的路径中读取
	cv::Mat image = cv::imread(argv[1], 0); // 0代表读取为gray image
    // 做一步判断,如果读取结果为不存在,则返回并输出信息
	if(image.empty())
	{
		cerr << "No image " << endl;
		return 0;
	}

	// cout << "Image type is " << image.type() << endl;

	int rows = image.rows, cols = image.cols;
	cout << "Image size: " << cols << " " << rows << endl;

	cv::Mat image_undistort = cv::Mat(rows, cols, CV_8UC1); //构造一个空图,作为去畸变后的图像

	for(int v = 0; v < rows; v++)
		for(int u = 0; u < cols; u++)
		{
			double u_distorted = 0, v_distorted = 0;

            // 获得真实的x和y归一化坐标
			double x_ud = (u - cx) / fx;
			double y_ud = (v - cy) / fy;
            // 计算r^2
			double r2 = x_ud * x_ud + y_ud * y_ud;
			double r4 = r2 * r2;
            // 根据畸变参数和公式计算有畸变的x和y的归一化坐标
			double x_d = x_ud*(1 + k1*r2 + k2*r4) + 2*p1*x_ud*y_ud + p2*(r2+2*x_ud*x_ud);
			double y_d = y_ud*(1+k1*r2+k2*r4)+p1*(r2+2*y_ud*y_ud)+2*p2*x_ud*y_ud;
            // 找到了对应关系(u, v) 对应 (u_distorted, v_distorted)
			u_distorted = fx*x_d + cx;
			v_distorted = fy*y_d + cy;
            // 直接插值获取去畸变后图像像素点的像素值
			if (u_distorted >= 0 && v_distorted >= 0 && u_distorted < cols && v_distorted < rows)
			{    // image_undistort.at<uchar>(v,u)是行和列,u和v中u对应列,v对应行
				image_undistort.at<uchar>(v,u) = image.at<uchar>((int) v_distorted, (int) u_distorted);
			}
			else
			{
				image_undistort.at<uchar>(v,u) = 0;
			}

		}

	cv::imwrite("./image Undistorted.jpg", image_undistort);
	// cv::waitKey();

	return 0;
}

此外,opencv中也提供了相应的API供调用者对图像进行去畸变操作。

见下面的例子:

 

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值