237 lines
9.6 KiB
C++
237 lines
9.6 KiB
C++
#ifndef SKELETON_HPP
|
|
#define SKELETON_HPP
|
|
|
|
#include <string>
|
|
#include <vector>
|
|
#include <sstream>
|
|
|
|
#include <opencv2/features2d/features2d.hpp>
|
|
|
|
#include <Skeleton/Branch.hpp>
|
|
#include <Geometry/Vector.hpp>
|
|
|
|
///////////////////////////////////////////////////////////
|
|
/// \defgroup skeleton Skeleton module
|
|
///
|
|
/// Module to manage 2D-skeletons
|
|
///
|
|
/// This module contains two programs.
|
|
/// - Skeleton
|
|
/// - SkeletonDrawing
|
|
///
|
|
/// \section Skeleton
|
|
/// This is the main binary. It is meant to read two skeletons splitted, and
|
|
/// match the branches accordingly to the keypoint detected in the pictures.
|
|
/// It generates a file with the following syntax :
|
|
/// \code
|
|
/// m 1 2
|
|
/// m 4 6
|
|
/// ...
|
|
/// \endcode
|
|
///
|
|
/// Each line like
|
|
/// \code
|
|
/// m i j
|
|
/// \endcode
|
|
/// means that the i-th branch of the first skeleton was associated to the j-th
|
|
/// branch on the second one
|
|
///
|
|
/// Note that this program will probably not work if there are not the same
|
|
/// number of branches in the two skeletons.
|
|
///
|
|
/// Allowed options:
|
|
/// - -h [ --help ] produce help message
|
|
/// - --img1 arg first image (for the keypoints detection)
|
|
/// - --img2 arg second image (for the keypoints detection)
|
|
/// - --mask1 arg binary mask of the first image (to remove useless
|
|
/// keypoints)
|
|
/// - --mask2 arg binary mask of the second image
|
|
/// - --skl1 arg first skeleton, and its branches
|
|
/// - --skl2 arg second skeleton
|
|
/// - -o [ --output ] arg output file
|
|
///
|
|
/// \section SkeletonDrawing
|
|
/// This program displays the result of a very simple test, where skeletons
|
|
/// were drawn by hand, and the keypoints are defined in the source (and not detected).
|
|
/// It shows how the program is able to work in simple cases.
|
|
///
|
|
/// This program is meant to be used like this
|
|
/// \code
|
|
/// bin/SkeletonDrawing data/skl/skullTest*
|
|
/// \endcode
|
|
///
|
|
///
|
|
///////////////////////////////////////////////////////////
|
|
|
|
///////////////////////////////////////////////////////////
|
|
/// \ingroup skeleton
|
|
/// \brief Class wrapping a 2D-skeleton
|
|
///////////////////////////////////////////////////////////
|
|
class Skeleton
|
|
{
|
|
public:
|
|
// This using will be nice for the next
|
|
template <class T>
|
|
using couples = std::vector<std::pair<T,T>>;
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
/// \brief default constructor
|
|
///
|
|
/// builds an empty skeleton
|
|
////////////////////////////////////////////////////////////////////////
|
|
Skeleton();
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
/// \brief computes the number of branches of the skeleton
|
|
/// \return the number of branches of the skeleton
|
|
////////////////////////////////////////////////////////////////////////
|
|
unsigned int numberOfBranches() const { return m_branches.size(); }
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
/// \brief read a file at format skl and extract vertices
|
|
/// and edges
|
|
///
|
|
/// \param path String containing the path to the file at format skl
|
|
/// \return true if the skeleton was correclty loaded
|
|
////////////////////////////////////////////////////////////////////////
|
|
bool loadFromFile(std::string const& path);
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
/// \brief 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<geo::Vector3<float>> const& vertices,
|
|
Branch const& path
|
|
);
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
/// \brief count the number of neighbors of each
|
|
/// vertex
|
|
///
|
|
/// \return a vector with the number of neighbors
|
|
///
|
|
/// 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 :
|
|
///
|
|
///
|
|
/// \code
|
|
/// 3 6
|
|
/// | |
|
|
/// 1-2-4-5-8-9
|
|
/// |
|
|
/// 7
|
|
/// \endcode
|
|
/// It would return neighbors_counters = [1,3,1,2,4,1,1,2,1]
|
|
////////////////////////////////////////////////////////////////////////
|
|
std::vector<unsigned int> countNeighbors();
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
/// \brief Draw the skeleton
|
|
///////////////////////////////////////////////////////////////////////
|
|
void draw() const;
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
/// \brief Draw the i-th branch of the skeleton
|
|
/// \param i number of the branch to draw
|
|
///////////////////////////////////////////////////////////////////////
|
|
void draw(unsigned int i) const;
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
/// \brief split the whole skeletons into branches of skeletons
|
|
///
|
|
/// \return a vector of branches
|
|
////////////////////////////////////////////////////////////////////////
|
|
void split();
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
/// \brief Overload of the operator<<
|
|
/// \param out stream to print the skeleton
|
|
/// \param s skeleton to print onthe stream
|
|
/// \return a reference to out
|
|
////////////////////////////////////////////////////////////////////////
|
|
friend std::ostream& operator<<(std::ostream& out, Skeleton const& s);
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
/// \ingroup skeleton
|
|
/// \brief 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> const& keypoints,
|
|
Skeleton branches1,
|
|
Skeleton branches2
|
|
);
|
|
|
|
|
|
private:
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
/// \brief add a point to a branch
|
|
///
|
|
/// \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,
|
|
Branch& path
|
|
) const;
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
/// \brief 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
|
|
////////////////////////////////////////////////////////////////////////
|
|
unsigned int searchNearestBrancheIndex(cv::KeyPoint const& keypoint,
|
|
Skeleton branches
|
|
);
|
|
|
|
std::vector<geo::Vector3<float>> m_vertices; ///< vertices of the skeleton
|
|
std::vector<geo::Vector<unsigned int,2>> m_edges; ///< edges of the skeleton
|
|
std::vector<Branch> m_branches; ///< branches of the skeleton, might be empty
|
|
};
|
|
|
|
#endif // SKELETON_HPP
|