comthread.cpp
Go to the documentation of this file.
00001 
00047 #include "comthread.h"
00048 #include <ros/ros.h>
00049 #include <QDebug>
00050 #include <QDir>
00051 #include <QPoint>
00052 #include <QImage>
00053 #include <pcl/io/pcd_io.h>
00054 #include <pcl/visualization/cloud_viewer.h>
00055 #include <pcl/filters/passthrough.h>
00056 
00057 #include "re_visionmodelcreator.h"
00058 
00059 ComThread::ComThread(QObject *parent) :
00060         QThread(parent)
00061 {
00062     ros::NodeHandle nh;
00063     sub = nh.subscribe<sensor_msgs::PointCloud2>("resulting_pcl",1,boost::bind(&ComThread::pointCloudReceived,this,_1));
00064     isRecording = false;
00065     npoints = 0;
00066     max_pointclouds = 100;
00067 
00068     cloudViewer = new pcl::visualization::CloudViewer("object point cloud");
00069 }
00070 
00071 ComThread::~ComThread() {
00072     delete cloudViewer;
00073 }
00074 
00075 void ComThread::run() {
00076     ros::Rate r(2);
00077     while (ros::ok() && !cloudViewer->wasStopped()) {
00078         ros::spinOnce();
00079         r.sleep();
00080     }
00081 }
00082 
00083 void ComThread::recording(bool startstop) {
00084     isRecording = startstop;
00085 }
00086 
00087 void ComThread::reset() {
00088     mutex.lock();
00089     npoints = 0;
00090     pcl::PointCloud<PointType> emptycloud;
00091 
00092     for (std::map<int,boost::shared_ptr<pcl::PointCloud<PointType> > >::const_iterator it = pcls.begin(); it != pcls.end(); ++it) {
00093         cloudViewer->showCloud(emptycloud.makeShared(),boost::lexical_cast<std::string>(it->first));
00094     }
00095 
00096     pcls.clear();
00097 
00098     cloudViewer->showCloud(emptycloud.makeShared());
00099 
00100     mutex.unlock();
00101     Q_EMIT newCloudReceived("-");
00102 }
00103 
00104 void ComThread::pointCloudReceived(const sensor_msgs::PointCloud2ConstPtr &pcl_msg) {
00105     ROS_INFO("Received PointCloud");
00106 
00107     boost::shared_ptr<pcl::PointCloud<PointType> > cloud(new pcl::PointCloud<PointType>);
00108     pcl::fromROSMsg(*pcl_msg,*cloud);
00109 
00110     // get camera pose in respect to object
00111     geometry_msgs::PoseStamped origin, markerToRGBCamera;
00112     origin.header.frame_id = pcl_msg->header.frame_id;
00113     origin.header.stamp = pcl_msg->header.stamp;
00114     origin.pose.orientation.w = 1.f;
00115     try {
00116         tf.transformPose("/camera_rgb_optical_frame", origin, markerToRGBCamera);
00117 
00118         cloud->sensor_origin_ = Eigen::Vector4f(markerToRGBCamera.pose.position.x,
00119                                                 markerToRGBCamera.pose.position.y,
00120                                                 markerToRGBCamera.pose.position.z,
00121                                                 0);
00122         cloud->sensor_orientation_ = Eigen::Quaternionf(markerToRGBCamera.pose.orientation.w,
00123                                                         markerToRGBCamera.pose.orientation.x,
00124                                                         markerToRGBCamera.pose.orientation.y,
00125                                                         markerToRGBCamera.pose.orientation.z);
00126     } catch(const std::exception& e) {
00127         ROS_WARN("could not get camera pose: %s", e.what());
00128         return;
00129     }
00130 
00131     if (!isRecording) {
00132         // just make the cloud yellow and display it
00133         BOOST_FOREACH(PointType& pt, cloud->points) {
00134             pt.rgb = 25590;
00135         }
00136         cloudViewer->showCloud(cloud,"current");
00137     } else {
00138         addPointCloud(cloud);
00139     }
00140 }
00141 
00150 int read_binary_PCL(const std::string& filename,  pcl::PointCloud<PointType>::Ptr cloud) {
00151     std::ifstream in_file(filename.c_str());
00152     std::string token("DATA binary\n");
00153 
00154     const size_t BUFFER_SIZE = 4096;
00155     char buffer[BUFFER_SIZE];
00156     in_file.read(buffer, BUFFER_SIZE);
00157     if (in_file.gcount() < BUFFER_SIZE) {
00158         std::cerr << "could not read whole file" << std::endl;
00159         return -1;
00160     }
00161 
00162     bool found_binary = false;
00163     bool null_after_header = false;
00164     size_t matched_chars = 0;
00165     size_t header_length = 0;
00166     for(size_t i=0; i<BUFFER_SIZE; i++) {
00167         if (buffer[i] == token[matched_chars]) {
00168             matched_chars++;
00169         } else
00170             matched_chars = 0;
00171 
00172         if (matched_chars == token.length()) {
00173             found_binary = true;
00174 
00175             header_length = i;
00176             size_t num_nulls = 0;
00177             for(size_t j=header_length+1; j<BUFFER_SIZE; j++) {
00178                 if (buffer[j] == '\0')
00179                     num_nulls++;
00180                 else
00181                     break;
00182             }
00183             null_after_header = num_nulls > 10;
00184             if (null_after_header) {
00185                 std::cout << "null bytes found after header, converting from old PCD binary format" << std::endl;
00186             }
00187             break;
00188         }
00189     }
00190 
00191     std::string tmp_filename;
00192     int temp_file_fd;
00193     if (null_after_header) {
00194         char tmp_name[] = "/tmp/pcd_file_XXXXXX";
00195 
00196         temp_file_fd = mkstemp(tmp_name);
00197         if (temp_file_fd < 0) {
00198             std::cerr << "could not create temporary file" << std::endl;
00199             return -1;
00200         }
00201         tmp_filename = tmp_name;
00202 
00203         std::ofstream tmp_file(tmp_filename.c_str());
00204         tmp_file.write(buffer, header_length+1);
00205 
00206         in_file.seekg(4096, std::ios::beg);
00207         while(in_file.good()) {
00208             in_file.read(buffer, BUFFER_SIZE);
00209             tmp_file.write(buffer, in_file.gcount());
00210         }
00211         in_file.close();
00212         tmp_file.close();
00213         pcl::io::loadPCDFile(tmp_filename, *cloud);
00214         remove(tmp_filename.c_str());
00215     } else {
00216         in_file.close();
00217         // just load it
00218         pcl::io::loadPCDFile(filename, *cloud);
00219     }
00220 
00221     return 0;
00222 }
00223 
00224 void ComThread::loadPointCloud(const QString &filename) {
00225     boost::shared_ptr<pcl::PointCloud<PointType> > cloud(new pcl::PointCloud<PointType>);
00226     // TODO: sensor origin/orientation? base frame?
00227     read_binary_PCL(filename.toStdString(), cloud);
00228     // TODO: move to parameter
00229     cloud->header.frame_id = "/PATTERN_BASE";
00230 
00231     int pcl_id = addPointCloud(cloud);
00232     Q_EMIT addStatusMessage("Loaded '" + filename + "' as scan number " + QString::number(pcl_id) + ".");
00233 }
00234 
00235 int ComThread::addPointCloud(boost::shared_ptr<pcl::PointCloud<PointType> > cloud) {
00236     QMutexLocker lock(&mutex);
00237 
00238     if (pcls.size() >= max_pointclouds) {
00239         Q_EMIT addStatusMessage(QString("Received a new point cloud, but we have already %1 pointclouds! Ignoring this one.").arg(pcls.size()));
00240         return -1;
00241     }
00242 
00243     npoints += cloud->width * cloud->height;
00244 
00245     int count = 0;
00246     while (pcls.find(count) != pcls.end()) {
00247         count ++;
00248     }
00249     pcls.insert(std::make_pair(count, cloud));
00250 
00251     Q_EMIT newCloudReceived(QString::number(count));
00252     cloudViewer->showCloud(cloud,boost::lexical_cast<std::string>(count));
00253     Q_EMIT addStatusMessage("Accumulated " + QString::number(npoints) + " points in " + QString::number(pcls.size()) + " point clouds");
00254     return count;
00255 }
00256 
00257 void ComThread::removeCloud(QStringList ids) {
00258     QMutexLocker lock(&mutex);
00259 
00260     Q_FOREACH(QString id, ids) {
00261         Q_EMIT addStatusMessage("Removing cloud " + id);
00262         if(pcls.find(id.toInt())!=pcls.end()) {
00263             pcls[id.toInt()]->points.clear();
00264             cloudViewer->showCloud(pcls[id.toInt()],id.toStdString());
00265             pcls.erase(pcls.find(id.toInt()));
00266         }
00267     }
00268 }
00269 
00270 void ComThread::selectCloud(QStringList newSelections) {
00271     QMutexLocker lock(&mutex);
00272 
00273     static QStringList alreadySelected;
00274 
00275     QStringList notselectedanymore;
00276     QStringList alreadyselectedandstillis;
00277 
00278     Q_FOREACH(QString id, alreadySelected) {
00279         if (newSelections.contains(id)) {
00280             alreadyselectedandstillis.append(id);
00281             newSelections.removeAll(id);
00282         } else {
00283             notselectedanymore.append(id);
00284         }
00285     }
00286 
00287     Q_FOREACH(QString id, notselectedanymore) {
00288 
00289         if(pcls.find(id.toInt())!=pcls.end()){
00290             cloudViewer->showCloud(pcls[id.toInt()],id.toStdString());
00291         } else {
00292             pcl::PointCloud<PointType> cloud;
00293             cloudViewer->showCloud(cloud.makeShared(),id.toStdString());
00294         }
00295     }
00296 
00297     Q_FOREACH(QString id, newSelections) {
00298         pcl::PointCloud<PointType> copy;
00299         if(pcls.find(id.toInt())!=pcls.end()){
00300             copy = *pcls[id.toInt()];
00301             BOOST_FOREACH(PointType& pt, copy.points) {
00302                 pt.rgb = 255;
00303             }
00304         }
00305         cloudViewer->showCloud(copy.makeShared(),id.toStdString());
00306     }
00307 
00308     alreadySelected = newSelections;
00309     alreadySelected.append(alreadyselectedandstillis);
00310 }
00311 
00312 void ComThread::getMergedPointCloud(pcl::PointCloud<PointType> &merged_pcl) {
00313     merged_pcl.points.clear();
00314     for (std::map<int,boost::shared_ptr<pcl::PointCloud<PointType> > >::const_iterator it = pcls.begin(); it != pcls.end(); ++it) {
00315         pcl::PointCloud<PointType> cleaned_cloud;
00316 
00317         pcl::PassThrough<PointType> nan_remover;
00318         nan_remover.setInputCloud(it->second);
00319         nan_remover.setFilterFieldName("z");
00320         nan_remover.setFilterLimits(0.0, 10.0);
00321         nan_remover.filter(cleaned_cloud);
00322 
00323         if (!merged_pcl.points.size())
00324             merged_pcl = cleaned_cloud;
00325         else
00326             merged_pcl += cleaned_cloud;
00327     }
00328 }
00329 
00330 void ComThread::saveMergedPCL(QString filename) {
00331     pcl::PointCloud<PointType> mergedpcls;
00332     getMergedPointCloud(mergedpcls);
00333 
00334     pcl::io::savePCDFileBinary(filename.toStdString(), mergedpcls);
00335 }
00336 
00337 void ComThread::saveFaces(QDir model_dir) {
00338     int i=0;
00339     for (std::map<int,boost::shared_ptr<pcl::PointCloud<PointType> > >::const_iterator it = pcls.begin(); it != pcls.end(); ++it, ++i) {
00340         QString recording = QString("dense_face_%1.pcd").arg(i, 3, 10, QChar('0'));
00341         QString recording_file = model_dir.absoluteFilePath(recording);
00342 
00343         pcl::io::savePCDFileBinary(recording_file.toStdString(), *it->second);
00344     }
00345 }
00346 
00347 void ComThread::changedBoxSize(double size) {
00348     pcl::PointXYZ minp(-size,-size,.01);
00349     pcl::PointXYZ maxp(size,size,2*size+.01);
00350 
00351     pcl::PointCloud<pcl::PointXYZ> boundingboxcloud;
00352     boundingboxcloud.push_back(pcl::PointXYZ(minp.x,minp.y,minp.z));
00353     boundingboxcloud.push_back(pcl::PointXYZ(minp.x,maxp.y,minp.z));
00354     boundingboxcloud.push_back(pcl::PointXYZ(minp.x,minp.y,maxp.z));
00355     boundingboxcloud.push_back(pcl::PointXYZ(minp.x,maxp.y,maxp.z));
00356 
00357     boundingboxcloud.push_back(pcl::PointXYZ(maxp.x,minp.y,minp.z));
00358     boundingboxcloud.push_back(pcl::PointXYZ(maxp.x,maxp.y,minp.z));
00359     boundingboxcloud.push_back(pcl::PointXYZ(maxp.x,minp.y,maxp.z));
00360     boundingboxcloud.push_back(pcl::PointXYZ(maxp.x,maxp.y,maxp.z));
00361     cloudViewer->showCloud(boundingboxcloud.makeShared(), "boundingbox");
00362 }
00363 
00364 void ComThread::createRe_visionModel(QDir &parent_dir, const QString& model_name) {
00365     QMutexLocker lock(&mutex);
00366 
00367     std::vector<boost::shared_ptr<pcl::PointCloud<PointType> > >  vec;
00368     for (std::map<int,boost::shared_ptr<pcl::PointCloud<PointType> > >::const_iterator it = pcls.begin(); it != pcls.end(); ++it) {
00369         vec.push_back(it->second);
00370     }
00371 
00372     pcl::PointCloud<PointType> merged_pcl;
00373     getMergedPointCloud(merged_pcl);
00374 
00375     re_visionModelCreator zmg(vec);
00376     zmg.createModel(parent_dir, merged_pcl, model_name);
00377 }
00378 
00379 void ComThread::createKinectModel(QDir &parent_dir, const QString &model_name) {
00380     QMutexLocker lock(&mutex);
00381 
00382     QString merged_file = parent_dir.absoluteFilePath("merged.pcd");
00383     qDebug() << "saving merged.pcd";
00384     saveMergedPCL(merged_file);
00385     qDebug() << "saving faces";
00386     saveFaces(parent_dir);
00387 
00388     qDebug() << "creating meta file";
00389     re_visionModelCreator::createMetaFile(parent_dir, model_name, "kinect_pcl", pcls.size(), 1);
00390 }
00391 
00392 void ComThread::maxScanNumberChanged(int value) {
00393     max_pointclouds = value;
00394 }
00395 
00396 void ComThread::markerSizeChanged(double value)
00397 {
00398   ros::param::set("/marker_size", value);
00399   return;
00400 }
00401 
00402 void ComThread::markerSpacingChanged(double value)
00403 {
00404   ros::param::set("/marker_spacing", value);
00405   return;
00406 }
00407 
00408 bool ComThread::createPreview(QDir& model_dir) {
00409     QMutexLocker lock(&mutex);
00410 
00411     size_t max_area = 0;
00412     boost::shared_ptr<pcl::PointCloud<PointType> > best_face;
00413     QPoint best_minp, best_maxp;
00414 
00415     // iterate through all faces and find biggest possible preview
00416     for (std::map<int,boost::shared_ptr<pcl::PointCloud<PointType> > >::const_iterator it = pcls.begin(); it != pcls.end(); ++it) {
00417         const pcl::PointCloud<PointType>& pcl = *it->second;
00418         size_t i=0;
00419         QPoint minp, maxp;
00420         minp.setX(pcl.width);
00421         minp.setY(pcl.height);
00422         for (size_t u = 0; u < pcl.height; ++u)
00423         {
00424             for (size_t v = 0; v < pcl.width; ++v, ++i)
00425             {
00426                 // If the point is invalid (i.e. belongs to background)
00427                 if (!(isnan (pcl.points[i].x) || isnan (pcl.points[i].y) || isnan (pcl.points[i].z))) {
00428                     if (v < minp.x())
00429                         minp.setX(v);
00430                     if (v > maxp.x())
00431                         maxp.setX(v);
00432                     if (u < minp.y())
00433                         minp.setY(u);
00434                     if (u > maxp.y())
00435                         maxp.setY(u);
00436                 }
00437             }
00438         }
00439 
00440         size_t area = (maxp.x() - minp.x() +1) * (maxp.y() - minp.y()+1);
00441         if (area > max_area) {
00442             max_area = area;
00443             best_face = it->second;
00444             best_minp = minp;
00445             best_maxp = maxp;
00446         }
00447     }
00448 
00449     if (max_area < 100)
00450         return false;
00451 
00452     const pcl::PointCloud<PointType>& pcl = *best_face;
00453     QImage img_color(best_maxp.x() - best_minp.x() +1, best_maxp.y() - best_minp.y()+1, QImage::Format_RGB32);
00454     size_t i = 0;
00455 
00456     for (size_t u = 0; u < pcl.height; ++u)
00457     {
00458         for (size_t v = 0; v < pcl.width; ++v, ++i)
00459         {
00460             if ((u >= best_minp.y()) && (u <= best_maxp.y()) &&
00461                     (v >= best_minp.x()) && (v <= best_maxp.x())) {
00462                 int32_t rgb = *(int32_t*)(&pcl.points[i].rgb);
00463                 char b = rgb & 0xFF;
00464                 char g = (rgb & (0xFF << 8)) >> 8;
00465                 char r = (rgb & (0xFF << 16)) >> 16;
00466 
00467                 img_color.setPixel(v - best_minp.x(), u - best_minp.y(), qRgb(r, g, b));
00468             }
00469         }
00470     }
00471 
00472     return img_color.save(model_dir.filePath("preview.png"));
00473 }


re_object_recorder
Author(s): Andreas Koch
autogenerated on Sun Jan 5 2014 11:39:12