IntelRealSense 深度相机 测量物体的实际长度 —— rs-measure 官网文档翻译

总览

本教程显示了使用深度数据测量真实世界距离的简单方法。

	## Note: 测量真实世界中物体的维度是深度相机的一个明显的应用之一。此样本不是适当的测量工具,而是展示关键概念。
	使用更好的算法可以显著改善测量结果。

在这个教程中你将会学到怎样:

  • 在空间上将颜色流与深度对齐(和在rs-align中深度到颜色的对齐相反)
  • 利用后处理来处理缺失和噪声的深度数据
  • 在2D像素和3D空间中的点之间进行转换
  • 利用多核来并行化数据流
  • 使用OpenGL在深度之上叠加颜色

预期输出

在这里插入图片描述
这个例子允许用户测量物理世界中的两个点。

代码总览

深度处理流程

我们通过定义所有的处理块来开始这个例子。我们将要使用

// Colorizer is used to visualize depth data
// Colorizer 用于可视化深度数据
rs2::colorizer color_map;
// Use black to white color map
// 使用黑色到白色颜色映射
color_map.set_option(RS2_OPTION_COLOR_SCHEME, 2.f);
// Decimation filter reduces the amount of data (while preserving best samples)
// 抽取滤波器减小数据的数量(同时保持最佳样本)
rs2::decimation_filter dec;
// If the demo is too slow, make sure you run in Release (-DCMAKE_BUILD_TYPE=Release)
// but you can also increase the following parameter to decimate depth more (reducing quality)
// 如果这个demo太慢,确保你在release中运行(-DCMAKE_BUILD_TYPE=Release)
// 但是你可以同样增加下面的参数来更多的减少深度(降低质量)
dec.set_option(RS2_OPTION_FILTER_MAGNITUDE, 2);
// Define transformations from and to Disparity domain
// 定义从和到时差域的转换
rs2::disparity_transform depth2disparity;
rs2::disparity_transform disparity2depth(false);
// Define spatial filter (edge-preserving)
// 定于空间过滤器(保留边)
rs2::spatial_filter spat;
// Enable hole-filling 
// Hole filling is an aggressive heuristic and it gets the depth wrong many times
// However, this demo is not built to handle holes 
// (the shortest-path will always prefer to "cut" through the holes since they have zero 3D distance)
// 开启填孔
// 填孔是一个积极的启发性策略,它多次错误地获得深度
// 然而,这个demo不是用于处理填孔的
// (最短的路径总是喜欢切穿这些孔,因为它们的3D距离为零。)
spat.set_option(RS2_OPTION_HOLES_FILL, 5); // 5 = fill all the zero pixels 5 = 填充所有的零像素
// Define temporal filter 
// 定义时间过滤器
rs2::temporal_filter temp;
// Spatially align all streams to depth viewport
// We do this because:
//   a. Usually depth has wider FOV, and we only really need depth for this demo
//   b. We don't want to introduce new holes
// 将所有流在空间上对齐到深度视口
// 我们这样做是因为:
//   a. 通常深度有一个更广的FOV,并且对于这个demo我们只需要深度
//   b. 我们不想引入新的洞
rs2::align align_to(RS2_STREAM_DEPTH);

下面,我们为深度+颜色流配置相机管道

// Declare RealSense pipeline, encapsulating the actual device and sensors
// 定义RealSense管道,封装真正的设备和传感器
rs2::pipeline pipe;

rs2::config cfg;
cfg.enable_stream(RS2_STREAM_DEPTH); // Enable default depth //启用默认深度
// For the color stream, set format to RGBA
// To allow blending of the color frame on top of the depth frame
// 对于颜色流,设置格式为RGBA
// 允许在深度帧顶部混合颜色帧
cfg.enable_stream(RS2_STREAM_COLOR, RS2_FORMAT_RGBA8);
auto profile = pipe.start(cfg);

我们的目标是生成没有任何孔的深度,因为这将会对我们的算法构成直接问题。
减少丢失像素的最好方法是让硬件来处理。
D400相机具有我们可以利用的高密度预设。

auto sensor = profile.get_device().first<rs2::depth_sensor>();

// Set the device to High Accuracy preset
// 将设备设置为高密度预设
auto sensor = profile.get_device().first<rs2::depth_sensor>();
sensor.set_option(RS2_OPTION_VISUAL_PRESET, RS2_RS400_VISUAL_PRESET_HIGH_ACCURACY);

给定一个帧集,我们将按顺序应用所有的处理块。
首先我们应用align处理块来将颜色帧对其到深度视口:

// First make the frames spatially aligned
// 首先使帧空间对齐
data = align_to.process(data);

然后,我们应用深度后处理流:

