stereo_disparity.cpp
Go to the documentation of this file.
00001 // ISSUES:
00002 // - Is my interpolation actually correct? I haven't tested the math/values
00003 #include "stereo_disparity.hpp"
00004 #include "feature_match.hpp"
00005 
00006 #define MIN_DISPARITY 0
00007 
00008 namespace fovis
00009 {
00010 
00011 StereoDisparity::StereoDisparity(const StereoCalibration* calib) :
00012     _calib(calib),
00013     _width(calib->getWidth()),
00014     _height(calib->getHeight())
00015 {
00016   _disparity_data = new float[ _width* _height];
00017   _uvd1_to_xyz = new Eigen::Matrix4d(calib->getUvdToXyz());
00018 }
00019 
00020 StereoDisparity::~StereoDisparity()
00021 {
00022   delete[] _disparity_data;
00023   delete _uvd1_to_xyz;
00024 }
00025 
00026 void
00027 StereoDisparity::setDisparityData(const float* disparity_data)
00028 {
00029   // copy disparity image
00030   int num_disparity_pixels = _width * _height;
00031   memcpy(_disparity_data, disparity_data, num_disparity_pixels * sizeof(float));
00032 }
00033 
00034 bool
00035 StereoDisparity::haveXyz(int u, int v)
00036 {
00037   float disp = _disparity_data[(int) v*_width + (int) u] ;
00038 
00039   // disp ==0 mean no disparity for that return
00040   // TODO: should this be done more in advance?
00041   if (disp == MIN_DISPARITY){
00042     return false;
00043   }
00044   return true;
00045 }
00046 
00047 Eigen::Vector3d
00048 StereoDisparity::getXyzValues(int u, int v, float disparity)
00049 {
00050   Eigen::Vector4d uvd1((double) u, (double) v, disparity, 1);
00051   Eigen::Vector4d xyzw = (*_uvd1_to_xyz) * uvd1;
00052   return xyzw.head<3>() / xyzw.w();
00053 }
00054 
00055 
00056 void
00057 StereoDisparity::getXyz(OdometryFrame * odom_frame)
00058 {
00059   int num_levels = odom_frame->getNumLevels();
00060   for(int level_num=0; level_num < num_levels; ++level_num) {
00061     PyramidLevel* level = odom_frame->getLevel(level_num);
00062     int num_kp = level->getNumKeypoints();
00063     //std::cout << level_num << " | number of keypoints: " << num_kp << "\n";
00064 
00065     for(int kp_ind=0; kp_ind < num_kp; ++kp_ind) {
00066       KeypointData* kpdata(level->getKeypointData(kp_ind));
00067 
00068       int u = (int)(kpdata->rect_base_uv(0)+0.5);
00069       int v = (int)(kpdata->rect_base_uv(1)+0.5);
00070 
00071       kpdata->disparity = _disparity_data[(int) v*_width + (int) u];
00072       if (kpdata->disparity == MIN_DISPARITY){ // disp ==0 if no disparity available given
00073         kpdata->disparity = NAN;
00074         kpdata->has_depth = false;
00075         kpdata->xyzw = Eigen::Vector4d(NAN, NAN, NAN, NAN);
00076         kpdata->xyz = Eigen::Vector3d(NAN, NAN, NAN);
00077       } else {
00078         kpdata->has_depth = true;
00079         kpdata->xyz = getXyzValues(u, v, kpdata->disparity);
00080         kpdata->xyzw.head<3>() = kpdata->xyz;
00081         kpdata->xyzw.w() = 1;
00082       }
00083     }
00084   }
00085 }
00086 
00087 void
00088 StereoDisparity::refineXyz(FeatureMatch * matches,
00089                        int num_matches,
00090                        OdometryFrame * odom_frame)
00091 {
00092   for (int m_ind = 0; m_ind < num_matches; m_ind++) {
00093     FeatureMatch& match = matches[m_ind];
00094     if (match.status == MATCH_NEEDS_DEPTH_REFINEMENT) {
00095       if (getXyzInterp(&match.refined_target_keypoint)) {
00096         match.status = MATCH_OK;
00097       } else {
00098         match.status = MATCH_REFINEMENT_FAILED;
00099         match.inlier = false;
00100       }
00101     }
00102   }
00103 }
00104 
00105 bool
00106 StereoDisparity::getXyzInterp(KeypointData* kpdata)
00107 {
00108   // 1. find the fractional pixel left, right and right&down from nearest unit pixel:
00109   // mfallon: this seems to support non-640x480 kinect data but I'm not sure its necessary for disparity data
00110   double _x_scale =1;
00111   double _y_scale =1;
00112   float u_f = kpdata->rect_base_uv(0);
00113   float v_f = kpdata->rect_base_uv(1);
00114   float v_f_d = v_f * _y_scale;
00115   float u_f_d = u_f * _x_scale;
00116   int v = (int)v_f_d;
00117   int u = (int)u_f_d;
00118   float wright  = (u_f_d - u);
00119   float wbottom = (v_f_d - v);
00120 
00121   // can't handle borders
00122   assert(u >= 0 && v >= 0 && u < _width - 1 && v < _height - 1);
00123 
00124   float w[4] = {
00125     (1 - wright) * (1 - wbottom),
00126     wright * (1 - wbottom),
00127     (1 - wright) * wbottom,
00128     wright * wbottom
00129   }; // weights sum to unity
00130 
00131   // 2. find corresponding disparities, u and v values around the non-unit pixel
00132   int index = v * _width + u;
00133   double disparities[4] = {
00134     _disparity_data[index ],
00135     _disparity_data[index + 1],
00136     _disparity_data[index + _width ],
00137     _disparity_data[index + _width  + 1]
00138   };
00139   for(int i = 0; i<4; i++){
00140     if( (disparities[i]==MIN_DISPARITY) ){ // set to a known value - TODO: find a better way to do this or assume this in advance
00141       disparities[i] = NAN;
00142     }
00143   }
00144   int u_vals[4] = {u, u+1,   u, u+1};
00145   int v_vals[4] = {v,   v, v+1, v+1};
00146 
00147   // missing any depth data for surrounding pixels?
00148   int num_missing_data = 0;
00149   for(int i = 0; i<4; i++)
00150     if(isnan(disparities[i]))
00151       num_missing_data++;
00152 
00153   if(num_missing_data == 4) { // missing all surrounding depth data.
00154     return false;
00155   }
00156 
00157   // 3. Interpolate the edge points to give refined x,y,z for pixel
00158   if(num_missing_data) {
00159     // if any of the surrounding depth data is missing, just clamp to the
00160     // nearest pixel.  interpolation gets messy if we try to do otherwise
00161     float wmax = -1;
00162     for(int i=0; i<4; i++) {
00163       if(isnan(disparities[i]) && w[i] > wmax) {
00164         kpdata->xyz = getXyzValues(u_vals[i]  , v_vals[i] , disparities[i]);
00165         wmax = w[i];
00166       }
00167     }
00168   } else {
00169     Eigen::Vector3d xyz_combined = Eigen::Vector3d (0.,0.,0.);
00170     // TODO: this simply averages the xyz pixel locations.
00171     // Should this be done in a manner e.g. averaging the disparity or with reprojective covariance?
00172     for(int i=0; i<4; i++){
00173       Eigen::Vector3d xyz = getXyzValues(u_vals[i]  , v_vals[i] , disparities[i]);
00174       xyz_combined= xyz_combined + xyz * w[i];
00175     }
00176     kpdata->xyz = xyz_combined;
00177   }
00178   kpdata->xyzw.head<3>() = kpdata->xyz;
00179   kpdata->xyzw.w() = 1;
00180   return true;
00181 }
00182 
00183 } /*  */


libfovis
Author(s): Albert Huang, Maurice Fallon
autogenerated on Thu Jun 6 2019 20:16:12