Jafar
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
rawSegProcessors.hpp
00001 
00014 #ifndef RAWSEGPROCESSORS_HPP
00015 #define RAWSEGPROCESSORS_HPP
00016 
00017 #ifdef HAVE_MODULE_DSEG
00018 
00019 #include "dseg/DirectSegmentsTracker.hpp"
00020 #include "dseg/SegmentHypothesis.hpp"
00021 #include "dseg/SegmentsSet.hpp"
00022 #include "dseg/ConstantVelocityPredictor.hpp"
00023 #include "dseg/RtslamPredictor.hpp"
00024 #include "dseg/HierarchicalDirectSegmentsDetector.hpp"
00025 #include "dseg/GradientStatsDescriptor.hpp"
00026 
00027 #include "rtslam/rawImage.hpp"
00028 #include "rtslam/sensorPinhole.hpp"
00029 #include "rtslam/descriptorImageSeg.hpp"
00030 
00031 namespace jafar {
00032 namespace rtslam {
00033 
00034   boost::weak_ptr<RawImage> lastDsegImage;
00035   dseg::PreprocessedImage preprocDsegImage;
00036 
00037   boost::weak_ptr<RawImage> lastDsegImageForDetection;
00038   dseg::PyramidSP* preprocDsegPyramid;
00039 
00040   float meanOnLine(const image::Image& img, int x1, int y1, int x2, int y2)
00041   {
00042     int x0 = x1;
00043     int y0 = y1;
00044     int dx = abs(x2 - x1);
00045     int dy = abs(y2 - y1);
00046     int sx = (x1 < x2) ? 1 : -1;
00047     int sy = (y1 < y2) ? 1 : -1;
00048     float err = dx - dy;
00049     float _2err;
00050 
00051     int sum = 0;
00052     int nbpoints = 0;
00053 
00054     const uchar* pix = img.data();
00055 
00056     if(x0 >= 0 && x0 < (int)img.width() &&
00057       y0 >= 0 && y0 < (int)img.height())
00058     {
00059       sum += *(pix + x0 * img.width() + y0); // TODO : check if it works
00060       nbpoints++;
00061     }
00062     while(x0 != x2 || y0 != y2)
00063     {
00064       _2err = 2*err;
00065 
00066       if(_2err > -dy)
00067       {
00068         err -= dy;
00069         x0 += sx;
00070       }
00071       if(_2err < dx)
00072       {
00073         err  += dx;
00074         y0 += sy;
00075       }
00076 
00077       if(x0 >= 0 && x0 < (int)img.width() &&
00078         y0 >= 0 && y0 < (int)img.height())
00079       {
00080         sum += *(pix + x0 * img.width() + y0); // TODO : check if it works
00081         nbpoints++;
00082       }
00083     }
00084 
00085     return float(sum)/nbpoints;
00086   }
00087 
00088   // compute the mean of all pixels inside the polygon v1 v2 v3 v4, the order is important, the polygon must be convex
00089   float meanOnPoly(const boost::shared_ptr<Image> & image, const jblas::vec2& v1, const jblas::vec2& v2, const jblas::vec2& v3, const jblas::vec2& v4)
00090   {
00091     float sum = 0.0;
00092     int nbmeasure = 0;
00093 
00094     const jblas::vec2* vertices[4] = {&v1,&v2,&v3,&v4};
00095     int uppermost = 0;
00096 
00097     int left_edges[] = {-1, -1, -1, -1,};
00098     int right_edges[] = {-1, -1, -1, -1,};
00099 
00100     // Get uppermost vertex
00101     for(int i = 1 ; i < 4 ; i++) {
00102       if((*vertices[i])[1] > (*vertices[uppermost])[1])
00103         uppermost = i;
00104     }
00105 
00106     // Compute left and right
00107     left_edges[0] = uppermost;
00108     right_edges[0] = uppermost;
00109     int left = (uppermost+3)%4;
00110     int right = (uppermost+1)%4;
00111     if((*vertices[left])[0] < (*vertices[right])[0]) {
00112       left_edges[1] = left;
00113       right_edges[1] = right;
00114     } else {
00115       left_edges[1] = right;
00116       right_edges[1] = left;
00117     }
00118 
00119     left = 1;
00120     right = 1;
00121     // Compute the rest of the left and right edges
00122     while(left < 3) // Left
00123     {
00124       // current edge is between left_edges[left -1] and left_edges[left]
00125       // since we draw a quad the next vertex adjacent to left_edges[left] is
00126       // such that (left_edges[left -1] - next)%2 != 0
00127       int next = ((left_edges[left -1] + 2)% 4);
00128 
00129       // if the next vertex is higher than the previous one we reached the bottom
00130       if((*vertices[next])[1] > (*vertices[left_edges[left]])[1])
00131         break;
00132 
00133       left++;
00134       left_edges[left] = next;
00135     }
00136     while(right < 3) // Right
00137     {
00138       int next = ((right_edges[right -1] + 2)% 4);
00139 
00140       if((*vertices[next])[1] > (*vertices[right_edges[right]])[1])
00141         break;
00142 
00143       right++;
00144       right_edges[right] = next;
00145     }
00146 
00147     left = 0;
00148     right = 0;
00149     // Draw the scanlines
00150     int line = (*vertices[uppermost])[1];
00151     bool done = false;
00152     while(!done)
00153     {
00154       // Update current edge
00155       // Left
00156       while(line < (*vertices[left_edges[left+1]])[1] && !done)
00157       {
00158         if(left < 2 && left_edges[left+2] >= 0)
00159           left++;
00160         else
00161           done = true;
00162       }
00163       // Right
00164       while(line < (*vertices[right_edges[right+1]])[1] && !done)
00165       {
00166         if(right < 2 && right_edges[right+2] >= 0)
00167           right++;
00168         else
00169           done = true;
00170       }
00171 
00172       if(!done)
00173       {
00174         // Compute scanline extremities
00175         int tl = left_edges[left];
00176         int bl = left_edges[left+1];
00177         int tr = right_edges[right];
00178         int br = right_edges[right+1];
00179 
00180         float left_alpha = (float)(line - (*vertices[bl])[1]) / (float)((*vertices[tl])[1] - (*vertices[bl])[1]);
00181         float right_alpha = (float)(line - (*vertices[br])[1]) / (float)((*vertices[tr])[1] - (*vertices[br])[1]);
00182 
00183         float col_beg = left_alpha * (*vertices[tl])[0] +  (1 - left_alpha) * (*vertices[bl])[0];
00184         float col_end = right_alpha * (*vertices[tr])[0] + (1 - right_alpha) * (*vertices[br])[0];
00185 
00186         if(col_beg - int(col_beg) > 0.5)
00187           col_beg = int(col_beg) + 1;
00188         else
00189           col_beg = int(col_beg);
00190 
00191         if(col_end - int(col_end) > 0.5)
00192           col_end = int(col_end) + 1;
00193         else
00194           col_end = int(col_end);
00195 
00196         // Measure on line
00197         for(int x=col_beg ; x<=col_end; x++)
00198         {
00199           if(x<0 || x>=image->width() || line<0 || line>=image->height())
00200             continue;
00201 
00202           sum += image->data()[line*image->width() + x];
00203           // image->data()[line*image->width() + x] = 255 - image->data()[y*image->width() + x]; // DEBUG : invert color in order to visualise the area
00204           nbmeasure++;
00205         }
00206 
00207         // Update line
00208         line--;
00209       }
00210     }
00211 
00212     return (nbmeasure > 0) ? sum / nbmeasure : 0;
00213   }
00214 
00215   class DsegMatcher
00216    {
00217       private:
00218          dseg::DirectSegmentsTracker matcher;
00219          dseg::RtslamPredictor predictor;
00220 
00221       public:
00222          struct matcher_params_t {
00223             // RANSAC
00224             int maxSearchSize;
00225             double lowInnov;      
00226             double threshold;     
00227             double mahalanobisTh; 
00228             double relevanceTh; 
00229             double measStd;       
00230             double measVar;       
00231          } params;
00232 
00233       private :
00234       void projectExtremities(const vec4& meas, const vec4& exp, vec4& newMeas, float* stdRatio) const
00235       {
00236             // extract predicted points
00237             vec2 P1 = subrange(exp,0,2);
00238         vec2 P2 = subrange(exp,2,4);
00239         double P12_2 = (P2(0) - P1(0))*(P2(0) - P1(0)) // Square(distance(P1,P2))
00240                 +   (P2(1) - P1(1))*(P2(1) - P1(1));
00241         double P12 = sqrt(P12_2);
00242             // extract measured line
00243             vec2 L1 = subrange(meas,0,2);
00244             vec2 L2 = subrange(meas,2,4);
00245         double L12_2 = (L2(0) - L1(0))*(L2(0) - L1(0)) // Square(distance(L1,L2))
00246               +   (L2(1) - L1(1))*(L2(1) - L1(1));
00247         double L12 = sqrt(L12_2);
00248 
00249         // compute predicted center
00250         vec2 Pc = (P1 + P2) / 2;
00251         // project on measured line
00252         double u = (((Pc(0) - L1(0))*(L2(0) - L1(0)))
00253                 +((Pc(1) - L1(1))*(L2(1) - L1(1))))
00254                 /(L12_2);
00255         vec2 Lc = L1 + u*(L2 - L1);
00256 
00257         // compute measured orientation
00258         double angle = atan2(L2(1) - L1(1), L2(0) - L1(0));
00259 
00260         // compute extremities
00261         newMeas[0] = Lc[0] - P12 * cos(angle) / 2;
00262         newMeas[1] = Lc[1] - P12 * sin(angle) / 2;
00263         newMeas[2] = Lc[0] + P12 * cos(angle) / 2;
00264         newMeas[3] = Lc[1] + P12 * sin(angle) / 2;
00265 /*
00266             // TODO : be carefull L1 != L2
00267             // project predicted points on line
00268             double u = (((P1(0) - L1(0))+(L2(0) - L1(0)))
00269                        +((P1(1) - L1(1))+(L2(1) - L1(1))))
00270                        /(norm_1(L1 - L2) * norm_1(L1 - L2));
00271             subrange(newMeas,0,2) = L1 + u*(L2 - L1);
00272 
00273         u = (((P2(0) - L2(0))+(L1(0) - L2(0)))
00274            +((P2(1) - L2(1))+(L1(1) - L2(1))))
00275                 /(norm_1(L1 - L2) * norm_1(L1 - L2));
00276         subrange(newMeas,2,4) = L2 + u*(L1 - L2);
00277 */
00278 
00279         *stdRatio = P12 / L12;
00280          }
00281 
00282       public:
00283          DsegMatcher(double lowInnov, double threshold, double mahalanobisTh, double relevanceTh, double measStd):
00284             matcher(), predictor()
00285          {
00286             params.lowInnov = lowInnov;
00287             params.threshold = threshold;
00288             params.mahalanobisTh = mahalanobisTh;
00289             params.relevanceTh = relevanceTh;
00290             params.measStd = measStd;
00291          }
00292 
00293          void match(const boost::shared_ptr<RawImage> & rawPtr, const appearance_ptr_t & targetApp, const image::ConvexRoi & roi, Measurement & measure, appearance_ptr_t & app)
00294       {
00295         if(rawPtr != lastDsegImage.lock())
00296         {
00297           matcher.preprocessImage(*(rawPtr->img),preprocDsegImage);
00298           lastDsegImage = rawPtr;
00299         }
00300 
00301         app_img_seg_ptr_t targetAppSpec = SPTR_CAST<AppearanceImageSegment>(targetApp);
00302         app_img_seg_ptr_t appSpec = SPTR_CAST<AppearanceImageSegment>(app);
00303 
00304             dseg::SegmentsSet setin, setout;
00305 
00306             setin.addSegment(targetAppSpec->hypothesis());
00307         matcher.trackSegment(preprocDsegImage,setin,&predictor,setout);
00308 
00309             if(setout.count() > 0) {
00310           vec4 pred;
00311           vec4 obs;
00312           vec4 projected;
00313           float ratio;
00314 
00315           pred(0) = targetAppSpec->hypothesis()->x1();
00316           pred(1) = targetAppSpec->hypothesis()->y1();
00317           pred(2) = targetAppSpec->hypothesis()->x2();
00318           pred(3) = targetAppSpec->hypothesis()->y2();
00319 
00320           obs(0) = setout.segmentAt(0)->x1();
00321           obs(1) = setout.segmentAt(0)->y1();
00322           obs(2) = setout.segmentAt(0)->x2();
00323           obs(3) = setout.segmentAt(0)->y2();
00324 
00325           vec2 normal;
00326           normal(0) = obs(1) - obs(3);
00327           normal(1) = obs(2) - obs(0);
00328           vec2 top,bottom;
00329           top[0]    = obs[0]; top[1]    = obs[1];
00330           bottom[0] = obs[2]; bottom[1] = obs[3];
00331 
00332           jmath::ublasExtra::normalize(normal);
00333           normal *= 5; // measure area width
00334 
00335           appSpec->patchMeanLeft = meanOnPoly(rawPtr->img, top, top + normal, bottom + normal, bottom);
00336           appSpec->patchMeanRight = meanOnPoly(rawPtr->img, top, top - normal, bottom - normal, bottom);
00337 
00338           projectExtremities(obs,pred, projected, &ratio);
00339           measure.x() = projected;
00340           measure.std(params.measStd * ratio);
00341 
00342           // Compute matchScore according to predicted and observed means
00343           float obsLeft = appSpec->patchMeanLeft;
00344           float obsRight = appSpec->patchMeanRight;
00345           float predLeft = targetAppSpec->patchMeanLeft;
00346           float predRight = targetAppSpec->patchMeanRight;
00347 
00348           float correlLeft = min(obsLeft,predLeft) / max(obsLeft,predLeft);
00349           float correlRight = min(obsRight,predRight) / max(obsRight,predRight);
00350           //measure.matchScore = 1;
00351           measure.matchScore = max(correlLeft, correlRight);
00352 
00353                appSpec->setHypothesis(setout.segmentAt(0));
00354         }
00355             else {
00356                measure.matchScore = 0;
00357             }
00358          }
00359    };
00360 
00361    class HDsegDetector
00362    {
00363       private:
00364       dseg::HierarchicalDirectSegmentsDetector detector;
00365          boost::shared_ptr<DescriptorFactoryAbstract> descFactory;
00366 
00367       public:
00368          struct detector_params_t {
00369         int patchSize;  
00370         // RANSAC
00371             double measStd;       
00372             double measVar;       
00373             // HDSEG
00374             int hierarchyLevel;
00375          } params;
00376 
00377       public:
00378       HDsegDetector(int patchSize, int hierarchyLevel, double measStd,
00379             boost::shared_ptr<DescriptorFactoryAbstract> const &descFactory):
00380             detector(), descFactory(descFactory)
00381          {
00382         params.patchSize = patchSize;
00383         params.hierarchyLevel = hierarchyLevel;
00384             params.measStd = measStd;
00385             params.measVar = measStd * measStd;
00386          }
00387 
00388       bool detect(const boost::shared_ptr<RawImage> & rawData, const image::ConvexRoi &roi, boost::shared_ptr<FeatureImageSegment> & featPtr)
00389          {
00390             bool ret = false;
00391         featPtr.reset(new FeatureImageSegment());
00392             featPtr->measurement.std(params.measStd);
00393 
00394         if(rawData != lastDsegImageForDetection.lock())
00395         {
00396           preprocDsegPyramid = detector.computePyramid(*(rawData->img));
00397           lastDsegImageForDetection = rawData;
00398         }
00399 
00400         dseg::SegmentsSet set;
00401         detector.detectSegment(preprocDsegPyramid, *(rawData->img.get()), &roi, set);
00402 
00403         if(set.count() > 0)
00404         {
00405           int bestId = -1;
00406 
00407           double bestSqrLength = -1;
00408           for(size_t i=0 ; i<set.count() ; i++)
00409           {
00410             const dseg::SegmentHypothesis* seg = set.segmentAt(i);
00411 
00412             double dx = seg->x1() - seg->x2();
00413             double dy = seg->y1() - seg->y2();
00414             double sqrLength = sqrt(dx*dx + dy*dy);
00415             sqrLength *= seg->gradientDescriptor().meanGradients();
00416 
00417             // If this segment is longer than the previous best
00418             if(sqrLength > bestSqrLength)
00419             {
00420                 vec2 v1,v2;
00421 
00422                 v1[0] = seg->x1();
00423                 v1[1] = seg->y1();
00424                 v2[0] = seg->x2();
00425                 v2[1] = seg->y2();
00426 
00427                 if(roi.isIn(v1) || roi.isIn(v2))
00428                 {
00429                   // Consider this segment as
00430                   bestId = i;
00431                   bestSqrLength = sqrLength;
00432                 }
00433             }
00434           }
00435 
00436           if(bestId >= 0)
00437           {
00438             featPtr->measurement.x(0) = set.segmentAt(bestId)->x1();
00439             featPtr->measurement.x(1) = set.segmentAt(bestId)->y1();
00440             featPtr->measurement.x(2) = set.segmentAt(bestId)->x2();
00441             featPtr->measurement.x(3) = set.segmentAt(bestId)->y2();
00442             featPtr->measurement.matchScore = 1;
00443 
00444             featPtr->appearancePtr.reset(new AppearanceImageSegment(params.patchSize, params.patchSize, JfrImage_CS_GRAY, set.segmentAt(bestId)));
00445 
00446             // extract appearance
00447             vec pix = featPtr->measurement.x();
00448             vec2 center;
00449             center[0] = ( pix[0] + pix[2] )/2;
00450             center[1] = ( pix[1] + pix[3] )/2;
00451 
00452             boost::shared_ptr<AppearanceImageSegment> appPtr = SPTR_CAST<AppearanceImageSegment>(featPtr->appearancePtr);
00453             rawData->img->extractPatch(appPtr->patch, (int)center(0), (int)center(1), params.patchSize, params.patchSize);
00454             appPtr->offsetTop.x()(0) = pix(0) - ((int)center(0) - params.patchSize);
00455             appPtr->offsetTop.x()(1) = pix(1) - ((int)center(1) - params.patchSize);
00456             appPtr->offsetTop.P() = jblas::zero_mat(2); // by definition this is our landmark projection
00457 
00458             appPtr->offsetBottom.x()(0) = pix(2) - ((int)center(0) - params.patchSize);
00459             appPtr->offsetBottom.x()(1) = pix(3) - ((int)center(1) - params.patchSize);
00460             appPtr->offsetBottom.P() = jblas::zero_mat(2); // by definition this is our landmark projection
00461 
00462             vec2 normal;
00463             normal(0) = pix(1) - pix(3);
00464             normal(1) = pix(2) - pix(0);
00465             vec2 top,bottom;
00466             top[0]    = pix[0]; top[1]    = pix[1];
00467             bottom[0] = pix[2]; bottom[1] = pix[3];
00468 
00469             jmath::ublasExtra::normalize(normal);
00470             normal *= 5; // measure area width
00471 
00472             appPtr->patchMeanLeft = meanOnPoly(rawData->img, top, top + normal, bottom + normal, bottom);
00473             appPtr->patchMeanRight = meanOnPoly(rawData->img, top, top - normal, bottom - normal, bottom);
00474 
00475             ret = true;
00476           }
00477         }
00478 
00479         return ret;
00480          }
00481 
00482       void fillDataObs(const boost::shared_ptr<FeatureImageSegment> & featPtr, boost::shared_ptr<ObservationAbstract> & obsPtr)
00483          {
00484             // extract observed appearance
00485         app_img_seg_ptr_t app_src = SPTR_CAST<AppearanceImageSegment>(featPtr->appearancePtr);
00486         app_img_seg_ptr_t app_dst = SPTR_CAST<AppearanceImageSegment>(obsPtr->observedAppearance);
00487             app_dst->setHypothesis(app_src->hypothesis());
00488         app_src->patch.copyTo(app_dst->patch);
00489         app_dst->offsetTop = app_src->offsetTop;
00490         app_dst->offsetBottom = app_src->offsetBottom;
00491 
00492         app_dst->patchMeanLeft = app_src->patchMeanLeft;
00493         app_dst->patchMeanRight = app_src->patchMeanRight;
00494 
00495             // create descriptor
00496             descriptor_ptr_t descPtr(descFactory->createDescriptor());
00497             obsPtr->landmarkPtr()->setDescriptor(descPtr);
00498          }
00499    };
00500 
00501 }}
00502 
00503 #endif //HAVE_MODULE_DSEG
00504 
00505 #endif // RAWSEGPROCESSORS_HPP
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated on Wed Oct 15 2014 00:37:27 for Jafar by doxygen 1.7.6.1
LAAS-CNRS