Cleaning Skeleton from the first part
This commit is contained in:
parent
303e728646
commit
3a3578b270
|
@ -20,6 +20,9 @@ find_package(OpenCV REQUIRED)
|
|||
# OpenGL
|
||||
find_package(OpenGL REQUIRED)
|
||||
|
||||
# Boost's program options
|
||||
find_package(Boost COMPONENTS program_options REQUIRED )
|
||||
|
||||
# Project version
|
||||
set(VERSION_MAJOR 1)
|
||||
set(VERSION_MINOR 0)
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
#ifndef BRANCH_HPP
|
||||
#define BRANCH_HPP
|
||||
|
||||
#include <vector>
|
||||
|
||||
class Branch
|
||||
{
|
||||
public:
|
||||
void push_back(unsigned int nextPoint);
|
||||
unsigned int size() const { return path.size(); };
|
||||
|
||||
std::vector<unsigned int>::iterator begin() { return path.begin(); }
|
||||
std::vector<unsigned int>::iterator end() { return path.end(); }
|
||||
std::vector<unsigned int>::const_iterator begin() const { return path.begin(); }
|
||||
std::vector<unsigned int>::const_iterator end() const { return path.end(); }
|
||||
std::vector<unsigned int>::const_iterator cbegin() const { return path.begin(); }
|
||||
std::vector<unsigned int>::const_iterator cend() const { return path.end(); }
|
||||
|
||||
bool operator==(Branch const& other);
|
||||
unsigned int& operator[](unsigned int i) { return path[i];}
|
||||
unsigned int& at(unsigned int i) { return path.at(i); }
|
||||
unsigned int const& at(unsigned int i) const { return path.at(i); }
|
||||
unsigned int const& operator[](unsigned int i) const { return path[i];}
|
||||
|
||||
private:
|
||||
std::vector<unsigned int> path;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -6,6 +6,7 @@
|
|||
#include <sstream>
|
||||
#include "opencv2/features2d/features2d.hpp"
|
||||
|
||||
#include "Skeleton/Branch.hpp"
|
||||
#include "Geometry/Vector.hpp"
|
||||
|
||||
class Skeleton
|
||||
|
@ -17,13 +18,15 @@ class Skeleton
|
|||
|
||||
Skeleton();
|
||||
|
||||
unsigned int numberOfBranches() { return m_branches.size(); }
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
/// \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);
|
||||
bool loadFromFile(std::string const& path);
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
@ -37,7 +40,7 @@ class Skeleton
|
|||
/// \param path Vector of vertices index
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
void loadFromVectors(std::vector<geo::Vector3<float>> const& vertices,
|
||||
std::vector<unsigned int> const& path
|
||||
Branch const& path
|
||||
);
|
||||
|
||||
|
||||
|
@ -68,6 +71,7 @@ class Skeleton
|
|||
/// \brief draw : Draw the skeleton
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
void draw() const;
|
||||
void draw(unsigned int i) const;
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
@ -75,7 +79,7 @@ class Skeleton
|
|||
///
|
||||
/// Returns a vector of branches
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
std::vector<Skeleton> split();
|
||||
void split();
|
||||
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& out, Skeleton const& s);
|
||||
|
@ -91,8 +95,8 @@ class Skeleton
|
|||
/// \param branches2
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
friend couples<unsigned int> branchesMatching(couples<cv::KeyPoint> const& keypoints,
|
||||
std::vector<Skeleton> branches1,
|
||||
std::vector<Skeleton> branches2
|
||||
Skeleton branches1,
|
||||
Skeleton branches2
|
||||
);
|
||||
|
||||
|
||||
|
@ -107,7 +111,7 @@ class Skeleton
|
|||
/// \param path Branche of skeleton to be added a point
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
void addNextPoint(std::vector<std::vector<bool>> const& connections,
|
||||
std::vector<unsigned int>& path
|
||||
Branch& path
|
||||
) const;
|
||||
|
||||
|
||||
|
@ -138,11 +142,12 @@ class Skeleton
|
|||
/// \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
|
||||
);
|
||||
unsigned int searchNearestBrancheIndex(cv::KeyPoint const& keypoint,
|
||||
Skeleton branches
|
||||
);
|
||||
std::vector<geo::Vector3<float>> m_vertices;
|
||||
std::vector<geo::Vector<unsigned int,2>> m_edges;
|
||||
std::vector<Branch> m_branches;
|
||||
|
||||
static std::stringstream stream;
|
||||
};
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
#include "Skeleton/Branch.hpp"
|
||||
|
||||
bool Branch::operator==(Branch const& other)
|
||||
{
|
||||
if (size() == 2 && other.size() == 2)
|
||||
{
|
||||
return ((*this)[0] == other[0] && (*this)[1] == other[1]) || ((*this)[0] == other[1] && (*this)[1] == other[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
return size() == other.size() &&
|
||||
( ((*this)[0] == other[0] && (*this)[1] == other[1] && (*this)[size()-1] == other[size()-1])
|
||||
|| ((*this)[0] == other[size()-1] && (*this)[1] == other[size()-2] && (*this)[size()-1] == other[0]));
|
||||
}
|
||||
}
|
||||
|
||||
void Branch::push_back(unsigned int nextPoint)
|
||||
{
|
||||
path.push_back(nextPoint);
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
file(GLOB SKELETON_SRC
|
||||
"*.cpp"
|
||||
)
|
||||
add_library(Skeleton2D Box.cpp Branch.cpp Skeleton.cpp)
|
||||
|
||||
add_executable(Skeleton ${SKELETON_SRC})
|
||||
target_link_libraries(Skeleton ${SFML_LIBRARIES} ${OPENGL_LIBRARIES} SFMLTools)
|
||||
add_executable(SkeletonDrawing draw.cpp)
|
||||
target_link_libraries(SkeletonDrawing ${SFML_LIBRARIES} ${OPENGL_LIBRARIES} SFMLTools Skeleton2D)
|
||||
|
||||
add_executable(Skeleton main.cpp)
|
||||
target_link_libraries(Skeleton ${OPENGL_LIBRARIES} ${OpenCV_LIBRARIES} ${Boost_LIBRARIES} SFMLTools Skeleton2D)
|
||||
|
|
|
@ -13,17 +13,23 @@
|
|||
std::stringstream Skeleton::stream{};
|
||||
|
||||
|
||||
Skeleton::Skeleton() : m_vertices{}, m_edges{}
|
||||
Skeleton::Skeleton() : m_vertices{}, m_edges{}, m_branches{}
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
void Skeleton::loadFromFile(std::string const& path)
|
||||
bool Skeleton::loadFromFile(std::string const& path)
|
||||
{
|
||||
std::ifstream file{path};
|
||||
std::string line;
|
||||
|
||||
if (!file)
|
||||
{
|
||||
std::cerr << "Warning : could not open file " << path << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
while (std::getline(file, line))
|
||||
{
|
||||
if (line.size() == 0)
|
||||
|
@ -38,36 +44,51 @@ void Skeleton::loadFromFile(std::string const& path)
|
|||
switch (first)
|
||||
{
|
||||
case 'v':
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
stream >> x >> y >> z;
|
||||
m_vertices.push_back(geo::Vector3<float>{x,y,z});
|
||||
break;
|
||||
}
|
||||
|
||||
case 'e':
|
||||
{
|
||||
unsigned int v1;
|
||||
unsigned int v2;
|
||||
stream >> v1 >> v2;
|
||||
m_edges.push_back(geo::Vector<unsigned int, 2>{v1-1,v2-1});
|
||||
break;
|
||||
}
|
||||
|
||||
case 'b':
|
||||
{
|
||||
unsigned int vi;
|
||||
Branch branch;
|
||||
while (stream >> vi)
|
||||
branch.push_back(vi);
|
||||
m_branches.push_back(branch);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void Skeleton::loadFromVectors(std::vector<geo::Vector3<float>> const& vertices,
|
||||
std::vector<unsigned int> const& path
|
||||
Branch const& path
|
||||
)
|
||||
{
|
||||
m_vertices = vertices;
|
||||
for (unsigned int i = 0; i < path.size() - 1; i++)
|
||||
{
|
||||
m_edges.push_back(geo::Vector<unsigned int,2>{path[i], path[i+1]});
|
||||
}
|
||||
m_branches.push_back(path);
|
||||
}
|
||||
|
||||
|
||||
|
@ -97,12 +118,19 @@ void Skeleton::draw() const
|
|||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
}
|
||||
|
||||
|
||||
std::vector<Skeleton> Skeleton::split()
|
||||
void Skeleton::draw(unsigned int i) const
|
||||
{
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glVertexPointer(2,GL_FLOAT,sizeof(geo::Vector3<float>),&m_vertices[0]);
|
||||
|
||||
glDrawElements(GL_LINE_STRIP,m_branches[i].size(), GL_UNSIGNED_INT,&(m_branches[i][0]));
|
||||
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
}
|
||||
|
||||
void 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;
|
||||
|
||||
neighbors_counters = countNeighbors();
|
||||
|
@ -132,7 +160,7 @@ std::vector<Skeleton> Skeleton::split()
|
|||
|
||||
for (auto const& pathNumber : onesPosition)
|
||||
{
|
||||
std::vector<unsigned int> path;
|
||||
Branch path;
|
||||
path.push_back(i);
|
||||
path.push_back(pathNumber);
|
||||
auto j = 0u;
|
||||
|
@ -147,22 +175,18 @@ std::vector<Skeleton> Skeleton::split()
|
|||
|
||||
bool toBeAdded = true;
|
||||
|
||||
for (unsigned int j = 0; j < paths.size(); j++)
|
||||
for (unsigned int j = 0; j < m_branches.size(); j++)
|
||||
{
|
||||
auto const& branche_path = paths[j];
|
||||
auto const& sizeBranche = branche_path.size();
|
||||
bool samePathOfSize2 = (path.size() == 2 && path.size() == sizeBranche && (path[0] == branche_path[1] && path[1] == branche_path[0]));
|
||||
bool samePath = (path.size() > 2 && path.size() == sizeBranche && (path[0] == branche_path[sizeBranche-1] && path[path.size()-1] == branche_path[0] && path[1] == branche_path[sizeBranche-2]));
|
||||
if (samePathOfSize2||samePath)
|
||||
if ( m_branches[j] == path )
|
||||
{
|
||||
toBeAdded = false;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
if (toBeAdded)
|
||||
{
|
||||
paths.push_back(path);
|
||||
branches.push_back(Skeleton{});
|
||||
branches[branches.size()-1].loadFromVectors(m_vertices, path);
|
||||
m_branches.push_back(path);
|
||||
numberOfBranchesFound++;
|
||||
}
|
||||
}
|
||||
|
@ -170,13 +194,11 @@ std::vector<Skeleton> Skeleton::split()
|
|||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
std::cout << "Nombre de branches de squelettes trouvées : " << branches.size() << std::endl;
|
||||
|
||||
return branches;
|
||||
std::cout << "Nombre de branches de squelettes trouvées : " << m_branches.size() << std::endl;
|
||||
}
|
||||
|
||||
|
||||
void Skeleton::addNextPoint(std::vector<std::vector<bool>> const& connections, std::vector<unsigned int>& path) const
|
||||
void Skeleton::addNextPoint(std::vector<std::vector<bool>> const& connections, Branch& path) const
|
||||
{
|
||||
auto lastPoint = path[path.size()-1];
|
||||
auto nextPointFound = false;
|
||||
|
@ -213,44 +235,40 @@ std::vector<unsigned int> Skeleton::findOnes(std::vector<std::vector<bool>> cons
|
|||
return onesPosition;
|
||||
}
|
||||
|
||||
std::vector<std::pair<unsigned int,unsigned int>> branchesMatching(std::vector<std::pair<cv::KeyPoint,cv::KeyPoint>> const& keypoints, std::vector<Skeleton> branches1, std::vector<Skeleton> branches2)
|
||||
std::vector<std::pair<unsigned int,unsigned int>> branchesMatching(std::vector<std::pair<cv::KeyPoint,cv::KeyPoint>> const& keypoints, Skeleton branches1, Skeleton branches2)
|
||||
{
|
||||
std::vector<std::pair<unsigned int,unsigned int>> matchingBranches;
|
||||
|
||||
// We verify that skeletons both have as many branches
|
||||
if (branches1.size() != branches2.size())
|
||||
if (branches1.m_branches.size() != branches2.m_branches.size())
|
||||
{
|
||||
std::cout << "Le premier squelette dispose de " << branches1.size() << " branches, tandis que le second en dispose de " << branches2.size() << "." << std::endl;
|
||||
std::cout << "Le premier squelette dispose de " << branches1.m_branches.size() << " branches, tandis que le second en dispose de " << branches2.m_branches.size() << "." << std::endl;
|
||||
}
|
||||
|
||||
// We divide the x and y coordinates of each vertex by the z-coordinate for both skeletons
|
||||
for (unsigned int i = 0; i < branches1.size() ; i++)
|
||||
for (unsigned int i = 0; i < branches1.m_vertices.size() ; i++)
|
||||
{
|
||||
for (unsigned int j = 0; j < branches1[i].m_vertices.size(); j++)
|
||||
{
|
||||
branches1[i].m_vertices[j].x() /= branches1[i].m_vertices[j].z();
|
||||
branches1[i].m_vertices[j].y() /= branches1[i].m_vertices[j].z();
|
||||
}
|
||||
branches1.m_vertices[i].x() /= branches1.m_vertices[i].z();
|
||||
branches1.m_vertices[i].y() /= branches1.m_vertices[i].z();
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < branches2.size() ; i++)
|
||||
for (unsigned int i = 0; i < branches2.m_vertices.size() ; i++)
|
||||
{
|
||||
for (unsigned int j = 0; j < branches2[i].m_vertices.size(); j++)
|
||||
{
|
||||
branches2[i].m_vertices[j].x() /= branches2[i].m_vertices[j].z();
|
||||
branches2[i].m_vertices[j].y() /= branches2[i].m_vertices[j].z();
|
||||
}
|
||||
branches2.m_vertices[i].x() /= branches2.m_vertices[i].z();
|
||||
branches2.m_vertices[i].y() /= branches2.m_vertices[i].z();
|
||||
}
|
||||
|
||||
std::vector<unsigned int> correspondingBranches1;
|
||||
std::vector<unsigned int> correspondingBranches2;
|
||||
|
||||
std::cout << "Hello" << std::endl;
|
||||
|
||||
// Matching between key points of the first image and branches of the first skeleton
|
||||
for (unsigned int i = 0; i < keypoints.size(); i++)
|
||||
{
|
||||
auto const& keypoint = keypoints[i].first;
|
||||
unsigned int nearest_branche_index;
|
||||
nearest_branche_index = searchNearestBrancheIndex(keypoint, branches1);
|
||||
nearest_branche_index = branches1.searchNearestBrancheIndex(keypoint, branches1);
|
||||
correspondingBranches1.push_back(nearest_branche_index);
|
||||
}
|
||||
|
||||
|
@ -259,13 +277,16 @@ std::vector<std::pair<unsigned int,unsigned int>> branchesMatching(std::vector<s
|
|||
{
|
||||
auto const& keypoint = keypoints[i].second;
|
||||
unsigned int nearest_branche_index;
|
||||
nearest_branche_index = searchNearestBrancheIndex(keypoint, branches2);
|
||||
nearest_branche_index = branches2.searchNearestBrancheIndex(keypoint, branches2);
|
||||
correspondingBranches2.push_back(nearest_branche_index);
|
||||
}
|
||||
|
||||
// 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
|
||||
boost::numeric::ublas::matrix<unsigned int> matchingMatrix
|
||||
= boost::numeric::ublas::zero_matrix<unsigned int>{branches1.size(),branches2.size()};
|
||||
= boost::numeric::ublas::zero_matrix<unsigned int>{
|
||||
branches1.m_branches.size(),
|
||||
branches2.m_branches.size()
|
||||
};
|
||||
|
||||
for (unsigned int i = 0; i < correspondingBranches1.size() ; i++)
|
||||
{
|
||||
|
@ -274,21 +295,21 @@ std::vector<std::pair<unsigned int,unsigned int>> branchesMatching(std::vector<s
|
|||
}
|
||||
|
||||
std::cout << "--------Matrix is--------------" << std::endl;
|
||||
for (auto i = 0u; i < branches1.size(); i++)
|
||||
for (auto i = 0u; i < branches1.m_branches.size(); i++)
|
||||
{
|
||||
for (auto j = 0u; j < branches2.size(); j++)
|
||||
for (auto j = 0u; j < branches2.m_branches.size(); j++)
|
||||
std::cout << matchingMatrix(i,j) << " ";
|
||||
std::cout << std::endl;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
std::cout << "----------------------------------" << std::endl;
|
||||
|
||||
for (unsigned int i = 0; i < branches1.size(); i++)
|
||||
for (unsigned int i = 0; i < branches1.m_branches.size(); i++)
|
||||
{
|
||||
unsigned int maximumMatchingScore = 0;
|
||||
unsigned int maximumMatchingScoreIndex = 0;
|
||||
|
||||
for (unsigned int j = 0; j < branches1.size(); j++)
|
||||
for (unsigned int j = 0; j < branches2.m_branches.size(); j++)
|
||||
{
|
||||
if (matchingMatrix(i,j) > maximumMatchingScore)
|
||||
{
|
||||
|
@ -303,21 +324,28 @@ std::vector<std::pair<unsigned int,unsigned int>> branchesMatching(std::vector<s
|
|||
return matchingBranches;
|
||||
}
|
||||
|
||||
unsigned int searchNearestBrancheIndex(cv::KeyPoint const& keypoint, std::vector<Skeleton> branches)
|
||||
unsigned int Skeleton::searchNearestBrancheIndex(cv::KeyPoint const& keypoint, Skeleton branches)
|
||||
{
|
||||
unsigned int nearest_branche_index = 0;
|
||||
float shortest_distance = std::numeric_limits<float>::max();
|
||||
|
||||
for (unsigned int j = 0 ; j < branches.size() ; j++)
|
||||
std::cout << "Sizes : m_vertices " << branches.m_vertices.size() << std::endl;
|
||||
std::cout << " m_edges " << branches.m_edges.size() << std::endl;
|
||||
std::cout << " m_branches " << branches.m_branches.size() << std::endl;
|
||||
|
||||
for (unsigned int j = 0 ; j < branches.m_branches.size() ; j++)
|
||||
{
|
||||
auto const& branche = branches[j];
|
||||
|
||||
for (unsigned int k = 0 ; k < branche.m_edges.size() ; k++)
|
||||
auto const& branche = branches.m_branches[j];
|
||||
for (unsigned int k = 0 ; k < branche.size()-1 ; k++)
|
||||
{
|
||||
auto const& edge = branche.m_edges[k];
|
||||
|
||||
// We compute the coordinates of the projection of the keypoint on each edge
|
||||
float d_keypoint_edge = geo::distanceToSegment(keypoint.pt, branche.m_vertices[edge.x()], branche.m_vertices[edge.y()]);
|
||||
float d_keypoint_edge = geo::distanceToSegment(
|
||||
keypoint.pt,
|
||||
// m_vertices[m_edges[branche[k]].x()],
|
||||
// m_vertices[m_edges[branche[k]].y()]
|
||||
m_vertices.at(branche.at(k)),
|
||||
m_vertices.at(branche.at(k+1))
|
||||
);
|
||||
|
||||
if (d_keypoint_edge < shortest_distance)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,193 @@
|
|||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <cmath>
|
||||
#include <SFML/Window.hpp>
|
||||
#include <SFML/Graphics.hpp>
|
||||
#include <SFML/OpenGL.hpp>
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glu.h>
|
||||
|
||||
#include "SFMLTools/FreeFlyCamera.hpp"
|
||||
#define private public
|
||||
#include "Skeleton/Skeleton.hpp"
|
||||
#undef private
|
||||
|
||||
|
||||
// Full hd : 1920x1080
|
||||
constexpr auto WIDTH = 1920;
|
||||
constexpr auto HEIGHT = 1080;
|
||||
|
||||
void drawScene(sft::FreeFlyCamera const& camera, Skeleton const& s, Skeleton const& s2, std::vector<std::pair<unsigned int, unsigned int>> const& matching, std::vector<std::array<float,3>> const& colors);
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc < 2)
|
||||
{
|
||||
std::cout << "I need a skeleton !" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
std::srand(std::time(0));
|
||||
|
||||
// Création de la fenêtre
|
||||
sf::RenderWindow window(sf::VideoMode(WIDTH, HEIGHT),
|
||||
"Skeleton",
|
||||
sf::Style::Fullscreen,
|
||||
sf::ContextSettings(32));
|
||||
|
||||
window.setVerticalSyncEnabled(true);
|
||||
window.setMouseCursorVisible(false);
|
||||
|
||||
//Initialisation du mode 3D
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
gluPerspective(70,(double)WIDTH/HEIGHT,0.2,10000);
|
||||
|
||||
// Initialisation de Z-Buffer
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
// Activer les textures
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
// Autoriser la transparence
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
// Ces 2 lignes améliorent le rendu
|
||||
glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST);
|
||||
glHint(GL_POINT_SMOOTH_HINT,GL_NICEST);
|
||||
|
||||
// On efface le tampon d'affichage
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
glFlush();
|
||||
|
||||
// Init mesh
|
||||
Skeleton s, s2;
|
||||
s.loadFromFile(std::string{argv[1]});
|
||||
std::vector<std::pair<unsigned int, unsigned int>> matching;
|
||||
s.split();
|
||||
|
||||
#include "init.cxx"
|
||||
|
||||
if (argc > 2)
|
||||
{
|
||||
s2.loadFromFile(std::string{argv[2]});
|
||||
s2.split();
|
||||
std::swap(s2.m_branches[0], s2.m_branches[1]);
|
||||
|
||||
std::cout << "Matching..." << std::endl;
|
||||
matching = branchesMatching(keypoints1, s, s2);
|
||||
std::cout << "Finished..." << std::endl;
|
||||
|
||||
for (auto const& pair : matching)
|
||||
std::cout << pair.first << " -> " << pair.second << std::endl;
|
||||
}
|
||||
|
||||
|
||||
std::vector<std::array<float,3>> colors;
|
||||
|
||||
for (auto i = 0u; i < s.numberOfBranches(); i++)
|
||||
{
|
||||
float r = static_cast<float>(std::rand())/RAND_MAX;
|
||||
float g = static_cast<float>(std::rand())/RAND_MAX;
|
||||
float b = static_cast<float>(std::rand())/RAND_MAX;
|
||||
colors.push_back({r,g,b});
|
||||
}
|
||||
|
||||
// Camera
|
||||
auto camera = sft::FreeFlyCamera{};
|
||||
|
||||
// la boucle principale
|
||||
auto running = true;
|
||||
auto captureRequired = false;
|
||||
while (running)
|
||||
{
|
||||
// gestion des évènements
|
||||
sf::Event event;
|
||||
while (window.pollEvent(event))
|
||||
{
|
||||
if (event.type == sf::Event::Closed)
|
||||
{
|
||||
// on stoppe le programme
|
||||
running = false;
|
||||
}
|
||||
else if (event.type == sf::Event::KeyPressed)
|
||||
{
|
||||
if (event.key.code == sf::Keyboard::Escape)
|
||||
{
|
||||
running = false;
|
||||
}
|
||||
else if (event.key.code == sf::Keyboard::P)
|
||||
{
|
||||
captureRequired = true;
|
||||
}
|
||||
}
|
||||
else if (event.type == sf::Event::MouseMoved)
|
||||
{
|
||||
// Hum...
|
||||
}
|
||||
else if (event.type == sf::Event::Resized)
|
||||
{
|
||||
// on ajuste le viewport lorsque la fenêtre est redimensionnée
|
||||
glViewport(0, 0, event.size.width, event.size.height);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Les trucs qui sont pas des évènements
|
||||
camera.nextStep(WIDTH, HEIGHT);
|
||||
sf::Mouse::setPosition(sf::Vector2i{WIDTH/2, HEIGHT/2});
|
||||
|
||||
// Dessin de la scene
|
||||
drawScene(camera, s, s2, matching, colors);
|
||||
|
||||
if (captureRequired)
|
||||
{
|
||||
window.capture().saveToFile("capture.jpg");
|
||||
captureRequired = false;
|
||||
}
|
||||
|
||||
// termine la trame courante (en interne, échange les deux tampons de rendu)
|
||||
window.display();
|
||||
}
|
||||
|
||||
// libération des ressources...
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void drawScene(sft::FreeFlyCamera const& camera, Skeleton const& split, Skeleton const& split2, std::vector<std::pair<unsigned int, unsigned int>> const& matching, std::vector<std::array<float,3>> const& colors)
|
||||
{
|
||||
// Initialisation
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
|
||||
// Position Camera gluLookAt(positionCamera, positionCible, vecteurVertical)
|
||||
camera.look();
|
||||
|
||||
|
||||
for (auto i = 0u; i < matching.size(); i++)
|
||||
{
|
||||
// Find random color
|
||||
glColor3f(colors[i][0], colors[i][1], colors[i][2]);
|
||||
split.draw(i);
|
||||
glPushMatrix();
|
||||
glTranslatef(1000,0,0);
|
||||
split2.draw(i);
|
||||
glPopMatrix();
|
||||
glPushMatrix();
|
||||
glTranslatef(0,-1500,0);
|
||||
split.draw(matching[i].first);
|
||||
glPushMatrix();
|
||||
glTranslatef(1000,0,0);
|
||||
split2.draw(matching[i].second);
|
||||
glPopMatrix();
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
// MAJ de l'écran
|
||||
glFlush();
|
||||
}
|
|
@ -1,191 +1,125 @@
|
|||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <cmath>
|
||||
#include <SFML/Window.hpp>
|
||||
#include <SFML/Graphics.hpp>
|
||||
#include <SFML/OpenGL.hpp>
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glu.h>
|
||||
#include <boost/program_options.hpp>
|
||||
|
||||
#include <opencv2/core/core.hpp>
|
||||
#include <opencv2/imgproc/imgproc.hpp>
|
||||
#include <opencv2/highgui/highgui.hpp>
|
||||
|
||||
#include "SFMLTools/FreeFlyCamera.hpp"
|
||||
#include "Skeleton/Skeleton.hpp"
|
||||
|
||||
// Full hd : 1920x1080
|
||||
constexpr auto WIDTH = 1920;
|
||||
constexpr auto HEIGHT = 1080;
|
||||
// std::pair<bool, bool>
|
||||
// first is true if program should continue
|
||||
// second is true if there was an error
|
||||
std::pair<bool, bool> parseArgs(int argc, char *argv[],
|
||||
std::string& img1, std::string& img2,
|
||||
std::string& mask1, std::string& mask2,
|
||||
std::string& skl1, std::string& skl2,
|
||||
std::string& output)
|
||||
{
|
||||
namespace po = boost::program_options;
|
||||
|
||||
void drawScene(sft::FreeFlyCamera const& camera, std::vector<Skeleton> const& s, std::vector<Skeleton> const& s2, std::vector<std::pair<unsigned int, unsigned int>> const& matching, std::vector<std::array<float,3>> const& colors);
|
||||
try
|
||||
{
|
||||
po::options_description desc("Allowed options");
|
||||
desc.add_options()
|
||||
("help,h", "produce help message")
|
||||
("img1", po::value<std::string>(), "first image (for the keypoints detection)")
|
||||
("img2", po::value<std::string>(), "second image (for the keypoints detection)")
|
||||
("mask1", po::value<std::string>(), "binary mask of the first image (to remove useless keypoints)")
|
||||
("mask2", po::value<std::string>(), "binary mask of the second image")
|
||||
("skl1", po::value<std::string>(), "first skeleton, and its branches")
|
||||
("skl2", po::value<std::string>(), "second skeleton")
|
||||
("output,o", po::value<std::string>(), "output file")
|
||||
;
|
||||
|
||||
po::variables_map vm;
|
||||
po::store(po::parse_command_line(argc, argv, desc), vm);
|
||||
po::notify(vm);
|
||||
|
||||
if (vm.count("help"))
|
||||
{
|
||||
std::cout << desc << "\n";
|
||||
return std::make_pair(false, true);
|
||||
}
|
||||
|
||||
// Process parameters
|
||||
if (vm.count("img1")) { img1 = vm["img1"].as<std::string>(); }
|
||||
if (vm.count("img2")) { img2 = vm["img2"].as<std::string>(); }
|
||||
if (vm.count("mask1")) { mask1 = vm["mask1"].as<std::string>(); }
|
||||
if (vm.count("mask2")) { mask2 = vm["mask2"].as<std::string>(); }
|
||||
if (vm.count("skl1")) { skl1 = vm["skl1"].as<std::string>(); }
|
||||
if (vm.count("skl2")) { skl2 = vm["skl2"].as<std::string>(); }
|
||||
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
std::cerr << "Unable to parse : "<< e.what() << std::endl;
|
||||
return std::make_pair(false,false);
|
||||
}
|
||||
|
||||
return std::make_pair(true,true);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc < 2)
|
||||
std::string img1Name;
|
||||
std::string img2Name;
|
||||
std::string mask1Name;
|
||||
std::string mask2Name;
|
||||
std::string skl1Name;
|
||||
std::string skl2Name;
|
||||
std::string output;
|
||||
|
||||
auto pair = parseArgs(argc, argv, img1Name, img2Name, mask1Name, mask2Name, skl1Name, skl2Name, output);
|
||||
|
||||
if (!pair.second)
|
||||
{
|
||||
std::cout << "I need a skeleton !" << std::endl;
|
||||
std::cerr << "Aborting" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
std::srand(std::time(0));
|
||||
|
||||
// Création de la fenêtre
|
||||
sf::RenderWindow window(sf::VideoMode(WIDTH, HEIGHT),
|
||||
"Skeleton",
|
||||
sf::Style::Fullscreen,
|
||||
sf::ContextSettings(32));
|
||||
|
||||
window.setVerticalSyncEnabled(true);
|
||||
window.setMouseCursorVisible(false);
|
||||
|
||||
//Initialisation du mode 3D
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
gluPerspective(70,(double)WIDTH/HEIGHT,0.2,10000);
|
||||
|
||||
// Initialisation de Z-Buffer
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
// Activer les textures
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
// Autoriser la transparence
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
// Ces 2 lignes améliorent le rendu
|
||||
glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST);
|
||||
glHint(GL_POINT_SMOOTH_HINT,GL_NICEST);
|
||||
|
||||
// On efface le tampon d'affichage
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
glFlush();
|
||||
|
||||
// Init mesh
|
||||
Skeleton s, s2;
|
||||
s.loadFromFile(std::string{argv[1]});
|
||||
// s.computeJunctions();
|
||||
std::vector<std::pair<unsigned int, unsigned int>> matching;
|
||||
std::vector<Skeleton> split = s.split();
|
||||
std::vector<Skeleton> split2;
|
||||
#include "init.cxx"
|
||||
|
||||
if (argc > 2)
|
||||
if (!pair.first)
|
||||
{
|
||||
s2.loadFromFile(std::string{argv[2]});
|
||||
// s2.computeJunctions();
|
||||
split2 = s2.split();
|
||||
std::swap(split2[1], split2[2]);
|
||||
matching = branchesMatching(keypoints1, split, split2);
|
||||
|
||||
std::cout << "-------------------------------------------" << std::endl;
|
||||
|
||||
for (auto const& pair : matching)
|
||||
std::cout << pair.first << " -> " << pair.second << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
std::vector<std::array<float,3>> colors;
|
||||
|
||||
for (auto i = 0u; i < split.size(); i++)
|
||||
// Init skeletons and images
|
||||
Skeleton skl1, skl2;
|
||||
if(!skl1.loadFromFile(skl1Name))
|
||||
{
|
||||
float r = static_cast<float>(std::rand())/RAND_MAX;
|
||||
float g = static_cast<float>(std::rand())/RAND_MAX;
|
||||
float b = static_cast<float>(std::rand())/RAND_MAX;
|
||||
colors.push_back({r,g,b});
|
||||
std::cerr << "Unable to load skl file " << skl1Name << std::endl;
|
||||
return -1;
|
||||
}
|
||||
if (!skl2.loadFromFile(skl2Name))
|
||||
{
|
||||
std::cerr << "Unable to load skl file " << skl2Name << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Camera
|
||||
auto camera = sft::FreeFlyCamera{};
|
||||
cv::Mat img1, img2, mask1, mask2;
|
||||
img1 = cv::imread(img1Name, CV_LOAD_IMAGE_GRAYSCALE);
|
||||
img2 = cv::imread(img2Name, CV_LOAD_IMAGE_GRAYSCALE);
|
||||
mask1 = cv::imread(mask1Name, CV_LOAD_IMAGE_GRAYSCALE);
|
||||
mask2 = cv::imread(mask2Name, CV_LOAD_IMAGE_GRAYSCALE);
|
||||
|
||||
// la boucle principale
|
||||
auto running = true;
|
||||
auto captureRequired = false;
|
||||
while (running)
|
||||
{
|
||||
// gestion des évènements
|
||||
sf::Event event;
|
||||
while (window.pollEvent(event))
|
||||
{
|
||||
if (event.type == sf::Event::Closed)
|
||||
{
|
||||
// on stoppe le programme
|
||||
running = false;
|
||||
}
|
||||
else if (event.type == sf::Event::KeyPressed)
|
||||
{
|
||||
if (event.key.code == sf::Keyboard::Escape)
|
||||
{
|
||||
running = false;
|
||||
}
|
||||
else if (event.key.code == sf::Keyboard::P)
|
||||
{
|
||||
captureRequired = true;
|
||||
}
|
||||
}
|
||||
else if (event.type == sf::Event::MouseMoved)
|
||||
{
|
||||
// Hum...
|
||||
}
|
||||
else if (event.type == sf::Event::Resized)
|
||||
{
|
||||
// on ajuste le viewport lorsque la fenêtre est redimensionnée
|
||||
glViewport(0, 0, event.size.width, event.size.height);
|
||||
}
|
||||
if (img1.data == nullptr) { std::cerr << "Unable to load image " << img1Name << std::endl; return -1; }
|
||||
if (img2.data == nullptr) { std::cerr << "Unable to load image " << img2Name << std::endl; return -1; }
|
||||
if (mask1.data == nullptr) { std::cerr << "Unable to load image " << mask1Name << std::endl; return -1; }
|
||||
if (mask2.data == nullptr) { std::cerr << "Unable to load image " << mask2Name << std::endl; return -1; }
|
||||
|
||||
}
|
||||
std::ofstream file{output};
|
||||
|
||||
// Les trucs qui sont pas des évènements
|
||||
camera.nextStep(WIDTH, HEIGHT);
|
||||
sf::Mouse::setPosition(sf::Vector2i{WIDTH/2, HEIGHT/2});
|
||||
// Compute the keypoints
|
||||
// Match the branches of skeletons
|
||||
// matching = branchesMatching(keypoints, skl1, skl2);
|
||||
|
||||
// Dessin de la scene
|
||||
drawScene(camera, split, split2, matching, colors);
|
||||
glScalef(0.01, 0.01, 1);
|
||||
|
||||
if (captureRequired)
|
||||
{
|
||||
window.capture().saveToFile("capture.jpg");
|
||||
captureRequired = false;
|
||||
}
|
||||
|
||||
// termine la trame courante (en interne, échange les deux tampons de rendu)
|
||||
window.display();
|
||||
}
|
||||
|
||||
// libération des ressources...
|
||||
// Write to file
|
||||
// for (auto const& pair : matching)
|
||||
// file << "m " << pair.first << " " << pair.second << "\n";
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void drawScene(sft::FreeFlyCamera const& camera, std::vector<Skeleton> const& split, std::vector<Skeleton> const& split2, std::vector<std::pair<unsigned int, unsigned int>> const& matching, std::vector<std::array<float,3>> const& colors)
|
||||
{
|
||||
// Initialisation
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
|
||||
// Position Camera gluLookAt(positionCamera, positionCible, vecteurVertical)
|
||||
camera.look();
|
||||
|
||||
for (auto i = 0u; i < matching.size(); i++)
|
||||
{
|
||||
// Find random color
|
||||
glColor3f(colors[i][0], colors[i][1], colors[i][2]);
|
||||
split[i].draw();
|
||||
glPushMatrix();
|
||||
glTranslatef(1000,0,0);
|
||||
split2[i].draw();
|
||||
glPopMatrix();
|
||||
glPushMatrix();
|
||||
glTranslatef(0,-1500,0);
|
||||
split[matching[i].first].draw();
|
||||
glPushMatrix();
|
||||
glTranslatef(1000,0,0);
|
||||
split2[matching[i].second].draw();
|
||||
glPopMatrix();
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
// MAJ de l'écran
|
||||
glFlush();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue