2014-10-28 449 views
1

我从摄像机获取图像,无法拍摄棋盘图像并使用OpenCV计算校正矩阵。到目前为止,我使用imagemagick转换使用选项'-distort Barrel“0.0 0.0 -0.035 1.1”'来校正图像,其中我得到了试验和错误的参数。手动校正OpenCV桶形失真,没有棋盘图像

现在我想在OpenCV中做到这一点,但我在网上找到的是使用棋盘图像的自动更正。有没有机会像我用imagemagick一样应用一些简单的手动试错镜头畸变校正?

+0

在例子。只需跳过计算并明确提供这些参数。如果封装了这部分,您可以查看oprnCV源代码并使用内部使用的函数 – Micka 2014-10-28 07:47:26

+0

我试图自己定义棋盘角(例如4x4点),但没有得到角阵列的结构应该是什么。有没有人有任何想法? – 2014-10-28 08:00:27

+0

好吧,我认为最小的数组应该像这样配置:corners = np.zeros((4 * 4,1,2),dtype =“float32”)。用3x3它似乎不工作。不过,我宁愿像convert -distort Barrel这样的东西,而不是现在定义扭曲的点。 – 2014-10-28 08:22:41

回答

2

如果你没有棋盘图案但是你知道失真系数,这里有一个方法可以使图像不失真。

因为我不知道哪个系数的桶形畸变参数对应(也许在http://docs.opencv.org/doc/tutorials/calib3d/camera_calibration/camera_calibration.html看看和http://docs.opencv.org/modules/imgproc/doc/geometric_transformations.html#initundistortrectifymap你将不得不尝试一下,也许有人能够帮助你在这里。

还有一点就是我不能确定的OpenCV是否会同时处理,浮动和自动加倍如果不是这种情况有可能是在这个代码中的错误(我不知道单或双精度是否假设):

cv::Mat distCoeff; 
distCoeff = cv::Mat::zeros(8,1,CV_64FC1); 

// indices: k1, k2, p1, p2, k3, k4, k5, k6 
// TODO: add your coefficients here! 
double k1 = 0; 
double k2 = 0; 
double p1 = 0; 
double p2 = 0; 
double k3 = 0; 
double k4 = 0; 
double k5 = 0; 
double k6 = 0; 

distCoeff.at<double>(0,0) = k1; 
distCoeff.at<double>(1,0) = k2; 
distCoeff.at<double>(2,0) = p1; 
distCoeff.at<double>(3,0) = p2; 
distCoeff.at<double>(4,0) = k3; 
distCoeff.at<double>(5,0) = k4; 
distCoeff.at<double>(6,0) = k5; 
distCoeff.at<double>(7,0) = k6; 




// assume unit matrix for camera, so no movement 
cv::Mat cam1,cam2; 
cam1 = cv::Mat::eye(3,3,CV_32FC1); 
cam2 = cv::Mat::eye(3,3,CV_32FC1); 
//cam2.at<float>(0,2) = 100; // for testing a translation 

// here the undistortion will be computed 
cv::Mat map1, map2; 
cv::initUndistortRectifyMap(cam1, distCoeff, cv::Mat(), cam2, input.size(), CV_32FC1, map1, map2); 

cv::Mat distCorrected; 
cv::remap(input, distCorrected, map1, map2, cv::INTER_LINEAR); 
+0

k4,k5和k6从哪里来?它不是文档的一部分,是吗?是否还有一个Python代码片段? – 2014-10-28 15:09:44

+0

如果我按照你的链接,我看到类似这样的东西:xcor = x *(1 + k1 * r^2 + k2 * r^4 + k3 * r^6);这与以下公式适用的imagemagick(http://www.imagemagick.org/Usage/distorts/#barrel)中的描述不同:Rsrc = r *(A * r^3 + B * r^2 + C * r + D);因此将例如k1设置为0.001会导致非常奇怪的图像,但不会校正桶形失真?尽管如此,我认为我们更接近解决方案。 – 2014-10-28 15:31:11

+0

抱歉,我这边没有python代码片段,但它只是关于initUndistortRectifyMap调用和设置系数。维基百科给出了一些与OpenCV类似的系数(虽然没有检查这些术语)http://en.wikipedia.org/wiki/Distortion_%28optics%29#Software_correction因此,也许imageMagick使用不同的失真模型,或者他们会假设某种反向参数?!?不知道,抱歉=) – Micka 2014-10-28 15:52:29

6

好,我想我知道了,在矩阵cam1,cam2中,图像中心缺失了(参见doc umentation)。我添加了它并改变了焦距以避免图像尺寸变化太大。这里是代码:

import numpy as np 
    import cv2 

    src = cv2.imread("distortedImage.jpg") 
    width = src.shape[1] 
    height = src.shape[0] 

    distCoeff = np.zeros((4,1),np.float64) 

    # TODO: add your coefficients here! 
    k1 = -1.0e-5; # negative to remove barrel distortion 
    k2 = 0.0; 
    p1 = 0.0; 
    p2 = 0.0; 

    distCoeff[0,0] = k1; 
    distCoeff[1,0] = k2; 
    distCoeff[2,0] = p1; 
    distCoeff[3,0] = p2; 

    # assume unit matrix for camera 
    cam = np.eye(3,dtype=np.float32) 

    cam[0,2] = width/2.0 # define center x 
    cam[1,2] = height/2.0 # define center y 
    cam[0,0] = 10.  # define focal length x 
    cam[1,1] = 10.  # define focal length y 

    # here the undistortion will be computed 
    dst = cv2.undistort(src,cam,distCoeff) 

    cv2.imshow('dst',dst) 
    cv2.waitKey(0) 
    cv2.destroyAllWindows() 

非常感谢您的支持。

+0

很高兴听到。如果你已经测试过它并且工作,afaik你可以接受你自己的答案来帮助其他人寻找相同问题的解决方案 – Micka 2014-10-28 21:14:04

1

这是一个互补的功能undistort,可能会更快,更好的方式来做到这一点,但它的工作原理:利用棋盘他们应该随时随地计算失真参数

void distort(const cv::Mat& src, cv::Mat& dst, const cv::Mat& cameraMatrix, const cv::Mat& distCoeffs) 
{ 

    cv::Mat distort_x = cv::Mat(src.size(), CV_32F); 
    cv::Mat distort_y = cv::Mat(src.size(), CV_32F); 

    cv::Mat pixel_locations_src = cv::Mat(src.size(), CV_32FC2); 

    for (int i = 0; i < src.size().height; i++) { 
    for (int j = 0; j < src.size().width; j++) { 
     pixel_locations_src.at<cv::Point2f>(i,j) = cv::Point2f(j,i); 
    } 
    } 

    cv::Mat fractional_locations_dst = cv::Mat(src.size(), CV_32FC2); 

    cv::undistortPoints(pixel_locations_src, pixel_locations_dst, cameraMatrix, distCoeffs); 

    cv::Mat pixel_locations_dst = cv::Mat(src.size(), CV_32FC2); 

    const float fx = cameraMatrix.at<double>(0,0); 
    const float fy = cameraMatrix.at<double>(1,1); 
    const float cx = cameraMatrix.at<double>(0,2); 
    const float cy = cameraMatrix.at<double>(1,2); 

    // is there a faster way to do this? 
    for (int i = 0; i < fractional_locations_dst.size().height; i++) { 
    for (int j = 0; j < fractional_locations_dst.size().width; j++) { 
     const float x = fractional_locations_dst.at<cv::Point2f>(i,j).x*fx + cx; 
     const float y = fractional_locations_dst.at<cv::Point2f>(i,j).y*fy + cy; 
     pixel_locations_dst.at<cv::Point2f>(i,j) = cv::Point2f(x,y); 
    } 
    } 

    cv::remap(src, dst, pixel_locations_dst, cv::Mat(), CV_INTER_LINEAR); 
}