如何在相机失真后保存视图

时间:2016-10-20 06:33:54

标签: opencv camera-calibration fisheye

我正在尝试找到一种方法来拼接来自两个鱼眼相机的两个图像。但我不知道如何纠正原始图像。我试图用opencv3.0中的类鱼眼来做这个,但它有很大的视图丢失,所以我没有足够的信息在下一步缝合。那么有什么想法可以解决这个问题吗?如果你能告诉我一个具体的策略,我很幸运。非常感谢你!

1 个答案:

答案 0 :(得分:0)

使用此link作为参考。我能够纠正图像的鱼变形。这是一个示例代码

#include <iostream>
#include <sstream>
#include <time.h>
#include <stdio.h>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/calib3d/calib3d.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace std;
using namespace cv;
#define PI 3.1415926536
#define CHANNELS 3
#define BORDER_TO_USE BORDER_REFLECT
/*
#define OUT_WIDTH 1920
#define OUT_HEIGHT 1513
*/
Point2f getInputPoint(int x, int y,int srcwidth, int srcheight,int hFov,int vFov)
 {
    Point2f pfish;
    float theta,phi,r;
    Point3f psph;
    //float FOV = PI;
    float FOV =(float)PI/180 * hFov;
    float FOV2 = (float)PI/180 * vFov;

    float width = srcwidth;

    float height = srcheight;
    theta = PI * (x / width - 0.5); // -pi to pi
    phi = PI * (y / height - 0.5);  // -pi/2 to pi/2
    psph.x = cos(phi) * sin(theta);
    psph.y = cos(phi) * cos(theta);
    psph.z = sin(phi);
    theta = atan2(psph.z,psph.x);
    phi = atan2(sqrt(psph.x*psph.x+psph.z*psph.z),psph.y);
    r = width * phi / FOV;
    float r2 = height * phi / FOV2;
    pfish.x = 0.5 * width + r * cos(theta);
    pfish.y = 0.5 * height + r2 * sin(theta);
    return pfish;
}

 void getMatColorValue(Mat src,const int& x, const int& y,
        int& val1, int& val2, int& val3)
    {
        if (x < 0 || x >= src.cols || y < 0 || y >= src.rows)
        {
            val1 = 0;
            val2 = 0;
            val3 = 0;
        }
        else
        {
            val1 = src.ptr(y)[x * CHANNELS];
            val2 = src.ptr(y)[x * CHANNELS + 1];
            val3 = src.ptr(y)[x * CHANNELS + 2];
        }
    }

