opencv 图像添加畸变

opencv 图像添加畸变

因为需要对相机标定效果进行评价,首先要制作一张有畸变的标定板图片。可是opencv对图片只能去畸变,没有直接添加畸变的方法。

基于畸变公式可以对求得畸变后的点的坐标。本文的方法就是根据这个公式+cv::remap

参考链接: https://stackoverflow.com/questions/66895102/how-to-apply-distortion-on-an-image-using-opencv-or-any-other-library#:~:text=OpenCV%20doesn%27t%20provide%20distort%20function%20for%20image%2C%20but,distortion%20coefficients%29%20and%20size%20of%20the%20distorted%20image..

在这里插入图片描述
制作的标定板↑
添加畸变后↓
在这里插入图片描述

#include <iterator>
#include <iostream>
#include <vector>
#include <stdio.h>
#include <string>
#include <opencv2/opencv.hpp>
#include <typeinfo>

using namespace std;
using namespace cv;

const int cp_number = 7;//控制点个数=7x7
const int width = 1280;//图片尺寸
const int height = 720;
const int framewidth = 50;//边框尺寸
const double circle_rad = 7.5;//控制点半径
double circle_dis = 2 * circle_rad;//控制点间隔
//相机内参
double fx = 906;
double fy = 906;
double cx = 647.5;
double cy = 378.5;
//Halcon直接算出来的。本文用的参数是一款RS相机415
double hk1 = -37668.9;
double hk2 = 2.4395e10;
double hk3 = -1.99655e15;
double hp1 = -0.308425;
double hp2 = -1.27456;
//Halcon畸变系数转为opencv格式
double f = 0.00194848;
double f2 = f * f;
double f4 = f2 * f2;
double f6 = f2 * f4;
double k1 = hk1 * f2;
double k2 = hk2 * f4;
double p1 = hp2 * f;
double p2 = hp1 * f;
double k3 = hk3 * f6;
//构造相机内参和畸变系数矩阵
cv::Mat_<double> cameraMatrix = (cv::Mat_<double>(3, 3) <<
	fx, 0, cx,
	0, fy, cy,
	0, 0, 1);
cv::Mat_<double> distCoeffs = (cv::Mat_<double>(5, 1) <<
	k1, k2, p1, p2, k3);

void distortimage(cv::Mat& imagein, cv::Mat& imageout, cv::Mat& cameraMatrix, cv::Mat& distCoef);

int main() {
	
	cv::Mat creat_src = cv::Mat(cv::Size(width,height), CV_8UC1,cv::Scalar(0,0,0));
	cv::rectangle(creat_src, cv::Point(framewidth, framewidth), cv::Point(width- framewidth, height- framewidth), cv::Scalar(255, 255, 255),-1);
	int circle_dis_pix,circle_rad_pix;
	for (int i = 0; i < 5; i++) {
		circle_dis_pix = (height - 2 * framewidth) / (cp_number + 1)+i;
		if (circle_dis_pix % 4 == 0){
			circle_rad_pix = circle_dis_pix / 4;
			cout << "控制点距离:" << circle_dis_pix << "," << "控制点半径:" << circle_rad_pix << endl;
			break;
		}
	}
	//画圆圈
	for (int i = 0; i < cp_number; i++) {
		cv::Point sp;
		sp.y = framewidth + circle_dis_pix*(i+1);
		for (int j = 0; j < cp_number; j++) {
			sp.x = width/2-(circle_dis_pix * (cp_number-1))/2+ circle_dis_pix *j;
			cv::circle(creat_src, sp, circle_rad_pix, cv::Scalar(0, 0, 0), -1);
		}
	}
	//添加高斯噪声(不需要可以不加)
	cv::Mat guss_noise = cv::Mat::zeros(creat_src.rows, creat_src.cols, creat_src.type());
	cv::RNG rng;
	rng.fill(guss_noise, cv::RNG::NORMAL, 20, 40);
	creat_src = creat_src + guss_noise;
	
	cv::Mat creat_src_dist = cv::Mat(cv::Size(width, height), CV_8UC1, cv::Scalar(0, 0, 0));
	creat_src_dist = creat_src_dist + guss_noise;
	
	
	//图像变形:畸变
	Mat creat_src_distort;
	distortimage(creat_src, creat_src_distort, cameraMatrix, distCoeffs);

	//保存图片
	//cv::imwrite("src.png", creat_src);
	//显示图片
	cv::namedWindow("creat_src_distort",cv::WINDOW_FREERATIO);
	cv::imshow("creat_src_distort", creat_src_distort);
	cv::waitKey(0);
}

