【问题标题】:Correct barrel distortion in OpenCV manually, without chessboard image手动纠正​​ OpenCV 中的桶形失真,没有棋盘图像
【发布时间】:2014-10-28 07:34:23
【问题描述】:

我从无法拍摄棋盘图片并使用 OpenCV 计算校正矩阵的相机获取图像。到目前为止,我使用 imagemagick convert 和选项 '-distort Barrel "0.0 0.0 -0.035 1.1"' 校正了图像,在那里我通过反复试验获得了参数。

现在我想在 OpenCV 中执行此操作,但我在网上找到的只是使用棋盘图像的自动校正。是否有机会像使用 imagemagick 一样应用一些简单的手动试错镜头畸变校正?

【问题讨论】:

  • 在使用棋盘的样本中,他们应该在任何地方计算失真参数。只需跳过计算并明确提供这些参数。如果该部分被封装,您可以查看 oprnCV 源代码并使用内部使用的函数
  • 我尝试自己定义棋盘角(例如 4x4 点),但没有得到角数组的结构应该是什么。有人知道吗?
  • 好的,我认为尽可能小的数组应该这样配置:corners = np.zeros((4*4,1,2),dtype="float32")。使用 3x3 似乎不起作用。不过,我更喜欢 convert -distort Barrel 之类的东西,而不是现在定义扭曲点。
  • 你试过 initUndistortRectifyMap(InputArray cameraMatrix, InputArray distCoeffs, InputArray R, InputArray newCameraMatrix, Size size, int m1type, OutputArray map1, OutputArray map2) 吗?它不使用任何棋盘,只使用失真系数......
  • 嗯......现在我发现它不是用一个扭曲的棋盘完成的,因为需要大约 10 个不同的扭曲图像来应用 cv2.calibrateCamera :-( 所以我尝试 cv2.initUndistortRectifyMap。

标签: opencv imagemagick distortion


【解决方案1】:

好的,我想我明白了。在矩阵 cam1、cam2 中,图像中心缺失(参见文档)。我添加了它并更改了焦距,以避免图像尺寸发生过大的变化。这是代码:

  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()

非常感谢您的帮助。

【讨论】:

  • 很高兴听到。如果您已经对其进行了测试并且它有效,那么您可以接受自己的答案来帮助其他人寻找相同问题的解决方案
【解决方案2】:

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

由于我不知道你的桶形失真参数对应于哪些系数(也许看看http://docs.opencv.org/doc/tutorials/calib3d/camera_calibration/camera_calibration.htmlhttp://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);

【讨论】:

  • k4、k5、k6从何而来?它不是文档的一部分,是吗?有没有Python代码sn-p?
  • 如果我点击您的链接,我会看到如下内容: xcor=x*(1+k1*r^2+k2*r^4+k3*r^6);这与 imagemagick(imagemagick.org/Usage/distorts/#barrel) 的描述不同,其中应用了以下公式: Rsrc = r * ( Ar^3 + Br^2 + C*r + D );所以设置例如k1 到 0.001 会产生一个非常奇怪的图像,但不能纠正桶形失真?!不过,我认为我们离解决方案更近了。
  • 对不起,我这边没有 python sn-p,但它只是关于 initUndistortRectifyMap 调用和设置系数。维基百科给出了一些类似于 OpenCV 的系数(虽然没有检查条款)en.wikipedia.org/wiki/… 所以也许 imageMagick 使用了不同的失真模型,或者他们假设某种逆参数?!?不知道,抱歉=)
  • 根据imagemagick.org/Usage/lens/correcting_lens_distortions.pdf,imagemagick 使用了 PTLens 不失真模型,它本身就是uses a third-order po- lynomial approach to describe radial distortion。看看那个 PDF,也许你可以找出这些模型之间的差异并写下你的问题的答案,这可以帮助其他人:)
  • 我必须提到的另一件事:cam1cam2 在我的示例中是单位矩阵。如果您根据需要调整焦距(如有必要,请阅读相机矩阵),失真系数也可能会改变?也许这是另一个错误?!?
【解决方案3】:

这是不失真的补充功能,可能是更快或更好的方法,但它有效:

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);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-04-20
    • 1970-01-01
    • 1970-01-01
    • 2015-02-25
    • 2013-12-29
    • 1970-01-01
    • 1970-01-01
    • 2017-02-22
    相关资源
    最近更新 更多