rs2::frame depth = data.get_depth_frame();
// Decimation will reduce the resultion of the depth image,
// closing small holes and speeding-up the algorithm
// 抽取将减少深度图像的结果
// 关闭小孔,并且加速算法
depth = dec.process(depth); 
// To make sure far-away objects are filtered proportionally
// we try to switch to disparity domain
// 确保按照比例过滤远处的物体
// 我们尝试转换到视差域
depth = depth2disparity.process(depth);
// Apply spatial filtering
// 应用空间过滤器
depth = spat.process(depth);
// Apply temporal filtering
// 应用时间过滤
depth = temp.process(depth);
// If we are in disparity domain, switch back to depth
// 如果我们在视差域,切回到深度
depth = disparity2depth.process(depth);
// Send the post-processed depth for path-finding
// 发送后处理深度用于路径查找
pathfinding_queue.enqueue(depth);
	所有基于立体的3D相机都具有噪声与距离平方成正比的特性。
	为了抵消这一点,我们将帧转换为视差域,使噪声在距离上更均匀。
	这对我们的结构光相机没有任何作用(因为他们没有这个属性)

我们同样应用标准颜色映射

// Apply color map for visualization of depth
// 应用颜色映射来可视化深度
auto colorized = color_map(depth);

将像素和3D中的点进行转换

要将深度图像中的像素转换为3D点,我们调用rs2_deproject_pixel_to_point C函数(定义在rsutil.h中)
这个函数需要深度内在函数(depths intrinsics),2D像素和距离(米为单位)。这是我们怎样得到深度内部函数(depth intrinsics)的:

auto stream = profile.get_stream(RS2_STREAM_DEPTH).as<rs2::video_stream_profile>();
auto intrinsics = stream.get_intrinsics(); // Calibration data 校准数据

可以使用depth_frame类的get_distance函数获取以米为单位的距离。

		过度调用get_distance会导致性能不佳,因为编译器无法跨模块边界进行优化,因此,直接从depth_sensor读取	DEPTH_UNITS选项并使用它将原始深度像素转换为米可能是有益的:

将所有内容放在一起会产生相当冗长的dist_3d函数:

float dist_3d(const rs2_intrinsics& intr, const rs2::depth_frame& frame, pixel u, pixel v)
{
    float upixel[2]; // From pixel //从像素
    float upoint[3]; // From point (in 3D) //从点(3D中)
 
    float vpixel[2]; // To pixel //到像素
    float vpoint[3]; // To point (in 3D) //到点(3D中)

    // Copy pixels into the arrays (to match rsutil signatures)
    // 将像素拷贝到数组中(匹配rsutil签名)
    upixel[0] = u.first;
    upixel[1] = u.second;
    vpixel[0] = v.first;
    vpixel[1] = v.second;

    // Query the frame for distance 
    // Note: this can be optimized
    // It is not recommended to issue an API call for each pixel
    // (since the compiler can't inline these)
    // However, in this example it is not one of the bottlenecks
    // 查询帧的距离
    // 注意:这个可以被优化
    // 不建议为每个像素发出API调用
    // (因为编译器不能内联这些)
    // 然而,在这里例子中它不是瓶颈之一
    auto udist = frame.get_distance(upixel[0], upixel[1]);
    auto vdist = frame.get_distance(vpixel[0], vpixel[1]);

    // Deproject from pixel to point in 3D
    // 将像素反映射到3D中的点
    rs2_deproject_pixel_to_point(upoint, &intr, upixel, udist);
    rs2_deproject_pixel_to_point(vpoint, &intr, vpixel, vdist);

    // Calculate euclidean distance between the two points
    // 计算空间中两个点的欧几里得距离
    return sqrt(pow(upoint[0] - vpoint[0], 2) +
                pow(upoint[1] - vpoint[1], 2) +
                pow(upoint[2] - vpoint[2], 2));
}

在后台线程上运行处理

在此示例中的后处理运算可能相对较慢。为了不阻塞主(UI)线程,我们将有一个专门的线程进行后处理。

视频处理线程

这个线程将消耗来自相机完整帧集,并且会产生包含颜色和着色深度帧的帧集(用于在主线程上渲染):

while (alive)
{
    // Fetch frames from the pipeline and send them for processing
    // 从管道中获取帧,并且发送它们进行处理 
    rs2::frameset fs;
    if (pipe.poll_for_frames(&fs)) 
    {
        // Apply post processing
        // ...
		// 应用后处理过程
		// ...
        // Send resulting frames for visualization in the main thread
        // 发送结果帧,用于在主线程中进行可视化。
        postprocessed_frames.enqueue(data);
    }
}

主线程

主线程是唯一允许用来渲染屏幕的。
它从postprocessed_frames中获取,并且只是展示结果:

