Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #include <pcl/common/gaussian.h>
00039
00040 void
00041 pcl::GaussianKernel::compute (float sigma,
00042 Eigen::VectorXf &kernel,
00043 unsigned kernel_width) const
00044 {
00045 assert (kernel_width %2 == 1);
00046 assert (sigma >= 0);
00047 kernel.resize (kernel_width);
00048 static const float factor = 0.01f;
00049 static const float max_gauss = 1.0f;
00050 const int hw = kernel_width / 2;
00051 float sigma_sqr = 1.0f / (2.0f * sigma * sigma);
00052 for (int i = -hw, j = 0, k = kernel_width - 1; i < 0 ; i++, j++, k--)
00053 kernel[k] = kernel[j] = expf (-static_cast<float>(i) * static_cast<float>(i) * sigma_sqr);
00054 kernel[hw] = 1;
00055 unsigned g_width = kernel_width;
00056 for (unsigned i = 0; fabs (kernel[i]/max_gauss) < factor; i++, g_width-= 2) ;
00057 if (g_width == kernel_width)
00058 {
00059 PCL_THROW_EXCEPTION (pcl::KernelWidthTooSmallException,
00060 "kernel width " << kernel_width
00061 << "is too small for the given sigma " << sigma);
00062 return;
00063 }
00064
00065
00066 unsigned shift = (kernel_width - g_width)/2;
00067 for (unsigned i =0; i < g_width; i++)
00068 kernel[i] = kernel[i + shift];
00069 kernel.conservativeResize (g_width);
00070
00071
00072 kernel/= kernel.sum ();
00073 }
00074
00075 void
00076 pcl::GaussianKernel::compute (float sigma,
00077 Eigen::VectorXf &kernel,
00078 Eigen::VectorXf &derivative,
00079 unsigned kernel_width) const
00080 {
00081 assert (kernel_width %2 == 1);
00082 assert (sigma >= 0);
00083 kernel.resize (kernel_width);
00084 derivative.resize (kernel_width);
00085 const float factor = 0.01f;
00086 float max_gauss = 1.0f, max_deriv = float (sigma * exp (-0.5));
00087 int hw = kernel_width / 2;
00088
00089 float sigma_sqr = 1.0f / (2.0f * sigma * sigma);
00090 for (int i = -hw, j = 0, k = kernel_width - 1; i < 0 ; i++, j++, k--)
00091 {
00092 kernel[k] = kernel[j] = expf (-static_cast<float>(i) * static_cast<float>(i) * sigma_sqr);
00093 derivative[j] = -static_cast<float>(i) * kernel[j];
00094 derivative[k] = -derivative[j];
00095 }
00096 kernel[hw] = 1;
00097 derivative[hw] = 0;
00098
00099 unsigned g_width = kernel_width;
00100 unsigned d_width = kernel_width;
00101 for (unsigned i = 0; fabs (derivative[i]/max_deriv) < factor; i++, d_width-= 2) ;
00102 for (unsigned i = 0; fabs (kernel[i]/max_gauss) < factor; i++, g_width-= 2) ;
00103 if (g_width == kernel_width || d_width == kernel_width)
00104 {
00105 PCL_THROW_EXCEPTION (KernelWidthTooSmallException,
00106 "kernel width " << kernel_width
00107 << "is too small for the given sigma " << sigma);
00108 return;
00109 }
00110
00111
00112
00113 unsigned shift = (kernel_width - g_width)/2;
00114 for (unsigned i =0; i < g_width; i++)
00115 kernel[i] = kernel[i + shift];
00116
00117 kernel.conservativeResize (g_width);
00118 kernel/= kernel.sum ();
00119
00120
00121 shift = (kernel_width - d_width)/2;
00122 for (unsigned i =0; i < d_width; i++)
00123 derivative[i] = derivative[i + shift];
00124 derivative.conservativeResize (d_width);
00125
00126 hw = d_width / 2;
00127 float den = 0;
00128 for (int i = -hw ; i <= hw ; i++)
00129 den -= static_cast<float>(i) * derivative[i+hw];
00130 derivative/= den;
00131 }
00132
00133 void
00134 pcl::GaussianKernel::convolveRows (const pcl::PointCloud<float>& input,
00135 const Eigen::VectorXf& kernel,
00136 pcl::PointCloud<float>& output) const
00137 {
00138 assert (kernel.size () % 2 == 1);
00139 size_t kernel_width = kernel.size () -1;
00140 size_t radius = kernel.size () / 2;
00141 const pcl::PointCloud<float>* input_;
00142 if (&input != &output)
00143 {
00144 if (output.height < input.height || output.width < input.width)
00145 {
00146 output.width = input.width;
00147 output.height = input.height;
00148 output.points.resize (input.height * input.width);
00149 }
00150 input_ = &input;
00151 }
00152 else
00153 input_ = new pcl::PointCloud<float>(input);
00154
00155 size_t i;
00156 for (size_t j = 0; j < input_->height; j++)
00157 {
00158 for (i = 0 ; i < radius ; i++)
00159 output (i,j) = 0;
00160
00161 for ( ; i < input_->width - radius ; i++)
00162 {
00163 output (i,j) = 0;
00164 for (int k = static_cast<int>(kernel_width), l = static_cast<int>(i - radius); k >= 0 ; k--, l++)
00165 output (i,j) += (*input_) (l,j) * kernel[k];
00166 }
00167
00168 for ( ; i < input_->width ; i++)
00169 output (i,j) = 0;
00170 }
00171
00172 if (&input == &output)
00173 {
00174 delete input_;
00175 }
00176 }
00177
00178 void
00179 pcl::GaussianKernel::convolveCols (const pcl::PointCloud<float>& input,
00180 const Eigen::VectorXf& kernel,
00181 pcl::PointCloud<float>& output) const
00182 {
00183 assert (kernel.size () % 2 == 1);
00184 size_t kernel_width = kernel.size () -1;
00185 size_t radius = kernel.size () / 2;
00186 const pcl::PointCloud<float>* input_;
00187 if (&input != &output)
00188 {
00189 if (output.height < input.height || output.width < input.width)
00190 {
00191 output.width = input.width;
00192 output.height = input.height;
00193 output.resize (input.width * input.height);
00194 }
00195 input_ = &input;
00196 }
00197 else
00198 input_ = new pcl::PointCloud<float> (input);
00199
00200 size_t j;
00201 for (size_t i = 0; i < input_->width; i++)
00202 {
00203 for (j = 0 ; j < radius ; j++)
00204 output (i,j) = 0;
00205
00206 for ( ; j < input_->height - radius ; j++) {
00207 output (i,j) = 0;
00208 for (int k = static_cast<int>(kernel_width), l = static_cast<int>(j - radius) ; k >= 0 ; k--, l++)
00209 {
00210 output (i,j) += (*input_) (i,l) * kernel[k];
00211 }
00212 }
00213
00214 for ( ; j < input_->height ; j++)
00215 output (i,j) = 0;
00216 }
00217 if (&input == &output)
00218 delete input_;
00219 }