畸变矫正、透视变换加速(OpenCV C++)
2023-02-18 16:27:20 时间
前两周,同事和我说检测时间超时,其中对图像做畸变矫正和投影变换就要花费25ms(3000×3000的图)。而此时我们已经用上了文章opencv图像畸变矫正加速、透视变换加速方法总结中的方法。突然我想到了我去年笔记OpenCV笔记(10) 相机模型与标定中的一个函数cv::undistortPoints(),对感兴趣点进行畸变矫正。在应用之前,需要测试下两种方法计算出来的点的差值,即remap和undistortPoints的不同。结论:对全图进行畸变矫正,再找点 VS 找点后,对点进行畸变矫正,两者的差值小于0.1个像素,可行!同样的方法可以运用在投影变换上。在尺寸测量方面,这样可以节省掉畸变矫正和投影变换的时间。
1 只对感兴趣的点进行畸变矫正
// 读取相机参数文件 FileStorage fs("D:/distortionLens.xml", FileStorage::READ); Mat intrinsic_matrix = Mat(3, 3, CV_32FC1, Scalar::all(0)); Mat distortion_coeffs = Mat(1, 5, CV_32FC1, Scalar::all(0)); fs["intrinsic_matrix"] >> intrinsic_matrix; fs["distortion_coeffs"] >> distortion_coeffs; Mat mapx = Mat(s, CV_32FC1); Mat mapy = Mat(s, CV_32FC1); // 根据内参和畸变系数,建立查找表 //intrinsic_matrix = getOptimalNewCameraMatrix(intrinsic_matrix, distortion_coeffs, s, 1, s, 0); initUndistortRectifyMap(intrinsic_matrix, distortion_coeffs, Mat(), intrinsic_matrix, s, CV_32FC1, mapx, mapy); // 方法1:畸变矫正后找角点 Mat distortionMat; remap(src, distortionMat, mapx, mapy, INTER_CUBIC); vector<Point2f> distortPoints; findChessboardCornersSB(src, Size(21, 21), distortPoints, 64); // 方法2:找角点后畸变矫正 vector<Point2f> oriPoints, sparsePoints; findChessboardCornersSB(src, Size(21, 21), oriPoints, 64); undistortPoints(oriPoints, sparsePoints, intrinsic_matrix, distortion_coeffs, Mat(), intrinsic_matrix); // 打印比较 cout << " 原图找角点 " << "\t" << " 原图remap后找角点 " << "\t" << " 对原图角点矫正 " << endl; for (int i = 0; i < sparsePoints.size(); i++) { cout << oriPoints[i] << "\t" << distortPoints[i] << "\t" << sparsePoints[i] << "\t" << "差值:" << distortPoints[i] - sparsePoints[i] << endl; }
部分数据如下所示,可以看出,两者差值小于0.1个像素,加速10ms完成,接下来再对投影变换加速一下。
2 只对感兴趣的点进行投影变换
// 读取变换矩阵 fs = FileStorage("D:/transMat.txt", FileStorage::READ); Mat transMat = Mat(3, 3, CV_32FC1, Scalar::all(0)); fs["transMat"] >> transMat; // 方法1:进行透视变换后找角点 Mat warpMat; warpPerspective(src, warpMat, transMat, s, INTER_LINEAR, BORDER_CONSTANT, Scalar(255)); vector<Point2f> warpPoints; findChessboardCornersSB(warpMat,Size(21, 21), warpPoints, 64); // 方法2:找角点后进行透视变换 vector<Point2f> outPoints; for (int i = 0; i < oriPoints.size(); i++) { Mat_<double> oriPoint(3, 1); oriPoint(0, 0) = oriPoints[i].x; oriPoint(1, 0) = oriPoints[i].y; oriPoint(2, 0) = 1; Mat dstPoints = transMat * oriPoint; double a1 = dstPoints.at<double>(0, 0); double a2 = dstPoints.at<double>(1, 0); double a3 = dstPoints.at<double>(2, 0); outPoints.push_back(Point2f(a1 * 1.0 / a3, a2 * 1.0 / a3)); }
//打印 cout << " 原图找角点 " << "\t" << " 原图透视变换后找角点 " << "\t" << " 对原图角点变换 " << endl; for (int i = 0; i < sparsePoints.size(); i++) { cout << oriPoints[i] << "\t" << warpPoints[i] << "\t" << outPoints[i] << "\t" << "差值:" << distortPoints[i] - sparsePoints[i] << endl; }
3 合并
3.1 读取文件
void GetMap() { FileStorage fs(path+"distortionLens.xml", FileStorage::READ); if (fs.isOpened()) { intrinsic_matrix = Mat(3, 3, CV_64FC1, Scalar::all(0)); distortion_coeffs = Mat(1, 5, CV_64FC1, Scalar::all(0)); fs["intrinsic_matrix"] >> intrinsic_matrix; fs["distortion_coeffs"] >> distortion_coeffs; } fs = FileStorage(path+"transMat.txt", FileStorage::READ); if (fs.isOpened()) { transMat = Mat(3, 3, CV_64FC1, Scalar::all(0)); fs["transMat"] >> transMat; } }
3.2 变换感兴趣点
void remapPoints(vector<Point2f>& points) { for (int i = 0; i < points.size(); i++) { Mat_<double> oriPoint(3, 1); oriPoint(0, 0) = points[i].x; oriPoint(1, 0) = points[i].y; oriPoint(2, 0) = 1; Mat dstPoint = transMat * oriPoint; double a1 = dstPoint.at<double>(0, 0); double a2 = dstPoint.at<double>(1, 0); double a3 = dstPoint.at<double>(2, 0); points[i] = Point2f(a1 * 1.0 / a3, a2 * 1.0 / a3); } undistortPoints(points, points, intrinsic_matrix, distortion_coeffs, Mat(), intrinsic_matrix); }
相关文章
- 利用 Kruise Rollouts 对 Kubernetes 资源实现金丝雀发布
- Kubernetes 的 CI/CD 管道概述
- ChatGPT初体验|在 ChatGPT 中运行容器或Kubernetes?
- [Briefings in Bioinformatics|论文简读]NetTDP:基于互换的真实发现比例的差异性共表达网络分析
- [IEEE Trans Med Imaging | 论文简读] Av-CasNet:OCT血管成像中的微血管全自动分割与区分
- [Information Sciences | 论文简读] DA-Net:用于多变量时间序列分类的双注意力网络
- 如何验证Kubernetes YAML Files
- 利用php脚本+redis,生成CSV测试文件,重复率为20%
- [MySQL]索引
- [MySQL]brew 安装 配置 操作 mysql(中文问题)
- [MySQl]MySQL忘记密码
- [MySQL]增加用户 授权 远程登录
- [编程题目]泥塑课
- How can I learn to program?
- 学渣的心酸(求职篇)
- 时间复杂度问题
- 测试Flask应用_学习笔记
- Flask模板_学习笔记
- 初学Flask(1)
- 今天安装了麒麟系统