Switch c-style array to boost array, cleaning, documenting
This commit is contained in:
parent
ccaf6aebd3
commit
c0aee0b921
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue