正确的鱼眼图像失真方式

时间:2017-02-12 14:48:05

标签: c++ opencv

我已经完成了一些示例程序,可以消除棋盘上的镜头失真,就像鱼眼图像一样,它可以正常工作,这是屏幕截图

enter image description here

接下来我想使用鱼眼棋盘图案(右上图)以消除相同的镜头失真但是从真实图像中没有运气 - 曲面仍然保留在未失真的图像上, 因此我得到了这个

enter image description here

代码

void getObjectPoints(cv::Size, std::vector<std::vector<cv::Point3f>>&);

bool getImagePoints(cv::Mat&, cv::Size&, std::vector<std::vector<cv::Point2f>>&);

void runCalibration(cv::Mat& image, cv::Matx33d&, cv::Vec4d&);

cv::Mat removeFisheyeLensDist(cv::Mat&, cv::Matx33d&, cv::Vec4d&);

// ... definitions    
void getObjectPoints(cv::Size patternSize, std::vector<std::vector<cv::Point3f>>& objectPoints)
{
    const float squareSize = 0.0015f;
    std::vector<cv::Point3f> knownBoardPositions;
    for (int i = 0; i < patternSize.height; ++i)
    {
        for (int j = 0; j < patternSize.width; ++j)
        {
            knownBoardPositions.push_back(cv::Point3f(j*squareSize, i*squareSize, 0.0f));
        }
    }
    if (knownBoardPositions.size() > 0)
        objectPoints.push_back(knownBoardPositions);
}

bool getImagePoints(cv::Mat& image, cv::Size& patternSize, std::vector<std::vector<cv::Point2f>>& imagePoints)
{
    bool patternFound = false;
    while (!patternFound)
    {
        std::vector<cv::Point2f> corners;
        for (int i = 7; i <= 30; ++i)
        {
            int w = i;
            int h = i - 2;

            patternFound = cv::findChessboardCorners(image, cv::Size(w, h), corners,
                                              cv::CALIB_CB_ADAPTIVE_THRESH | cv::CALIB_CB_NORMALIZE_IMAGE);
            if (patternFound)
            {
                patternSize.width = w;
                patternSize.height = h;
                imagePoints.push_back(corners);
                break;
            }
        }
    }

    return patternFound;
}

void runCalibration(cv::Mat& image, cv::Matx33d& K, cv::Vec4d& D)
{
    std::vector< std::vector<cv::Point2f> > imagePoints;
    std::vector< std::vector<cv::Point3f> > objectPoints;
    cv::Size patternSize;
    bool patternFound = getImagePoints(image, patternSize, imagePoints);

    if (patternFound)
    {
        getObjectPoints(patternSize, objectPoints);

        std::vector<cv::Vec3d> rvecs;
        std::vector<cv::Vec3d> tvecs;
        cv::fisheye::calibrate(
            objectPoints,
            imagePoints,
            image.size(),
            K,
            D,
            rvecs,
            tvecs,
            cv::fisheye::CALIB_FIX_SKEW |   cv::fisheye::CALIB_RECOMPUTE_EXTRINSIC
        |   cv::fisheye::CALIB_FIX_K1   |   cv::fisheye::CALIB_FIX_K2
        |   cv::fisheye::CALIB_FIX_K3   |   cv::fisheye::CALIB_FIX_K4
//            cv::TermCriteria(3, 20, 1e-6)
        );
    }
}

cv::Mat removeFisheyeLensDist(cv::Mat& distorted, cv::Matx33d& K, cv::Vec4d& D)
{
    cv::Mat undistorted;
    cv::Matx33d newK = K;
    cv::fisheye::undistortImage(distorted, undistorted, K, D, newK);
    return undistorted;
}

int main(int argc, char* argv[])
{
    cv::Mat chessBoardPattern = //..
    cv::Mat distortedImage = //...
    cv::imshow("distorted", distortedImage);

    cv::Matx33d K;  cv::Vec4d D;
    runCalibration(chessBoardPattern, K, D);
    cv::Mat undistoredImage = removeFisheyeLensDist(distortedImage, K, D);    
    cv::imshow("undistored", undistoredImage);
    cv::waitKey(0);
    return 0;
}

我认为塔的图像在右边有一个非常类似于棋盘的曲线,所以相同的图案应该适用于塔图像......

我在那里做错了什么? 为什么它没有修复塔形图像的镜头失真?

1 个答案:

答案 0 :(得分:3)

不幸的是你的假设

  

如果图像具有相同的曲率,那么相机参数应该大致相同,因此我可以用棋盘图案来展现鱼眼图像

错了。即使相同型号的相机也会在焦距,镜头几何形状和位置等方面存在差异,需要单独校准。除了在使用相机时,这些参数可能会因加热,振动和其他影响而改变(通常在实践中忽略这一点)。

要在不使用相机的情况下取消图像,您只需选择一些简单的鱼眼相机模型并尝试手动估计参数,尝试使直线看起来笔直(例如使用带滑块的GUI用于所有参数)。这可能很乏味,但我不知道更好的选择。此外,一些图像编辑软件可能有工具(如果我没记错GIMP)