Cleaning Skeleton from the first part

This commit is contained in:
Thomas FORGIONE 2015-03-03 17:03:58 +01:00
parent 303e728646
commit 3a3578b270
8 changed files with 445 additions and 232 deletions

View File

@ -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)

View File

@ -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

View File

@ -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;
};

View File

@ -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);
}

View File

@ -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)

View File

@ -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)
{

193
Code/src/Skeleton/draw.cpp Normal file
View File

@ -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();
}

View File

@ -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();
}