日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

双目摄像头立体成像(二)畸变矫正与立体校正

發布時間:2023/12/20 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 双目摄像头立体成像(二)畸变矫正与立体校正 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、立體校正的原因

**原因一:**當畸變系數和內外參數矩陣標定完成后,就應該進行畸變矯正,以達到消除畸變的目的。

**原因二:**在立體成像原理中提到,要通過兩幅圖像估計物點的深度信息,就必須在兩幅圖像中準確的匹配到同一物點,這樣才能根據該物點在兩幅圖像中的位置關系,計算物體深度。
為了降低匹配的計算量,兩個攝像頭的成像平面應處于同一平面。但是,單單依靠嚴格的擺放攝像頭來達到這個目的顯然有些困難。立體校正就是利用幾何圖形變換(Geometric Image Transformation)關系,使得原先不滿足上述位置關系的兩幅圖像滿足該條件。

二、畸變校正(compensate lens distortion)和立體校正(stereo rectify)的數學原理
(一)畸變校正(compensate lens distortion)
畸變矯正的方法就是用上一篇博文給出的公式對像素位置進行重新映射。這里重新寫出重新映射的公式。
先矯正徑向畸變

再矯正切向畸變

(二)立體校正(stereo rectify)
立體矯正能夠有效降低立體匹配的計算量,立體矯正的具體作用見下圖,

立體矯正前,

立體矯正后,

立體矯正的算法原理沒有詳細了解,此處從略。

OpenCV相關函數說明

一、畸變矯正函數 undistort( )

undistort() 是獨立的一個畸變矯正函數,一次性可以完成映射矩陣的求解和重新映射。下面我們還會看到把這兩步分開來做的函數。
調用方法:略
參數介紹:
1. src-輸入未經過矯正的圖像
2. dst-經過矯正后輸出的圖像
3. cameraMatrix-標定而得到的攝像機矩陣
4. distCoeffs-標定得到的攝像機畸變矩陣
5. newCameraMatrix-輸入矯正后的攝像機矩陣(可以省略)

二、立體標定函數 stereoCalibrate()

stereoCalibrate( ) 是用來標定一個立體攝像頭的,也就是同時標定兩個攝像頭。標定的結果除了能夠求出兩個攝像頭的內外參數矩陣,跟能夠得出兩個攝像頭的位置關系R,T

調用方法:

double stereoCalibrate(InputArrayOfArrays objectPoints,InputArrayOfArrays imagePoints1, InputArrayOfArrays imagePoints2, InputOutputArray cameraMatrix1,InputOutputArray distCoeffs1, InputOutputArray cameraMatrix2, InputOutputArray distCoeffs2, Size imageSize, OutputArray R,OutputArray T, OutputArray E, OutputArray F, TermCriteria criteria=TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 30, 1e-6), int flags=CALIB_FIX_INTRINSIC )

