简单的实现 相片去畸变,调用opencv读写图像,其他库函数不用

刚入职,leader给我 一些入门级的事情来做,帮助理解原理,以后的目标是 能够完全读懂现有的图像处理的库,并能够根据实际进行改进和优化。

利用matlab单相机标定获得了 相机的 内参矩阵和畸变函数,然后进行 去畸变。

文字流程如下(注意几次坐标系转换):

1),将图像的像素坐标系通过内参矩阵转换到相机坐标系

2),在相机坐标系下进行去畸变操作

3),去畸变操作结束后,将相机坐标系重新转换到图像像素坐标系

4),并用源图像的像素值对新图像的像素点进行插值。

// Undistortion.cpp: 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include
#include
using namespace cv;

//matlab 单相机标定结果,相机A
double k[3] = { -0.0903,0.7409,0.0 };//径向畸变 k1,k2,k3
double p[2] = { -0.0012,0.0013 };	//切向畸变 p1,p2
double intrinsic[3][3] = { {3449.6,0,0},{6.3538,3449.63,0},{668.4023,472.6526,1} };
void undistortion(Mat input, Mat &output);		//去畸变

int main()
{
	Mat picture = imread("D:\\week1\\A_006.bmp");
	Mat srcImage;
	cvtColor(picture, srcImage, CV_BGR2GRAY);
	imshow("【原图片】", srcImage);
	//a blank image of the same size
	Mat dstImage = Mat::zeros(srcImage.rows, srcImage.cols, CV_8UC1);

	undistortion(srcImage, dstImage);
	imshow("【去畸变后】", dstImage);

	Mat diffImage = (srcImage - dstImage)*50;
	imshow("【变化图-放大50倍的效果】", diffImage);
	waitKey();
	return 0;
}

void undistortion(Mat input, Mat &output)
{
	double fx = intrinsic[0][0];
	double fy = intrinsic[1][1];	//焦距
	double cx = intrinsic[2][0];
	double cy = intrinsic[2][1];	//光心位置
	double k1 = k[0];
	double k2 = k[1];
	double k3 = k[2];		//径向畸变系数
	double p1 = p[0];
	double p2 = p[1];		//切向畸变系数
	double r;		//畸变图 距离中心点的距离
	double x1, y1, x2, y2;	//中间变量
	for (int i = 0; i < input.cols; i++)
	{
		for (int j = 0; j < input.rows; j++) {
			//①像素坐标系到 相机坐标系
			x1 = (i - cx) / fx;
			y1 = (j - cy) / fy;

			//②在相机坐标系下进行去畸变操作
			r = x1 * x1 + y1 * y1;
			x2 = x1 * (1 + k1 * pow(r, 2) + k2 * pow(r, 4)) + 2 * p1*x1*y1 + p2 * (pow(r, 2) + 2 * pow(x1, 2));
			y2 = y1 * (1 + k1 * pow(r, 2) + k2 * pow(r, 4)) + 2 * p2*x1*y1 + p1 * (pow(r, 2) + 2 * pow(y1, 2));

			//③在去畸变操作后,重新转换到 像素坐标系
			x2 = x2 * fx + cx;
			y2 = y2 * fy + cy;

			//④并用源图像的像素值对新图像的像素点进行插值
			if (y2 > 0 && y2 < input.rows - 1 && x2>0 && x2 < input.cols - 1) {	//防止越界
				double h = y2;
				double w = x2;
				double result = (floor(w + 1) - w)*(floor(h + 1) - h)*input.at(floor(h), floor(w)) +
					(floor(w + 1) - w)*(h - floor(h))*input.at(floor(h + 1), floor(w)) +
					(w - floor(w))*(floor(h + 1) - h)*input.at(floor(h), floor(w + 1)) +
					(w - floor(w))*(h - floor(h))*input.at(floor(h + 1), floor(w + 1));		//双线性内插
				output.at(j, i) = floor(result);
				//std::cout << output.at(j, i) - input.at(j, i) << "\t";
			}
		}
	}
}

原图:

简单的实现 相片去畸变,调用opencv读写图像,其他库函数不用_第1张图片

简单的实现 相片去畸变,调用opencv读写图像,其他库函数不用_第2张图片

简单的实现 相片去畸变,调用opencv读写图像,其他库函数不用_第3张图片 越靠近边上的 越亮。说明变形越大,与实际相符合,总体变形不严重,所以这里放大了50倍,没有考虑太多是否溢出的问题,如果是彩色图片,计算三次即可。

你可能感兴趣的:(简单的实现 相片去畸变,调用opencv读写图像,其他库函数不用)