[kinect]地面信息提取算法

created by Dejavu
(不断更新中)


  • 简介

地面信息的提取对于车形的智能机器人来说十分重要,之前一直采用双目视觉来绘制周边环境的三维点云,但是由于双目视觉两个CCD摄像头采集速率无法做到绝对的同步,所以在动态计算的过程中难免会出现较大的重建误差,所以现在采用了kinect来做动态的重建工作。
这里的算法在kinect处于静态的环境下,且kinect水平面与地面呈(0~45°)之间时,算法的地面提取效果最佳,由于对于动态精度较高的slam算法还在学习中,这里的算法只做学习用,有很多优化还没做,在ubuntu下运行大概是10fps的样子。

点云导入octovis后的3D图
地面三维坐标二维化并且做简单的slam拼合
  • 用到的库和算法

(有空补齐)

  • c++代码

  • imgStream.h --- 包含kinect驱动部分代码,一些基本的空间运算方法
    #ifndef _IMGSTREAM_H
    #define _IMGSTREAM_H

     #include "libfreenect.hpp"
     #include <iostream>
     #include <vector>
     #include <cmath>
     #include <pthread.h>
     #include <opencv2/opencv.hpp>
    
     using namespace std;
    
     #define COLS 640
     #define ROWS 480
     #define INDEX(pt,xoffset,yoffset) depthIndex[pt.x+xoffset+(pt.y+yoffset)*COLS]
    
     typedef unsigned short US;
    
     class Mutex
     {
     public:
         Mutex()
         {
             pthread_mutex_init(&m_mutex, NULL);
         }
    
         void lock()
         {
             pthread_mutex_lock(&m_mutex);
         }
    
         void unlock()
         {
             pthread_mutex_unlock(&m_mutex);
         }
    
         class ScopedLock
         {
         public:
             ScopedLock(Mutex &mutex) : _mutex(mutex)
             {
                 _mutex.lock();
             }
    
             ~ScopedLock()
             {
                 _mutex.unlock();
             }
    
         private:
             Mutex &_mutex;
         };
    
     private:
         pthread_mutex_t m_mutex;
     };
    
     class MyFreenectDevice : public Freenect::FreenectDevice
     {
    
     public:
         MyFreenectDevice(freenect_context *_ctx, int _index)
             : Freenect::FreenectDevice(_ctx, _index),
             rgbMat(cv::Size(640, 480), CV_8UC3, cv::Scalar::all(0)),
             depthMat(cv::Size(640, 480), CV_16UC1),
             m_new_rgb_frame(false), m_new_depth_frame(false)
         {
             setDepthFormat(FREENECT_DEPTH_REGISTERED);
         }
    
         // Do not call directly, even in child
         void VideoCallback(void *_rgb, uint32_t timestamp)
         {
             Mutex::ScopedLock lock(m_rgb_mutex);
             uint8_t* rgb = static_cast<uint8_t*>(_rgb);
             rgbMat.data = rgb;
             m_new_rgb_frame = true;
         }
         // Do not call directly, even in child
         void DepthCallback(void *_depth, uint32_t timestamp)
         {
             Mutex::ScopedLock lock(m_depth_mutex);
             uint16_t* depth = static_cast<uint16_t*>(_depth);
             depthMat.data = (uchar*)depth;
             m_new_depth_frame = true;
         }
    
         bool getRGB(cv::Mat &buffer)
         {
             Mutex::ScopedLock lock(m_rgb_mutex);
    
             if (!m_new_rgb_frame)
                 return false;
    
             cv::cvtColor(rgbMat, buffer, CV_RGB2BGR);
             m_new_rgb_frame = false;
    
             return true;
         }
    
         bool getDepth(cv::Mat &buffer)
         {
             Mutex::ScopedLock lock(m_depth_mutex);
    
             if (!m_new_depth_frame)
                 return false;
    
             buffer = depthMat.clone();
             m_new_depth_frame = false;
    
             return true;
         }
    
     private:
         Mutex m_rgb_mutex;
         Mutex m_depth_mutex;
         cv::Mat rgbMat;
         cv::Mat depthMat;
         bool m_new_rgb_frame;
         bool m_new_depth_frame;
     };
    
     struct DepthIndex {
         cv::Point cameraPt;
         cv::Point3f worldPt;
         cv::Vec3b color;
         int planeFlags;
         bool isGnd;
     };
    
     struct DataStream {
         cv::Mat color;
         cv::Mat depth;
     };
    
     class CameraData {
     public:
         static const float fx = 594.21f;
         static const float fy = 591.04f;
         static const float cx = 339.5f;
         static const float cy = 242.7f;
     };
    
     cv::Point3f depth_to_world(int camerax, int cameray, int depth) {
         float f = 595.f;
         return cv::Point3f((camerax - (640 - 1) / 2.f)*depth / f, (cameray - (480 - 1) / 2.f)*depth / f, depth);
     }
    
     double a,b,c,d;
     double staticA,staticB,staticC;
     float gnd_camera_pitch,gnd_camera_roll,gnd_camera_yaw;
     //typical plane ax+by+cz+d=0
     bool get_param(cv::Point3f p1, cv::Point3f p2, cv::Point3f p3) {
         if ((p1.x*p2.y - p2.x*p1.y) + (p1.y*p2.z - p2.y*p1.z) + (p1.z*p2.x - p2.z*p1.x) == 0)
             return false;
         a = ((p2.y - p1.y)*(p3.z - p1.z) - (p2.z - p1.z)*(p3.y - p1.y));
         b = ((p2.z - p1.z)*(p3.x - p1.x) - (p2.x - p1.x)*(p3.z - p1.z));
         c = ((p2.x - p1.x)*(p3.y - p1.y) - (p2.y - p1.y)*(p3.x - p1.x));
         d = -(a*p1.x + b*p1.y + c*p1.z);
         return true;
     }
    
     double get_distance(cv::Point3f pt) {
         return abs(a*pt.x + b*pt.y + c*pt.z + d) / sqrt(a*a + b*b + c*c);
     }
    
     double get_2d_pt2pt_distance(cv::Point p1, cv::Point p2) {
         return sqrt((p1.x - p2.x)*(p1.x - p2.x) + (p1.y - p2.y)*(p1.y - p2.y));
     }
    
     void get_cross(cv::Point p1, cv::Point p2, float &line_k, float &line_offset) {
         line_k = -1 / ((p1.y - p2.y) / (p1.x - p2.x));
         line_offset = (p2.y + p1.y) / 2.0 - line_k*(p2.x + p1.x) / 2.0;
     }
    
     #endif
    
  • rotateQuater.h --- 四元数旋转用到的一些函数
    #ifndef _ROTATEQUATER_H
    #define _ROTATEQUATER_H

     #include <iostream>
     #include <math.h>
     #include <opencv2/opencv.hpp>
    
     struct Quater {
         double t;
         double x;
         double y;
         double z;
     };
    
     struct rotateAction {
         cv::Point3f vec;
         double radian;
     };
    
     Quater cross(Quater l, Quater r) {
         Quater ans;
         double d1, d2, d3, d4;
    
         d1 = l.t*r.t;
         d2 = -l.x*r.x;
         d3 = -l.y*r.y;
         d4 = -l.z*r.z;
         ans.t = d1 + d2 + d3 + d4;
    
         d1 = l.t*r.x;
         d2 = l.x*r.t;
         d3 = l.y*r.z;
         d4 = -l.z*r.y;
         ans.x = d1 + d2 + d3 + d4;
    
         d1 = l.t*r.y;
         d2 = l.y*r.t;
         d3 = l.z*r.x;
         d4 = -l.x*r.z;
         ans.y = d1 + d2 + d3 + d4;
    
         d1 = l.t*r.z;
         d2 = l.z*r.t;
         d3 = l.x*r.y;
         d4 = -l.y*r.x;
         ans.z = d1 + d2 + d3 + d4;
         return ans;
     }
    
     rotateAction getGndVector(cv::Point3f vec) {
         cv::Point3f GND = cv::Point3f(0, 1, 0);
    
         rotateAction data;
         data.vec.x = GND.y*vec.z - GND.z*vec.y;
         data.vec.y = GND.z*vec.x - GND.x*vec.z;
         data.vec.z = GND.x*vec.y - GND.y*vec.x;
    
         data.radian = 90 * 3.1415926 / 180.0 - acos(vec.z / sqrt(vec.x*vec.x + vec.y*vec.y + vec.z*vec.z));
    
         return data;
     }
    
     Quater rotationalQuater(double radian, cv::Point3f axis) {
         Quater ans;
         double norm;
         double tmp_sin;
    
         norm = axis.x*axis.x + axis.y*axis.y + axis.z*axis.z;
         if (norm <= 0.0) return ans;
    
         norm = 1.0 / sqrt(norm);
         axis.x *= norm;
         axis.y *= norm;
         axis.z *= norm;
    
         tmp_sin = sin(0.5*radian);
    
         ans.t = cos(0.5*radian);
         ans.x = tmp_sin*axis.x;
         ans.y = tmp_sin*axis.y;
         ans.z = tmp_sin*axis.z;
    
         return ans;
     }
    
     cv::Point3f rotate(Quater quater[], cv::Point3f pt) {
         Quater quater_pt;
         quater_pt.t = 0.0;
         quater_pt.x = pt.x;
         quater_pt.y = pt.y;
         quater_pt.z = pt.z;
    
         Quater tmp = cross(quater[1], quater_pt);
         tmp = cross(quater_pt, quater[0]);
    
         cv::Point3f data;
         data.x = tmp.x;
         data.y = tmp.y;
         data.z = tmp.z;
         return data;
     }
    
     #endif
    
  • uhoo_cloud.h --- 一些三维点云处理的函数
    #ifndef _UHOO_CLOUD_H
    #define _UHOO_CLOUD_H

     #include "uhoo_tools.h"
     #include "imgStream.h"
     #include "rotateQuater.h"
     #include <vector>
     #include <pcl/common/transforms.h>
     #include <pcl/io/pcd_io.h>
     #include <Eigen/Core>
     #include <Eigen/Geometry>
     #include <opencv2/core/eigen.hpp>
     #include <octomap/octomap.h>
    
     #define ROBOT_HEIGHT 200.0
     #define ROBOT_WIDTH  150.0
    
     class DataStruct {
     public:
         DepthIndex *depthInfo;
         DataStream dataStream;
     };
    
     pcl::PointCloud<pcl::PointXYZRGBA>::Ptr worldPt2cloud(DataStruct data) {
         pcl::PointCloud<pcl::PointXYZRGBA>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZRGBA>);
         int cnt = 0;
         for(int y=0;y<ROWS;y++)
             for(int x=0;x<COLS;x++) {
                 int index = x+y*COLS;
                 cv::Point3f pt = data.depthInfo[index].worldPt;
                 if(pt.z == 0) continue;
                 //cv::Vec3b color = data.dataStream.color.at<cv::Vec3b>(y,x);
                 pcl::PointXYZRGBA p;
                 p.x = pt.x;
                 p.y = pt.y;
                 p.z = pt.z;
                 if( data.depthInfo[index].isGnd ){
                     p.b = 255;
                     p.g = 0;
                     p.r = 0;
                     cnt++;
                 }
                 else {
                     p.b = 0;
                     p.g = 150;
                     p.r = 50;
                 }
                 cloud->points.push_back(p);
             }
         std::cout<<"src gnd cnt:"<<cnt<<std::endl;
         cloud->height = 1;
         cloud->width = cloud->points.size();
         cloud->is_dense = false;
    
         return cloud;
     }
    
     pcl::PointCloud<pcl::PointXYZRGBA>::Ptr gnd2cloud(pcl::PointCloud<pcl::PointXYZRGBA>::Ptr cloud) {
         pcl::PointCloud<pcl::PointXYZRGBA>::Ptr gndCloud(new pcl::PointCloud<pcl::PointXYZRGBA>);
         int cnt = 0;
         for(int i=0;i<cloud->points.size();i++) if(cloud->points[i].b == 255) {
             gndCloud->points.push_back(cloud->points[i]);
             cnt++;
         }
    
         std::cout<<"cnt:"<<cnt<<std::endl;
         gndCloud->height = 1;
         gndCloud->width = cnt;
         gndCloud->is_dense = false;
    
         return gndCloud;
     }
    
     void colorToPlane(cv::Mat rgb) {
             cv::Mat color(ROWS,COLS,CV_8UC3,cv::Scalar::all(0));
             //jump = 17
    
             for(int y=0;y<ROWS;y++)
                     for(int x=0;x<COLS;x++) if( INDEX(cv::Point(x,y),0,0).isGnd)
                 color.at<cv::Vec3b>(y,x) = cv::Vec3b(150,50,20);
         cv::addWeighted(color,0.5,rgb,0.5,0,color);
             cv::imshow("color",color);
     }
    
     cv::Vec3f matrix2angle(cv::Mat R) {
         cv::Vec3f angle;
         if(abs(R.at<float>(2,0)) != 1) {
                     angle[0] = -asin(R.at<float>(2,0));
                     angle[1] = atan2(R.at<float>(2,1)/cos(angle[0]),
                                      R.at<float>(2,2)/cos(angle[0]));
                     angle[2] = atan2(R.at<float>(1,0)/cos(angle[0]),
                                      R.at<float>(0,0)/cos(angle[0]));
             }
             else {
                     angle[2] = 0;
                     if(R.at<float>(2,0) == -1) {
                             angle[0] = PI/2;
                             angle[1] = angle[2]+atan2(R.at<float>(0,1),
                                                       R.at<float>(0,2));
                     }
                     else {
                             angle[0] = -PI/2;
                             angle[1] = -angle[2]+atan2(-R.at<float>(0,1),
                                                        -R.at<float>(0,2));
                     }
             }
         for(int i=0;i<3;i++) angle[i] = angle[i]*180/PI;
             return angle;
     }
    
     void translate2gnd(pcl::PointCloud<pcl::PointXYZRGBA>::Ptr &currentCloud) {
         // take gnd -> combine them to one -> set range -> 空洞矩形,宁可多取不可少取
         rotateAction vec = getGndVector(cv::Point3f(staticA,staticB,staticC));
         Quater quater[2];
    
         quater[0] = rotationalQuater(vec.radian,vec.vec);
         quater[1] = rotationalQuater(-vec.radian,vec.vec);
    
         for(int i=0;i<currentCloud->points.size();i++) {
             cv::Point3f pt;
             pt = rotate(quater,cv::Point3f(currentCloud->points[i].x,currentCloud->points[i].y,currentCloud->points[i].z));
             currentCloud->points[i].x = pt.x;
             currentCloud->points[i].y = pt.y;
             currentCloud->points[i].z = pt.z;
         }
     }
    
     double pos(0);
     void initCloud(pcl::PointCloud<pcl::PointXYZRGBA>::Ptr output) {
         bool calcStart(false);
         for(int i=0;i<output->points.size()*0.3;i++) {
             double data = output->points[random()%output->points.size()].y;
             pos += data;
             if(calcStart) pos /= 2;
             else calcStart = true;
         }
         std::cout<<"---->pos:"<<pos<<std::endl;
     }
    
     cv::Mat gnd2img(pcl::PointCloud<pcl::PointXYZRGBA>::Ptr cloud) {
         int z_min=9999,z_max=-9999,x_min=9999,x_max=-9999;
         std::cout<<"gnd2img init...."<<std::endl;
         for(int i = 0; i<cloud->points.size(); i++) {
             pcl::PointXYZRGBA pt = cloud->points[i];
             if(pt.z > z_max) z_max = pt.z;
             if(pt.z < z_min) z_min = pt.z;
             if(pt.x > x_max) x_max = pt.x;
             if(pt.x < x_min) x_min = pt.x;
         }
    
         std::cout<<"max//min:"<<x_max<<","<<z_max<<"//"<<x_min<<","<<z_min<<std::endl;
         cv::Mat map(cv::Size(int(abs(x_max-x_min)),int(abs(z_max-z_min))),CV_8UC3,cv::Scalar(255,255,255));
         for(int i=0;i<cloud->points.size();i++) {
             pcl::PointXYZRGBA pt = cloud->points[i];
             //map.at<uchar>(int(pt.z-z_min),int(pt.x-x_min)) = 100;
             circle(map,cv::Point(int(pt.x-x_min),int(pt.z-z_min)),4,cv::Scalar(0,200,50),-1);
         }
         cv::resize(map,map,cv::Size(map.cols/4,map.rows/4));
         cv::imwrite("uhoo_frist_map'_'.jpg",map);
         return map;
     }
    
     bool combine(pcl::PointCloud<pcl::PointXYZRGBA>::Ptr currentCloud,pcl::PointCloud<pcl::PointXYZRGBA>::Ptr &output) {
         bool calcStart(false);
         double pos_now(0);
    
         cv::Mat map_part;
    
         for(int i=0;i<currentCloud->points.size()*0.3;i++) {
                     pos_now += currentCloud->points[i].y;
                     if(calcStart) pos_now /= 2;
                     else calcStart = true;
             }
    
         int move_pos = pos - pos_now;
    
         std::cout<<"pos,pos_now,move_pos:"<<pos<<","<<pos_now<<","<<move_pos<<std::endl;
         if(abs(move_pos) > 300) return false;
         if(move_pos < 25 && move_pos > -25) {
             *output += *currentCloud;
             map_part = gnd2img(output);
             cv::imshow("map",map_part);
             return true;
         } else {
             for(int i=0;i<currentCloud->points.size();i++)
                 currentCloud->points[i].y += move_pos;
             *output += *currentCloud;
             map_part = gnd2img(output);
             cv::imshow("map",map_part);
             return true;
         }
     }
    
     bool bf_match(DataStruct dataStruct[],pcl::PointCloud<pcl::PointXYZRGBA>::Ptr &output,int dist_norm_l2) {
         cv::Mat img[4];
         img[0] = dataStruct[0].dataStream.color;
         img[1] = dataStruct[1].dataStream.color;
         if(img[0].empty() || img[1].empty()) return false;
    
         std::vector<cv::KeyPoint> kp[2];
         cv::Mat im[2];
         cv::OrbFeatureDetector ofd;
         cv::OrbDescriptorExtractor ode;
    
         cout<<"obj create done !"<<endl;
    
         for(int i=0;i<2;i++) {
             cv::blur(img[i],img[i],cv::Size(3,3));
             cv::cvtColor(img[i],img[i+2],CV_BGR2GRAY);
             ofd.detect(img[i+2],kp[i]);
             ode.compute(img[i+2],kp[i],im[i]);
             if(im[i].empty() || img[i+2].empty()) return false;
         }
         cv::BFMatcher matcher(cv::NORM_L2);
         std::vector<cv::DMatch> matches;
         std::cout<<"create val ok"<<std::endl;
         matcher.match(im[0],im[1],matches);
         std::cout<<"matches size: "<<matches.size()<<std::endl;
         if(matches.size() < 2) return false;
    
         std::vector<cv::DMatch> goodMatches;
         double minDist = 9999;
         for(int i=0;i<matches.size();i++) if(matches[i].distance != 0 && matches[i].distance < minDist)
             minDist = matches[i].distance;
    
         for(int i=0;i<matches.size();i++) if(matches[i].distance < dist_norm_l2*minDist)
             goodMatches.push_back(matches[i]);
         std::cout<<"goodMatches size: "<<goodMatches.size()<<std::endl;
         if(goodMatches.size() < 3) return false;
    
         cv::Mat dst;
         cv::drawMatches(img[0],kp[0],img[1],kp[1],goodMatches,dst);
         cv::imshow("dst",dst);
    
         std::vector<cv::Point3f> wpt;
         std::vector<cv::Point2f> cpt;
         for(int i=0;i<goodMatches.size();i++) {
             cv::Point2f p = kp[0][goodMatches[i].queryIdx].pt;
             cv::Point pt = cv::Point(p.x,p.y);
             if(INDEX(pt,0,0).worldPt.z == 0) continue;
             cpt.push_back(cv::Point2f(kp[1][goodMatches[i].trainIdx].pt));
             wpt.push_back(INDEX(pt,0,0).worldPt);
         }
         if(wpt.size() < 2) return false;
    
         CameraData cameraData;
    
         double camera_matrix_data[3][3] = {
             {cameraData.fx,0,cameraData.cx},
             {0,cameraData.fy,cameraData.cy},
             {0,0,1}
         };
         cv::Mat cameraMatrix(3,3,CV_64F,camera_matrix_data);
         cv::Mat rvec,tvec,inliers;
    
         cv::solvePnPRansac(wpt,cpt,cameraMatrix,cv::Mat(),rvec,tvec,false,100,1.0,100,inliers);
    
         for(int i=0;i<3;i++) if( abs(tvec.at<double>(0,i)) > 200 || abs(rvec.at<double>(0,i)) > 200 )
                     return false;
    
         std::cout<<"inliers: "<<inliers.rows<<std::endl;
         std::cout<<"R="<<rvec<<std::endl;
         std::cout<<"T="<<tvec<<std::endl;
    
         cv::Mat R;
         Eigen::Matrix3d r;
    
         cv::Rodrigues(rvec,R);
         cv::cv2eigen(R,r);
    
         Eigen::Isometry3d T = Eigen::Isometry3d::Identity();
         Eigen::AngleAxisd angle(r);
         Eigen::Translation<double,3> trans(tvec.at<double>(0,0),tvec.at<double>(0,1),tvec.at<double>(0,2));
         T = angle;
    
         // 012 021 102 120 201 210
    
         T(0,3) = tvec.at<double>(0,1);
         T(1,3) = tvec.at<double>(0,2);
         T(2,3) = tvec.at<double>(0,0);
    
         pcl::PointCloud<pcl::PointXYZRGBA>::Ptr currentCloud = worldPt2cloud(dataStruct[0]);
         pcl::PointCloud<pcl::PointXYZRGBA>::Ptr currentGnd = gnd2cloud(currentCloud);
    
         pcl::transformPointCloud( *currentGnd, *currentGnd, T.matrix() );
         translate2gnd(currentGnd);
         if(!combine(currentGnd,output)) std::cout<<"failed to combine"<<std::endl;
    
         //pcl::io::savePCDFileASCII("./pcd/cloud_final_gnd.pcd",*output);
    
         std::cout<<"done!"<<std::endl;
         return true;
     }
    
     #endif
    
  • uhoo_tools.h -- 在重建的三维坐标提取地面信息用到的函数
    #ifndef _UHOO_TOOLS_H
    #define _UHOO_TOOLS_H

     #include "imgStream.h"
     #include <sys/time.h>
    
     #define PI 3.14159
    
     #define COLS 640
     #define ROWS 480
    
     DepthIndex depthIndex[COLS*ROWS];
     DepthIndex gndCandidate[COLS*ROWS];
     DepthIndex depthIndex_previous[COLS*ROWS];
     DepthIndex ydepthIndex[COLS*ROWS];
     DepthIndex radixArrays[10][COLS*ROWS];
    
     int GetNumInPos(int num,int pos)
     {
             int temp = 1;
             for (int i = 0; i < pos - 1; i++)
                     temp *= 10;
    
             return (num / temp) % 10;
     }
    
     void get_angle() {
             gnd_camera_pitch = atan2(c,b)*180.0/PI;
             gnd_camera_roll = atan2(b,a)*180.0/PI;
             gnd_camera_yaw = atan2(c,a)*180.0/PI;
             //std::cout<<"[/] vector: ["<<a<<","<<b<<","<<c<<","<<d<<" ]"<<std::endl;
             //std::cout<<"[/] angle:  ["<<gnd_camera_pitch<<","<<gnd_camera_roll<<","<<gnd_camera_yaw<<"]"<<std::endl;
     }
    
     bool isGnd_angle(int pitchSet,int rollSet,int yawSet) {
             get_angle();
             bool is_gnd_pitch = ((gnd_camera_pitch < pitchSet && gnd_camera_pitch > 0) || (gnd_camera_pitch < -180+pitchSet && gnd_camera_pitch > -180));
             bool is_gnd_roll = ((gnd_camera_roll < 180-rollSet && gnd_camera_roll > rollSet) || (gnd_camera_roll < -rollSet && gnd_camera_roll > -180+rollSet));
             bool is_gnd_yaw = ((gnd_camera_yaw < 180-yawSet && gnd_camera_yaw > yawSet) || (gnd_camera_yaw < -yawSet && gnd_camera_yaw > -180+yawSet));
             //std::cout<<"[+] bool:  ["<<is_gnd_pitch<<","<<is_gnd_roll<<","<<is_gnd_yaw<<"]"<<std::endl;
             return (is_gnd_pitch && is_gnd_roll && is_gnd_yaw);
     }
    
     bool find_gnd(DataStream dataStream,int minDist,int pitchSet,int rollSet,int yawSet) {
    
         cv::Mat depthMat = dataStream.depth;
             //cv::Mat show_all(ROWS,COLS,CV_8UC3,cv::Scalar::all(0));
             int ylistCnt = 0;
             for(int y=0;y<ROWS;y++)
                     for(int x=0;x<COLS;x++) {
                             int ind = COLS*y+x;
                             depthIndex[ind].worldPt = depth_to_world(x,y,depthMat.at<unsigned short>(y,x));
                             depthIndex[ind].cameraPt = cv::Point(x,y);
                 depthIndex[ind].color = dataStream.color.at<cv::Vec3b>(y,x);
                             depthIndex[ind].planeFlags = ind;
                             depthIndex[ind].isGnd = false;
                             if( depthIndex[ind].worldPt.y > 0 ){
                                     ydepthIndex[ylistCnt] = depthIndex[ind];
                                     ylistCnt++;
                             }
                     }
    
             //基数排序 awesome !!!!
             for (int i = 0; i < 10; i++)
                     radixArrays[i][0].worldPt = cv::Point3f(0,0,0);    //index为0处记录这组数据的个数
    
             for (int pos = 1; pos <= 4; pos++)
             {
                     for (int i = 0; i < ylistCnt; i++)
                     {
                             int pty = abs(ydepthIndex[i].worldPt.y);
                             int num = GetNumInPos(pty, pos);
                             int ptytmp = radixArrays[num][0].worldPt.y;
                             int index = ++ptytmp;
                             radixArrays[num][0].worldPt.y = ptytmp;
                             radixArrays[num][index] = ydepthIndex[i];
                     }
    
                     for (int i = 0, j =0; i < 10; i++)
                     {
                             for (int k = 1; k <= (int)radixArrays[i][0].worldPt.y; k++)
                                     ydepthIndex[j++] = radixArrays[i][k];
                             radixArrays[i][0].worldPt = cv::Point3f(0,0,0);
                     }
             }
    
             int gnd = ydepthIndex[ylistCnt-50].worldPt.y;
             int candidateCnt = 0;
             for(int i=0;i<COLS*ROWS;i++) if(depthIndex[i].worldPt.y > gnd - 25) {
                     gndCandidate[candidateCnt] = depthIndex[i];
                     candidateCnt++;
                     //cv::circle(show_all,gndCandidate[candidateCnt].cameraPt,2,cv::Scalar(0,200,150));
             }
             //std::cout<<"candidateCnt: "<<candidateCnt<<std::endl;
    
         if(candidateCnt < 50) return false;
    
             cv::Point planePt[4];
             cv::Point3f planeWPt[4];
             int ptCnt(0);
             vector<float> va,vb,vc,vd;
             for(int i=1;i<10;i++) {
                     bool badPt(false),GoodPt(false);
                     bool isCheck[] = {false,false,false,false};
                     int where = rand()%candidateCnt;
                     DepthIndex randomCandidate = gndCandidate[where];
                     //std::cout<<"where: "<<where<<"  Pt:"<<randomCandidate.cameraPt<<std::endl;
                     int b1 = randomCandidate.cameraPt.y-randomCandidate.cameraPt.x;
                     int b2 = randomCandidate.cameraPt.y+randomCandidate.cameraPt.x;
                     planePt[0] = cv::Point(randomCandidate.cameraPt.x+minDist,randomCandidate.cameraPt.x+minDist+b1);
                     planePt[1] = cv::Point(randomCandidate.cameraPt.x-minDist,randomCandidate.cameraPt.x-minDist+b1);
                     planePt[2] = cv::Point(randomCandidate.cameraPt.x-minDist,-randomCandidate.cameraPt.x+minDist+b2);
                     planePt[3] = cv::Point(randomCandidate.cameraPt.x+minDist,-randomCandidate.cameraPt.x-minDist+b2);
             for(int j=0;j<4;j++) {
                             //std::cout<<" Pt:"<<planePt[j]<<"  ";
                             planeWPt[j] = cv::Point3f(.0,.0,.0);
                             //cv::circle(show_all,planePt[j],3,cv::Scalar(200,100,0));
                             if(planePt[j].x > COLS || planePt[j].y > ROWS || planePt[j].x < 0 || planePt[j].y < 0)
                                     badPt = true;
                     }
                     //std::cout<<std::endl;
                     if(badPt) continue;
                     for(int j=0;j<candidateCnt;j++) {
                             for(int k=0;k<4;k++) {
                                     if(!isCheck[k]) {
                                             if( abs(planePt[k].x - gndCandidate[j].cameraPt.x) < 2 && abs(planePt[k].y - gndCandidate[j].cameraPt.y) < 2 ) {
                                                     //std::cout<<"================================================================================"<<std::endl;
                                                     planeWPt[k] = gndCandidate[j].worldPt;
                                                     isCheck[k] = true;
                                             }
                                     }
                                     if( isCheck[0] && isCheck[1] && isCheck[2] && isCheck[3] ) {
                                             GoodPt = true;
                                             break;
                                     }
                             }
                     }
                     //if(!GoodPt) continue;
                     //cv::imshow("test",show_all);
                     //cv::waitKey(0);
                     //for(int j=0;j<4;j++) std::cout<<planeWPt[j]<"  ";
                     //std::cout<<std::endl;
    
                     if( planeWPt[0] != cv::Point3f(.0,.0,.0) && planeWPt[2] != cv::Point3f(.0,.0,.0) ) {
                             get_param( randomCandidate.worldPt, planeWPt[0], planeWPt[2]);
                             if( isGnd_angle(pitchSet,rollSet,yawSet) ) {
                                     va.push_back(a);vb.push_back(b);
                                     vc.push_back(c);vd.push_back(d);
                             }
                     }
                     if( planeWPt[0] != cv::Point3f(.0,.0,.0) && planeWPt[3] != cv::Point3f(.0,.0,.0) ) {
                             get_param( randomCandidate.worldPt, planeWPt[0], planeWPt[3]);
                             if( isGnd_angle(pitchSet,rollSet,yawSet) ) {
                                     va.push_back(a);vb.push_back(b);
                                     vc.push_back(c);vd.push_back(d);
                             }
                     }
                     if( planeWPt[1] != cv::Point3f(.0,.0,.0) && planeWPt[2] != cv::Point3f(.0,.0,.0) ) {
                             get_param( randomCandidate.worldPt, planeWPt[1], planeWPt[2]);
                             if( isGnd_angle(pitchSet,rollSet,yawSet) ) {
                                     va.push_back(a);vb.push_back(b);
                                     vc.push_back(c);vd.push_back(d);
                             }
                     }
                     if( planeWPt[1] != cv::Point3f(.0,.0,.0) && planeWPt[3] != cv::Point3f(.0,.0,.0) ) {
                             get_param( randomCandidate.worldPt, planeWPt[1], planeWPt[3]);
                             if( isGnd_angle(pitchSet,rollSet,yawSet) ) {
                                     va.push_back(a);vb.push_back(b);
                                     vc.push_back(c);vd.push_back(d);
                             }
                     }
                     ptCnt++;
             }
             //std::cout<<"param_num size:"<<va.size()<<std::endl;
             if( va.size() == 0 ) return false;
    
             //for(int i=0;i<va.size();i++) std::cout<<"[/] vector final [ "<<va[i]<<","<<vb[i]<<","<<vc[i]<<","<<vd[i]<<" ]"<<std::endl;
    
             double sum[] = {.0, .0, .0, .0};
             for(int j=0;j<va.size();j++) {
             sum[0] += va[j];sum[1] += vb[j];
                     sum[2] += vc[j];sum[3] += vd[j];
             }
             a = sum[0]/va.size()*1.0;
             b = sum[1]/va.size()*1.0;
             c = sum[2]/va.size()*1.0;
             d = sum[3]/va.size()*1.0;
    
             //std::cout<<"params: "<<a<<" "<<b<<" "<<c<<" "<<d<<std::endl;
             return true;
     }
    
     #endif
    
  • func.cpp -- 主文件
    #include "uhoo_cloud.h"

     int main() {
         bool die(false);
    
         DataStream dataStream;
         DataStruct dataStruct, match, payload[2];
         cv::Mat depthMat(cv::Size(COLS, ROWS), CV_16UC1);
         cv::Mat colorMat(cv::Size(COLS, ROWS), CV_8UC3);
         Freenect::Freenect freenect;
         MyFreenectDevice& device = freenect.createDevice<MyFreenectDevice>(0);
    
         device.startVideo();
         device.startDepth();
    
         while (1) {
             device.getDepth(depthMat);
             device.getRGB(colorMat);
             cv::imshow("rgb", colorMat);
             if (char(cv::waitKey(1)) == 27) break;
         }
    
         cv::Mat src;
         pcl::PointCloud<pcl::PointXYZRGBA>::Ptr output(new pcl::PointCloud<pcl::PointXYZRGBA>);
         bool isGND_previous(false);
         while (!die) {
             bool isGND_current(false);
    
             device.getDepth(depthMat);
             //src = depthMat.clone();
    
             dataStream.depth = depthMat;
             dataStream.color = colorMat;
             dataStruct.dataStream = dataStream;
             dataStruct.depthInfo = depthIndex;
    
             std::cout << "try to find gnd now !" << std::endl;
             if (find_gnd(dataStream, 20, 30, 60, 60)) {
                 for (int y = 0;y < ROWS;y++)
                     for (int x = 0;x < COLS;x++) {
                         cv::Point pt = cv::Point(x, y);
                         if (get_distance(INDEX(pt, 0, 0).worldPt) < 50)
                             INDEX(pt, 0, 0).isGnd = true;
                     }
                 isGND_current = true;
             }
             else continue;
    
             cout << "pass gnd check" << endl;
             dataStruct.depthInfo = depthIndex;
    
             colorToPlane(colorMat);
             device.getRGB(colorMat);
             cv::imshow("rgb", colorMat);
    
             payload[0] = dataStruct;
             payload[1] = match;
    
             std::cout << "check match now" << std::endl;
             if (isGND_previous) {
                 bf_match(payload, output, 2);
             }
             else {
                 staticA = a;
                 staticB = b;
                 staticC = c;
                 isGND_previous = true;
                 output = worldPt2cloud(dataStruct);
                 translate2gnd(output);
                 std::cout << "line params:" << a << "," << b << "," << c << "," << d << std::endl;
                 initCloud(output);
             }
             if (char(cv::waitKey(1)) == 27) break;
    
             std::cout << "copy depth data now" << std::endl;
             for (int i = 0;i < COLS*ROWS;i++) depthIndex_previous[i] = depthIndex[i];
    
             std::cout << "copy complieted!" << std::endl;
             std::cout << "data trans now" << std::endl;;
             match = dataStruct; // need create a new space to save depthInfo
             match.depthInfo = depthIndex_previous;
             std::cout << "trans complieted !" << std::endl;
             match.dataStream.color = colorMat.clone();
             match.dataStream.depth = depthMat.clone();
         }
    
         return 0;
     }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容