相机畸变主要是由于透镜成像原理导致的,其畸变的原理可以参考相机模型,它的畸变按照原理可以分解为切向畸变和径向畸变。
畸变校正
opencv提供了可以直接使用的矫正算法,即通过calibrate Camera()得到的畸变系数,生成矫正后的图像。我们可以通过undistort()函数一次性完成;也可以通过initUndistortRectifyMap()和remap()的组合来处理。
1、initUndistortRectifyMap()和remap()
void initUndistortRectifyMap( InputArray cameraMatrix,
InputArray distCoeffs,
InputArray R,
InputArray newCameraMatrix,
Size size,
int m1type,
OutputArray map1,
OutputArray map2 );
函数功能:计算无畸变和修正转换映射。
参数说明:
函数说明:
这个函数用于计算无畸变和修正转换关系,为了重映射,将结果以映射的形式表达。无畸变的图像看起来就像原始的图像,就像这个图像是用内参为newCameraMatrix
的且无畸变的相机采集得到的。
在单目相机例子中,newCameraMatrix
一般和cameraMatrix
相等,或者可以用cv::getOptimalNewCameraMatrix
来计算,获得一个更好的有尺度的控制结果。
在双目相机例子中,newCameraMatrix
一般是用cv::stereoRectify
计算而来的,设置为P1或P2。 此外,根据R,新的相机在坐标空间中的取向是不同的。例如,它帮助配准双目相机的两个相机方向,从而使得两个图像的极线是水平的,且y坐标相同(在双目相机的两个相机谁水平放置的情况下)。 该函数实际上为反向映射算法构建映射,供反向映射使用。也就是,对于在已经修正畸变的图像中的每个像素(u,v),该函数计算原来图像(从相机中获得的原始图像)中对应的坐标系。
介绍下getOptimalNewCameraMatrix()函数。
Void getOptimalNewCameraMatrix(cv::InputArray cameraMatrix,
cv::InputArray distCoeffs,
cv::Size imgSize,
double alpha,
cv::Size newImgSize,
cv::Rect* validPixROI,
bool centerPrincipalPoint)
alpha之后的参数都可以视为默认。在getOptimalNewCameraMatrix()函数中,有上述一段代码,意思是从内参/畸变系数中得到两个inner和outer矩阵,当alpha为0时,取inner即内矩阵,用内矩阵大小作为新的图像大小,重新得到fx,fy,cx,cy,因此新的内参矩阵诞生了. 当alpha为1时,取outer即外矩阵。当alpha介于0~1时,则按照比例重新计算fx,fy,cx,cy。
函数输出得到map1和map2,然后使用remap()函数:
void remap( InputArray src,
OutputArray dst,
InputArray map1,
InputArray map2,
int interpolation,
int borderMode=BORDER_CONSTANT,
const Scalar& borderValue=Scalar());
- 第一个参数:输入图像,即原图像,需要单通道8位或者浮点类型的图像
- 第二个参数:输出图像,即目标图像,需和原图形一样的尺寸和类型
- 第三个参数:它有两种可能表示的对象:(1)表示点(x,y)的第一个映射;(2)表示CV_16SC2,CV_32FC1等
- 第四个参数:它有两种可能表示的对象:(1)若map1表示点(x,y)时,这个参数不代表任何值;(2)表示 CV_16UC1,CV_32FC1类型的Y值
- 第五个参数:插值方式,有四种插值方式:
(1)INTER_NEAREST——最近邻插值
(2)INTER_LINEAR——双线性插值(默认)
(3)INTER_CUBIC——双三样条插值(默认)
(4)INTER_LANCZOS4——lanczos插值(默认)
第六个参数:边界模式,默认BORDER_CONSTANT
第七个参数:边界颜色,默认Scalar()黑色
2、undistort()函数
void undistort( InputArray src, //输入原图
OutputArray dst,//输出矫正后的图像
InputArray cameraMatrix,//内参矩阵
InputArray distCoeffs,//畸变系数
InputArray newCameraMatrix=noArray() );
有时不需要矫正整个图像,而仅仅计算图像中特定点的位置,这是可以使用undistortPoints函数:
void undistortPoints( InputArray src,
OutputArray dst,
InputArray cameraMatrix,
InputArray distCoeffs,
InputArray R=noArray(),
InputArray P=noArray());
undistortPoints函数与undistort()的区别在于:参数src,dst是二维点的向量,std::vector<cv::Point2f> ,P对应cameraMatrix。该参数与立体校正方面的使用有关。调用方式:
void undistortPoints(inputDistortedPoints,
outputUndistortedPoints,
cameraMatrix,
distCoeffs,
cv::noArray(),
cameraMatrix);
3、Python程序
### 函数引用方法
def getUndistortRectifyMap(self, imgWidth, imgHeight):
if self.mapx is not None and self.mapx.shape == (imgHeight, imgWidth):
return self.mapx, self.mapy
mtx = self.coeffs['cameraMatrix']
dist = self.coeffs['distortionCoeffs']
(newCameraMatrix, self.roi) = cv2.getOptimalNewCameraMatrix(mtx,
dist, (imgWidth,
imgHeight), 1,
(imgWidth, imgHeight))
self.mapx, self.mapy = cv2.initUndistortRectifyMap(mtx,
dist, None, newCameraMatrix,
(imgWidth, imgHeight), cv2.CV_32FC1)
return self.mapx, self.mapy
import numpy as np
import cv2
import matplotlib.pyplot as plt
image = cv2.imread('/home/zhy/Documents/Perception/Lanelinedetection/DNN/LaneNet/lanenet-lane-detection'
'/data/tusimple_test_image/chessbord690.JPG', cv2.IMREAD_COLOR)
gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
h, w = image.shape[:2] # a (1 to see the whole picture)
dist = np.array([-0.13615181, 0.53005398, 0, 0, 0]) # no translation
mtx = np.array([(1079.2921262026000022, 0.0000000000000000, 918.6822518287709727), (0.0000000000000000,
1082.8921320173517415,
555.5723432905268737),
(0.0000000000000000, 0.0000000000000000, 1.0000000000000000)])
newcameramtx, roi = cv2.getOptimalNewCameraMatrix(mtx, dist, (w, h), 1, (w, h))
if np.size(roi) == 4 and np.mean(roi) != 0:
# undistort
mapx, mapy = cv2.initUndistortRectifyMap(mtx, dist, None, newcameramtx, (w, h), 5)
x, y, w, h = roi
n = 0
f = open('remp_x.txt', 'w+')
for i in range(877):
for j in range(1606):
if n % 4 != 0:
strNum = mapx[i][j] # 每行
f.write(str(strNum))
f.write(',')
else:
f.write('\n')
f.write(' ')
strNum = mapx[i][j] # 每行
f.write(str(strNum))
f.write(',')
n += 1
f.write('\n')
f.close()
#crop the image
dst = cv2.remap(image, mapx, mapy, cv2.INTER_LINEAR)
#dst = cv2.cvtColor(dst, cv2.COLOR_RGB2BGR)
plt.figure('dst')
plt.imshow(dst)
cv2.imwrite('result.jpg', dst)
4、C++程序
#include <iostream>
#include<stdio.h>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main()
{
image=cv::imread("/home/zhy/Documents/Perception/camera_data/lane_image/0000.JPG");
cv::cvtColor(image,image, CV_BGR2GRAY);
cv::Mat cameraMatrix = Mat::eye(3, 3, CV_64F);
//内参矩阵, 就算复制代码,也不要用我的参数。摄像头都不一样...
cameraMatrix.at<double>(0, 0) =1079.2921262026000022;
cameraMatrix.at<double>(0, 1) = 0;
cameraMatrix.at<double>(0, 2) = 918.6822518287709727;
cameraMatrix.at<double>(1, 1) = 1082.8921320173517415;
cameraMatrix.at<double>(1, 2) = 555.5723432905268737;
//畸变参数,不要用我的参数~
Mat distCoeffs = Mat::zeros(5, 1, CV_64F);
distCoeffs.at<double>(0, 0) = -0.1318412926647311;
distCoeffs.at<double>(1, 0) = -0.0036319330386551;
distCoeffs.at<double>(2, 0) = -0.0036319330386551;
distCoeffs.at<double>(3, 0) = -0.0037894134236598;
distCoeffs.at<double>(4, 0) = -0.000074821933;
Mat view, rview, map1, map2;
Size imageSize;
imageSize = image.size();
initUndistortRectifyMap(cameraMatrix, distCoeffs, Mat(),getOptimalNewCameraMatrix(cameraMatrix, distCoeffs, imageSize, 1, imageSize, 0), imageSize, CV_32FC1, map1, map2);
//remap(image, image, map1, map2, INTER_LINEAR);
std::string fileName = "rmp_x.txt" ;
int n=0;
std::ofstream outfile( fileName.c_str() ) ; // file name and the operation type.
for(int i=0; i<map1.rows; i++){
for(int j=0; j<map1.cols; j++){
if (n%4!=0)
outfile<<map1.at<float>(i,j)<<",";
else
outfile<<'\n' <<" "<<map1.at<float>(i,j)<<"," ;
n=n+1;
}
outfile << std::endl ; // a newline after storing all the values of a line of the img
}
outfile.close();
return 0;
}