【问题标题】:How to save view after camera undistortion相机不失真后如何保存视图
【发布时间】:2017-03-02 00:25:02
【问题描述】:

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

【问题讨论】:

    标签: opencv camera-calibration fisheye


    【解决方案1】:

    使用此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);
    }
    

    【讨论】:

    • 感谢您的回复!我注意到这种方法不是基于鱼眼相机的内在参数,在 3D 空间中重建无失真图像,而是在 2D 中校正图像。这可能会导致与人类不同的怪异观点。那么有什么方法可以使图像不失真并保存相机的FOV?
    猜你喜欢
    • 1970-01-01
    • 2014-11-29
    • 1970-01-01
    • 1970-01-01
    • 2016-02-18
    • 1970-01-01
    • 2014-01-20
    • 1970-01-01
    相关资源
    最近更新 更多