paella/Code/include/Skeleton/Skeleton.hpp

266 lines
11 KiB
C++

////////////////////////////////////////////////////////////////////////////////
//
// Paella
// Copyright (C) 2015 - Thomas FORGIONE, Emilie JALRAS, Marion LENFANT, Thierry MALON, Amandine PAILLOUX
// Authors :
// Thomas FORGIONE
// Emilie JALRAS
// Marion LENFANT
// Thierry MALON
// Amandine PAILLOUX
//
// This file is part of the project Paella
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
// you must not claim that you wrote the original software.
// If you use this software in a product, an acknowledgment
// in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
// and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
////////////////////////////////////////////////////////////////////////////////
#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