使用opencv从3d点创建全景图像

时间:2013-08-21 09:57:44

标签: opencv panoramas

我有一台PointGrey Ladybug3相机。它是一个全景(多)摄像头(5个摄像头可以360º和1个摄像头查找)。 我已经完成了所有的校准和校正,所以我最终得到的是6幅图像中的所有像素,我知道它是一个全局帧的3d位置。 我现在要做的是将这个3d点转换为全景图像。最常见的是径向(Equirectangular)投影,如下所示: Radial Porjection

对于所有3D点(X,Y,Z),可以找到theta和phi坐标,如:

Radial Picture Equation

我的问题是,是否可以使用opencv自动执行此操作?或者,如果我手动执行此操作,那么在theta中转换那组像素的最佳方法是什么,phi坐标为图像?

官方瓢虫SDK使用OpenGL进行所有这些操作,但我想知道是否可以在opencv中执行此操作。

谢谢,

何塞普

1 个答案:

答案 0 :(得分:7)

我用来解决这个问题的方法如下:

  1. 使用所需的输出尺寸创建一个空图像。
  2. 对于输出图像中的每个像素,找到theta和phi坐标。 (线性地)Theta从-Pi变为Pi,phi从0变为Pi
  3. 设置投影半径R并从theta,phi和R中找到3D坐标。
  4. 查找3D点可见的相机数量和对应的像素位置。
  5. 复制像素更接近主点的图像像素。或任何其他有效标准......
  6. 我的代码如下:

    cv::Mat panoramic;
    panoramic=cv::Mat::zeros(PANO_HEIGHT,PANO_WIDTH,CV_8UC3);
    double theta, phi;
    double R=calibration.getSphereRadius();
    int result;
    
    double dRow=0;
    double dCol=0;
    
    for(int y = 0; y!= PANO_HEIGHT; y++){
        for(int x = 0; x !=PANO_WIDTH ; x++) {
                //Rescale to [-pi, pi]
            theta=-(2*PI*x/(PANO_WIDTH-1)-PI); //Sign change needed.
                phi=PI*y/(PANO_HEIGHT-1);
    
            //From theta and phi find the 3D coordinates.
            double globalZ=R*cos(phi);
                double globalX=R*sin(phi)*cos(theta);
            double globalY=R*sin(phi)*sin(theta);
    
    
            float minDistanceCenter=5000; // Doesn't depend on the image.
    
            float distanceCenter;
    
            //From the 3D coordinates, find in how many camera falls the point!
            for(int cam = 0; cam!= 6; cam++){
                result=calibration.ladybugXYZtoRC(globalX, globalY, globalZ, cam, dRow, dCol);
                if (result==0){ //The 3d point is visible from this camera
                    cv::Vec3b intensity = image[cam].at<cv::Vec3b>(dRow,dCol);
                    distanceCenter=sqrt(pow(dRow-imageHeight/2,2)+pow(dCol-imageWidth/2,2));
                    if (distanceCenter<minDistanceCenter) {
                        panoramic.ptr<unsigned char>(y,x)[0]=intensity.val[0];
                        panoramic.ptr<unsigned char>(y,x)[1]=intensity.val[1];
                        panoramic.ptr<unsigned char>(y,x)[2]=intensity.val[2];
    
                        minDistanceCenter=distanceCenter;
                    }
                }
            }
    
        }
    }