《PCL点云库学习VS2010(X64)》Part 23 快速双边滤波算法之三线插值

本文主要是介绍《PCL点云库学习VS2010(X64)》Part 23 快速双边滤波算法之三线插值,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

《PCL点云库学习&VS2010(X64)》Part 23 快速双边滤波算法之三线插值


一、源代码

       快速双边滤波算法的精华部分在3D网格分配、控制网格延伸范围、下采样和上采样线性插值三个主要部分。

核心代码:

#ifndef PCL_FILTERS_IMPL_FAST_BILATERAL_HPP_
#define PCL_FILTERS_IMPL_FAST_BILATERAL_HPP_#include <pcl/common/io.h>//
template <typename PointT> void
pcl::FastBilateralFilter<PointT>::applyFilter (PointCloud &output)
{if (!input_->isOrganized ()){PCL_ERROR ("[pcl::FastBilateralFilter] Input cloud needs to be organized.\n");return;}copyPointCloud (*input_, output);float base_max = -std::numeric_limits<float>::max (),base_min = std::numeric_limits<float>::max ();bool found_finite = false;for (size_t x = 0; x < output.width; ++x){for (size_t y = 0; y < output.height; ++y){if (pcl_isfinite (output (x, y).z)){if (base_max < output (x, y).z)base_max = output (x, y).z;if (base_min > output (x, y).z)base_min = output (x, y).z;found_finite = true;}}}if (!found_finite){PCL_WARN ("[pcl::FastBilateralFilter] Given an empty cloud. Doing nothing.\n");return;}for (size_t x = 0; x < output.width; ++x)for (size_t y = 0; y < output.height; ++y)if (!pcl_isfinite (output (x, y).z))output (x, y).z = base_max;const float base_delta = base_max - base_min;const size_t padding_xy = 2;const size_t padding_z  = 2;const size_t small_width  = static_cast<size_t> (static_cast<float> (input_->width  - 1) / sigma_s_) + 1 + 2 * padding_xy;const size_t small_height = static_cast<size_t> (static_cast<float> (input_->height - 1) / sigma_s_) + 1 + 2 * padding_xy;const size_t small_depth  = static_cast<size_t> (base_delta / sigma_r_)   + 1 + 2 * padding_z;Array3D data (small_width, small_height, small_depth);for (size_t x = 0; x < input_->width; ++x){const size_t small_x = static_cast<size_t> (static_cast<float> (x) / sigma_s_ + 0.5f) + padding_xy;for (size_t y = 0; y < input_->height; ++y){const float z = output (x,y).z - base_min;const size_t small_y = static_cast<size_t> (static_cast<float> (y) / sigma_s_ + 0.5f) + padding_xy;const size_t small_z = static_cast<size_t> (static_cast<float> (z) / sigma_r_ + 0.5f) + padding_z;Eigen::Vector2f& d = data (small_x, small_y, small_z);d[0] += output (x,y).z;d[1] += 1.0f;}}std::vector<long int> offset (3);offset[0] = &(data (1,0,0)) - &(data (0,0,0));offset[1] = &(data (0,1,0)) - &(data (0,0,0));offset[2] = &(data (0,0,1)) - &(data (0,0,0));Array3D buffer (small_width, small_height, small_depth);for (size_t dim = 0; dim < 3; ++dim){const long int off = offset[dim];for (size_t n_iter = 0; n_iter < 2; ++n_iter){std::swap (buffer, data);for(size_t x = 1; x < small_width - 1; ++x)for(size_t y = 1; y < small_height - 1; ++y){Eigen::Vector2f* d_ptr = &(data (x,y,1));Eigen::Vector2f* b_ptr = &(buffer (x,y,1));for(size_t z = 1; z < small_depth - 1; ++z, ++d_ptr, ++b_ptr)*d_ptr = (*(b_ptr - off) + *(b_ptr + off) + 2.0 * (*b_ptr)) / 4.0;}}}if (early_division_){for (std::vector<Eigen::Vector2f >::iterator d = data.begin (); d != data.end (); ++d)*d /= ((*d)[0] != 0) ? (*d)[1] : 1;for (size_t x = 0; x < input_->width; x++)for (size_t y = 0; y < input_->height; y++){const float z = output (x,y).z - base_min;const Eigen::Vector2f D = data.trilinear_interpolation (static_cast<float> (x) / sigma_s_ + padding_xy,static_cast<float> (y) / sigma_s_ + padding_xy,z / sigma_r_ + padding_z);output(x,y).z = D[0];}}else{for (size_t x = 0; x < input_->width; ++x)for (size_t y = 0; y < input_->height; ++y){const float z = output (x,y).z - base_min;const Eigen::Vector2f D = data.trilinear_interpolation (static_cast<float> (x) / sigma_s_ + padding_xy,static_cast<float> (y) / sigma_s_ + padding_xy,z / sigma_r_ + padding_z);output (x,y).z = D[0] / D[1];}}
}//
template <typename PointT> size_t
pcl::FastBilateralFilter<PointT>::Array3D::clamp (const size_t min_value,const size_t max_value,const size_t x)
{if (x >= min_value && x <= max_value){return x;}else if (x < min_value){return (min_value);}else{return (max_value);}
}//
template <typename PointT> Eigen::Vector2f
pcl::FastBilateralFilter<PointT>::Array3D::trilinear_interpolation (const float x,const float y,const float z)
{const size_t x_index  = clamp (0, x_dim_ - 1, static_cast<size_t> (x));const size_t xx_index = clamp (0, x_dim_ - 1, x_index + 1);const size_t y_index  = clamp (0, y_dim_ - 1, static_cast<size_t> (y));const size_t yy_index = clamp (0, y_dim_ - 1, y_index + 1);const size_t z_index  = clamp (0, z_dim_ - 1, static_cast<size_t> (z));const size_t zz_index = clamp (0, z_dim_ - 1, z_index + 1);const float x_alpha = x - static_cast<float> (x_index);const float y_alpha = y - static_cast<float> (y_index);const float z_alpha = z - static_cast<float> (z_index);return(1.0f-x_alpha) * (1.0f-y_alpha) * (1.0f-z_alpha) * (*this)(x_index, y_index, z_index) +x_alpha        * (1.0f-y_alpha) * (1.0f-z_alpha) * (*this)(xx_index, y_index, z_index) +(1.0f-x_alpha) * y_alpha        * (1.0f-z_alpha) * (*this)(x_index, yy_index, z_index) +x_alpha        * y_alpha        * (1.0f-z_alpha) * (*this)(xx_index, yy_index, z_index) +(1.0f-x_alpha) * (1.0f-y_alpha) * z_alpha        * (*this)(x_index, y_index, zz_index) +x_alpha        * (1.0f-y_alpha) * z_alpha        * (*this)(xx_index, y_index, zz_index) +(1.0f-x_alpha) * y_alpha        * z_alpha        * (*this)(x_index, yy_index, zz_index) +x_alpha        * y_alpha        * z_alpha        * (*this)(xx_index, yy_index, zz_index);
}#endif /* PCL_FILTERS_IMPL_FAST_BILATERAL_HPP_ */


