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);
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);
00081 nbpoints++;
00082 }
00083 }
00084
00085 return float(sum)/nbpoints;
00086 }
00087
00088
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
00101 for(int i = 1 ; i < 4 ; i++) {
00102 if((*vertices[i])[1] > (*vertices[uppermost])[1])
00103 uppermost = i;
00104 }
00105
00106
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
00122 while(left < 3)
00123 {
00124
00125
00126
00127 int next = ((left_edges[left -1] + 2)% 4);
00128
00129
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)
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
00150 int line = (*vertices[uppermost])[1];
00151 bool done = false;
00152 while(!done)
00153 {
00154
00155
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
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
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
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
00204 nbmeasure++;
00205 }
00206
00207
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
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
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))
00240 + (P2(1) - P1(1))*(P2(1) - P1(1));
00241 double P12 = sqrt(P12_2);
00242
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))
00246 + (L2(1) - L1(1))*(L2(1) - L1(1));
00247 double L12 = sqrt(L12_2);
00248
00249
00250 vec2 Pc = (P1 + P2) / 2;
00251
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
00258 double angle = atan2(L2(1) - L1(1), L2(0) - L1(0));
00259
00260
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
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
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;
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
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
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
00371 double measStd;
00372 double measVar;
00373
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
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
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
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);
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);
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;
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
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
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