#include <iostream>
#include <opencv2/opencv_modules.hpp>
#ifdef HAVE_OPENCV_VIZ
#endif
static const char* keys =
{ "{@images_list | | 保存已捕获图案图像的图像列表}"
"{@calib_param_path | | 校准参数}"
"{@proj_width | | 用于获取图案的投影仪宽度}"
"{@proj_height | | 用于获取图案的投影仪高度}"
"{@white_thresh | | 白色阈值高度(可选)}"
"{@black_thresh | | 黑色阈值(可选)}" };
static void help()
{
cout << "\n此示例演示如何使用“结构光模块”解码先前获取的格雷码模式,生成点云"
"\n调用:\n"
"./example_structured_light_pointcloud <images_list> <calib_param_path> <proj_width> <proj_height> <white_thresh> <black_thresh>\n"
<< endl;
}
static bool readStringList( const string& filename, vector<string>& l )
{
l.resize( 0 );
if( !fs.isOpened() )
{
cerr << "无法打开 " << filename << endl;
return false;
}
if( n.
type() != FileNode::SEQ )
{
cerr << "cam 1 图像不是序列!失败" << endl;
return false;
}
for( ; it != it_end; ++it )
{
l.push_back( ( string ) *it );
}
n = fs["cam2"];
if( n.
type() != FileNode::SEQ )
{
cerr << "cam 2 图像不是序列!失败" << endl;
return false;
}
for( ; it != it_end; ++it )
{
l.push_back( ( string ) *it );
}
if( l.size() % 2 != 0 )
{
cout << "错误:图像列表包含奇数(非偶数)个元素\n";
return false;
}
return true;
}
int main(
int argc,
char** argv )
{
params.width = parser.get<
int>( 2 );
params.height = parser.get<
int>( 3 );
如果 (images_file.empty() || calib_file.empty() ||
params.width < 1 ||
params.height < 1 || argc < 5 || argc > 7 )
{
help();
return; -1;
}
size_t white_thresh = 0;
size_t black_thresh = 0;
如果 (argc == 7)
{
white_thresh = parser.get<unsigned>( 4 );
black_thresh = parser.get<unsigned>( 5 );
graycode->setWhiteThreshold( white_thresh );
graycode->setBlackThreshold( black_thresh );
}
vector<string> imagelist;
bool ok = readStringList( images_file, imagelist );
如果 (!ok || imagelist.empty() )
{
cout << "无法打开 " << images_file << " 或字符串列表为空" << endl;
help();
return; -1;
}
if( !fs.isOpened() )
{
cout << "无法打开标定数据文件。" << endl;
help();
return; -1;
}
Mat cam1intrinsics, cam1distCoeffs, cam2intrinsics, cam2distCoeffs, R, T;
fs["cam1_intrinsics"] >> cam1intrinsics;
fs["cam2_intrinsics"] >> cam2intrinsics;
fs["cam1_distorsion"] >> cam1distCoeffs;
fs["cam2_distorsion"] >> cam2distCoeffs;
fs["R"] >> R;
fs["T"] >> T;
cout << "cam1intrinsics" << endl << cam1intrinsics << endl;
cout << "cam1distCoeffs" << endl << cam1distCoeffs << endl;
cout << "cam2intrinsics" << endl << cam2intrinsics << endl;
cout << "cam2distCoeffs" << endl << cam2distCoeffs << endl;
cout << "T" << endl << T << endl << "R" << endl << R << endl;
如果 ((!R.data) || (!T.data) || (!cam1intrinsics.
data) || (!cam2intrinsics.
data) || (!cam1distCoeffs.
data) || (!cam2distCoeffs.
data) )
{
cout << "无法加载相机标定参数" << endl;
help();
return; -1;
}
size_t numberOfPatternImages = graycode->getNumberOfPatternImages();
vector<vector<Mat> > captured_pattern;
captured_pattern.resize( 2 );
captured_pattern[0].resize( numberOfPatternImages );
captured_pattern[1].resize( numberOfPatternImages );
Mat color =
imread( imagelist[numberOfPatternImages], IMREAD_COLOR );
cout << "正在校正图像..." << endl;
stereoRectify( cam1intrinsics, cam1distCoeffs, cam2intrinsics, cam2distCoeffs, imagesSize, R, T, R1, R2, P1, P2, Q, 0,
-1, imagesSize, &validRoi[0], &validRoi[1] );
Mat map1x, map1y, map2x, map2y;
for (size_t i = 0; i < numberOfPatternImages; i++)
{
captured_pattern[0][i] =
imread( imagelist[i], IMREAD_GRAYSCALE );
captured_pattern[1][i] =
imread( imagelist[i + numberOfPatternImages + 2], IMREAD_GRAYSCALE );
如果 ((!captured_pattern[0][i].data) || (!captured_pattern[1][i].data) )
{
cout << "图像为空" << endl;
help();
return; -1;
}
remap( captured_pattern[1][i], captured_pattern[1][i], map1x, map1y, INTER_NEAREST, BORDER_CONSTANT,
Scalar() );
remap( captured_pattern[0][i], captured_pattern[0][i], map2x, map2y, INTER_NEAREST, BORDER_CONSTANT,
Scalar() );
}
cout << "完成" << endl;
vector<Mat> blackImages;
vector<Mat> whiteImages;
blackImages.resize( 2 );
whiteImages.resize( 2 );
cvtColor( color, whiteImages[0], COLOR_RGB2GRAY );
whiteImages[1] =
imread( imagelist[2 * numberOfPatternImages + 2], IMREAD_GRAYSCALE );
blackImages[0] =
imread( imagelist[numberOfPatternImages + 1], IMREAD_GRAYSCALE );
blackImages[1] =
imread( imagelist[2 * numberOfPatternImages + 2 + 1], IMREAD_GRAYSCALE );
remap( color, color, map2x, map2y, INTER_NEAREST, BORDER_CONSTANT,
Scalar() );
remap( whiteImages[0], whiteImages[0], map2x, map2y, INTER_NEAREST, BORDER_CONSTANT,
Scalar() );
remap( whiteImages[1], whiteImages[1], map1x, map1y, INTER_NEAREST, BORDER_CONSTANT,
Scalar() );
remap( blackImages[0], blackImages[0], map2x, map2y, INTER_NEAREST, BORDER_CONSTANT,
Scalar() );
remap( blackImages[1], blackImages[1], map1x, map1y, INTER_NEAREST, BORDER_CONSTANT,
Scalar() );
cout << endl << "正在解码图案..." << endl;
bool decoded = graycode->decode( captured_pattern, disparityMap, blackImages, whiteImages,
structured_light::DECODE_3D_UNDERWORLD );
如果 (decoded)
{
cout << endl << "图案解码完成" << endl;
double min;
double max;
Mat cm_disp, scaledDisparityMap;
cout << "disp min " << min << endl << "disp max " << max << endl;
resize( cm_disp, cm_disp,
Size( 640, 480 ), 0, 0, INTER_LINEAR_EXACT );
imshow(
"cm disparity m", cm_disp );
Mat dst, thresholded_disp;
threshold( scaledDisparityMap, thresholded_disp, 0, 255, THRESH_OTSU + THRESH_BINARY );
resize( thresholded_disp, dst,
Size( 640, 480 ), 0, 0, INTER_LINEAR_EXACT );
imshow(
"threshold disp otsu", dst );
#ifdef HAVE_OPENCV_VIZ
Mat pointcloud_tresh, color_tresh;
pointcloud.
copyTo( pointcloud_tresh, thresholded_disp );
color.
copyTo( color_tresh, thresholded_disp );
myWindow.setBackgroundMeshLab();
myWindow.showWidget(
"pointcloud",
viz::WCloud( pointcloud_tresh, color_tresh ) );
myWindow.showWidget(
"text2d",
viz::WText(
"点云",
Point(20, 20), 20, viz::Color::green() ) );
myWindow.spin();
#endif
}
return; 0;
}
用于命令行解析。
定义 utility.hpp:890
用于迭代序列和映射。
定义 persistence.hpp:595
文件存储节点类。
定义 persistence.hpp:441
FileNodeIterator begin() const
返回指向第一个节点元素的迭代器
FileNodeIterator end() const
返回指向最后一个节点元素之后元素的迭代器
XML/YAML/JSON 文件存储类,封装了写入或读取所需的所有信息...
定义 persistence.hpp:261
MatSize size
定义 mat.hpp:2177
void copyTo(OutputArray m) const
将矩阵复制到另一个矩阵。
uchar * data
指向数据的指针
定义 mat.hpp:2157
void convertTo(OutputArray m, int rtype, double alpha=1, double beta=0) const
将数组转换为另一种数据类型,并可以选择缩放。
二维矩形的模板类。
定义 types.hpp:444
用于指定图像或矩形大小的模板类。
定义 types.hpp:335
Viz3d 类表示一个 3D 可视化窗口。此类是隐式共享的。
定义 viz3d.hpp:68
文本和图像部件。
定义 widgets.hpp:408
void reprojectImageTo3D(InputArray disparity, OutputArray _3dImage, InputArray Q, bool handleMissingValues=false, int ddepth=-1)
将视差图像重投影到 3D 空间。
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)
计算已校准立体摄像机的每个头的校正变换。
void initUndistortRectifyMap(InputArray cameraMatrix, InputArray distCoeffs, InputArray R, InputArray newCameraMatrix, Size size, int m1type, OutputArray map1, OutputArray map2)
计算去畸变和校正变换映射。
void convertScaleAbs(InputArray src, OutputArray dst, double alpha=1, double beta=0)
缩放、计算绝对值并将结果转换为 8 位。
void minMaxIdx(InputArray src, double *minVal, double *maxVal=0, int *minIdx=0, int *maxIdx=0, InputArray mask=noArray())
查找数组中的全局最小值和最大值。
std::string String
定义 cvstd.hpp:151
std::shared_ptr< _Tp > Ptr
定义 cvstd_wrapper.hpp:23
#define CV_32FC1
定义 interface.h:118
void imshow(const String &winname, InputArray mat)
在指定的窗口中显示图像。
int waitKey(int delay=0)
等待按下按键。
CV_EXPORTS_W Mat imread(const String &filename, int flags=IMREAD_COLOR_BGR)
从文件加载图像。
void cvtColor(InputArray src, OutputArray dst, int code, int dstCn=0, AlgorithmHint hint=cv::ALGO_HINT_DEFAULT)
将图像从一个颜色空间转换为另一个颜色空间。
void applyColorMap(InputArray src, OutputArray dst, int colormap)
在给定图像上应用 GNU Octave/MATLAB 等效颜色映射。
double threshold(InputArray src, OutputArray dst, double thresh, double maxval, int type)
将固定级别阈值应用于每个数组元素。
int main(int argc, char *argv[])
定义 highgui_qt.cpp:3
PyParams params(const std::string &tag, const std::string &model, const std::string &weights, const std::string &device)
结构光模式构造函数的参数。
定义 graycodepattern.hpp:77
例如,本教程中使用的数据集是使用分辨率为 1280x800 的投影仪获取的,因此使用两个摄像头捕获了 42 幅图案图像(从 1 到 42)+ 1 幅白色图像(43 号)和 1 幅黑色图像(44 号)。
cout << "正在校正图像..." << endl;
stereoRectify( cam1intrinsics, cam1distCoeffs, cam2intrinsics, cam2distCoeffs, imagesSize, R, T, R1, R2, P1, P2, Q, 0,
-1, imagesSize, &validRoi[0], &validRoi[1] );
Mat map1x, map1y, map2x, map2y;
initUndistortRectifyMap( cam1intrinsics, cam1distCoeffs, R1, P1, imagesSize,
CV_32FC1, map1x, map1y );
initUndistortRectifyMap( cam2intrinsics, cam2distCoeffs, R2, P2, imagesSize,
CV_32FC1, map2x, map2y );
........
for (size_t i = 0; i < numberOfPatternImages; i++)
{
........
remap( captured_pattern[1][i], captured_pattern[1][i], map1x, map1y, INTER_NEAREST, BORDER_CONSTANT,
Scalar() );
remap( captured_pattern[0][i], captured_pattern[0][i], map2x, map2y, INTER_NEAREST, BORDER_CONSTANT,
Scalar() );
}
........
remap( color, color, map2x, map2y, INTER_NEAREST, BORDER_CONSTANT,
Scalar() );
remap( whiteImages[0], whiteImages[0], map2x, map2y, INTER_NEAREST, BORDER_CONSTANT,
Scalar() );
remap( whiteImages[1], whiteImages[1], map1x, map1y, INTER_NEAREST, BORDER_CONSTANT,
Scalar() );
remap( blackImages[0], blackImages[0], map2x, map2y, INTER_NEAREST, BORDER_CONSTANT,
Scalar() );
remap( blackImages[1], blackImages[1], map1x, map1y, INTER_NEAREST, BORDER_CONSTANT,
Scalar() );