二、代码分析——函数

根据上面的代码:主要有三个函数:

1、

template <typename PointT> void
pcl::FastBilateralFilter<PointT>::applyFilter (PointCloud &output)
2、

template <typename PointT> size_t
pcl::FastBilateralFilter<PointT>::Array3D::clamp (const size_t min_value,const size_t max_value,const size_t x)
3、

template <typename PointT> Eigen::Vector2f
pcl::FastBilateralFilter<PointT>::Array3D::trilinear_interpolation (const float x,const float y,const float z)


三、代码分析——关键代码

1、分配3D网格,其中的padding_xy和padding_z用来控制网格的延拓范围,代码如下:

 for (size_t x = 0; x < output.width; ++x)for (size_t y = 0; y < output.height; ++y)if (!pcl_isfinite (output (x, y).z))output (x, y).z = base_max;const float base_delta = base_max - base_min;const size_t padding_xy = 2;const size_t padding_z  = 2;const size_t small_width  = static_cast<size_t> (static_cast<float> (input_->width  - 1) / sigma_s_) + 1 + 2 * padding_xy;const size_t small_height = static_cast<size_t> (static_cast<float> (input_->height - 1) / sigma_s_) + 1 + 2 * padding_xy;const size_t small_depth  = static_cast<size_t> (base_delta / sigma_r_)   + 1 + 2 * padding_z;


2、对分割的网格进行下采样处理,其核心代码如下:

 Array3D data (small_width, small_height, small_depth);for (size_t x = 0; x < input_->width; ++x){const size_t small_x = static_cast<size_t> (static_cast<float> (x) / sigma_s_ + 0.5f) + padding_xy;for (size_t y = 0; y < input_->height; ++y){const float z = output (x,y).z - base_min;const size_t small_y = static_cast<size_t> (static_cast<float> (y) / sigma_s_ + 0.5f) + padding_xy;const size_t small_z = static_cast<size_t> (static_cast<float> (z) / sigma_r_ + 0.5f) + padding_z;Eigen::Vector2f& d = data (small_x, small_y, small_z);d[0] += output (x,y).z;d[1] += 1.0f;}}

