點擊上方“3D視覺工坊”,選擇“星標”
乾貨第一時間送達
通過採集的圖像我們可以得到畸變後的圖像,要得到沒有畸變的圖像要通過畸變模型推導其映射關係。
真實圖像 imgR 與 畸變圖像 imgD 之間的關係爲: imgR(U, V) = imgD(Ud, Vd) 。遍歷所有(U,V)填充爲映射對應的(Ud,Vd)即可實現圖像去畸變處理。
前提條件是:已經得知相機內參K以及畸變參數k1,k2,k3,p1,p2,這部分可以由matlab工具箱實現。
接下來,我們將詳細介紹如何去除圖像的畸變。
1. 圖像去畸變代碼
#include <opencv2/opencv.hpp>
#include <string>
#include <math.h>
using namespace std;
using namespace cv;
int main(int argc, char **argv) {
// 內參
double k1 = -0.3630, k2 = 0.1100, p1 = 0, p2 = 0;
double fx = 1026, fy = 1019.2, cx = 922.9716, cy = 589.6080;
char image_name[100];
for (int num = 1; num < 302; num )
{
sprintf_s(image_name,"./image/%d.jpg",num);
Mat image = cv::imread(image_name, 0); // 圖像是灰度圖,CV_8UC1
int rows = image.rows, cols = image.cols;
Mat image_undistort = Mat(rows, cols, CV_8UC1); // 去畸變以後的圖
// 計算去畸變後圖像的內容image_undistort
for (int v = 0; v < rows; v )
for (int u = 0; u < cols; u ) {
double u_distorted = 0, v_distorted = 0;
double x1, y1, x2, y2;
//未畸變像素平面到成像平面
x1 = (u - cx) / fx;
y1 = (v - cy) / fy;
double r2;
//成像平面畸變後
r2 = pow(x1, 2) pow(y1, 2);
x2 = x1*(1 k1*r2 k2*pow(r2, 2)) 2 * p1*x1*y1 p2*(r2 2 * x1*x1);
y2 = y1*(1 k1*r2 k2*pow(r2, 2)) p1*(r2 2 * y1*y1) 2 * p2*x1*y1;
//畸變的成像平面到像素平面
u_distorted = fx*x2 cx;
v_distorted = fy*y2 cy;
// 賦值 (最近鄰插值)
if (u_distorted >= 0 && v_distorted >= 0 && u_distorted < cols && v_distorted < rows) {
image_undistort.at<uchar>(v, u) = image.at<uchar>((int)v_distorted, (int)u_distorted);
}
else {
image_undistort.at<uchar>(v, u) = 0;
}
}
// 畫圖去畸變後圖像
char outname[100];
sprintf_s(outname, "./image1/%d.jpg", num);
cv::imwrite(outname,image_undistort);
}
cv::waitKey();
return 0;
}
方法二:調用 initUndistortRectifyMap和remap函數
#include <opencv2/opencv.hpp>
#include <string>
#include <math.h>
using namespace std;
using namespace cv;
int main(int argc, char **argv) {
// 內參
double k1 = -0.4183, k2 = 0.1584, p1 = 0, p2 = 0;
double fx = 1047.8, fy = 1028.6, cx = 885.1422, cy = 579.8241;
Mat cameraMatrix = (Mat_<double>(3, 3) <<
1047.8, 0, 885.1422,
0, 1028.6, 579.8241,
0,0,1);
Mat distCoeffs = (Mat_<double>(1, 4) << -0.4183, 0.1584, 0, 0);
char image_name[100];
for (int num = 1; num < 500; num )
{
sprintf_s(image_name, "./image_indoor/%d.jpg", num);
Mat image = cv::imread(image_name, 0); // 原圖image是灰度圖,CV_8UC1
int rows = image.rows, cols = image.cols;
Mat image_undistort = Mat(rows, cols, CV_8UC1); // 去畸變以後的圖
// 計算去畸變後圖像的內容image_undistort
Mat map1, map2;
//initUndistortRectifyMap(cameraMatrix, distCoeffs, Mat(), getOptimalNewCameraMatrix(cameraMatrix, distCoeffs, image.size(), 1, image.size(), 0), image.size(), CV_16SC2, map1, map2);
initUndistortRectifyMap(cameraMatrix, distCoeffs, Mat(), Mat(),image.size(), CV_16SC2, map1, map2);
remap(image, image_undistort, map1, map2, INTER_LINEAR);
// 畫圖去畸變後圖像
char outname[100];
sprintf_s(outname, "./image_indoor2/%d.jpg", num);
cv::imwrite(outname, image_undistort);
}
cv::waitKey();
return 0;
}
效果對比:
2. 雙線性內插法去畸變
雙線性內插法利用待求像素四個相鄰像素的灰度在兩個方向上做線性內插,在光流法求取某像素位置的灰度值時同樣用到了二維線性插值。
光流法這裏返回的是某個像素位置的灰度值。
protected:
// get a gray scale value from reference image (bilinear interpolated)
//取得變換後的圖中對應像素座標處的灰度值,這裏並不是返回一張圖像的灰度值,而是就是寫死了,就是類構造裏傳入的那張圖
inline float getPixelValue ( float x, float y )
{
//這裏先說一下各個參數的類型:
//image_爲Mat*類型,圖像指針,所以調用data時用->符號,
//data爲圖像矩陣首地址,支持數組形式訪問,data[]就是訪問到像素的值了,此處爲像素的灰度值,類型爲uchar
//關於step有點複雜,data[]中括號的式子有點複雜,總的意思就是y行乘上每行內存數,定位到行,然後在加上x,定位到像素
//step具體解釋在最後面有一些資料
//image_->data[int(y)*image_->step int(x)]這一步讀到了x,y處的灰度值,類型爲uchar,
//但是後面由於線性插值,需要定位這個像素的位置,而不是他的灰度值,所以取其地址,賦值給data_ptr,記住它的位置,後面使用
uchar* data_ptr = & image_->data[int(y)*image_->step int(x)];
//由於x,y這裏有可能帶小數,但是像素位置肯定是整數,所以,問題來了,(1.2, 4.5)像素座標處的灰度值爲多少呢?OK,線性插值!
//說一下floor(),std中的cmath函數。向下取整,返回不大於x的整數。例floor(4.9)=4
//xx和yy,就是取到小數部分。例:x=4.9的話,xx=x-floor(x)就爲0.9。y同理
float xx = x - floor ( x );
float yy = y - floor ( y );
//這整個return一個float值包含了線性插值,二維線性差值,這裏後文有具體高清無碼解釋
return float (
(1-xx) * ( 1-yy ) * data_ptr[0]
xx* ( 1-yy ) * data_ptr[1]
( 1-xx ) *yy*data_ptr[ image_->step ]
xx*yy*data_ptr[image_->step 1]
);
}
參考:
1.https://blog.csdn.net/weixin_41074793/article/details/88886153
2.https://blog.csdn.net/a472609409/article/details/90515742?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task