mesh_filter_base.cpp
Go to the documentation of this file.
00001 /*********************************************************************
00002  * Software License Agreement (BSD License)
00003  *
00004  *  Copyright (c) 2013, Willow Garage, Inc.
00005  *  All rights reserved.
00006  *
00007  *  Redistribution and use in source and binary forms, with or without
00008  *  modification, are permitted provided that the following conditions
00009  *  are met:
00010  *
00011  *   * Redistributions of source code must retain the above copyright
00012  *     notice, this list of conditions and the following disclaimer.
00013  *   * Redistributions in binary form must reproduce the above
00014  *     copyright notice, this list of conditions and the following
00015  *     disclaimer in the documentation and/or other materials provided
00016  *     with the distribution.
00017  *   * Neither the name of Willow Garage nor the names of its
00018  *     contributors may be used to endorse or promote products derived
00019  *     from this software without specific prior written permission.
00020  *
00021  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00022  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00023  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00024  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00025  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00026  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00027  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00028  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00029  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00031  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00032  *  POSSIBILITY OF SUCH DAMAGE.
00033  *********************************************************************/
00034 
00035 /* Author: Suat Gedikli */
00036 
00037 #include <moveit/mesh_filter/mesh_filter_base.h>
00038 #include <moveit/mesh_filter/gl_mesh.h>
00039 #include <moveit/mesh_filter/filter_job.h>
00040 
00041 #include <geometric_shapes/shapes.h>
00042 #include <geometric_shapes/shape_operations.h>
00043 #include <Eigen/Eigen>
00044 #include <stdexcept>
00045 #include <sstream>
00046 #include <sensor_msgs/image_encodings.h>
00047 
00048 #include <ros/console.h>
00049 
00050 // include SSE headers
00051 #ifdef HAVE_SSE_EXTENSIONS
00052 #include <xmmintrin.h>
00053 #endif
00054 
00055 using std::string;
00056 using namespace Eigen;
00057 using shapes::Mesh;
00058 using boost::shared_ptr;
00059 using boost::unique_lock;
00060 using boost::mutex;
00061 
00062 mesh_filter::MeshFilterBase::MeshFilterBase (const TransformCallback& transform_callback,
00063               const SensorModel::Parameters& sensor_parameters,
00064               const string& render_vertex_shader, const string& render_fragment_shader,
00065               const string& filter_vertex_shader, const string& filter_fragment_shader)
00066 : sensor_parameters_ (sensor_parameters.clone ())
00067 , next_handle_ (FirstLabel) // 0 and 1 are reserved!
00068 , min_handle_ (FirstLabel)
00069 , stop_ (false)
00070 , transform_callback_ (transform_callback)
00071 , padding_scale_ (1.0)
00072 , padding_offset_ (0.01)
00073 , shadow_threshold_ (0.5)
00074 {
00075   using boost::thread;
00076   filter_thread_ = thread (boost::bind(&MeshFilterBase::run, this,
00077                                        render_vertex_shader, render_fragment_shader, filter_vertex_shader, filter_fragment_shader));
00078 }
00079 
00080 void mesh_filter::MeshFilterBase::initialize (const string& render_vertex_shader, const string& render_fragment_shader,
00081                                               const string& filter_vertex_shader, const string& filter_fragment_shader)
00082 {
00083   mesh_renderer_.reset (new GLRenderer (sensor_parameters_->getWidth(), sensor_parameters_->getHeight(),
00084                                         sensor_parameters_->getNearClippingPlaneDistance (),
00085                                         sensor_parameters_->getFarClippingPlaneDistance ()));
00086   depth_filter_.reset (new GLRenderer (sensor_parameters_->getWidth(), sensor_parameters_->getHeight(),
00087                                         sensor_parameters_->getNearClippingPlaneDistance (),
00088                                         sensor_parameters_->getFarClippingPlaneDistance ()));
00089 
00090   mesh_renderer_->setShadersFromString (render_vertex_shader, render_fragment_shader);
00091   depth_filter_->setShadersFromString (filter_vertex_shader, filter_fragment_shader);
00092 
00093   depth_filter_->begin ();
00094 
00095   glGenTextures (1, &sensor_depth_texture_);
00096 
00097   glUniform1i (glGetUniformLocation (depth_filter_->getProgramID (), "sensor"), 0);
00098   glUniform1i (glGetUniformLocation (depth_filter_->getProgramID (), "depth"), 2);
00099   glUniform1i (glGetUniformLocation (depth_filter_->getProgramID (), "label"), 4);
00100 
00101   shadow_threshold_location_ = glGetUniformLocation (depth_filter_->getProgramID (), "shadow_threshold");
00102 
00103   depth_filter_->end ();
00104 
00105   canvas_ = glGenLists (1);
00106   glNewList (canvas_, GL_COMPILE);
00107   glBegin (GL_QUADS);
00108 
00109   glColor3f (1, 1, 1);
00110   glTexCoord2f (0, 0);
00111   glVertex3f (-1, -1, 1);
00112 
00113   glTexCoord2f (1, 0);
00114   glVertex3f (1, -1, 1);
00115 
00116   glTexCoord2f ( 1, 1);
00117   glVertex3f (1, 1, 1);
00118 
00119   glTexCoord2f ( 0, 1);
00120   glVertex3f (-1, 1, 1);
00121 
00122   glEnd ();
00123   glEndList ();
00124 }
00125 
00126 mesh_filter::MeshFilterBase::~MeshFilterBase ()
00127 {
00128   {
00129     unique_lock<mutex> lock (jobs_mutex_);
00130     stop_ = true;
00131     while (!jobs_queue_.empty())
00132     {
00133       jobs_queue_.front ()->cancel ();
00134       jobs_queue_.pop();
00135     }
00136   }
00137   jobs_condition_.notify_one ();
00138   filter_thread_.join();
00139 }
00140 
00141 void mesh_filter::MeshFilterBase::addJob (const boost::shared_ptr<Job> &job) const
00142 {
00143   {
00144     unique_lock<mutex> _(jobs_mutex_);
00145     jobs_queue_.push (job);
00146   }
00147   jobs_condition_.notify_one();
00148 }
00149 
00150 void mesh_filter::MeshFilterBase::deInitialize ()
00151 {
00152   glDeleteLists (canvas_, 1);
00153   glDeleteTextures (1, &sensor_depth_texture_);
00154 
00155   meshes_.clear ();
00156   mesh_renderer_.reset();
00157   depth_filter_.reset();
00158 }
00159 
00160 void mesh_filter::MeshFilterBase::setSize (unsigned int width, unsigned int height)
00161 {
00162   mesh_renderer_->setBufferSize (width, height);
00163   mesh_renderer_->setCameraParameters (width, width, width >> 1, height >> 1);
00164 
00165   depth_filter_->setBufferSize (width, height);
00166   depth_filter_->setCameraParameters (width, width, width >> 1, height >> 1);
00167 }
00168 
00169 void mesh_filter::MeshFilterBase::setTransformCallback (const TransformCallback& transform_callback)
00170 {
00171   mutex::scoped_lock _(transform_callback_mutex_);
00172   transform_callback_ = transform_callback;
00173 }
00174 
00175 mesh_filter::MeshHandle mesh_filter::MeshFilterBase::addMesh (const Mesh& mesh)
00176 {
00177   mutex::scoped_lock _(meshes_mutex_);
00178 
00179   shared_ptr<Job> job (new FilterJob<void> (boost::bind (&MeshFilterBase::addMeshHelper, this, next_handle_, &mesh)));
00180   addJob(job);
00181   job->wait ();
00182   mesh_filter::MeshHandle ret = next_handle_;
00183   const std::size_t sz = min_handle_ + meshes_.size() + 1;
00184   for (std::size_t i = min_handle_ ; i < sz ; ++i)
00185     if (meshes_.find(i) == meshes_.end())
00186     {
00187       next_handle_ = i;
00188       break;
00189     }
00190   min_handle_ = next_handle_;
00191   return ret;
00192 }
00193 
00194 void mesh_filter::MeshFilterBase::addMeshHelper (MeshHandle handle, const Mesh *cmesh)
00195 {
00196   meshes_[handle] = shared_ptr<GLMesh> (new GLMesh (*cmesh, handle));
00197 }
00198 
00199 void mesh_filter::MeshFilterBase::removeMesh (MeshHandle handle)
00200 {
00201   mutex::scoped_lock _(meshes_mutex_);
00202   FilterJob<bool>* remover = new FilterJob<bool> (boost::bind (&MeshFilterBase::removeMeshHelper, this, handle));
00203   shared_ptr<Job> job (remover);
00204   addJob(job);
00205   job->wait ();
00206 
00207   if (!remover->getResult ())
00208     throw std::runtime_error ("Could not remove mesh. Mesh not found!");
00209   min_handle_ = std::min(handle, min_handle_);
00210 }
00211 
00212 bool mesh_filter::MeshFilterBase::removeMeshHelper (MeshHandle handle)
00213 {
00214   std::size_t erased = meshes_.erase (handle);
00215   return (erased != 0);
00216 }
00217 
00218 void mesh_filter::MeshFilterBase::setShadowThreshold (float threshold)
00219 {
00220   shadow_threshold_ = threshold;
00221 }
00222 
00223 void mesh_filter::MeshFilterBase::getModelLabels (LabelType* labels) const
00224 {
00225   shared_ptr<Job> job (new FilterJob<void> (boost::bind (&GLRenderer::getColorBuffer, mesh_renderer_.get(), (unsigned char*) labels)));
00226   addJob(job);
00227   job->wait ();
00228 }
00229 
00230 void mesh_filter::MeshFilterBase::getModelDepth (float* depth) const
00231 {
00232   shared_ptr<Job> job1 (new FilterJob<void> (boost::bind (&GLRenderer::getDepthBuffer, mesh_renderer_.get(), depth)));
00233   shared_ptr<Job> job2 (new FilterJob<void> (boost::bind (&SensorModel::Parameters::transformModelDepthToMetricDepth, sensor_parameters_.get(), depth)));
00234   {
00235     unique_lock<mutex> lock (jobs_mutex_);
00236     jobs_queue_.push (job1);
00237     jobs_queue_.push (job2);
00238   }
00239   jobs_condition_.notify_one();
00240   job1->wait ();
00241   job2->wait ();
00242 }
00243 
00244 void mesh_filter::MeshFilterBase::getFilteredDepth (float* depth) const
00245 {
00246   shared_ptr<Job> job1 (new FilterJob<void> (boost::bind (&GLRenderer::getDepthBuffer, depth_filter_.get(), depth)));
00247   shared_ptr<Job> job2 (new FilterJob<void> (boost::bind (&SensorModel::Parameters::transformFilteredDepthToMetricDepth, sensor_parameters_.get(), depth)));
00248   {
00249     unique_lock<mutex> lock (jobs_mutex_);
00250     jobs_queue_.push (job1);
00251     jobs_queue_.push (job2);
00252   }
00253   jobs_condition_.notify_one();
00254   job1->wait ();
00255   job2->wait ();
00256 }
00257 
00258 void mesh_filter::MeshFilterBase::getFilteredLabels (LabelType* labels) const
00259 {
00260   shared_ptr<Job> job (new FilterJob<void> (boost::bind (&GLRenderer::getColorBuffer, depth_filter_.get(), (unsigned char*) labels)));
00261   addJob(job);
00262   job->wait ();
00263 }
00264 
00265 void mesh_filter::MeshFilterBase::run (const string& render_vertex_shader, const string& render_fragment_shader,
00266                                        const string& filter_vertex_shader, const string& filter_fragment_shader)
00267 {
00268   initialize (render_vertex_shader, render_fragment_shader, filter_vertex_shader, filter_fragment_shader);
00269 
00270   while (!stop_)
00271   {
00272 
00273     unique_lock<mutex> lock (jobs_mutex_);
00274     // check if we have new sensor data to be processed. If not, wait until we get notified.
00275     if (jobs_queue_.empty ())
00276       jobs_condition_.wait (lock);
00277 
00278     if (!jobs_queue_.empty ())
00279     {
00280       shared_ptr<Job> job = jobs_queue_.front ();
00281       jobs_queue_.pop ();
00282       lock.unlock ();
00283       job->execute ();
00284       lock.lock ();
00285     }
00286   }
00287   deInitialize ();
00288 }
00289 
00290 void mesh_filter::MeshFilterBase::filter (const void* sensor_data, GLushort type, bool wait) const
00291 {
00292   if (type != GL_FLOAT && type != GL_UNSIGNED_SHORT)
00293   {
00294     std::stringstream msg;
00295     msg << "unknown type \"" << type << "\". Allowed values are GL_FLOAT or GL_UNSIGNED_SHORT.";
00296     throw std::runtime_error (msg.str ());
00297   }
00298 
00299   shared_ptr<Job> job (new FilterJob<void> (boost::bind (&MeshFilterBase::doFilter, this, sensor_data, type)));
00300   addJob(job);
00301   if (wait)
00302     job->wait ();
00303 }
00304 
00305 void mesh_filter::MeshFilterBase::doFilter (const void* sensor_data, const int encoding) const
00306 {
00307   mutex::scoped_lock _(transform_callback_mutex_);
00308 
00309   mesh_renderer_->begin ();
00310   sensor_parameters_->setRenderParameters (*mesh_renderer_);
00311 
00312   glEnable (GL_TEXTURE_2D);
00313   glEnable (GL_DEPTH_TEST);
00314   glDepthFunc(GL_LESS);
00315   glEnable (GL_CULL_FACE);
00316   glCullFace (GL_FRONT);
00317   glDisable (GL_ALPHA_TEST);
00318   glDisable (GL_BLEND);
00319 
00320   GLuint padding_coefficients_id = glGetUniformLocation (mesh_renderer_->getProgramID (), "padding_coefficients");
00321   Eigen::Vector3f padding_coefficients = sensor_parameters_->getPaddingCoefficients () * padding_scale_ + Eigen::Vector3f (0, 0, padding_offset_);
00322   glUniform3f (padding_coefficients_id, padding_coefficients [0], padding_coefficients [1], padding_coefficients [2]);
00323 
00324   Affine3d transform;
00325   for (std::map<MeshHandle, shared_ptr<GLMesh> >::const_iterator meshIt = meshes_.begin (); meshIt != meshes_.end (); ++meshIt)
00326     if (transform_callback_ (meshIt->first, transform))
00327       meshIt->second->render (transform);
00328 
00329   mesh_renderer_->end ();
00330 
00331   // now filter the depth_map with the second rendering stage
00332   //depth_filter_.setBufferSize (width, height);
00333   //depth_filter_.setCameraParameters (fx, fy, cx, cy);
00334   depth_filter_->begin ();
00335   sensor_parameters_->setFilterParameters (*depth_filter_);
00336   glEnable (GL_TEXTURE_2D);
00337   glEnable (GL_DEPTH_TEST);
00338   glDepthFunc(GL_ALWAYS);
00339   glDisable (GL_CULL_FACE);
00340   glDisable (GL_ALPHA_TEST);
00341   glDisable (GL_BLEND);
00342 
00343 //  glUniform1f (near_location_, depth_filter_.getNearClippingDistance ());
00344 //  glUniform1f (far_location_, depth_filter_.getFarClippingDistance ());
00345   glUniform1f (shadow_threshold_location_, shadow_threshold_);
00346 
00347   GLuint depth_texture = mesh_renderer_->getDepthTexture ();
00348   GLuint color_texture = mesh_renderer_->getColorTexture ();
00349 
00350   // bind sensor depth
00351   glActiveTexture (GL_TEXTURE0);
00352   glBindTexture ( GL_TEXTURE_2D, sensor_depth_texture_ );
00353 
00354   float scale = 1.0 / (sensor_parameters_->getFarClippingPlaneDistance () - sensor_parameters_->getNearClippingPlaneDistance ());
00355 
00356   if (encoding == GL_UNSIGNED_SHORT)
00357     // unsigned shorts shorts will be mapped to the range 0-1 during transfer. Afterwards we can apply another scale + offset to
00358     // map the values between near and far clipping plane to 0 - 1. -> scale = (65535 * depth - near ) / (far - near)
00359     // we have: [0 - 65535] -> [0 - 1]
00360     // we want: [near - far] -> [0 - 1]
00361     glPixelTransferf (GL_DEPTH_SCALE, scale * 65.535);
00362   else
00363     glPixelTransferf (GL_DEPTH_SCALE, scale);
00364   glPixelTransferf (GL_DEPTH_BIAS, -scale * sensor_parameters_->getNearClippingPlaneDistance ());
00365 
00366   glTexImage2D ( GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, sensor_parameters_->getWidth (), sensor_parameters_->getHeight (), 0, GL_DEPTH_COMPONENT, encoding, sensor_data);
00367   glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
00368   glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
00369   glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
00370   glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
00371 
00372   // bind depth map
00373   glActiveTexture (GL_TEXTURE2);
00374   glBindTexture (GL_TEXTURE_2D, depth_texture);
00375 
00376   // bind labels
00377   glActiveTexture (GL_TEXTURE4);
00378   glBindTexture (GL_TEXTURE_2D, color_texture);
00379   glCallList (canvas_);
00380   depth_filter_->end ();
00381 }
00382 
00383 void mesh_filter::MeshFilterBase::setPaddingOffset (float offset)
00384 {
00385   padding_offset_ = offset;
00386 }
00387 
00388 void mesh_filter::MeshFilterBase::setPaddingScale (float scale)
00389 {
00390   padding_scale_ = scale;
00391 }


perception
Author(s): Ioan Sucan , Jon Binney , Suat Gedikli
autogenerated on Wed Aug 26 2015 12:43:21