Vec3b BilinearInterpolation(Point2f inP,Mat src)
{
    // Bilinear interpolation

    int tXi = floor(inP.x);
    int tYi = floor(inP.y);

    float dX = inP.x - tXi; // differential
    float dY = inP.y - tYi;

    int rgbValues[4][3];

    int val1,val2,val3;
    getMatColorValue(src, tXi, tYi,     rgbValues[0][0], rgbValues[0][1], rgbValues[0][2]);
    getMatColorValue(src, tXi+1, tYi,   rgbValues[1][0], rgbValues[1][1], rgbValues[1][2]);
    getMatColorValue(src, tXi, tYi+1,   rgbValues[2][0], rgbValues[2][1], rgbValues[2][2]);
    getMatColorValue(src, tXi+1, tYi+1, rgbValues[3][0], rgbValues[3][1], rgbValues[3][2]);

    float x;

    // Update val1
    x = rgbValues[0][0] * (1-dX) * (1-dY) +
        rgbValues[1][0] * (dX) * (1-dY) +
        rgbValues[2][0] * (1-dX) * (dY) +
        rgbValues[3][0] * (dX) * (dY);
    if (x < 0)
        val1 = 0;
    else if (x > (unsigned char)(-1))
        val1 = (unsigned char)(-1);
    else
        val1 = x;

    // Update val2
    x = rgbValues[0][1] * (1-dX) * (1-dY) +
        rgbValues[1][1] * (dX) * (1-dY) +
        rgbValues[2][1] * (1-dX) * (dY) +
        rgbValues[3][1] * (dX) * (dY);
    if (x < 0)
        val2 = 0;
    else if (x > (unsigned char)(-1))
        val2 = (unsigned char)(-1);
    else
        val2 = x;

    // Update val3
    x = rgbValues[0][2] * (1-dX) * (1-dY) +
        rgbValues[1][2] * (dX) * (1-dY) +
        rgbValues[2][2] * (1-dX) * (dY) +
        rgbValues[3][2] * (dX) * (dY);
    if (x < 0)
        val3 = 0;
    else if (x > (unsigned char)(-1))
        val3 = (unsigned char)(-1);
    else
        val3 = x;
    Vec3b color;
    color.val[0] = val1;
    color.val[1] = val2;
    color.val[2] = val3;
    return color;
}
/*Vec3b getColorSubpix(const cv::Mat& img, cv::Point2f pt)
{

    int x = (int)pt.x;
    int y = (int)pt.y;

    int x0 = cv::borderInterpolate(x, img.cols, BORDER_TO_USE);
    int x1 = cv::borderInterpolate(x + 1, img.cols, BORDER_TO_USE);
    int y0 = cv::borderInterpolate(y, img.rows, BORDER_TO_USE);
    int y1 = cv::borderInterpolate(y + 1, img.rows, BORDER_TO_USE);

    float a = pt.x - (float)x;
    float c = pt.y - (float)y;

    uchar b = (uchar)cvRound((img.at<cv::Vec3b>(y0, x0)[0] * (1.f - a) + img.at<cv::Vec3b>(y0, x1)[0] * a) * (1.f - c)
        + (img.at<cv::Vec3b>(y1, x0)[0] * (1.f - a) + img.at<cv::Vec3b>(y1, x1)[0] * a) * c);
    uchar g = (uchar)cvRound((img.at<cv::Vec3b>(y0, x0)[1] * (1.f - a) + img.at<cv::Vec3b>(y0, x1)[1] * a) * (1.f - c)
        + (img.at<cv::Vec3b>(y1, x0)[1] * (1.f - a) + img.at<cv::Vec3b>(y1, x1)[1] * a) * c);
    uchar r = (uchar)cvRound((img.at<cv::Vec3b>(y0, x0)[2] * (1.f - a) + img.at<cv::Vec3b>(y0, x1)[2] * a) * (1.f - c)
        + (img.at<cv::Vec3b>(y1, x0)[2] * (1.f - a) + img.at<cv::Vec3b>(y1, x1)[2] * a) * c);

    return cv::Vec3b(b, g, r);
}*/
void CropBlackArea(Mat image,int &top,int &bottom)
{
    Mat slider;
    Mat gray;
    cvtColor(image,gray,CV_BGR2GRAY);
    int i=0;
    for(i=0; i<image.rows-1;i++)
    {
        slider = gray(Rect(0,i,gray.cols,1));
        if(countNonZero(slider) == 0)
            continue;
        else
            break;
    }
    top = i;
    i=0;
    for(i=image.rows-1; i>=0;i--)
    {

        slider = gray(Rect(0,i,gray.cols,1));
        if(countNonZero(slider) == 0)
            continue;
        else
            break;

    }
    bottom = i;
}
int main(int argc, char **argv)
{
     /*Arguments should be 1-input_image_path 2-Output_image_path 3-Horizontal fov(Field of view) of the lense 4-Vertical fov of the lense*/
    if(argc< 5)
        return 0;
    FileStorage fsx("FishEyeConversionXmap.yml", FileStorage::WRITE);
    FileStorage fsy("FishEyeConversionYmap.yml", FileStorage::WRITE);
    Mat orignalImage = imread(argv[1]);
    int hFov = atoi(argv[3]);
    int vFov = atoi(argv[4]);
    //resize(orignalImage,orignalImage,Size(720,1280));
    if(orignalImage.empty())
    {
        cout<<"Empty image\n";
        return 0;
    }
    Mat outImage(orignalImage.rows,orignalImage.cols,CV_8UC3);
    Mat xMap(orignalImage.rows,orignalImage.cols,CV_32FC1);
    Mat yMap(orignalImage.rows,orignalImage.cols,CV_32FC1);
        //getInputPoint(0,5,10,10);
    namedWindow("result",CV_WINDOW_NORMAL);
    for(int i=0; i<outImage.cols; i++)
    {
        for(int j=0; j<outImage.rows; j++)
        {
            Point2f inP =  getInputPoint(i,j,orignalImage.cols,orignalImage.rows,hFov,vFov);

            xMap.at<float>(j,i) = inP.x;
            yMap.at<float>(j,i) = inP.y;
            Point inP2((int)inP.x,(int)inP.y);
            if(inP2.x >= orignalImage.cols || inP2.y >= orignalImage.rows)
                continue;
            if(inP2.x < 0 || inP2.y < 0)
                continue;

            //Vec3b color = getColorSubpix(orignalImage,inP);
            //Vec3b color = orignalImage.at<cv::Vec3b>(inP2.y,inP2.x);
            Vec3b color = BilinearInterpolation(inP,orignalImage);
            outImage.at<Vec3b>(Point(i,j)) = color;
        }
    }
    int top,bottom;
    CropBlackArea(outImage,top,bottom);
    cout<<"Croping "<<top<<","<<bottom<<"\n";
    cout<<outImage.size()<<endl;
    Rect r(0,top,outImage.cols,(bottom-top));
    cout<<r<<endl;
    outImage = outImage(r);
    xMap = xMap(r);
    yMap = yMap(r);
   /* resize(outImage,outImage,Size(OUT_WIDTH,OUT_HEIGHT));
    resize(outImage,outImage,Size(OUT_WIDTH,OUT_HEIGHT));
    resize(xMap,xMap,Size(OUT_WIDTH,OUT_HEIGHT));
    resize(yMap,yMap,Size(OUT_WIDTH,OUT_HEIGHT));*/

    fsx << "xMap" << xMap;
    fsy << "yMap" << yMap;
    fsx.release();
    fsy.release();
    imshow("result",outImage);
    imwrite(argv[2],outImage);
    waitKey(0);
}