00001 #include "CurvatureDetector.h"
00002
00003 CurvatureDetector::CurvatureDetector(const PeakFinder* peak, unsigned int scales, double sigma, double step, unsigned int dmst):
00004 m_peakFinder(peak),
00005 m_scaleNumber(scales),
00006 m_baseSigma(sigma),
00007 m_sigmaStep(step),
00008 m_useMaxRange(false),
00009 m_dmst(dmst)
00010 {
00011 computeScaleBank();
00012 }
00013
00014
00015 unsigned int CurvatureDetector::detect(const LaserReading& reading, std::vector<InterestPoint*>& _point) const
00016 {
00017 Graph graph;
00018 std::vector< std::vector<Point2D> > operatorA;
00019 std::vector< std::vector<double> > signalDiff;
00020 std::vector< std::vector<unsigned int> > indexes;
00021 return detect(reading, _point, graph, operatorA, signalDiff, indexes);
00022 }
00023
00024 unsigned int CurvatureDetector::detect(const LaserReading& reading, std::vector<InterestPoint*>& point,
00025 Graph& graph,
00026 std::vector< std::vector<Point2D> >& operatorA,
00027 std::vector< std::vector<double> >& signalDiff,
00028 std::vector< std::vector<unsigned int> >& indexes) const
00029 {
00030 std::vector<unsigned int> maxRangeMapping;
00031 std::vector<Point2D> graphPoints;
00032 computeGraph(reading, graphPoints, graph, maxRangeMapping);
00033 detect(graph, graphPoints, operatorA, signalDiff, indexes);
00034 return computeInterestPoints(reading, operatorA, point, indexes, maxRangeMapping);
00035 }
00036
00037 unsigned int CurvatureDetector::detect( const LaserReading& reading, std::vector<InterestPoint*>& point,
00038 std::vector< double >& signal,
00039 std::vector< std::vector<double> >& signalSmooth,
00040 std::vector< std::vector<double> >& signalDiff,
00041 std::vector< std::vector<unsigned int> >& indexes) const
00042 {
00043 std::vector<unsigned int> maxRangeMapping;
00044 std::vector<Point2D> graphPoints;
00045 Graph graph;
00046 std::vector< std::vector<Point2D> > operatorA;
00047 computeGraph(reading, graphPoints, graph, maxRangeMapping);
00048 detect(graph, graphPoints, operatorA, signalDiff, indexes);
00049 signal.resize(graphPoints.size());
00050 signalSmooth.resize(m_scales.size(), std::vector<double> (graphPoints.size()));
00051 for(unsigned int i = 0; i < graphPoints.size(); i++){
00052 Point2D difference = graphPoints[i] - reading.getLaserPose();
00053 signal[i] = hypot(difference.x, difference.y);
00054 for(unsigned int scale = 0; scale < m_scales.size(); scale++){
00055 difference = operatorA[scale][i] - reading.getLaserPose();
00056 signalSmooth[scale][i] = hypot(difference.x, difference.y);
00057 }
00058 }
00059 return computeInterestPoints(reading, operatorA, point, indexes, maxRangeMapping);
00060 }
00061
00062 void CurvatureDetector::computeGraph(const LaserReading& reading, std::vector<Point2D>& graphPoints, Graph& graph, std::vector<unsigned int>& maxRangeMapping) const
00063 {
00064 const std::vector<Point2D>& worldPoints = reading.getWorldCartesian();
00065 graphPoints.reserve(worldPoints.size());
00066 std::vector<GraphEdge> edges;
00067 std::vector< boost::property < boost::edge_weight_t, double > > weights;
00068 edges.reserve(worldPoints.size()*worldPoints.size());
00069 weights.reserve(worldPoints.size()*worldPoints.size());
00070 unsigned int currentVertexNumber = 0;
00071 for(unsigned int i = 0; i < worldPoints.size(); i++){
00072 if(m_useMaxRange || reading.getRho()[i] < reading.getMaxRange()){
00073 graphPoints.push_back(worldPoints[i]);
00074 maxRangeMapping.push_back(i);
00075 unsigned int targetVertexNumber = currentVertexNumber + 1;
00076 for(unsigned int j = i + 1; j < worldPoints.size(); j++){
00077 if(m_useMaxRange || reading.getRho()[j] < reading.getMaxRange()){
00078 Point2D difference = worldPoints[i] - worldPoints[j];
00079 edges.push_back(GraphEdge(currentVertexNumber,targetVertexNumber));
00080 weights.push_back(hypot(difference.x, difference.y));
00081 targetVertexNumber++;
00082 }
00083 }
00084 currentVertexNumber++;
00085 }
00086 }
00087
00088 MatrixGraph costGraph(currentVertexNumber);
00089 for(unsigned int i = 0; i < edges.size(); i++){
00090 boost::add_edge(edges[i].first, edges[i].second, weights[i], costGraph);
00091 }
00092 boost::remove_edge(0, currentVertexNumber - 1, costGraph);
00093
00094 for(unsigned int iter = 0; iter <= m_dmst; iter++){
00095 std::vector < boost::graph_traits < Graph >::vertex_descriptor > predecessor(boost::num_vertices(costGraph));
00096 boost::prim_minimum_spanning_tree(costGraph, &predecessor[0]);
00097 for(unsigned int i = 1; i < predecessor.size(); i++){
00098 boost::add_edge(predecessor[i], i, boost::get(boost::edge_weight, costGraph, boost::edge(predecessor[i], i, costGraph).first), graph);
00099 boost::remove_edge(predecessor[i], i, costGraph);
00100 }
00101 }
00102 }
00103
00104 void CurvatureDetector::detect(const Graph& graph, const std::vector<Point2D>& graphPoints, std::vector< std::vector<Point2D> >& operatorA, std::vector< std::vector<double> >& signalDiff,
00105 std::vector< std::vector<unsigned int> >& indexes) const
00106 {
00107 operatorA.resize(m_scales.size());
00108 signalDiff.resize(m_scales.size());
00109 indexes.resize(m_scales.size());
00110
00111 unsigned int vertexNumber = boost::num_vertices(graph);
00112 std::vector< std::vector< double > > distances(vertexNumber, std::vector<double>(vertexNumber));
00113 boost::johnson_all_pairs_shortest_paths(graph, distances);
00114
00115 for(unsigned int scale = 0; scale < m_scales.size(); scale++){
00116 double currentScale = m_scales[scale];
00117 double normalizer = sqrt(2*M_PI)*currentScale;
00118 std::vector<double> densities(vertexNumber, 0.);
00119 operatorA[scale].resize(vertexNumber);
00120 signalDiff[scale].resize(vertexNumber,0.);
00121 double weights[vertexNumber][vertexNumber];
00122 double weightNormalizer[vertexNumber];
00123 for(unsigned int vertex1 = 0; vertex1 < vertexNumber; vertex1++){
00124 for(unsigned int vertex2 = 0; vertex2 < vertexNumber; vertex2++){
00125 weights[vertex1][vertex2] = normalizer * exp(-distances[vertex1][vertex2] * distances[vertex1][vertex2]/(2 * currentScale * currentScale));
00126 densities[vertex1] += weights[vertex1][vertex2];
00127 }
00128 }
00129 for(unsigned int vertex1 = 0; vertex1 < vertexNumber; vertex1++){
00130 weightNormalizer[vertex1] = 0.;
00131 for(unsigned int vertex2 = 0; vertex2 < vertexNumber; vertex2++){
00132 weights[vertex1][vertex2] /= densities[vertex1] * densities[vertex2];
00133 weightNormalizer[vertex1] += weights[vertex1][vertex2];
00134 }
00135 }
00136 for(unsigned int vertex1 = 0; vertex1 < vertexNumber; vertex1++){
00137 for(unsigned int vertex2 = 0; vertex2 < vertexNumber; vertex2++){
00138 operatorA[scale][vertex1] = operatorA[scale][vertex1] + weights[vertex1][vertex2] * graphPoints[vertex2];
00139 }
00140 operatorA[scale][vertex1] = operatorA[scale][vertex1] * ( 1. / weightNormalizer[vertex1]);
00141 Point2D pointDifference = operatorA[scale][vertex1] - graphPoints[vertex1];
00142 double temporary = 2 * (1/currentScale) * hypot(pointDifference.x, pointDifference.y);
00143 signalDiff[scale][vertex1] = temporary * exp(-temporary);
00144 }
00145 for(unsigned int j = 2; j < signalDiff[scale].size() - 2; j++){
00146 if(m_peakFinder->isPeak(signalDiff[scale], j)){
00147 indexes[scale].push_back(j);
00148 }
00149 }
00150 }
00151 }
00152
00153 unsigned int CurvatureDetector::computeInterestPoints(const LaserReading& reading, const std::vector< std::vector<Point2D> >& operatorA, std::vector<InterestPoint*>& point,
00154 const std::vector< std::vector<unsigned int> >& indexes, std::vector<unsigned int>& maxRangeMapping) const
00155 {
00156 point.clear();
00157 point.reserve(reading.getRho().size());
00158 const std::vector<Point2D>& worldPoints = reading.getWorldCartesian();
00159 for(unsigned int i = 0; i < indexes.size(); i++){
00160 for(unsigned int j = 0; j < indexes[i].size(); j++){
00161 OrientedPoint2D pose;
00162 unsigned int pointIndex = maxRangeMapping[indexes[i][j]];
00163
00164
00165 double rangeBefore = (pointIndex > 1)? reading.getRho()[pointIndex - 1] : reading.getMaxRange();
00166 double rangeAfter = (pointIndex < worldPoints.size() - 1)? reading.getRho()[pointIndex + 1] : reading.getMaxRange();
00167 double rangeCurrent = reading.getRho()[pointIndex];
00168 if(rangeBefore < rangeAfter){
00169 if(rangeBefore < rangeCurrent){
00170 pointIndex = pointIndex - 1;
00171 }
00172 } else if(rangeAfter < rangeCurrent){
00173 pointIndex = pointIndex + 1;
00174 }
00175
00176
00177 if(reading.getRho()[pointIndex] >= reading.getMaxRange()){
00178 continue;
00179 }
00180
00181
00182 pose.x = (worldPoints[pointIndex]).x;
00183 pose.y = (worldPoints[pointIndex]).y;
00184 Point2D difference = operatorA[i][j] - worldPoints[pointIndex];
00185 pose.theta = atan2(difference.y, difference.x);
00186
00187 bool exists = false;
00188 for(unsigned int k = 0; !exists && k < point.size(); k++){
00189 exists = exists || (fabs(pose.x - point[k]->getPosition().x) <= 0.2 && fabs(pose.y - point[k]->getPosition().y) <= 0.2);
00190 }
00191 if(exists) continue;
00192
00193 double distance = 2. * m_scales[i];
00194 Point2D diffStart = pose - worldPoints.front();
00195 Point2D diffEnd = pose - worldPoints.back();
00196
00197 if(hypot(diffStart.x, diffStart.y) < distance || hypot(diffEnd.x, diffEnd.y) < distance){
00198 continue;
00199 }
00200
00201 std::vector<Point2D> support;
00202 for(unsigned int k = 0; k < worldPoints.size(); k++){
00203 Point2D diff2 = pose - worldPoints[k];
00204 if(hypot(diff2.x, diff2.y) < distance) support.push_back(worldPoints[k]);
00205 }
00206 InterestPoint *interest = new InterestPoint(pose, distance);
00207
00208 interest->setSupport(support);
00209 interest->setScaleLevel(i);
00210 point.push_back(interest);
00211 }
00212 }
00213 return point.size();
00214
00215 }
00216
00217 void CurvatureDetector::computeScaleBank()
00218 {
00219 m_scales.resize(m_scaleNumber);
00220 for(unsigned int i = 0; i < m_scales.size(); i++){
00221 m_scales[i] = m_baseSigma * pow(m_sigmaStep, i);
00222 }
00223 }