matlab畸变校正代码_关于OpenCV中的去畸变
在opencv中,有關圖像或像素點(角點)去畸變的函數有cv::undistort(),cv::getOptimalNewCameraMatrix(),cv::initUndistortRectifyMap(),remap(),cv::undistortPoints()。其中undistort可以直接對圖像去畸變,getOptimalNewCameraMatrix、initUndistortRectifyMap和remap配合也可以對圖像去畸變,他們之間有相同之處,又有各自特性,而undistortPoints是只針對像素點去畸變。下面就使用方法及細節進行梳理,并給出代碼示例,以便加深印象。
1. 函數功能及參數介紹
1.1 cv::getOptimalNewCameraMatrix()
函數參數說明:
Mat cv::getOptimalNewCameraMatrix ( InputArray cameraMatrix, // 相機內參矩陣InputArray distCoeffs, // 相機畸變參數Size imageSize, // 圖像尺寸double alpha, // 縮放比例Size newImgSize = Size(), // 校正后的圖像尺寸Rect * validPixROI = 0, // 輸出感興趣區域設置bool centerPrincipalPoint = false // 可選標志 )這個函數的功能是,"Return the new camera matrix based on the free scaling parameter",即根據根據比例因子返回相應的新的相機內參矩陣。
這里的"比例因子"就是函數的第四個參數(alpha),這個參數的范圍是(0, 1)。調節alpha的值能夠控制得到的新矩陣中的fx和fy的大小。
當alpha=1的時候,原圖像中的所有像素能夠得到保留,因此這個時候得到的矯正后的圖像是帶黑框的,如后面圖1所示。
當alpha=0時,得到的圖像是不帶黑色邊框的,相對于原圖像,此時的圖像損失了部分像素,如后面圖2所示。alpha的值控制著具體損失多少像素。
alpha和newImageSize是兩個互不干擾的參數,alpha只管是否對圖像進行裁剪,而newImageSize只負責把圖像進行縮放,這二者都會對返回的新的相機參數造成影響.
1.2 cv::initUndistortRectifyMap()
函數參數說明:
void cv::initUndistortRectifyMap ( InputArray cameraMatrix, // 原相機內參矩陣InputArray distCoeffs, // 原相機畸變參數InputArray R, // 可選的修正變換矩陣 InputArray newCameraMatrix, // 新相機內參矩陣Size size, // 去畸變后圖像的尺寸int m1type, // 第一個輸出的映射(map1)的類型,CV_32FC1 or CV_16SC2OutputArray map1, // 第一個輸出映射OutputArray map2 // 第二個輸出映射 )這個函數用于計算原始圖像和矯正圖像之間的轉換關系,將結果以映射的形式表達,映射關系存儲在map1和map2中。
在單目相機例子中,newCameraMatrix可以用cv::getOptimalNewCameraMatrix來計算,或者直接與cameraMatrix相等。在雙目相機例子中,newCameraMatrix一般是用cv::stereoRectify計算而來的(這里不做討論)。
1.3 cv::remap()
void cv::remap ( InputArray src, // 原始圖像OutputArray dst, // 矯正圖像 InputArray map1, // 第一個映射 InputArray map2, // 第二個映射 int interpolation, // 插值方式int borderMode=BORDER_CONSTANT, // 邊界模式 const Scalar& borderValue=Scalar() // 邊界顏色,默認Scalar()黑色 )函數功能:把原始圖像中某位置的像素映射到矯正后的圖像指定位置。
這里的map1和map2就是上面cv::initUndistortRectifyMap()計算出來的結果。
1.4 cv::undistort()
void cv::undistort ( InputArray src, // 原始圖像OutputArray dst, // 矯正圖像InputArray cameraMatrix, // 原相機內參矩陣InputArray distCoeffs, // 相機畸變參數InputArray newCameraMatrix = noArray() // 新相機內參矩陣 )函數功能:直接對圖像進行畸變矯正。
其內部調用了initUndistortRectifyMap和remap函數。
1.5 cv::undistortPoints()
void cv::undistortPoints ( InputArray src, // 原始像素點矩陣 1xN or Nx1 (CV_32FC2 or CV_64FC2).OutputArray dst, // 矯正像素點矩陣InputArray cameraMatrix, // 原相機內參矩陣InputArray distCoeffs, // 相機畸變參數InputArray R = noArray(), // 可選的修正變換矩陣InputArray P = noArray() // 新的相機矩陣 )函數功能:只對圖像中的某些點做畸變矯正。
2. 示例代碼
2.1 使用 getOptimalNewCameraMatrix + initUndistortRectifyMap + remap 矯正圖像
// // Created by jiang on 2020/4/29. // #include <iostream> #include <opencv2/opencv.hpp>using namespace std;int main() {const cv::Mat K = ( cv::Mat_<double> ( 3,3 ) << 931.73, 0.0, 480.0, 0.0, 933.16, 302.0, 0.0, 0.0, 1.0 );const cv::Mat D = ( cv::Mat_<double> ( 5,1 ) << -1.7165e-1, 1.968259e-1, 0.0, 0.0, -3.639514e-1 );const string str = "/home/jiang/4_learn/WeChatCode/ImageUndistort/data/";const int nImage = 5;const int ImgWidth = 960;const int ImgHeight = 640;cv::Mat map1, map2;cv::Size imageSize(ImgWidth, ImgHeight);const double alpha = 1;cv::Mat NewCameraMatrix = getOptimalNewCameraMatrix(K, D, imageSize, alpha, imageSize, 0);initUndistortRectifyMap(K, D, cv::Mat(), NewCameraMatrix, imageSize, CV_16SC2, map1, map2);for(int i=0; i<nImage; i++){string InputPath = str + to_string(i) + ".png";cv::Mat RawImage = cv::imread(InputPath);cv::imshow("RawImage", RawImage);cv::Mat UndistortImage;remap(RawImage, UndistortImage, map1, map2, cv::INTER_LINEAR);cv::imshow("UndistortImage", UndistortImage);string OutputPath = str + to_string(i) + "_un" + ".png";cv::imwrite(OutputPath, UndistortImage);cv::waitKey(0);}return 0; }當alpha=1時,所有像素均保留,但存在黑色邊框,矯正后的圖像如圖1所示。
當alpha=0時,損失最多的像素,沒有黑色邊框,矯正后的圖像如圖2所示。
圖1 alpha=1,所有像素均保留,帶黑框。圖2 alpha=0,損失最多的像素,無黑框。2.2 使用 undistort 矯正圖像
// // Created by jiang on 2020/4/29. // #include <iostream> #include <opencv2/opencv.hpp>using namespace std;int main() {const cv::Mat K = ( cv::Mat_<double> ( 3,3 ) << 931.73, 0.0, 480.0, 0.0, 933.16, 302.0, 0.0, 0.0, 1.0 );const cv::Mat D = ( cv::Mat_<double> ( 5,1 ) << -1.7165e-1, 1.968259e-1, 0.0, 0.0, -3.639514e-1 );const string str = "/home/jiang/4_learn/WeChatCode/ImageUndistort/data/";const int nImage = 5;const int ImgWidth = 960;const int ImgHeight = 640;cv::Mat map1, map2;cv::Size imageSize(ImgWidth, ImgHeight);const double alpha = 1;cv::Mat NewCameraMatrix = getOptimalNewCameraMatrix(K, D, imageSize, alpha, imageSize, 0);for(int i=0; i<nImage; i++){string InputPath = str + to_string(i) + ".png";cv::Mat RawImage = cv::imread(InputPath);cv::imshow("RawImage", RawImage);cv::Mat UndistortImage;cv::undistort(RawImage, UndistortImage, K, D, K); // cv::undistort(RawImage, UndistortImage, K, D, NewCameraMatrix);cv::imshow("UndistortImage", UndistortImage);string OutputPath = str + to_string(i) + "_un2" + ".png";cv::imwrite(OutputPath, UndistortImage);cv::waitKey(0);}return 0; }如果undistort函數的最后一個參數使用原相機內參,那么得到的結果就是上面圖2的結果,相當于alpha=0的情況。
如果undistort函數的最后一個參數使用getOptimalNewCameraMatrix計算出來的新矩陣,那么得到損失像素后的圖像,當alpha=1時,就得到上面圖1的結果。
如果像我示例程序一樣,有多個圖片需要矯正,那么推薦使用2.1的方法,因為initUndistortRectifyMap函數只需要計算一次就行,不需要每次循環都計算,可以像我程序中一樣,將initUndistortRectifyMap放在循環外面。而使用2.2的方法,因為undistort函數內部調用了initUndistortRectifyMap和remap,所以相當于你n張圖像計算了n次initUndistortRectifyMap,這會大大降低效率,增加程序耗時。
2.3 使用 undistortPoints 矯正角點
方法一:
// // Created by jiang on 2020/4/29. // #include <iostream> #include <opencv2/opencv.hpp>using namespace std;const cv::Mat K = ( cv::Mat_<double> ( 3,3 ) << 931.73, 0.0, 480.0, 0.0, 933.16, 302.0, 0.0, 0.0, 1.0 ); const cv::Mat D = ( cv::Mat_<double> ( 5,1 ) << -1.7165e-1, 1.968259e-1, 0.0, 0.0, -3.639514e-1 );void UndistortKeyPoints(vector<cv::Point2f> &points);int main() {const string str = "/home/jiang/4_learn/WeChatCode/ImageUndistort/data/";const int nImage = 5;const int MAX_CNT = 150;const int MIN_DIST = 30;for(int i=0; i<nImage; i++){string InputPath = str + to_string(i) + ".png";cv::Mat RawImage = cv::imread(InputPath);vector<cv::Point2f> pts;cv::Mat RawImage_Gray;cv::cvtColor(RawImage, RawImage_Gray, CV_RGB2GRAY);cv::goodFeaturesToTrack(RawImage_Gray, pts, MAX_CNT, 0.01, MIN_DIST);for(auto& pt:pts)circle(RawImage, pt, 2, cv::Scalar(255, 0, 0), 2);cv::imshow("pts", RawImage);UndistortKeyPoints(pts);cv::Mat UndistortImage;cv::undistort(RawImage, UndistortImage, K, D, K);for(auto& pt:pts)circle(UndistortImage, pt, 2, cv::Scalar(0, 0, 255), 2);cv::imshow("pts_un", UndistortImage);string OutputPath = str + to_string(i) + "_pts_un" + ".png";cv::imwrite(OutputPath, UndistortImage);cv::waitKey(0);}return 0; }void UndistortKeyPoints(vector<cv::Point2f> &points) {if(D.at<float>(0)==0.0) // 圖像矯正過return;// N為提取的特征點數量,將N個特征點保存在N*2的mat中uint N = points.size();cv::Mat mat(N,2,CV_32F);for(int i=0; i<N; i++){mat.at<float>(i,0)=points[i].x;mat.at<float>(i,1)=points[i].y;}// 調整mat的通道為2,矩陣的行列形狀不變mat=mat.reshape(2);cv::undistortPoints(mat, mat, K, D, cv::Mat(), K);mat=mat.reshape(1);// 存儲校正后的特征點for(int i=0; i<N; i++){cv::Point2f kp = points[i];kp.x=mat.at<float>(i,0);kp.y=mat.at<float>(i,1);points[i] = kp;} }方法二:
// // Created by jiang on 2020/4/29. // #include <iostream> #include <opencv2/opencv.hpp>using namespace std;const cv::Mat K = ( cv::Mat_<double> ( 3,3 ) << 931.73, 0.0, 480.0, 0.0, 933.16, 302.0, 0.0, 0.0, 1.0 ); const cv::Mat D = ( cv::Mat_<double> ( 5,1 ) << -1.7165e-1, 1.968259e-1, 0.0, 0.0, -3.639514e-1 );void UndistortKeyPoints(vector<cv::Point2f> &points, cv::Mat &newCamMatrix);int main() {const string str = "/home/jiang/4_learn/WeChatCode/ImageUndistort/data/";const int nImage = 5;const int ImgWidth = 960;const int ImgHeight = 640;const int MAX_CNT = 150;const int MIN_DIST = 30;cv::Mat map1, map2;cv::Size imageSize(ImgWidth, ImgHeight);const double alpha = 1;cv::Mat NewCameraMatrix = getOptimalNewCameraMatrix(K, D, imageSize, alpha, imageSize, 0);initUndistortRectifyMap(K, D, cv::Mat(), NewCameraMatrix, imageSize, CV_16SC2, map1, map2);for(int i=0; i<nImage; i++){string InputPath = str + to_string(i) + ".png";cv::Mat RawImage = cv::imread(InputPath);cv::Mat UndistortImage;cv::remap(RawImage, UndistortImage, map1, map2, cv::INTER_LINEAR);vector<cv::Point2f> pts;cv::Mat RawImage_Gray;cv::cvtColor(RawImage, RawImage_Gray, CV_RGB2GRAY);cv::goodFeaturesToTrack(RawImage_Gray, pts, MAX_CNT, 0.01, MIN_DIST);for(auto& pt:pts)circle(RawImage, pt, 2, cv::Scalar(255, 0, 0), 2);cv::imshow("pts", RawImage);UndistortKeyPoints(pts, NewCameraMatrix);for(auto& pt:pts)circle(UndistortImage, pt, 2, cv::Scalar(0, 0, 255), 2);cv::imshow("pts_un", UndistortImage);string OutputPath = str + to_string(i) + "_pts_un" + ".png";cv::imwrite(OutputPath, UndistortImage);cv::waitKey(0);}return 0; }void UndistortKeyPoints(vector<cv::Point2f> &points, cv::Mat &newCamMatrix) {if(D.at<float>(0)==0.0) // 圖像矯正過return;// N為提取的特征點數量,將N個特征點保存在N*2的mat中uint N = points.size();cv::Mat mat(N,2,CV_32F);for(int i=0; i<N; i++){mat.at<float>(i,0)=points[i].x;mat.at<float>(i,1)=points[i].y;}// 調整mat的通道為2,矩陣的行列形狀不變mat=mat.reshape(2);cv::undistortPoints(mat, mat, K, D, cv::Mat(), newCamMatrix);mat=mat.reshape(1);// 存儲校正后的特征點for(int i=0; i<N; i++){cv::Point2f kp = points[i];kp.x=mat.at<float>(i,0);kp.y=mat.at<float>(i,1);points[i] = kp;} }先使用cv::goodFeaturesToTrack函數在圖像中提取一些FAST角點,如圖3所示。
圖3 FAST角點提取然后對這些角點去畸變,注意,我們矯正后的點是不能直接打印在原圖像上的,所以我們需要先對圖像去畸變(這里的兩種方法就是為了應對兩種不同的圖像矯正),然后將矯正后的點打印在矯正后的圖像上。矯正結果如圖3所示。
圖4 FAST角點去畸變注意,undistortPoints和undistort函數都有newCameraMatrix參數,這兩個函數要使用相同的newCameraMatrix參數,這樣才能將去畸變的點和去畸變的圖像對應起來,這里的newCameraMatrix使用原相機內參。
2.4 undistortPoints 矯正BoundingBox
// // Created by jiang on 2020/4/29. // #include <iostream> #include <opencv2/opencv.hpp>using namespace std;const cv::Mat K = ( cv::Mat_<double> ( 3,3 ) << 931.73, 0.0, 480.0, 0.0, 933.16, 302.0, 0.0, 0.0, 1.0 ); const cv::Mat D = ( cv::Mat_<double> ( 5,1 ) << -1.7165e-1, 1.968259e-1, 0.0, 0.0, -3.639514e-1 );void UndistortBbox(cv::Rect &rect, cv::Mat &newCamMatrix);int main() {const string str = "/home/jiang/4_learn/WeChatCode/ImageUndistort/data/";const int nImage = 5;const int ImgWidth = 960;const int ImgHeight = 640;cv::Mat map1, map2;cv::Size imageSize(ImgWidth, ImgHeight);const double alpha = 1;cv::Mat NewCameraMatrix = getOptimalNewCameraMatrix(K, D, imageSize, alpha, imageSize, 0);initUndistortRectifyMap(K, D, cv::Mat(), NewCameraMatrix, imageSize, CV_16SC2, map1, map2);cv::Rect Bbox{338, 141, 23, 57};for(int i=0; i<nImage; i++){string InputPath = str + to_string(i) + ".png";cv::Mat RawImage = cv::imread(InputPath);cv::Mat UndistortImage;cv::remap(RawImage, UndistortImage, map1, map2, cv::INTER_LINEAR); // cv::undistort(RawImage, UndistortImage, K, D, K);cv::rectangle(RawImage, Bbox, cv::Scalar(255, 0, 0), 2, 1);cv::imshow("RawImage", RawImage);string OutputPath1 = str + to_string(i) + "_Bbox" + ".png";cv::imwrite(OutputPath1, RawImage);UndistortBbox(Bbox, NewCameraMatrix);cv::rectangle(UndistortImage, Bbox, cv::Scalar(0, 0, 255), 2, 1);cv::imshow("UndistortImage", UndistortImage);string OutputPath2 = str + to_string(i) + "_Bbox_un" + ".png";cv::imwrite(OutputPath2, UndistortImage);cv::waitKey(0);}return 0; }void UndistortBbox(cv::Rect &rect, cv::Mat &newCamMatrix) {cv::Mat mat(4, 2, CV_32F);mat.at<float>(0, 0) = rect.x;mat.at<float>(0, 1) = rect.y;mat.at<float>(1, 0) = rect.x + rect.width;mat.at<float>(1, 1) = rect.y;mat.at<float>(2, 0) = rect.x;mat.at<float>(2, 1) = rect.y + rect.height;mat.at<float>(3, 0) = rect.x + rect.width;mat.at<float>(3, 1) = rect.y + rect.height;mat = mat.reshape(2); // 2通道,行列不變cv::undistortPoints(mat, mat, K, D, cv::Mat(), newCamMatrix);mat = mat.reshape(1); // 單通道,行列不變double MaxX, MaxY;rect.x = min(mat.at<float>(0, 0), mat.at<float>(2, 0));MaxX = max(mat.at<float>(1, 0), mat.at<float>(3, 0));rect.y = min(mat.at<float>(0, 1), mat.at<float>(1, 1));MaxY = max(mat.at<float>(2, 1), mat.at<float>(3, 1));rect.width = MaxX - rect.x;rect.height = MaxY - rect.y; }這里我們手動畫了一個Bbox{338,141,23,57}。然后用remap的方式矯正了圖像。
在矯正BoundingBox也就是矯正BoundingBox的四個點。只是這里有一個細節要考慮,就是Bbox的四個角點在矯正后的大小不確定,因此要判斷一下。矯正前的圖像如圖5所示,矯正后的圖像如圖6所示。
圖5 Bbox矯正前圖6 Bbox矯正后3. 總結與補充
關于圖像、角點和Bbox的去畸變就介紹到這里,后續有更深入的研究在加以補充。本人才疏學淺,如文章中有錯誤,還請讀者不吝賜教,吾當感激不盡。
文中用的opencv版本是3.3.0,CMakeLists如下:
cmake_minimum_required(VERSION 3.14) project(ImageUndistort)set(CMAKE_CXX_STANDARD 11)set(OpenCV_DIR "/home/jiang/6_lib/install/opencv3.3.0/share/OpenCV")find_package(OpenCV REQUIRED)add_executable(undistort2_1 undistort2_1.cpp) target_link_libraries(undistort2_1${OpenCV_LIBS} )add_executable(undistort2_2 undistort2_2.cpp) target_link_libraries(undistort2_2${OpenCV_LIBS})add_executable(undistort2_3_1 undistort2_3_1.cpp) target_link_libraries(undistort2_3_1${OpenCV_LIBS})add_executable(undistort2_3_2 undistort2_3_2.cpp) target_link_libraries(undistort2_3_2${OpenCV_LIBS})add_executable(undistort2_4 undistort2_4.cpp) target_link_libraries(undistort2_4${OpenCV_LIBS})完整的代碼在這里:
https://github.com/JiangZhengok/WeChatCode/tree/master/ImageUndistort?github.com總結
以上是生活随笔為你收集整理的matlab畸变校正代码_关于OpenCV中的去畸变的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: phpdesigner8 php7.0,
- 下一篇: java f.lenth返回值,这个是什