Switch c-style array to boost array, cleaning, documenting

This commit is contained in:
terry-dango 2015-02-06 17:47:18 +01:00
parent ccaf6aebd3
commit c0aee0b921
3 changed files with 156 additions and 167 deletions

View File

@ -1,23 +1,22 @@
#include <iostream>
#include <fstream>
#include <algorithm>
#include <valarray>
#include <GL/gl.h>
#include <boost/numeric/ublas/matrix.hpp>
#include "opencv2/features2d/features2d.hpp"
#include "Skeleton.hpp"
#include "Box.hpp"
std::stringstream Skeleton::stream{};
Skeleton::Skeleton() : m_vertices{}, m_edges{}, m_neighbourgs_counters{}, m_junctions{}, m_bounding_box{}
Skeleton::Skeleton() : m_vertices{}, m_edges{}
{
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/// \brief loadFromFile : read a file at format skl and extract vertices and edges
///
/// \param path String containing the path to the file at format skl
////////////////////////////////////////////////////////////////////////////////////////////////////
void Skeleton::loadFromFile(std::string const& path)
{
std::ifstream file{path};
@ -57,16 +56,10 @@ void Skeleton::loadFromFile(std::string const& path)
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/// \brief loadFromVectors : create edges from a vector of vertices index
///
/// For example, with the vector path = [1, 5, 8, 9, 12], the created edges are (1,5), (5,8), (8,9)
/// and (9,12)
///
/// \param vertices Vector of vertices
/// \param path Vector of vertices index
////////////////////////////////////////////////////////////////////////////////////////////////////
void Skeleton::loadFromVectors(std::vector<Vertex> const& vertices, std::vector<unsigned int> const& path)
void Skeleton::loadFromVectors(std::vector<Vertex> const& vertices,
std::vector<unsigned int> const& path
)
{
m_vertices = vertices;
for (unsigned int i = 0; i < path.size() - 1; i++)
@ -75,95 +68,42 @@ void Skeleton::loadFromVectors(std::vector<Vertex> const& vertices, std::vector<
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/// \brief countNeighbourgs : count the number of neighbors of each vertex
///
/// Compute a vector of counters which has the same size as the number of vertices.
/// The k-th element of the vector is the number of neighbors of the k-th vertex.
///
/// For example, with the following skeleton :
///
///
/// 3 6
/// | |
/// 1-2-4-5-8-9
/// |
/// 7
///
/// It would compute : m_neighbors_counters = [1,3,1,2,4,1,1,2,1]
////////////////////////////////////////////////////////////////////////////////////////////////////
void Skeleton::countNeighbourgs()
std::vector<unsigned int> Skeleton::countNeighbors()
{
m_neighbourgs_counters.reserve(m_vertices.size());
std::vector<unsigned int> neighbors_counters;
neighbors_counters.reserve(m_vertices.size());
for (auto i = 0u; i < m_vertices.size(); i++)
{
m_neighbourgs_counters.push_back(0);
neighbors_counters.push_back(0);
}
for (auto const& edge : m_edges)
{
m_neighbourgs_counters[edge.v1]++;
m_neighbourgs_counters[edge.v2]++;
neighbors_counters[edge.v1]++;
neighbors_counters[edge.v2]++;
}
return neighbors_counters;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/// \brief draw : draw the skeleton with OpenGL
////////////////////////////////////////////////////////////////////////////////////////////////////
void Skeleton::draw() const
{
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2,GL_FLOAT,sizeof(Vertex),&m_vertices[0]);
glDrawElements(GL_LINES,m_edges.size()*2,GL_UNSIGNED_INT,&m_edges[0]);
glDisableClientState(GL_VERTEX_ARRAY);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/// \brief computeJunctions : compute the junctions
////////////////////////////////////////////////////////////////////////////////////////////////////
void Skeleton::computeJunctions()
{
countNeighbourgs();
for (unsigned int i = 0; i < m_vertices.size(); i++)
{
if (m_neighbourgs_counters[i]>2 || m_neighbourgs_counters[i]==1)
{
m_junctions.push_back(Junction{i});
}
}
for (auto& junction : m_junctions)
{
for (auto const& edge : m_edges)
{
if (edge.v1 == junction.center)
{
junction.neighbourgs.push_back(edge.v2);
}
if (edge.v2 == junction.center)
{
junction.neighbourgs.push_back(edge.v1);
}
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/// \brief split : split the whole skeletons into branches of skeletons
////////////////////////////////////////////////////////////////////////////////////////////////////
std::vector<Skeleton> Skeleton::split()
{
std::vector<Skeleton> branches;
std::vector<std::vector<bool>> connections;
std::vector<std::vector<unsigned int>> paths;
std::vector<unsigned int> neighbors_counters;
if (m_junctions.size() == 0)
computeJunctions();
computeBoundingBox();
neighbors_counters = countNeighbors();
for (unsigned int i = 0; i < m_vertices.size(); i++)
{
@ -183,10 +123,10 @@ std::vector<Skeleton> Skeleton::split()
for (unsigned int i = 0; i < m_vertices.size(); i++)
{
if (m_neighbourgs_counters[i]>2 || m_neighbourgs_counters[i]==1)
if (neighbors_counters[i]>2 || neighbors_counters[i]==1)
{
unsigned int numberOfBranchesFound = 0;
std::vector <unsigned int> onesPosition = findOnes(connections,i);
std::vector <unsigned int> onesPosition = findOnes(connections,neighbors_counters[i], i);
for (auto const& pathNumber : onesPosition)
{
@ -201,7 +141,7 @@ std::vector<Skeleton> Skeleton::split()
addNextPoint(connections, path);
j++;
k = path[path.size()-1];
} while (m_neighbourgs_counters[k] == 2);
} while (neighbors_counters[k] == 2);
bool toBeAdded = true;
@ -221,7 +161,6 @@ std::vector<Skeleton> Skeleton::split()
paths.push_back(path);
branches.push_back(Skeleton{});
branches[branches.size()-1].loadFromVectors(m_vertices, path);
branches[branches.size()-1].m_bounding_box = m_bounding_box;
numberOfBranchesFound++;
}
}
@ -234,46 +173,28 @@ std::vector<Skeleton> Skeleton::split()
return branches;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/// \brief addNextPoint : add a point to a branche
///
/// \param connections Inferior triangular matrix (j<i) wit 0 in (i,j) if the i-th vertex is
/// connected to the j-th vertex
/// \param path Branche of skeleton to be added a point
////////////////////////////////////////////////////////////////////////////////////////////////////
void Skeleton::addNextPoint(std::vector<std::vector<bool>> const& connections, std::vector<unsigned int>& path) const
{
auto lastPoint = path[path.size()-1];
auto nextPointFound = false;
auto i = 0u;
while (!nextPointFound)
while (!nextPointFound && i < m_vertices.size())
{
if (i >= m_vertices.size())
{
break;
}
if (lastPoint != i && connections[std::max(i,lastPoint)][std::min(i,lastPoint)]
&& std::find(std::begin(path), std::end(path), i) == std::end(path))
{
path.push_back(i);
nextPointFound = true;
}
i++;
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/// \brief findOnes : return a vector containing the column containing a 1 in a triangular matrix
/// given a certain line
///
/// \param connections Inferior triangular matrix containing 1 in (i,j) if the vertex i is connected
/// to the vertex j
/// \param lineNumber Index i of the line of connections where the algorithm looks for 1
////////////////////////////////////////////////////////////////////////////////////////////////////
std::vector<unsigned int> Skeleton::findOnes(std::vector<std::vector<bool>> const& connections, unsigned int lineNumber) const
std::vector<unsigned int> Skeleton::findOnes(std::vector<std::vector<bool>> const& connections, unsigned int numberOfOnesToFind, unsigned int lineNumber) const
{
std::vector<unsigned int> onesPosition;
unsigned int numberOfOnesToFind = m_neighbourgs_counters[lineNumber];
unsigned int numberOfOnesFound = 0;
unsigned int counter = 0;
@ -290,41 +211,6 @@ std::vector<unsigned int> Skeleton::findOnes(std::vector<std::vector<bool>> cons
return onesPosition;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/// \brief computeBoundingBox : computes the bounding box of the skeleton
////////////////////////////////////////////////////////////////////////////////////////////////////
void Skeleton::computeBoundingBox()
{
m_bounding_box.m_x_min = m_vertices[0].x;
m_bounding_box.m_x_max = m_vertices[0].x;
m_bounding_box.m_y_min = m_vertices[0].y;
m_bounding_box.m_y_max = m_vertices[0].y;
for (auto const& vertex : m_vertices)
{
m_bounding_box.m_x_min = std::min(m_bounding_box.m_x_min,vertex.x);
m_bounding_box.m_x_max = std::max(m_bounding_box.m_x_max,vertex.x);
m_bounding_box.m_y_min = std::min(m_bounding_box.m_y_min,vertex.y);
m_bounding_box.m_y_max = std::max(m_bounding_box.m_y_max,vertex.y);
}
std::cout << "Affichage de la bounding box : " << std::endl;
std::cout << "[" << m_bounding_box.m_x_min << "," << m_bounding_box.m_x_max << "] "
<< "[" << m_bounding_box.m_y_min << "," << m_bounding_box.m_y_max << "]"
<< std::endl;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/// \brief branchesMatching : match branches of two skeletons together
///
/// On considère que les deux squelettes que l'on cherche à apparier ont le même nombre de points
/// We use the copy parameters to avoid side effects
///
/// \param keypoints
/// \param branches1
/// \param branches2
////////////////////////////////////////////////////////////////////////////////////////////////////
std::vector<std::pair<unsigned int,unsigned int>> branchesMatching(std::vector<std::pair<cv::KeyPoint,cv::KeyPoint>> keypoints, std::vector<Skeleton> branches1, std::vector<Skeleton> branches2)
{
std::vector<std::pair<unsigned int,unsigned int>> matchingBranches;
@ -376,24 +262,24 @@ std::vector<std::pair<unsigned int,unsigned int>> branchesMatching(std::vector<s
}
// Initialisation of a 2D matching matrix couting the number of times that each branche of the first skeleton is associated to another branche of the second skeleton as their respective associated keypoints are paired
unsigned int matchingMatrix[branches1.size()][branches2.size()];
boost::numeric::ublas::matrix<unsigned int> matchingMatrix{branches1.size(),branches1.size()};
for (auto i = 0u; i < 6; i++)
{
for (auto j = 0u; j < 6; j++)
matchingMatrix[i][j] = 0;
matchingMatrix(i,j) = 0;
}
for (unsigned int i = 0; i < correspondingBranches1.size() ; i++)
{
std::cout << "Le morceau du premier squelette d'indice " << correspondingBranches1[i] << " semble correspondre au morceau du second squelette d'indice " << correspondingBranches2[i] << "." << std::endl;
matchingMatrix[correspondingBranches1[i]][correspondingBranches2[i]]++;
matchingMatrix(correspondingBranches1[i],correspondingBranches2[i])++;
}
std::cout << "--------Matrix is--------------" << std::endl;
for (auto i = 0u; i < 6; i++)
{
for (auto j = 0u; j < 6; j++)
std::cout << matchingMatrix[i][j] << " ";
std::cout << matchingMatrix(i,j) << " ";
std::cout << std::endl;
}
std::cout << std::endl;
@ -406,9 +292,9 @@ std::vector<std::pair<unsigned int,unsigned int>> branchesMatching(std::vector<s
for (unsigned int j = 0; j < branches1.size(); j++)
{
if (matchingMatrix[i][j] > maximumMatchingScore)
if (matchingMatrix(i,j) > maximumMatchingScore)
{
maximumMatchingScore = matchingMatrix[i][j];
maximumMatchingScore = matchingMatrix(i,j);
maximumMatchingScoreIndex = j;
}
}

View File

@ -22,37 +22,140 @@ class Edge
unsigned int v2;
};
class Junction
{
public:
Junction(unsigned int i) : center{i}, neighbourgs{} {};
unsigned int center;
std::vector<unsigned int> neighbourgs;
};
class Skeleton
{
public:
// This using will be nice for the next
template <class T>
using couples = std::vector<std::pair<T,T>>;
Skeleton();
////////////////////////////////////////////////////////////////////////
/// \brief loadFromFile : read a file at format skl and extract vertices
/// and edges
///
/// \param path String containing the path to the file at format skl
////////////////////////////////////////////////////////////////////////
void loadFromFile(std::string const& path);
////////////////////////////////////////////////////////////////////////
/// \brief loadFromVectors : create edges from a vector of vertices
/// index
///
/// For example, with the vector path = [1, 5, 8, 9, 12], the created
/// edges are (1,5), (5,8), (8,9) and (9,12)
///
/// \param vertices Vector of vertices
/// \param path Vector of vertices index
////////////////////////////////////////////////////////////////////////
void loadFromVectors(std::vector<Vertex> const& vertices,
std::vector<unsigned int> const& path
);
////////////////////////////////////////////////////////////////////////
/// \brief countNeighbors : count the number of neighbors of each
/// vertex
///
/// Compute a vector of counters which has the same size as the number
/// of vertices. The k-th element of the vector is the number of
/// neighbors of the k-th vertex.
///
/// For example, with the following skeleton :
///
///
/// 3 6
/// | |
/// 1-2-4-5-8-9
/// |
/// 7
///
/// It would return neighbors_counters = [1,3,1,2,4,1,1,2,1]
////////////////////////////////////////////////////////////////////////
std::vector<unsigned int> countNeighbors();
///////////////////////////////////////////////////////////////////////
/// \brief draw : Draw the skeleton
///////////////////////////////////////////////////////////////////////
void draw() const;
void loadFromVectors(std::vector<Vertex> const& vertices, std::vector<unsigned int> const& path);
void countNeighbourgs();
void computeJunctions();
////////////////////////////////////////////////////////////////////////
/// \brief split : split the whole skeletons into branches of skeletons
///
/// Returns a vector of branches
////////////////////////////////////////////////////////////////////////
std::vector<Skeleton> split();
friend std::ostream& operator<<(std::ostream& out, Skeleton const& s);
void computeBoundingBox();
friend std::vector<std::pair<unsigned int,unsigned int>> branchesMatching(std::vector<std::pair<cv::KeyPoint,cv::KeyPoint>> keypoints, std::vector<Skeleton> branches1, std::vector<Skeleton> branches2);
////////////////////////////////////////////////////////////////////////
/// \brief branchesMatching : match branches of two skeletons together
///
/// We consider that both skeletons have the number of branches.
///
/// \param keypoints
/// \param branches1
/// \param branches2
////////////////////////////////////////////////////////////////////////
friend couples<unsigned int> branchesMatching(couples<cv::KeyPoint> keypoints,
std::vector<Skeleton> branches1,
std::vector<Skeleton> branches2
);
private:
void addNextPoint(std::vector<std::vector<bool>> const& connections, std::vector<unsigned int>& path) const;
std::vector<unsigned int> findOnes(std::vector<std::vector<bool>> const& connections, unsigned int lineNumber) const;
friend unsigned int searchNearestBrancheIndex(cv::KeyPoint const& keypoint, std::vector<Skeleton> branches);
////////////////////////////////////////////////////////////////////////
/// \brief addNextPoint : add a point to a branche
///
/// \param connections Inferior triangular matrix (j<i) wit 0 in (i,j)
/// if the i-th vertex is
/// connected to the j-th vertex
/// \param path Branche of skeleton to be added a point
////////////////////////////////////////////////////////////////////////
void addNextPoint(std::vector<std::vector<bool>> const& connections,
std::vector<unsigned int>& path
) const;
////////////////////////////////////////////////////////////////////////
/// \brief findOnes : return a vector containing the column containing a
/// 1 in a triangular matrix given the number of 1 to
/// be found and a certain line index
///
/// \param connections Inferior triangular matrix containing 1 in
/// (i,j) if the vertex i is connected to the
/// vertex j
/// \param numberOfOnesToFind Number of ones to find in the matrix
/// connections
/// \param lineNumber Index i of the line of connections where
/// the algorithm looks for 1
////////////////////////////////////////////////////////////////////////
std::vector<unsigned int> findOnes(std::vector<std::vector<bool>> const& connections,
unsigned int numberOfOnesToFind,
unsigned int lineNumber
) const;
////////////////////////////////////////////////////////////////////////
/// \brief searchNearestBrancheIndex : return the index of the branche
/// associated to a keypoint
///
/// \param keypoint The keypoint that we want to associate to a branche
/// \param branches The list of branches in which we look for the
/// nearest branche to associate the keypoint
////////////////////////////////////////////////////////////////////////
friend unsigned int searchNearestBrancheIndex(cv::KeyPoint const& keypoint,
std::vector<Skeleton> branches
);
std::vector<Vertex> m_vertices;
std::vector<Edge> m_edges;
std::vector<unsigned int> m_neighbourgs_counters;
std::vector<Junction> m_junctions;
Box m_bounding_box;
static std::stringstream stream;
};

View File

@ -63,7 +63,7 @@ int main(int argc, char *argv[])
// Init mesh
Skeleton s, s2;
s.loadFromFile(std::string{argv[1]});
s.computeJunctions();
// s.computeJunctions();
std::vector<std::pair<unsigned int, unsigned int>> matching;
std::vector<Skeleton> split = s.split();
std::vector<Skeleton> split2;
@ -72,7 +72,7 @@ int main(int argc, char *argv[])
if (argc > 2)
{
s2.loadFromFile(std::string{argv[2]});
s2.computeJunctions();
// s2.computeJunctions();
split2 = s2.split();
std::swap(split2[1], split2[2]);
matching = branchesMatching(keypoints1, split, split2);