去畸变 opencv

相机畸变主要是由于透镜成像原理导致的,其畸变的原理可以参考相机模型,它的畸变按照原理可以分解为切向畸变和径向畸变。

 

畸变校正

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());
  1. 第一个参数:输入图像,即原图像,需要单通道8位或者浮点类型的图像
  2. 第二个参数:输出图像,即目标图像,需和原图形一样的尺寸和类型
  3. 第三个参数:它有两种可能表示的对象:(1)表示点(x,y)的第一个映射;(2)表示CV_16SC2,CV_32FC1等
  4. 第四个参数:它有两种可能表示的对象:(1)若map1表示点(x,y)时,这个参数不代表任何值;(2)表示                                     CV_16UC1,CV_32FC1类型的Y值
  5. 第五个参数:插值方式,有四种插值方式:

(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;
}

猜你喜欢

转载自blog.csdn.net/zhngyue123/article/details/105900938