【发布时间】:2019-09-27 12:15:54
【问题描述】:
目前我正在使用来自 titathink (TT522PW) 的 IP 摄像头,它以 30 FPS 的速度提供 1280 * 720 的流使用普通传感器(不是具有高灵敏度低光的型号)
在捕获视频流时,我们在帧上看到鱼眼类型的失真。
未修正的图像
我首先单独校准每个相机以消除失真(在校准中,我得到左相机的 rms 误差 rms_left = 0.166 和右相机的 RMS rms_right = 0.162强>)。然后使用单个校准相机过程产生的 xml 文件,我校准了立体相机,在立体校准中,我得到 RMS 误差 = 0.207
通过显示校准后的图像,我们看到立体校准做得很好
校准后的图像
用水平线校正图像
- 我接手了dji的视差图计算功能和点云计算功能
视差图计算及过滤代码
bool Disparity_filter::initDispParam(){
#ifdef USE_CUDA
block_matcher_ = cv::cuda::createStereoBM(num_disp_, block_size_);
#else
block_matcher_ = cv::StereoBM::create(num_disp_, block_size_);
#endif
#ifdef USE_OPEN_CV_CONTRIB
wls_filter_ = cv::ximgproc::createDisparityWLSFilter(block_matcher_); // left_matcher
wls_filter_->setLambda(8000.0);
wls_filter_->setSigmaColor(1.5);
right_matcher_ = cv::ximgproc::createRightMatcher(block_matcher_);
#endif
return true;
}
void Disparity_filter::computeDisparityMap(std::shared_ptr<Frame> framel, std::shared_ptr<Frame> framer){
framel->raw_disparity_map_=cv::Mat(HEIGHT, WIDTH, CV_16SC1);
#ifdef USE_CUDA
cv::cuda::GpuMat cuda_disp_left;
framel->cuda_crop_left.upload(framel->cpu_crop_left);
framer->cuda_crop_right.upload(framer->cpu_crop_right);
// GPU implementation of stereoBM outputs uint8_t, i.e. CV_8U
block_matcher_->compute(framel->cuda_crop_left.clone(),
framer->cuda_crop_right.clone(),
cuda_disp_left);
cuda_disp_left.download(framel->raw_disparity_map_);
framel->raw_disparity_map_.convertTo(framel->disparity_map_8u_, CV_8UC1, 1);
// convert it from CV_8U to CV_16U for unified
// calculation in filterDisparityMap() & unprojectPtCloud()
framel->raw_disparity_map_.convertTo(framel->raw_disparity_map_, CV_16S, 16);
#else
// CPU implementation of stereoBM outputs short int, i.e. CV_16S
cv::Mat left_for_matcher ,right_for_matcher;
left_for_matcher = framel->cpu_crop_left.clone();
right_for_matcher = framer->cpu_crop_right.clone();
cv::cvtColor(left_for_matcher, left_for_matcher, cv::COLOR_BGR2GRAY);
cv::cvtColor(right_for_matcher, right_for_matcher, cv::COLOR_BGR2GRAY);
block_matcher_->compute(left_for_matcher, right_for_matcher, framel->raw_disparity_map_);
framel->raw_disparity_map_.convertTo(framel->disparity_map_8u_, CV_8UC1, 0.0625);
#endif
}
void Disparity_filter::filterDisparityMap(std::shared_ptr<Frame> framel, std::shared_ptr<Frame> framer){
right_matcher_->compute(framer->cpu_crop_right.clone(),
framel->cpu_crop_left.clone(),
raw_right_disparity_map_);
// Only takes CV_16S type cv::Mat
wls_filter_->filter(framel->raw_disparity_map_,
framel->cpu_crop_left,
filtered_disparity_map_,
raw_right_disparity_map_);
filtered_disparity_map_.convertTo(framel->filtered_disparity_map_8u_, CV_8UC1, 0.0625);
}
计算点云代码
bool PointCloud::initPointCloud(){
std::string stereo_c2="../calibration/sterolast.xml"; //calib_stereo.xml"; //
cv::FileStorage ts(stereo_c2,cv::FileStorage::READ);
if (!ts.isOpened()) {
std::cerr << "Failed to open calibration parameter file." << std::endl;
return false;
}
cv::Mat P1,P2;
ts["P1"] >> param_proj_left_;
ts["P2"] >> param_proj_right_;
principal_x_ = param_proj_left_.at<double>(0, 2);
principal_y_ = param_proj_left_.at<double>(1, 2);
fx_ = param_proj_left_.at<double>(0, 0);
fy_ = param_proj_left_.at<double>(1, 1);
baseline_x_fx_ = -param_proj_right_.at<double>(0, 3);
std::cout<<"** principal_x= " << principal_x_ <<" ** principal_y= " << principal_y_ <<" ** fx= " << fx_ <<" ** fy= " << fy_<<" ** baseline_x_fx= " << baseline_x_fx_<<std::endl<< std::flush;
return true;
}
void PointCloud::unprojectPtCloud(std::shared_ptr<Frame> framel)
{
// due to rectification, the image boarder are blank
// we cut them out
int border_size = num_disp_;
const int trunc_img_width_end = HEIGHT - border_size;
const int trunc_img_height_end = WIDTH - border_size;
mat_vec3_pt_ = cv::Mat_<cv::Vec3f>(HEIGHT, WIDTH, cv::Vec3f(0, 0, 0));
cv::Mat color_mat_(HEIGHT, WIDTH, CV_8UC1, &color_buffer_[0]) ;
for(int v = border_size; v < trunc_img_height_end; ++v)
{
for(int u = border_size; u < trunc_img_width_end; ++u)
{
cv::Vec3f &point = mat_vec3_pt_.at<cv::Vec3f>(v, u);
#ifdef USE_OPEN_CV_CONTRIB
float disparity = (float)(framel->raw_disparity_map_.at<short int>(v, u)*0.0625);
#else
float disparity = (float)(framel->raw_disparity_map_.at<short int>(v, u)*0.0625);
#endif
//std::cout<<"** disparity " << disparity << std::endl<< std::flush;
// do not consider pts that are farther than 8.6m, i.e. disparity < 6
if(disparity >= 60)
{
point[2] = baseline_x_fx_/disparity;
point[0] = (u-principal_x_)*point[2]/fx_;
point[1] = (v-principal_y_)*point[2]/fy_;
}
color_buffer_[v*WIDTH+u] = framel->cpu_crop_left.at<uint8_t>(v, u);
}
}
color_mat_ = cv::Mat(HEIGHT, WIDTH, CV_8UC1, &color_buffer_[0]).clone();
framel->mat_vec3=mat_vec3_pt_;
framel->color_m=color_mat_;
pt_cloud_ = cv::viz::WCloud(mat_vec3_pt_, color_mat_);
}
当我计算视差图并对其进行过滤时,我得到 100% 的地图不清晰(我们看到尽管相机的位置和障碍物固定在流中的区域会改变光强度,不是很清晰但可以接受) 你可以看到一个小视频,我在其中使用 RMS = 0.2 的校准文件对其进行了测试。
立体视觉-视差图测试
test of stereo vision- disparity map
点云
问题
我执行的误差为 RMS=0.20 的立体校准是否足以得到清晰的视差图和两个摄像头视野的完整云点?
如何获得稳定干净的视差图和干净的DEPTH MAP?
感谢您的帮助:)
【问题讨论】:
标签: opencv camera-calibration stereo-3d disparity-mapping