From b641c5986a39b5d3bdd481f1ad828e5bf96a7676 Mon Sep 17 00:00:00 2001 From: Guillaume Courrier Date: Tue, 17 Dec 2019 13:55:33 +0100 Subject: [PATCH] =?UTF-8?q?Impl=C3=A9mentation=20de=20l'algorithme=20de=20?= =?UTF-8?q?knn?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/CMakeLists.txt | 2 + tests/src/CMakeLists.txt | 12 +-- tests/src/k_proches_voisins.cpp | 87 -------------------- tests/src/knn.cpp | 139 ++++++++++++++++++++++++++++++++ tests/src/math.hpp | 91 +++++++++++++++------ 5 files changed, 212 insertions(+), 119 deletions(-) delete mode 100644 tests/src/k_proches_voisins.cpp create mode 100644 tests/src/knn.cpp diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index beb1b85..2da5c72 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -4,6 +4,8 @@ project(miniprojet) set(PROJECT_CFLAGS "-Wall -Wextra -Wno-missing-braces -std=c++1z") find_package(OpenCV REQUIRED) +add_compile_options(-std=c++17) + add_subdirectory(src) add_subdirectory(examples) add_subdirectory(jean-luc-collette) diff --git a/tests/src/CMakeLists.txt b/tests/src/CMakeLists.txt index a47be66..73854df 100644 --- a/tests/src/CMakeLists.txt +++ b/tests/src/CMakeLists.txt @@ -1,13 +1,7 @@ -# file(GLOB headers *.hpp) -# file(GLOB lib_files *.cpp) - add_executable(traitement traitement.cpp) target_link_libraries(traitement ${OpenCV_LIBS}) -#add_executable(k_proches_voisins k_proches_voisins.cpp) -#target_link_libraries(k_proches_voisins ${OpenCV_LIBS}) -# target_include_directories(blk PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) -# target_compile_options (blk PUBLIC -std=c++11 ) +find_package(Boost COMPONENTS system filesystem REQUIRED) -# install(TARGETS blk DESTINATION lib ) -# install(FILES ${headers} DESTINATION include/${CMAKE_PROJECT_NAME}) +add_executable(knn knn.cpp) +target_link_libraries(knn ${OpenCV_LIBS} ${Boost_FILESYSTEM_LIBRARY} ${Boost_SYSTEM_LIBRARY}) diff --git a/tests/src/k_proches_voisins.cpp b/tests/src/k_proches_voisins.cpp deleted file mode 100644 index 265c2c6..0000000 --- a/tests/src/k_proches_voisins.cpp +++ /dev/null @@ -1,87 +0,0 @@ -#include -#include "math.hpp" -#include - -double distance(math::csignal& v1, math::csignal& v2, int n){ - if (v1.size() != v2.size()) { - throw std::runtime_error("les deux vecteurs doivent être de même longueur"); - } - double d; - double di; - for (int i=0; i& v){ - int arg = 0; - int max = v[0]; - for(int i = 1; i < v.size() ; ++i){ - if (v[i]>max){ - arg = i; - max = v[i]; - }; - }; - return arg; -}; - -//int main(math::csignal new_vect, std::map< math::csignal, std::string > dico, int k){ -int main(int argc, char** argv) { - std::vector> k_min; - std::map dico; - math::csignal new_vect; - int k; - double d; - int avance = 0; - int arret = 0; - int droite = 0; - int gauche = 0; - int rejet = 0; - std::vector vchoix; - for(auto& ref_vect : dico){ - d = distance(new_vect, ref_vect.first); - if (k_min.size() < k ){ - k_min.push_back({d, ref_vect.first}); - } else if (d < k_min[k-1].first){ - k_min.push_back({d, ref_vect.first}); - sort(k_min.begin(), k_min.end()); - k_min.pop_back(); - } - - } - for(auto i = k_min.begin(); i != k_min.end(); i++) { - if (dico[k_min[i].second].second == "avance"){ - avance = avance + 1 - } else if (dico[k_min[i].second].second == "arret"){ - arret = arret + 1 - } else if (dico[k_min[i].second].second == "droite"){ - arret = droite + 1 - } else if (dico[k_min[i].second].second == "gauche"){ - arret = gauche + 1 - } else if (dico[k_min[i].second].second == "rejet"){ - arret = rejet + 1 - } - } - vchoix.push_back(avance); - vchoix.push_back(arret); - vchoix.push_back(droite); - vchoix.push_back(gauche); - vchoix.push_back(rejet); - - int nchoix = argmax(vchoix); - std::string choix; - if (nchoix == 0){ - choix = "avance" - } else if (nchoix == 1){ - choix = "arret" - } else if (nchoix == 2){ - choix = "droite" - } else if (nchoix == 3){ - choix = "gauche" - } else if (nchoix == 4){ - choix = "rejet" - } -}; diff --git a/tests/src/knn.cpp b/tests/src/knn.cpp new file mode 100644 index 0000000..4dddf1b --- /dev/null +++ b/tests/src/knn.cpp @@ -0,0 +1,139 @@ +#include +#include "math.hpp" +#include +#include +#include +#include +#include +#include +#include + +using dataset = std::vector>; + +struct path_leaf_string { + std::string operator()(const boost::filesystem::directory_entry& entry) const + { + return entry.path().leaf().string(); + } +}; + +void read_directory(const std::string& name, std::vector& v) { + boost::filesystem::path p(name); + boost::filesystem::directory_iterator start(p); + boost::filesystem::directory_iterator end; + std::transform(start, end, std::back_inserter(v), path_leaf_string()); +} + +double distance(math::csignal& v1, math::csignal& v2, int n){ + if (v1.size() != v2.size()) { + throw std::runtime_error("les deux vecteurs doivent être de même longueur"); + } + double d = 0; + + auto v1_it = v1.begin(); + auto v2_it = v2.begin(); + + while (v1_it != v1.end()) { + double dist = std::abs(*(v1_it++) - *(v2_it++)); + d += std::pow(dist, n); + } + return std::pow(d, 1/n); +}; + +int argmax(std::vector& v){ + int arg = 0; + int max = v[0]; + for(int i = 1; i < v.size() ; ++i){ + if (v[i]>max){ + arg = i; + max = v[i]; + }; + }; + return arg; +}; + +struct pair_comp { + bool operator()(std::pair a, std::pair b) { + if (a.first == b.first) { + return false; + } + if (a.first > b.first) { + return true; + } + return false; + }; +}; + +math::csignal img2desc(std::string filename, int cmax, int threshold) { + cv::Mat img = cv::imread(filename, CV_LOAD_IMAGE_COLOR); + return math::descriptors(img, cmax, threshold); +} + +dataset get_data(std::string path, int size, int cmax, int threshold) { + dataset res; + std::vector dirs; + read_directory(path, dirs); + for (auto dir: dirs) { + std::vector files; + read_directory(path+"/"+dir, files); + + std::string label = dir; + int count = 0; + for (int i=0; count 2) { + path = argv[1]; + threshold = atoi(argv[2]); + } else { + std::cout << "Invalid number of arguments" << std::endl; + return 0; + } + + dataset references = get_data(path, size, cmax, threshold); + math::csignal sample = img2desc(path+"/arret/arret0199.jpg", cmax, threshold); + std::priority_queue, std::vector>, pair_comp> neighbors; + std::map labels; + + for (auto desc: references) { + double d = distance(desc.first, sample, 1); + neighbors.push({d, desc.second}); + } + + for (int i=0; i nearest = neighbors.top(); + neighbors.pop(); + labels[nearest.second] += 1; + } + + int max = 0; + std::string label; + + for (auto val: labels) { + if (val.second > max) { + max = val.second; + label = val.first; + } + } + + std::cout << label << std::endl; +}; diff --git a/tests/src/math.hpp b/tests/src/math.hpp index 9428bc6..6fe90c5 100644 --- a/tests/src/math.hpp +++ b/tests/src/math.hpp @@ -5,6 +5,7 @@ #include #include #include +#include namespace math { @@ -284,29 +285,6 @@ namespace math { return res; } - csignal descriptors(const contour& cont, int cmax) { - csignal z = cont2sig(cont); - complex zm = mean(z); - csignal tfd = dft(diff(z, zm)); - tfd /= z.size(); - int cmin = -cmax; - csignal desc = extract(tfd, cmin, cmax); - - if (std::abs(desc[desc.size()/2-1]) > std::abs(desc[desc.size()/2+1])) { - std::reverse(desc.begin(), desc.end()); - } - - double phy = std::arg(desc[desc.size()/2-1]*desc[desc.size()/2+1])/2; - desc *= std::exp(complex(0, -phy)); - double theta = std::arg(desc[desc.size()/2+1]); - - for (int k=0; k> contours; + + cv::Mat binary(img.rows, img.cols, CV_8UC1); + cv::Mat blur_img; + cv::GaussianBlur(img, blur_img, cv::Size(7,7), 1.5, 1.5); + + std::vector hierarchy; + + math::filter(img, binary, threshold); + + cv::findContours(binary, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE); + if (contours.size() > 0) { + std::vector> contrs; + + int id = max_cont(contours); + + csignal z = cont2sig(contours[id]); + complex zm = mean(z); + csignal tfd = dft(diff(z, zm)); + tfd /= z.size(); + int cmin = -cmax; + csignal desc = extract(tfd, cmin, cmax); + + if (std::abs(desc[desc.size()/2-1]) > std::abs(desc[desc.size()/2+1])) { + std::reverse(desc.begin(), desc.end()); + } + + double phy = std::arg(desc[desc.size()/2-1]*desc[desc.size()/2+1])/2; + desc *= std::exp(complex(0, -phy)); + double theta = std::arg(desc[desc.size()/2+1]); + + for (int k=0; k std::abs(desc[desc.size()/2+1])) { + std::reverse(desc.begin(), desc.end()); + } + + double phy = std::arg(desc[desc.size()/2-1]*desc[desc.size()/2+1])/2; + desc *= std::exp(complex(0, -phy)); + double theta = std::arg(desc[desc.size()/2+1]); + + for (int k=0; k