栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

使用OpenCV给图像去畸变

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

使用OpenCV给图像去畸变

    相机畸变模型
    我们计算畸变都是在归一化平面上进行的,下面的(x,y), (x_distort,y_distort)都是在归一化坐标,相机坐标(X,Y,Z)的归一化坐标(X/Z, Y/Z, 1)

    1、径向畸变
    由透镜形状引起的,畸变系数k1, k2, k3,畸变模型:

    2、切向畸变
    由镜片安装和成像平面不平行引起的,畸变系数p1, p2,切向畸变模型:

    3、总的畸变模型

    求解思路
    我们得到的原图是畸变后的图像(x_distort,y_distort),要计算畸变之前的真实图像(x,y),不是用逆运算,太难麻烦了,而是计算真是图像畸变后会投影在哪,对应过去。先把原图像设置为一个空的图像,把一个个像素畸变投影过去,找到和畸变后图像像素点的对应关系(可以参考下面代码方法1理解)。

    代码示例

     注意,OpenCV畸变系数矩阵的默认顺序 [k1, k2, p1, p2, k3]
    
    #include 
    #include 
    using namespace std;
    
    int main(int argc, char **argv)
    {
      // 内参
      double fx = 458.654, fy = 457.296, cx = 367.215, cy = 248.375;
      
      // 畸变参数
      double k1 = -0.28340811, k2 = 0.07395907, p1 = 0.00019359, p2 = 1.76187114e-05;
    
      cv::Mat image = cv::imread(argv[1], 0); // 图像是灰度图,CV_8UC1
      int rows = image.rows, cols = image.cols;
      cv::Mat image_undistort = cv::Mat(rows, cols, CV_8UC1); // 方法1去畸变以后的图
      cv::Mat image_undistort2 = cv::Mat(rows, cols, CV_8UC1);  // 方法2 OpenCV去畸变以后的图
    
      chrono::steady_clock::time_point t1 = chrono::steady_clock::now();
      //! 方法1. 自己写计算去畸变后图像的内容
      for (int v = 0; v < rows; v++)
      {
        for (int u = 0; u < cols; u++)
        {
          double x = (u - cx) / fx, y = (v - cy) / fy; //要求解的真实图,归一化平面上的坐标
          double r = sqrt(x * x + y * y);
          double x_distorted = x * (1 + k1 * r * r + k2 * r * r * r * r) + 2 * p1 * x * y + p2 * (r * r + 2 * x * x); //畸变后归一化坐标
          double y_distorted = y * (1 + k1 * r * r + k2 * r * r * r * r) + p1 * (r * r + 2 * y * y) + 2 * p2 * x * y;
          double u_distorted = fx * x_distorted + cx; //畸变后像素坐标,即原图
          double v_distorted = fy * y_distorted + cy;
          // 投影赋值
          if (u_distorted >= 0 && v_distorted >= 0 && u_distorted < cols && v_distorted < rows) //真实图畸变后仍然在图上的
          {
            image_undistort.at(v, u) = image.at((int)v_distorted, (int)u_distorted);
          }
          else
          {
            image_undistort.at(v, u) = 0; //这里最好用插值法
          }
        }
      }
      chrono::steady_clock::time_point t2 = chrono::steady_clock::now();
      chrono::duration time_used = chrono::duration_cast>(t2 - t1);
      cout << "time = " << time_used.count() << endl;
    
      //! 方法2. OpenCV自带的undistort函数,更快速
      cv::Mat K = cv::Mat::eye(3, 3, CV_32FC1); //内参矩阵
      K.at(0, 0) = fx;
      K.at(1, 1) = fy;
      K.at(0, 2) = cx;
      K.at(1, 2) = cy;
      cv::Mat distort_coeffs = cv::Mat::zeros(1, 5, CV_32FC1); //畸变系数矩阵 顺序是[k1, k2, p1, p2, k3]
      distort_coeffs.at(0, 0) = k1;
      distort_coeffs.at(0, 1) = k2;
      distort_coeffs.at(0, 3) = p1;
      distort_coeffs.at(0, 4) = p2;
      cout << "K = " << endl
           << K << endl;
      cout << "distort_coeffs = " << endl
           << distort_coeffs << endl;
    
      t1 = chrono::steady_clock::now();
      cv::undistort(image, image_undistort2, K, distort_coeffs); //去畸变
      t2 = chrono::steady_clock::now();
      time_used = chrono::duration_cast>(t2 - t1);
      cout << "time = " << time_used.count() << endl;
    
      // 展示去畸变后图像
      cv::imshow("distorted", image);
      cv::imshow("undistorted", image_undistort);
      cv::imshow("image_undistort2", image_undistort2);
      cv::waitKey(0);
      return 0;
    }
    
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/784823.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号