opencv 图像添加畸变
因为需要对相机标定效果进行评价,首先要制作一张有畸变的标定板图片。可是opencv对图片只能去畸变,没有直接添加畸变的方法。
基于畸变公式可以对求得畸变后的点的坐标。本文的方法就是根据这个公式+cv::remap
制作的标定板↑
添加畸变后↓
#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的转换好像错了,所有参数都应该再取负