while(app) // Application still alive? // 应用仍然存在吗?
{
    postprocessed_frames.poll_for_frame(&current_frameset);

    if (current_frameset)
    {
        auto depth = current_frameset.get_depth_frame();
        auto color = current_frameset.get_color_frame();

        glEnable(GL_BLEND);
        // Use the Alpha channel for blending 
        // 使用Alpha通道进行混合
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

        // First render the colorized depth image
        // 首先渲染着色的深度图像
        depth_image.render(depth, { 0, 0, app.width(), app.height() });
        // Next, set global alpha for the color image to 90%
        // (to make it slightly translucent)
        // 下一步,将彩色图像的全局alpha设置为90%
        // (使其略微半透明)
        glColor4f(1.f, 1.f, 1.f, 0.9f);
        // Render the color frame (since we have selected RGBA format
        // pixels out of FOV will appear transparent)
        // 渲染颜色帧(因为我们选择了RGBA格式,超出FOV的像素将会显示为透明)
        color_image.render(color, { 0, 0, app.width(), app.height() });

        // Render the simple pythagorean distance
        // 渲染简单的Pythagorean距离(勾股距离)
        render_simple_distance(depth, app_state, app, intrinsics);

        // Render the ruler
        // 渲染直尺
        app_state.ruler_start.render(app);
        app_state.ruler_end.render(app);

        glDisable(GL_BLEND);
    }
}

我们使用glBlendFunc使用颜色alpha通道在深度之上覆盖对其的颜色(流必须是格式RGBA才能工作)。


这个例子演示了一个简单而复杂的处理流程。每个线程都有一些不同的速率,它们都需要同步而不是相互堵塞。
这是使用线程安全的frame_queues作为同步原语和rs2::frame引用计数来实现的,用于跨线程的对象生命周期管理。

  • 3
    点赞
  • 51
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
### 回答1: s-measure和e-measure 也被称为结构相似度指标和误差相对测量指标,它们是用来评估图像质量的指标。 s-measure是由Wang等人于2011年提出的一种全参考图像质量评价指标。它基于结构相似性指数(SSIM)和图像对比度指数(Contrast),用于测量图像的结构相似性和对比度。s-measure综合了这两个指标的结果,并通过引入一个调整因子来平衡它们的影响。s-measure的值范围从0到1,值越高表示图像质量越好。 e-measure是由Yeganeh和Wang于2013年提出的一种无参考图像质量评价指标。它基于误差的能量相对测量,用于衡量图像质量的主观感知。e-measure通过计算图像重建误差的均方根(RMSE)和对比度的标准差来评估图像质量。e-measure的值范围从0到1,值越高表示图像质量越好。 s-measure和e-measure都是基于图像的结构和对比度特征来评价图像质量的指标。它们适用于不同的评估场景和需求。s-measure适合用于全参考图像质量评估,即需要参考图像进行对比的场景。而e-measure适合用于无参考图像质量评估,即无需参考图像进行对比的场景。两者都能够提供准确的图像质量评估结果,有助于图像处理和计算机视觉领域的研究和应用。 ### 回答2: s-measure和e-measure是两种常用的评估指标,用于评估信息检索系统的性能。 s-measure是一种综合性指标,用于衡量信息检索系统的准确性和完整性。它将系统检索的相关文档与相关但未检索到的文档进行比较,通过计算系统检索到的相关文档中没有被检索到的相关文档的比例,来衡量系统的遗漏情况。s-measure的取值范围为0到1,值越接近1表示系统的性能越好。 e-measure是另一种常用的评估指标,用于衡量信息检索系统的效率。它主要关注系统检索到的非相关文档的数量,通过计算系统检索到的非相关文档与系统检索到的全部文档的比例,来衡量系统的非相关文档的占比。e-measure的取值范围也是0到1,与s-measure类似,值越接近1表示系统的性能越好。 s-measure和e-measure可以同时使用,以综合评估信息检索系统的性能。通过比较两个指标的取值,可以分析系统在准确性和效率方面的表现。在信息检索领域,s-measure和e-measure被广泛应用于实验评估、性能提升和系统比较等方面,以帮助研究人员和开发者改进和优化信息检索系统。 ### 回答3: s-measure和e-measure都是用来评估图像分割质量的指标。 s-measure是一种结构相似度度量,用于比较两个图像之间的相似性。它通过比较原始图像与分割结果之间的结构信息,来评估分割的准确性。s-measure考虑了两个方面的因素:分割结果与原始图像的结构相似度以及分割结果与真实分割的结构一致性。通过这样的综合指标,可以更全面和全局地评估图像分割的好坏,其值越接近1,表示分割结果越准确。 e-measure是一种边缘保留度量,用于评估图像分割结果的边缘保留程度。边缘保留是指分割结果边缘与原始图像边缘的接近程度。e-measure主要通过计算分割结果与真实分割之间的边缘距离来评估分割的准确性。它具有较好的边缘保留性能,能更好地反映分割结果的边缘清晰度。其值越接近1,表示分割结果的边缘保留越好。 综上所述,s-measure和e-measure都是用来评估图像分割质量的指标,但判断的角度略有不同。s-measure主要关注分割结果整体与原始图像以及真实分割之间的结构相似度和一致性;而e-measure则主要关注分割结果的边缘保留程度。两者结合使用可以更全面和准确地评估图像分割的好坏。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值