參數介紹:

  • objectPoints- vector 型的數據結構,存儲標定角點在世界坐標系中的位置。
  • imagePoints1- vector<vector> 型的數據結構,存儲標定角點在第一個攝像機下的投影后的亞像素坐標。
  • imagePoints2- vector<vector> 型的數據結構,存儲標定角點在第二個攝像機下的投影后的亞像素坐標。
  • cameraMatrix1-輸入/輸出型的第一個攝像機的相機矩陣。如果CV_CALIB_USE_INTRINSIC_GUESS , CV_CALIB_FIX_ASPECT_RATIO ,CV_CALIB_FIX_INTRINSIC , or CV_CALIB_FIX_FOCAL_LENGTH其中的一個或多個標志被設置,該攝像機矩陣的一些或全部參數需要被初始化
  • distCoeffs1-第一個攝像機的輸入/輸出型畸變向量。根據矯正模型的不同,輸出向量長度由標志決定
  • cameraMatrix2-輸入/輸出型的第二個攝像機的相機矩陣。參數意義同第一個相機矩陣相似
  • distCoeffs2-第一個攝像機的輸入/輸出型畸變向量。根據矯正模型的不同,輸出向量長度由標志決定
  • imageSize-圖像的大小
  • R-輸出型,第一和第二個攝像機之間的旋轉矩陣
  • T-輸出型,第一和第二個攝像機之間的平移矩陣
  • E-輸出型,基本矩陣
  • F-輸出型,基礎矩陣
  • term_crit-迭代優化的終止條件
  • flag-
    14.1 CV_CALIB_FIX_INTRINSIC 如果該標志被設置,那么就會固定輸入的cameraMatrix和distCoeffs不變,只求解 $R,T,E,F
    $.
    14.2 CV_CALIB_USE_INTRINSIC_GUESS 根據用戶提供的cameraMatrix和distCoeffs為初始值開始迭代
    14.3 CV_CALIB_FIX_PRINCIPAL_POINT 迭代過程中不會改變主點的位置
    14.4. CV_CALIB_FIX_FOCAL_LENGTH 迭代過程中不會改變焦距
    14.5 CV_CALIB_SAME_FOCAL_LENGTH 強制保持兩個攝像機的焦距相同
    14.6 CV_CALIB_ZERO_TANGENT_DIST 切向畸變保持為零
    14.7 CV_CALIB_FIX_K1,…,CV_CALIB_FIX_K6 迭代過程中不改變相應的值。如果設置了 CV_CALIB_USE_INTRINSIC_GUESS 將會使用用戶提供的初始值,否則設置為零
    14.8 CV_CALIB_RATIONAL_MODEL 畸變模型的選擇,如果設置了該參數,將會使用更精確的畸變模型,distCoeffs的長度就會變成8
  • 三、立體校正函數 stereoRectify()

    stereoRectify() 的作用是為每個攝像頭計算立體校正的映射矩陣。所以其運行結果并不是直接將圖片進行立體矯正,而是得出進行立體矯正所需要的映射矩陣。

    調用方法:

    void stereoRectify( InputArray cameraMatrix1, InputArray distCoeffs1, InputArray cameraMatrix2, InputArray distCoeffs2, Size imageSize, InputArray R, InputArray T,OutputArray R1, OutputArray R2, OutputArray P1, OutputArray P2, OutputArray Q, int flags=CALIB_ZERO_DISPARITY, double alpha=-1, Size newImageSize=Size(), Rect* validPixROI1=0, Rect* validPixROI2=0 )

    參數介紹:

  • cameraMatrix1-第一個攝像機的攝像機矩陣
  • distCoeffs1-第一個攝像機的畸變向量
  • cameraMatrix2-第二個攝像機的攝像機矩陣
  • distCoeffs2-第二個攝像機的畸變向量
  • imageSize-圖像大小
  • R- stereoCalibrate() 求得的R矩陣
  • T- stereoCalibrate() 求得的T矩陣
  • R1-輸出矩陣,第一個攝像機的校正變換矩陣(旋轉矩陣)
  • R2-輸出矩陣,第二個攝像機的校正變換矩陣(旋轉矩陣)
  • P1-輸出矩陣,第一個攝像機在新坐標系下的投影矩陣
  • P2-輸出矩陣,第二個攝像機在想坐標系下的投影矩陣
  • Q-4*4的深度差異映射矩陣
  • flags-可選的標志有兩種零或者 CV_CALIB_ZERO_DISPARITY ,如果設置 CV_CALIB_ZERO_DISPARITY 的話,該函數會讓兩幅校正后的圖像的主點有相同的像素坐標。否則該函數會水平或垂直的移動圖像,以使得其有用的范圍最大
  • alpha-拉伸參數。如果設置為負或忽略,將不進行拉伸。如果設置為0,那么校正后圖像只有有效的部分會被顯示(沒有黑色的部分),如果設置為1,那么就會顯示整個圖像。設置為0~1之間的某個值,其效果也居于兩者之間。
  • newImageSize-校正后的圖像分辨率,默認為原分辨率大小。
  • validPixROI1-可選的輸出參數,Rect型數據。其內部的所有像素都有效
  • validPixROI2-可選的輸出參數,Rect型數據。其內部的所有像素都有效
  • 四、映射變換計算函數 initUndistortRectifyMap()

    該函數功能是計算畸變矯正和立體校正的映射變換。

    調用方法:

    void initUndistortRectifyMap(InputArray cameraMatrix, InputArray distCoeffs, InputArray R,InputArray newCameraMatrix, Size size, int m1type, OutputArray map1, OutputArray map2)

    調用方法:

  • cameraMatrix-攝像機參數矩陣
  • distCoeffs-畸變參數矩陣
  • R- stereoCalibrate() 求得的R矩陣
  • newCameraMatrix-矯正后的攝像機矩陣(可省略)
  • Size-沒有矯正圖像的分辨率
  • m1type-第一個輸出映射的數據類型,可以為 CV_32FC1 或 CV_16SC2
  • map1-輸出的第一個映射變換
  • map2-輸出的第二個映射變換
  • 五、像素重映射函數 remap()


    調用方法:

    void remap(InputArray src, OutputArray dst, InputArray map1, InputArray map2, int interpolation,int borderMode=BORDER_CONSTANT, const Scalar&borderValue=Scalar())

    第五個參數:插值方式,有四中插值方式:

  • src-輸入圖像,即原圖像,需要單通道8位或者浮點類型的圖像。
  • dst-輸出圖像,即目標圖像,需和原圖形一樣的尺寸和類型。
  • map1- x 映射表 ,它有兩種可能表示的對象:(1)表示點(x,y)的第一個映射;(2)表示CV_16SC2,CV_32FC1等
  • map2- y 映射表 ,它有兩種可能表示的對象:。(1)若map1表示點(x,y)時,這個參數不代表任何值;(2)表示 CV_16UC1,CV_32FC1類型的Y值。
  • interpolation-選擇的插值方法,常見線性插值INTER_LINEAR,可選擇立方等 ,但是不支持最近鄰插值。
    (1)INTER_NEAREST——最近鄰插值
    (2)INTER_LINEAR——雙線性插值(默認)
    (3)INTER_CUBIC——雙三樣條插值(默認)
    (4)INTER_LANCZOS4——lanczos插值(默認)
  • 邊界模式,默認BORDER_CONSTANT
  • 邊界顏色,默認Scalar()黑色
  • 基于OpenCV的仿真

    仿真程序

    int main() {//initialize some parametersbool okcalib = false;Mat intrMatFirst, intrMatSec, distCoeffsFirst, distCoffesSec;Mat R, T, E, F, RFirst, RSec, PFirst, PSec, Q;vector<vector<Point2f>> imagePointsFirst, imagePointsSec;vector<vector<Point3f>> ObjectPoints(1);Rect validRoi[2];Size imageSize;int cameraIdFirst = 0, cameraIdSec = 1;double rms = 0;//get pictures and calibratevector<string> imageList;string filename = "stereo_calib.xml";bool okread = readStringList(filename, imageList);if (!okread || imageList.empty()){cout << "can not open " << filename << " or the string list is empty" << endl;return false;}if (imageList.size() % 2 != 0){cout << "Error: the image list contains odd (non-even) number of elements\n";return false;}//calibratecout << "calibrate left camera..." << endl;okcalib = calibrate(intrMatFirst, distCoeffsFirst, imagePointsFirst, ObjectPoints,imageSize, cameraIdFirst, imageList);if (!okcalib){cout << "fail to calibrate left camera" << endl;return -1;}else{cout << "calibrate the right camera..." << endl;}okcalib = calibrate(intrMatSec, distCoffesSec, imagePointsSec, ObjectPoints,imageSize, cameraIdSec, imageList);if (!okcalib){cout << "fail to calibrate the right camera" << endl;return -1;}destroyAllWindows();//estimate position and orientationcout << "estimate position and orientation of the second camera" << endl<< "relative to the first camera..." << endl;rms = stereoCalibrate(ObjectPoints, imagePointsFirst, imagePointsSec,intrMatFirst, distCoeffsFirst, intrMatSec, distCoffesSec,imageSize, R, T, E, F, CV_CALIB_FIX_INTRINSIC,TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 30, 1e-6));cout << "done with RMS error=" << rms << endl;//stereo rectifycout << "stereo rectify..." << endl;stereoRectify(intrMatFirst, distCoeffsFirst, intrMatSec, distCoffesSec, imageSize, R, T, RFirst,RSec, PFirst, PSec, Q, 0, 1, imageSize, &validRoi[0], &validRoi[1]);//read pictures for 3d-reconstructionnamedWindow("canvas", 1);cout << "read the picture for 3d-reconstruction...";Mat canvas(imageSize.height, imageSize.width * 2, CV_8UC3), viewLeft, viewRight;Mat canLeft = canvas(Rect(0, 0, imageSize.width, imageSize.height));Mat canRight = canvas(Rect(imageSize.width, 0, imageSize.width, imageSize.height));viewLeft = imread(imageList[cameraIdFirst], 1);viewRight = imread(imageList[cameraIdSec], 1);viewLeft.copyTo(canLeft);viewRight.copyTo(canRight);cout << "done" << endl;imshow("canvas", canvas);waitKey(50);//stereoRectifyMat rmapFirst[2], rmapSec[2], rviewFirst, rviewSec;initUndistortRectifyMap(intrMatFirst, distCoeffsFirst, RFirst, PFirst,imageSize, CV_16SC2, rmapFirst[0], rmapFirst[1]);initUndistortRectifyMap(intrMatSec, distCoffesSec, RSec, PSec,imageSize, CV_16SC2, rmapSec[0], rmapSec[1]);remap(viewLeft, rviewFirst, rmapFirst[0], rmapFirst[1], INTER_LINEAR);remap(viewRight, rviewSec, rmapSec[0], rmapSec[1], INTER_LINEAR);rviewFirst.copyTo(canLeft);rviewSec.copyTo(canRight);rectangle(canLeft, validRoi[0], Scalar(255, 0, 0), 3, 8);rectangle(canRight, validRoi[1], Scalar(255, 0, 0), 3, 8);for (int j = 0; j <= canvas.rows; j += 16)line(canvas, Point(0, j), Point(canvas.cols, j), Scalar(0, 255, 0), 1, 8);cout << "stereo rectify done" << endl;imshow("canvas", canvas);waitKey(50);

    子函數calibrate()和calcChessboardCorners()分別是用來表達相機和計算objectPoints的。函數體如下,

    bool calibrate(Mat& intrMat, Mat& distCoeffs, vector<vector<Point2f>>& imagePoints, vector<vector<Point3f>>& ObjectPoints, Size& imageSize,const int cameraId , vector<string> imageList) { int w = 6;int h = 9; double rms = 0;Size boardSize; boardSize.width = w; boardSize.height = h; vector<Point2f> pointBuf; float squareSize = 1.f; vector<Mat> rvecs, tvecs; bool ok = false;int nImages = (int)imageList.size() / 2; namedWindow("View", 1); for (int i = 0; i<nImages ; i++){ Mat view, viewGray; view = imread(imageList[i*2+cameraId], 1); imageSize = view.size(); cvtColor(view, viewGray, COLOR_BGR2GRAY);bool found = findChessboardCorners(view, boardSize, pointBuf, CV_CALIB_CB_ADAPTIVE_THRESH | CV_CALIB_CB_FAST_CHECK | CV_CALIB_CB_NORMALIZE_IMAGE);if (found) {cornerSubPix(viewGray, pointBuf, Size(11, 11), Size(-1, -1), TermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 30, 0.1)); drawChessboardCorners(view, boardSize, Mat(pointBuf), found);bitwise_not(view, view); imagePoints.push_back(pointBuf); cout << '.'; } imshow("View", view); waitKey(50); } //calculate chessboardCorners calcChessboardCorners(boardSize, squareSize, ObjectPoints[0]); ObjectPoints.resize(imagePoints.size(), ObjectPoints[0]);rms = calibrateCamera(ObjectPoints, imagePoints, imageSize, intrMat, distCoeffs, rvecs, tvecs); ok = checkRange(intrMat) && checkRange(distCoeffs);if (ok){cout << "done with RMS error=" << rms << endl; return true;}elsereturn false;} static void calcChessboardCorners(Size boardSize, float squareSize, vector<Point3f>& corners) {corners.resize(0); for (int i = 0; i < boardSize.height; i++) //height和width位置不能顛倒for (int j = 0; j < boardSize.width; j++){corners.push_back(Point3f(j*squareSize, i*squareSize, 0));} }

    仿真結果

    轉載自:https://www.cnblogs.com/german-iris/p/5199203.html

    總結

    以上是生活随笔為你收集整理的双目摄像头立体成像(二)畸变矫正与立体校正的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。