3、其中的这段代码不是特别理解:

  std::vector<long int> offset (3);offset[0] = &(data (1,0,0)) - &(data (0,0,0));offset[1] = &(data (0,1,0)) - &(data (0,0,0));offset[2] = &(data (0,0,1)) - &(data (0,0,0));Array3D buffer (small_width, small_height, small_depth);for (size_t dim = 0; dim < 3; ++dim){const long int off = offset[dim];for (size_t n_iter = 0; n_iter < 2; ++n_iter){std::swap (buffer, data);for(size_t x = 1; x < small_width - 1; ++x)for(size_t y = 1; y < small_height - 1; ++y){Eigen::Vector2f* d_ptr = &(data (x,y,1));Eigen::Vector2f* b_ptr = &(buffer (x,y,1));for(size_t z = 1; z < small_depth - 1; ++z, ++d_ptr, ++b_ptr)*d_ptr = (*(b_ptr - off) + *(b_ptr + off) + 2.0 * (*b_ptr)) / 4.0;}}}


4、clamp函数:限制x的范围,插值过程中控制其size大小。代码如下:

template <typename PointT> size_t
pcl::FastBilateralFilter<PointT>::Array3D::clamp (const size_t min_value,const size_t max_value,const size_t x)
{if (x >= min_value && x <= max_value){return x;}else if (x < min_value){return (min_value);}else{return (max_value);}
}


5、三线插值:

      三线插值要先给出六面体的八个顶点;各个顶点的数值分别是:V000, V100, V010, ....V111
计算立方体里面的(x,y,z)的值Vxyz。


Vxyz = V000 (1 - x) (1 - y) (1 - z) +
            V100 x (1 - y) (1 - z) +
            V010 (1 - x) y (1 - z) +
            V001 (1 - x) (1 - y) z +
            V101 x (1 - y) z +
            V011 (1 - x) y z +
            V110 x y (1 - z) +
            V111 x y z

           对于更一般的情况就需要对各个维度进行一定的尺度变换操作。其示计算过程意图如下:



                   三线性插值的几何可视化。在期望点(黑色点)和整个体积值的乘积等于每个顶点处的值的乘积和对角处的部分体积的总和。

template <typename PointT> Eigen::Vector2f
pcl::FastBilateralFilter<PointT>::Array3D::trilinear_interpolation (const float x,const float y,const float z)
{const size_t x_index  = clamp (0, x_dim_ - 1, static_cast<size_t> (x));const size_t xx_index = clamp (0, x_dim_ - 1, x_index + 1);const size_t y_index  = clamp (0, y_dim_ - 1, static_cast<size_t> (y));const size_t yy_index = clamp (0, y_dim_ - 1, y_index + 1);const size_t z_index  = clamp (0, z_dim_ - 1, static_cast<size_t> (z));const size_t zz_index = clamp (0, z_dim_ - 1, z_index + 1);const float x_alpha = x - static_cast<float> (x_index);const float y_alpha = y - static_cast<float> (y_index);const float z_alpha = z - static_cast<float> (z_index);return(1.0f-x_alpha) * (1.0f-y_alpha) * (1.0f-z_alpha) * (*this)(x_index, y_index, z_index) +x_alpha        * (1.0f-y_alpha) * (1.0f-z_alpha) * (*this)(xx_index, y_index, z_index) +(1.0f-x_alpha) * y_alpha        * (1.0f-z_alpha) * (*this)(x_index, yy_index, z_index) +x_alpha        * y_alpha        * (1.0f-z_alpha) * (*this)(xx_index, yy_index, z_index) +(1.0f-x_alpha) * (1.0f-y_alpha) * z_alpha        * (*this)(x_index, y_index, zz_index) +x_alpha        * (1.0f-y_alpha) * z_alpha        * (*this)(xx_index, y_index, zz_index) +(1.0f-x_alpha) * y_alpha        * z_alpha        * (*this)(x_index, yy_index, zz_index) +x_alpha        * y_alpha        * z_alpha        * (*this)(xx_index, yy_index, zz_index);
}

四:《三维法线分布转换

The Three-Dimensional Normal-Distributions Transform

论文网址——p86-87





第一句说的很清楚,在空间细分为离散单元格后,单元格边缘处的曲面显示会不连续,所以由二维插值到三维插值的演变过程,出现了三线插值。

