一、首先說(shuō)明幾個(gè)情況:
1、完成雙目標(biāo)定必須是自個(gè)拿棋盤(pán)圖擺拍,網(wǎng)上涉及用opencv自帶的標(biāo)定圖完成雙目標(biāo)定僅僅是提供個(gè)參考流程。我原來(lái)還以為用自帶的圖標(biāo)定就行,但想不通的是咱們實(shí)際擺放的雙目攝像頭和人家當(dāng)時(shí)擺放的肯定不一樣,那用人家的標(biāo)定圖怎么能反應(yīng)自己攝像頭的實(shí)際情況;后來(lái)問(wèn)了大神,才知道用opencv自帶的標(biāo)定圖(或者說(shuō)別人提供的圖)進(jìn)行標(biāo)定,這是完全沒(méi)有意義的。
2、進(jìn)行雙目標(biāo)定必須是左右相機(jī)同時(shí)進(jìn)行拍攝,再把圖保存下來(lái)。這點(diǎn)我是看opencv自帶的圖發(fā)現(xiàn)的,左右相機(jī)對(duì)應(yīng)的圖擺拍的姿勢(shì)是一模一樣的,除了左右相機(jī)視角帶來(lái)的影響。
3、我是先完成單目標(biāo)定,再完成雙目標(biāo)定。記得把理論看看,要不然有些概念不清楚。
二、
1、先固定好左右相機(jī),拿棋盤(pán)標(biāo)定圖擺拍并保存,我左右相機(jī)各15張,網(wǎng)上看的說(shuō)是總共30~40張為宜,這個(gè)大家隨意。
棋盤(pán)標(biāo)定圖在我另發(fā)的一個(gè)博客里免費(fèi)下載,當(dāng)時(shí)找了好久,下載的、程序生成的都或多或少有那么一些問(wèn)題。知識(shí)是得有價(jià),但棋盤(pán)圖這種最最基本的工具,博客里基本都需要拿幣下載,真是服。
程序:
// 同時(shí)調(diào)用兩個(gè)攝像頭,暫停并保存左右相機(jī)的標(biāo)定棋盤(pán)圖
#include
#include
#include
using namespace cv;
using namespace std; //開(kāi)頭我是從教程學(xué)的,一般不變,直接用
int main(int argc, char* argv[])
{
VideoCapture cap(0);
VideoCapture cap1(1); //打開(kāi)兩個(gè)攝像頭
if(!cap.isOpened())
{
printf("Could not open camera0... ");
return -1;
}
if (!cap1.isOpened())
{
printf("Could not open camera1... ");
return -2;
} //判斷還是加上為好,便于調(diào)程序
Mat frame, frame1;
bool stop = false;
while (!stop)
{
cap.read(frame);
cap1.read(frame1);
imshow("camera0", frame);
imshow("camera1", frame1);
int delay = 30;
if (delay >= 0 && waitKey(delay) >= 0)
{
waitKey(0); //實(shí)時(shí)拍攝暫停的程序
}
imwrite("C:/Users/Administrator/Desktop/11/left1.jpg", frame1);
imwrite("C:/Users/Administrator/Desktop/11/right1.jpg", frame); //給個(gè)位置保存圖片,注意圖片到底是左相機(jī)還是右相機(jī)的(用手在攝像頭前晃晃),我用的笨方法,保存一下,再把(left1.jpg/right1.jpg)+1,接著保存
}
cap.release();
cap1.release(); //兩個(gè)攝像頭數(shù)據(jù)釋放
return 0;
}
2、完成單目標(biāo)定,程序我是借鑒網(wǎng)上的,修改的不多。
//左右單目相機(jī)分別標(biāo)定
#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/calib3d/calib3d.hpp"
#include "opencv2/highgui/highgui.hpp"
#include
#include "cv.h"
#include
#include
using namespace std;
using namespace cv; //人家這開(kāi)頭都長(zhǎng),遇到有紅線標(biāo)記的就刪了,把你知道的開(kāi)頭加上,沒(méi)問(wèn)題
const int boardWidth = 9; //橫向的角點(diǎn)數(shù)目
const int boardHeight = 6; //縱向的角點(diǎn)數(shù)據(jù)
const int boardCorner = boardWidth * boardHeight; //總的角點(diǎn)數(shù)據(jù)
const int frameNumber = 15; //相機(jī)標(biāo)定時(shí)需要采用的圖像幀數(shù)
const int squareSize = 25; //標(biāo)定板黑白格子的大小 單位mm
const Size boardSize = Size(boardWidth, boardHeight); //總的內(nèi)角點(diǎn)
Mat intrinsic; //相機(jī)內(nèi)參數(shù)
Mat distortion_coeff; //相機(jī)畸變參數(shù)
vectorrvecs; //旋轉(zhuǎn)向量
vectortvecs; //平移向量
vector
vector
vectorcorner; //某一副圖像找到的角點(diǎn)
/*計(jì)算標(biāo)定板上模塊的實(shí)際物理坐標(biāo)*/
void calRealPoint(vector
{
vectorimgpoint;
for (int rowIndex = 0; rowIndex < boardheight; rowIndex++)
{
for (int colIndex = 0; colIndex < boardwidth; colIndex++)
{
imgpoint.push_back(Point3f(rowIndex * squaresize, colIndex * squaresize, 0));
}
}
for (int imgIndex = 0; imgIndex < imgNumber; imgIndex++)
{
obj.push_back(imgpoint);
}
}
/*設(shè)置相機(jī)的初始參數(shù) 也可以不估計(jì)*/
void guessCameraParam(void)
{
/*分配內(nèi)存*/
intrinsic.create(3, 3, CV_64FC1); //相機(jī)內(nèi)參數(shù)
distortion_coeff.create(5, 1, CV_64FC1); //畸變參數(shù)
/*
fx 0 cx
0 fy cy
0 0 1 內(nèi)參數(shù)
*/
intrinsic.at(0, 0) = 256.8093262; //fx
intrinsic.at(0, 2) = 160.2826538; //cx
intrinsic.at(1, 1) = 254.7511139; //fy
intrinsic.at(1, 2) = 127.6264572; //cy
intrinsic.at(0, 1) = 0;
intrinsic.at(1, 0) = 0;
intrinsic.at(2, 0) = 0;
intrinsic.at(2, 1) = 0;
intrinsic.at(2, 2) = 1;
/*
k1 k2 p1 p2 p3 畸變參數(shù)
*/
distortion_coeff.at(0, 0) = -0.193740; //k1
distortion_coeff.at(1, 0) = -0.378588; //k2
distortion_coeff.at(2, 0) = 0.028980; //p1
distortion_coeff.at(3, 0) = 0.008136; //p2
distortion_coeff.at(4, 0) = 0; //p3
}
void outputCameraParam(void)
{
/*保存數(shù)據(jù)*/
//cvSave("cameraMatrix.xml", &intrinsic);
//cvSave("cameraDistoration.xml", &distortion_coeff);
//cvSave("rotatoVector.xml", &rvecs);
//cvSave("translationVector.xml", &tvecs);
/*輸出數(shù)據(jù)*/
//cout << "fx :" << intrinsic.at(0, 0) << endl << "fy :" << intrinsic.at(1, 1) << endl;
//cout << "cx :" << intrinsic.at(0, 2) << endl << "cy :" << intrinsic.at(1, 2) << endl;//內(nèi)參數(shù)
printf("fx:%lf... ", intrinsic.at(0, 0));
printf("fy:%lf... ", intrinsic.at(1, 1));
printf("cx:%lf... ", intrinsic.at(0, 2));
printf("cy:%lf... ", intrinsic.at(1, 2)); //我學(xué)的是printf,就試著改了一下,都能用
//cout << "k1 :" << distortion_coeff.at(0, 0) << endl;
//cout << "k2 :" << distortion_coeff.at(1, 0) << endl;
//cout << "p1 :" << distortion_coeff.at(2, 0) << endl;
//cout << "p2 :" << distortion_coeff.at(3, 0) << endl;
//cout << "p3 :" << distortion_coeff.at(4, 0) << endl; ? //畸變參數(shù)
printf("k1:%lf... ", distortion_coeff.at(0, 0));
printf("k2:%lf... ", distortion_coeff.at(1, 0));
printf("p1:%lf... ", distortion_coeff.at(2, 0));
printf("p2:%lf... ", distortion_coeff.at(3, 0));
printf("p3:%lf... ", distortion_coeff.at(4, 0));
}
int main()
{
int imageHeight; //圖像高度
int imageWidth; //圖像寬度
int goodFrameCount = 0; //有效圖像的數(shù)目
Mat rgbImage,grayImage;
Mat tImage = imread("C:/Users/Administrator/Desktop/11/right1.jpg");
if (tImage.empty())
{
printf("Could not load tImage... ");
return -1;
}
imageHeight = tImage.rows;
imageWidth = tImage.cols;
grayImage = Mat::ones(tImage.size(), CV_8UC1);
while (goodFrameCount < frameNumber)
{
char filename[100];
sprintf_s(filename, "C:/Users/Administrator/Desktop/11/right%d.jpg", goodFrameCount + 1);
rgbImage = imread(filename);
if (rgbImage.empty())
{
printf("Could not load grayImage... ");
return -2;
}
cvtColor(rgbImage, grayImage, CV_BGR2GRAY);
imshow("Camera", grayImage);
bool isFind = findChessboardCorners(rgbImage, boardSize, corner, CALIB_CB_ADAPTIVE_THRESH + CALIB_CB_NORMALIZE_IMAGE);
//bool isFind = findChessboardCorners( rgbImage, boardSize, corner,
//CV_CALIB_CB_ADAPTIVE_THRESH | CV_CALIB_CB_FAST_CHECK | CV_CALIB_CB_NORMALIZE_IMAGE);
if (isFind == true) //所有角點(diǎn)都被找到 說(shuō)明這幅圖像是可行的
{
//精確角點(diǎn)位置,亞像素角點(diǎn)檢測(cè)
cornerSubPix(grayImage, corner, Size(5, 5), Size(-1, -1), TermCriteria(CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 20, 0.1));
//繪制角點(diǎn)
drawChessboardCorners(rgbImage, boardSize, corner, isFind);
imshow("chessboard", rgbImage);
corners.push_back(corner);
goodFrameCount++;
/*cout << "The image" << goodFrameCount << " is good" << endl;*/
printf("The image %d is good... ", goodFrameCount);
}
else
{
printf("The image is bad please try again... ");
}
if (waitKey(10) == 'q')
{
break;
}
}
/*
圖像采集完畢 接下來(lái)開(kāi)始攝像頭的校正
calibrateCamera()
輸入?yún)?shù) objectPoints 角點(diǎn)的實(shí)際物理坐標(biāo)
imagePoints 角點(diǎn)的圖像坐標(biāo)
imageSize 圖像的大小
輸出參數(shù)
cameraMatrix 相機(jī)的內(nèi)參矩陣
distCoeffs 相機(jī)的畸變參數(shù)
rvecs 旋轉(zhuǎn)矢量(外參數(shù))
tvecs 平移矢量(外參數(shù))
*/
/*設(shè)置實(shí)際初始參數(shù) 根據(jù)calibrateCamera來(lái) 如果flag = 0 也可以不進(jìn)行設(shè)置*/
guessCameraParam();
printf("guess successful... ");
/*計(jì)算實(shí)際的校正點(diǎn)的三維坐標(biāo)*/
calRealPoint(objRealPoint, boardWidth, boardHeight, frameNumber, squareSize);
printf("calculate real successful... ");
/*標(biāo)定攝像頭*/
calibrateCamera(objRealPoint, corners, Size(imageWidth, imageHeight), intrinsic, distortion_coeff, rvecs, tvecs, 0);
printf("calibration successful... ");
/*保存并輸出參數(shù)*/
outputCameraParam();
printf("output successful... ");
/*顯示畸變校正效果*/
Mat cImage;
undistort(rgbImage, cImage, intrinsic, distortion_coeff); //矯正相機(jī)鏡頭變形
imshow("Corret Image", cImage);
printf("Corret Image.... ");
printf("Wait for Key.... ");
waitKey(0);
return 0;
}
注意:(1)把你得到的左右相機(jī)標(biāo)定完的參數(shù)記下來(lái),雙目標(biāo)定的時(shí)候會(huì)用;
(2)如果遇到cvtColor出問(wèn)題,那就查一下構(gòu)造一個(gè)新圖像的Mat類使用方法;
(3)如果遇到結(jié)果一閃而過(guò)的問(wèn)題,可以先用網(wǎng)上提供的兩種方法試一下(一搜就有),但是我用這兩種方法都沒(méi)解決,最后才知道是frameNumber 的問(wèn)題,我設(shè)的值比現(xiàn)有的圖多一張。到時(shí)候具體問(wèn)題具體分析吧,都是應(yīng)該經(jīng)歷的過(guò)程。
3、完成雙目標(biāo)定,程序也是借鑒網(wǎng)上的,稍加修改。
// 雙目相機(jī)標(biāo)定
#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/calib3d/calib3d.hpp"
#include "opencv2/highgui/highgui.hpp"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "cv.h"
#include
using namespace std;
using namespace cv; //依舊很長(zhǎng)的開(kāi)頭
const int imageWidth = 640; //攝像頭的分辨率
const int imageHeight = 480;
const int boardWidth = 9; //橫向的角點(diǎn)數(shù)目
const int boardHeight = 6; //縱向的角點(diǎn)數(shù)據(jù)
const int boardCorner = boardWidth * boardHeight; //總的角點(diǎn)數(shù)據(jù)
const int frameNumber = 15; //相機(jī)標(biāo)定時(shí)需要采用的圖像幀數(shù)
const int squareSize = 25; //標(biāo)定板黑白格子的大小 單位mm
const Size boardSize = Size(boardWidth, boardHeight); //標(biāo)定板的總內(nèi)角點(diǎn)
Size imageSize = Size(imageWidth, imageHeight);
Mat R, T, E, F; //R 旋轉(zhuǎn)矢量 T平移矢量 E本征矩陣 F基礎(chǔ)矩陣
vectorrvecs; //旋轉(zhuǎn)向量
vectortvecs; //平移向量
vector
vector
vector
vectorcornerL; //左邊攝像機(jī)某一照片角點(diǎn)坐標(biāo)集合
vectorcornerR; //右邊攝像機(jī)某一照片角點(diǎn)坐標(biāo)集合
Mat rgbImageL, grayImageL;
Mat rgbImageR, grayImageR;
Mat Rl, Rr, Pl, Pr, Q; //校正旋轉(zhuǎn)矩陣R,投影矩陣P 重投影矩陣Q (下面有具體的含義解釋)
Mat mapLx, mapLy, mapRx, mapRy; //映射表
Rect validROIL, validROIR; //圖像校正之后,會(huì)對(duì)圖像進(jìn)行裁剪,這里的validROI就是指裁剪之后的區(qū)域
/*
事先標(biāo)定好的左相機(jī)的內(nèi)參矩陣
fx 0 cx
0 fy cy
0 0 1
*/
Mat cameraMatrixL = (Mat_(3, 3) << 462.279595, 0, 312.781587,
0, 460.220741, 208.225803,
0, 0, 1); //這時(shí)候就需要你把左右相機(jī)單目標(biāo)定的參數(shù)給寫(xiě)上
//獲得的畸變參數(shù)
Mat distCoeffL = (Mat_(5, 1) << -0.054929, 0.224509, 0.000386, 0.001799, -0.302288);
/*
事先標(biāo)定好的右相機(jī)的內(nèi)參矩陣
fx 0 cx
0 fy cy
0 0 1
*/
Mat cameraMatrixR = (Mat_(3, 3) << 463.923124, 0, 322.783959,
0, 462.203276, 256.100655,
0, 0, 1);
Mat distCoeffR = (Mat_(5, 1) << -0.049056, 0.229945, 0.001745, -0.001862, -0.321533);
/*計(jì)算標(biāo)定板上模塊的實(shí)際物理坐標(biāo)*/
void calRealPoint(vector
{
vectorimgpoint;
for (int rowIndex = 0; rowIndex < boardheight; rowIndex++)
{
for (int colIndex = 0; colIndex < boardwidth; colIndex++)
{
imgpoint.push_back(Point3f(rowIndex * squaresize, colIndex * squaresize, 0));
}
}
for (int imgIndex = 0; imgIndex < imgNumber; imgIndex++)
{
obj.push_back(imgpoint);
}
}
void outputCameraParam(void)
{
/*保存數(shù)據(jù)*/
/*輸出數(shù)據(jù)*/
FileStorage fs("intrinsics.yml", FileStorage::WRITE); //文件存儲(chǔ)器的初始化
if (fs.isOpened())
{
fs << "cameraMatrixL" << cameraMatrixL << "cameraDistcoeffL" << distCoeffL << "cameraMatrixR" << cameraMatrixR << "cameraDistcoeffR" << distCoeffR;
fs.release();
cout << "cameraMatrixL=:" << cameraMatrixL << endl << "cameraDistcoeffL=:" << distCoeffL << endl << "cameraMatrixR=:" << cameraMatrixR << endl << "cameraDistcoeffR=:" << distCoeffR << endl;
}
else
{
cout << "Error: can not save the intrinsics!!!!!" << endl;
}
fs.open("extrinsics.yml", FileStorage::WRITE);
if (fs.isOpened())
{
fs << "R" << R << "T" << T << "Rl" << Rl << "Rr" << Rr << "Pl" << Pl << "Pr" << Pr << "Q" << Q;
cout << "R=" << R << endl << "T=" << T << endl << "Rl=" << Rl << endl << "Rr=" << Rr << endl << "Pl=" << Pl << endl << "Pr=" << Pr << endl << "Q=" << Q << endl;
fs.release();
}
else
cout << "Error: can not save the extrinsic parameters ";
}
int main(int argc, char* argv[])
{
Mat img;
int goodFrameCount = 0;
while (goodFrameCount < frameNumber)
{
char filename[100];
/*讀取左邊的圖像*/
sprintf_s(filename, "C:/Users/Administrator/Desktop/11/left%d.jpg", goodFrameCount + 1);
rgbImageL = imread(filename, CV_LOAD_IMAGE_COLOR);
cvtColor(rgbImageL, grayImageL, CV_BGR2GRAY);
/*讀取右邊的圖像*/
sprintf_s(filename, "C:/Users/Administrator/Desktop/11/right%d.jpg", goodFrameCount + 1);
rgbImageR = imread(filename, CV_LOAD_IMAGE_COLOR);
cvtColor(rgbImageR, grayImageR, CV_BGR2GRAY);
bool isFindL, isFindR;
isFindL = findChessboardCorners(rgbImageL, boardSize, cornerL);
isFindR = findChessboardCorners(rgbImageR, boardSize, cornerR);
if (isFindL == true && isFindR == true) //如果兩幅圖像都找到了所有的角點(diǎn) 則說(shuō)明這兩幅圖像是可行的
{
/*
Size(5,5) 搜索窗口的一半大小
Size(-1,-1) 死區(qū)的一半尺寸
TermCriteria(CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 20, 0.1)迭代終止條件
*/
cornerSubPix(grayImageL, cornerL, Size(5, 5), Size(-1, -1), TermCriteria(CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 20, 0.1));
drawChessboardCorners(rgbImageL, boardSize, cornerL, isFindL);
imshow("chessboardL", rgbImageL);
imagePointL.push_back(cornerL);
cornerSubPix(grayImageR, cornerR, Size(5, 5), Size(-1, -1), TermCriteria(CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 20, 0.1));
drawChessboardCorners(rgbImageR, boardSize, cornerR, isFindR);
imshow("chessboardR", rgbImageR);
imagePointR.push_back(cornerR);
//string filename = "res\image\calibration";
//filename += goodFrameCount + ".jpg";
//cvSaveImage(filename.c_str(), &IplImage(rgbImage)); //把合格的圖片保存起來(lái)
goodFrameCount++;
cout << "The image" << goodFrameCount << " is good" << endl;
}
else
{
cout << "The image is bad please try again" << endl;
}
if (waitKey(10) == 'q')
{
break;
}
}
/*
計(jì)算實(shí)際的校正點(diǎn)的三維坐標(biāo)
根據(jù)實(shí)際標(biāo)定格子的大小來(lái)設(shè)置
*/
calRealPoint(objRealPoint, boardWidth, boardHeight, frameNumber, squareSize);
cout << "cal real successful" << endl;
/*
標(biāo)定攝像頭
由于左右攝像機(jī)分別都經(jīng)過(guò)了單目標(biāo)定
所以在此處選擇flag = CALIB_USE_INTRINSIC_GUESS
*/
double rms = stereoCalibrate(objRealPoint, imagePointL, imagePointR,
cameraMatrixL, distCoeffL,
cameraMatrixR, distCoeffR,
Size(imageWidth, imageHeight),R, T,E, F, CALIB_USE_INTRINSIC_GUESS,
TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 100, 1e-5)); //需要注意,應(yīng)該是版本的原因,該函數(shù)最后兩個(gè)參數(shù),我是調(diào)換過(guò)來(lái)后才顯示不出錯(cuò)的
cout << "Stereo Calibration done with RMS error = " << rms << endl;
/*
立體校正的時(shí)候需要兩幅圖像共面并且行對(duì)準(zhǔn) 以使得立體匹配更加的可靠
使得兩幅圖像共面的方法就是把兩個(gè)攝像頭的圖像投影到一個(gè)公共成像面上,這樣每幅圖像從本圖像平面投影到公共圖像平面都需要一個(gè)旋轉(zhuǎn)矩陣R
stereoRectify 這個(gè)函數(shù)計(jì)算的就是從圖像平面投影到公共成像平面的旋轉(zhuǎn)矩陣Rl,Rr。Rl,Rr即為左右相機(jī)平面行對(duì)準(zhǔn)的校正旋轉(zhuǎn)矩陣。
左相機(jī)經(jīng)過(guò)Rl旋轉(zhuǎn),右相機(jī)經(jīng)過(guò)Rr旋轉(zhuǎn)之后,兩幅圖像就已經(jīng)共面并且行對(duì)準(zhǔn)了。
其中Pl,Pr為兩個(gè)相機(jī)的投影矩陣,其作用是將3D點(diǎn)的坐標(biāo)轉(zhuǎn)換到圖像的2D點(diǎn)的坐標(biāo):P*[X Y Z 1]' =[x y w]
Q矩陣為重投影矩陣,即矩陣Q可以把2維平面(圖像平面)上的點(diǎn)投影到3維空間的點(diǎn):Q*[x y d 1] = [X Y Z W]。其中d為左右兩幅圖像的時(shí)差
*/
//對(duì)標(biāo)定過(guò)的圖像進(jìn)行校正
stereoRectify(cameraMatrixL, distCoeffL, cameraMatrixR, distCoeffR, imageSize, R, T, Rl, Rr, Pl, Pr, Q,
CALIB_ZERO_DISPARITY, -1, imageSize, &validROIL, &validROIR);
/*
根據(jù)stereoRectify 計(jì)算出來(lái)的R 和 P 來(lái)計(jì)算圖像的映射表 mapx,mapy
mapx,mapy這兩個(gè)映射表接下來(lái)可以給remap()函數(shù)調(diào)用,來(lái)校正圖像,使得兩幅圖像共面并且行對(duì)準(zhǔn)
ininUndistortRectifyMap()的參數(shù)newCameraMatrix就是校正后的攝像機(jī)矩陣。在openCV里面,校正后的計(jì)算機(jī)矩陣Mrect是跟投影矩陣P一起返回的。
所以我們?cè)谶@里傳入投影矩陣P,此函數(shù)可以從投影矩陣P中讀出校正后的攝像機(jī)矩陣
*/
//攝像機(jī)校正映射
initUndistortRectifyMap(cameraMatrixL, distCoeffL, Rl, Pr, imageSize, CV_32FC1, mapLx, mapLy);
initUndistortRectifyMap(cameraMatrixR, distCoeffR, Rr, Pr, imageSize, CV_32FC1, mapRx, mapRy);
Mat rectifyImageL, rectifyImageR;
cvtColor(grayImageL, rectifyImageL, CV_GRAY2BGR);
cvtColor(grayImageR, rectifyImageR, CV_GRAY2BGR);
imshow("Rectify Before", rectifyImageL);
cout << "按Q1退出 ..." << endl;
/*
經(jīng)過(guò)remap之后,左右相機(jī)的圖像已經(jīng)共面并且行對(duì)準(zhǔn)了
*/
Mat rectifyImageL2, rectifyImageR2;
remap(rectifyImageL, rectifyImageL2, mapLx, mapLy, INTER_LINEAR);
remap(rectifyImageR, rectifyImageR2, mapRx, mapRy, INTER_LINEAR);
cout << "按Q2退出 ..." << endl;
imshow("rectifyImageL", rectifyImageL2);
imshow("rectifyImageR", rectifyImageR2);
/*保存并輸出數(shù)據(jù)*/
outputCameraParam();
/*
把校正結(jié)果顯示出來(lái)
把左右兩幅圖像顯示到同一個(gè)畫(huà)面上
這里只顯示了最后一副圖像的校正結(jié)果。并沒(méi)有把所有的圖像都顯示出來(lái)
*/
Mat canvas;
double sf;
int w, h;
sf = 600. / MAX(imageSize.width, imageSize.height);
w = cvRound(imageSize.width * sf);
h = cvRound(imageSize.height * sf);
canvas.create(h, w * 2, CV_8UC3);
/*左圖像畫(huà)到畫(huà)布上*/
Mat canvasPart = canvas(Rect(w * 0, 0, w, h)); //得到畫(huà)布的一部分
resize(rectifyImageL2, canvasPart, canvasPart.size(), 0, 0, INTER_AREA); //把圖像縮放到跟canvasPart一樣大小
Rect vroiL(cvRound(validROIL.x*sf), cvRound(validROIL.y*sf), //獲得被截取的區(qū)域
cvRound(validROIL.width*sf), cvRound(validROIL.height*sf));
rectangle(canvasPart, vroiL, Scalar(0, 0, 255), 3, 8); //畫(huà)上一個(gè)矩形
cout << "Painted ImageL" << endl;
/*右圖像畫(huà)到畫(huà)布上*/
canvasPart = canvas(Rect(w, 0, w, h)); //獲得畫(huà)布的另一部分
resize(rectifyImageR2, canvasPart, canvasPart.size(), 0, 0, INTER_LINEAR);
Rect vroiR(cvRound(validROIR.x * sf), cvRound(validROIR.y*sf),
cvRound(validROIR.width * sf), cvRound(validROIR.height * sf));
rectangle(canvasPart, vroiR, Scalar(0, 255, 0), 3, 8);
cout << "Painted ImageR" << endl;
/*畫(huà)上對(duì)應(yīng)的線條*/
for (int i = 0; i < canvas.rows; i += 16)
line(canvas, Point(0, i), Point(canvas.cols, i), Scalar(0, 255, 0), 1, 8);
imshow("rectified", canvas);
cout << "wait key" << endl;
waitKey(0);
//system("pause");
return 0;
}
附上最后效果圖:

審核編輯 :李倩
-
攝像頭
+關(guān)注
關(guān)注
61文章
5097瀏覽量
103203 -
OpenCV
+關(guān)注
關(guān)注
33文章
652瀏覽量
44865
原文標(biāo)題:opencv 雙目標(biāo)定操作完整版
文章出處:【微信號(hào):機(jī)器視覺(jué)沙龍,微信公眾號(hào):機(jī)器視覺(jué)沙龍】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
IMU+多相機(jī)高速聯(lián)合自動(dòng)標(biāo)定方案
RTT完整版,DAP無(wú)法燒錄怎么解決?
【開(kāi)發(fā)實(shí)例】基于GM-3568JHF開(kāi)發(fā)板安裝OpenCV并使用視頻目標(biāo)跟蹤 ( CamShift)
【GM-3568JHF開(kāi)發(fā)板免費(fèi)體驗(yàn)】OpenCV 視頻目標(biāo)跟蹤 ( CamShift)
光伏逆變器簡(jiǎn)介(57頁(yè)P(yáng)PT完整版)
華為硬件工程師手冊(cè)(完整版)
尋求AFE4960P芯片的完整資料
完整版—單片機(jī)編程思想(推薦下載!)
華為2024年?duì)I收8621億凈利潤(rùn)626億 華為2024年年報(bào)完整版免費(fèi)下載
opencv雙目標(biāo)定操作完整版
評(píng)論