void distortimage(cv::Mat& imagein,cv::Mat& imageout,cv::Mat& cameraMatrix, cv::Mat& distCoef) {

	double fx = cameraMatrix.at<double>(0, 0);
	double fy = cameraMatrix.at<double>(1, 1);
	double cx = cameraMatrix.at<double>(0, 2);
	double cy = cameraMatrix.at<double>(1, 2);
	double k1 = distCoef.at<double>(0, 0);
	double k2 = distCoef.at<double>(0, 1);
	double p1 = distCoef.at<double>(0, 2);
	double p2 = distCoef.at<double>(0, 3);
	double k3 = distCoef.at<double>(0, 4);
	
	double x;
	double y;
	double r2;
	double xDistort;
	double yDistort;

	cv::Mat map_x = cv::Mat(cv::Size(imagein.cols, imagein.rows), CV_32FC1);//原图中所有点在变形后点的x位置
	cv::Mat map_y = cv::Mat(cv::Size(imagein.cols, imagein.rows), CV_32FC1);//原图中所有点在变形后点的y位置
	vector<Point2f>  pts_src;

	//图像变形:畸变——原图中的每个点的x,y都pushback进点集pts_distort,pts_distort大小为图片长×宽
	for (int y_count = 0; y_count < imagein.rows; ++y_count)
		for (int x_count = 0; x_count < imagein.cols; ++x_count)
			pts_src.emplace_back(x_count, y_count);
	
	for (int y_count = 0; y_count < imagein.rows; ++y_count) {
		float* ptr1 = map_x.ptr<float>(y_count);//ptr1指向x方向偏移map_x的各行
		float* ptr2 = map_y.ptr<float>(y_count);//ptr2指向y方向偏移map_y的各行
		for (int x_count = 0; x_count < imagein.cols; ++x_count) {
			const auto& pt = pts_src[y_count * imagein.cols + x_count];//pt遍历指向pts_src中每点
			
			x = (pt.x - cx) / fx;
			y = (pt.y - cy) / fy;
			r2 = x * x + y * y;

			// Radial distorsion
			xDistort = x * (1 + k1 * r2 + k2 * pow(r2, 2) + k3 * pow(r2, 3));
			yDistort = y * (1 + k1 * r2 + k2 * pow(r2, 2) + k3 * pow(r2, 3));

			// Tangential distorsion
			xDistort = xDistort + (2 * p1 * x * y + p2 * (r2 + 2 * x * x));
			yDistort = yDistort + (p1 * (r2 + 2 * y * y) + 2 * p2 * x * y);

			// Back to absolute coordinates.
			xDistort = xDistort * fx + cx;
			yDistort = yDistort * fy + cy;

			ptr1[x_count] = xDistort; //map_x某行中的第x个点 = 原图中该点x坐标变换f(x)
			ptr2[x_count] = yDistort;
		}
	}
	cv::remap(imagein, imageout, map_x, map_y, INTER_CUBIC);//双三次样条插值	
}


-----------------------------------
那个halcon和opencv的转换好像错了,所有参数都应该再取负
  • 0
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
要以上代码添加相机畸变校正,你需要使用相机的畸变参数,例如径向畸变系数和切向畸变系数。以下是一个假设相机畸变参数已知的示例代码: ```cpp #include <iostream> #include <vector> #include <opencv2/opencv.hpp> int main() { cv::VideoCapture cap(0); // 打开摄像头 // 相机内参 cv::Mat cameraMatrix = (cv::Mat_<double>(3, 3) << fx, 0, cx, 0, fy, cy, 0, 0, 1); // 相机畸变参数 cv::Mat distCoeffs = (cv::Mat_<double>(1, 5) << k1, k2, p1, p2, k3); cv::Ptr<cv::ORB> orb = cv::ORB::create(); // 创建 ORB 特征提取器 cv::Mat prevFrame, prevDescriptors; std::vector<cv::KeyPoint> prevKeypoints; while (true) { cv::Mat frame; cap >> frame; // 读取当前帧 // 畸变校正 cv::Mat undistortedFrame; cv::undistort(frame, undistortedFrame, cameraMatrix, distCoeffs); std::vector<cv::KeyPoint> keypoints; cv::Mat descriptors; orb->detectAndCompute(undistortedFrame, cv::noArray(), keypoints, descriptors); // 检测特征点和计算描述子 if (prevDescriptors.empty()) { prevKeypoints = keypoints; prevDescriptors = descriptors; prevFrame = frame.clone(); continue; } std::vector<cv::DMatch> matches; cv::Ptr<cv::DescriptorMatcher> matcher = cv::DescriptorMatcher::create("BruteForce-Hamming"); matcher->match(prevDescriptors, descriptors, matches); // 特征点匹配 // 可以使用 RANSAC 算法去除错误匹配点对 // 计算相机运动 cv::Mat R, t; std::vector<cv::Point2f> prevPoints, currPoints; for (const cv::DMatch& match : matches) { prevPoints.push_back(prevKeypoints[match.queryIdx].pt); currPoints.push_back(keypoints[match.trainIdx].pt); } cv::findEssentialMat(prevPoints, currPoints, cv::Mat::eye(3, 3, CV_64F), cv::RANSAC, 0.999, 1.0, cv::noArray(), R, t); // 更新相机位姿 cv::Mat prevPose = cv::Mat::eye(4, 4, CV_64F); cv::Mat currPose = prevPose.clone(); cv::Mat R_vec; cv::Rodrigues(R, R_vec); R_vec.copyTo(currPose(cv::Rect(0, 0, 3, 3))); t.copyTo(currPose(cv::Rect(3, 0, 1, 3))); currPose = prevPose * currPose; // 输出当前帧的位姿 std::cout << "Current pose:\n" << currPose << std::endl; // 更新上一帧的信息 prevKeypoints = keypoints; prevDescriptors = descriptors; prevFrame = frame.clone(); cv::imshow("Frame", frame); if (cv::waitKey(1) == 'q') { break; } } cap.release(); cv::destroyAllWindows(); return 0; } ``` 在代码中,我们首先定义了相机内参 `cameraMatrix` 和相机畸变参数 `distCoeffs`。然后,在每一帧图像处理之前,使用 `cv::undistort` 函数对图像进行畸变校正,得到 `undistortedFrame`,然后再对 `undistortedFrame` 进行特征提取和匹配。这样可以在视觉里程计中考虑相机畸变的影响。请确保将 `fx`、`fy`、`cx`、`cy`、`k1`、`k2`、`p1`、`p2`、`k3` 替换为实际的相机参数值。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值