五、让该算法的加速计算可以利用线程技术,但是根据论文中的体积,插值过程是由卷积计算来完成的,当然插值的算法有很多,但是总体的思路很重要。


这篇关于《PCL点云库学习VS2010(X64)》Part 23 快速双边滤波算法之三线插值的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/515320

相关文章

Python多线程实现大文件快速下载的代码实现

《Python多线程实现大文件快速下载的代码实现》在互联网时代,文件下载是日常操作之一,尤其是大文件,然而,网络条件不稳定或带宽有限时,下载速度会变得很慢,本文将介绍如何使用Python实现多线程下载... 目录引言一、多线程下载原理二、python实现多线程下载代码说明:三、实战案例四、注意事项五、总结引

Unity新手入门学习殿堂级知识详细讲解(图文)

《Unity新手入门学习殿堂级知识详细讲解(图文)》Unity是一款跨平台游戏引擎,支持2D/3D及VR/AR开发,核心功能模块包括图形、音频、物理等,通过可视化编辑器与脚本扩展实现开发,项目结构含A... 目录入门概述什么是 UnityUnity引擎基础认知编辑器核心操作Unity 编辑器项目模式分类工程

C#使用Spire.XLS快速生成多表格Excel文件

《C#使用Spire.XLS快速生成多表格Excel文件》在日常开发中,我们经常需要将业务数据导出为结构清晰的Excel文件,本文将手把手教你使用Spire.XLS这个强大的.NET组件,只需几行C#... 目录一、Spire.XLS核心优势清单1.1 性能碾压:从3秒到0.5秒的质变1.2 批量操作的优雅

Python学习笔记之getattr和hasattr用法示例详解

《Python学习笔记之getattr和hasattr用法示例详解》在Python中,hasattr()、getattr()和setattr()是一组内置函数,用于对对象的属性进行操作和查询,这篇文章... 目录1.getattr用法详解1.1 基本作用1.2 示例1.3 原理2.hasattr用法详解2.

Mybatis-Plus 3.5.12 分页拦截器消失的问题及快速解决方法

《Mybatis-Plus3.5.12分页拦截器消失的问题及快速解决方法》作为Java开发者,我们都爱用Mybatis-Plus简化CRUD操作,尤其是它的分页功能,几行代码就能搞定复杂的分页查询... 目录一、问题场景:分页拦截器突然 “失踪”二、问题根源:依赖拆分惹的祸三、解决办法:添加扩展依赖四、分页

c++日志库log4cplus快速入门小结

《c++日志库log4cplus快速入门小结》文章浏览阅读1.1w次,点赞9次,收藏44次。本文介绍Log4cplus,一种适用于C++的线程安全日志记录API,提供灵活的日志管理和配置控制。文章涵盖... 目录简介日志等级配置文件使用关于初始化使用示例总结参考资料简介log4j 用于Java,log4c

使用Redis快速实现共享Session登录的详细步骤

《使用Redis快速实现共享Session登录的详细步骤》在Web开发中,Session通常用于存储用户的会话信息,允许用户在多个页面之间保持登录状态,Redis是一个开源的高性能键值数据库,广泛用于... 目录前言实现原理:步骤:使用Redis实现共享Session登录1. 引入Redis依赖2. 配置R

C# $字符串插值的使用

《C#$字符串插值的使用》本文介绍了C#中的字符串插值功能,详细介绍了使用$符号的实现方式,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起学习学习吧... 目录$ 字符使用方式创建内插字符串包含不同的数据类型控制内插表达式的格式控制内插表达式的对齐方式内插表达式中使用转义序列内插表达式中使用

Java中的雪花算法Snowflake解析与实践技巧

《Java中的雪花算法Snowflake解析与实践技巧》本文解析了雪花算法的原理、Java实现及生产实践,涵盖ID结构、位运算技巧、时钟回拨处理、WorkerId分配等关键点,并探讨了百度UidGen... 目录一、雪花算法核心原理1.1 算法起源1.2 ID结构详解1.3 核心特性二、Java实现解析2.

Linux如何快速检查服务器的硬件配置和性能指标

《Linux如何快速检查服务器的硬件配置和性能指标》在运维和开发工作中,我们经常需要快速检查Linux服务器的硬件配置和性能指标,本文将以CentOS为例,介绍如何通过命令行快速获取这些关键信息,... 目录引言一、查询CPU核心数编程(几C?)1. 使用 nproc(最简单)2. 使用 lscpu(详细信