├── .gitignore ├── .travis.yml ├── CMakeLists.txt ├── LICENSE ├── README.md ├── benchmarks ├── CMakeLists.txt ├── box2d_filter.cc ├── boxNd_iterator.cc ├── box_5x5_filter.cc ├── box_5x5_filter2.cc ├── box_filter.cc ├── distance_transform.cc ├── fast_count.hh ├── fast_detector.cc ├── fast_detector_draw_speedup.py ├── fast_detector_draw_speedup_1d.py ├── fill.cc ├── for_fast.cc ├── get_time.hh ├── image_add.cc ├── image_add2.cc ├── image_iterations.cc ├── image_iterator.cc ├── integral_images.cc ├── iteration_on_domains.cc ├── lbp.cc ├── liie.cc ├── parallel_for.cc ├── patch_malloc_vs_static.cc └── pyrlk_opencv_comparison.cc ├── evaluation ├── semi_dense_optical_flow │ ├── CMakeLists.txt │ ├── KITTI.cc │ ├── display.py │ ├── pareto_KITTI.py │ └── symbols.hh └── utils │ └── kitti.hh ├── examples ├── CMakeLists.txt ├── README.md ├── box_filter.cc ├── fast_detector.cc ├── hough_extruder_example.hh ├── hough_extruder_main.cc ├── image_view.cc ├── keypoint_matching.cc ├── optical_flow.cc ├── symbols.hh ├── tutorial.cc ├── video_extruder.cc ├── video_extruder_javascript │ ├── cpp │ │ ├── Makefile │ │ ├── main.cc │ │ └── symbols.hh │ ├── gumwrapper.min.js │ ├── test.html │ └── test.js └── video_extruder_paint.cc ├── install.sh ├── tests ├── CMakeLists.txt ├── block_wise.cc ├── border.cc ├── boxNd_iterator.cc ├── box_nbh2d.cc ├── cast.cc ├── colorspace_conversions.cc ├── descriptor_matcher.cc ├── fill.cc ├── image2d.cc ├── image3d.cc ├── imageNd.cc ├── imageNd_iterator.cc ├── lbp.cc ├── liie.cc ├── opencv_bridge.cc ├── pixel_wise.cc ├── pyramid.cc ├── pyrlk.cc ├── sandbox.cc ├── sum.cc ├── tuple_utils.cc └── window.cc └── vpp ├── algorithms ├── descriptor_matcher.hh ├── descriptor_matcher │ ├── bruteforce_matcher.hh │ ├── dispatch.hh │ ├── distances.hh │ ├── global_search.hh │ ├── grid_index.hh │ ├── index.hh │ ├── index1d.hh │ ├── index1d.old.hh │ ├── local_index1d_sad_descriptor_matcher.hh │ └── local_search.hh ├── distance_transforms │ └── distance_transforms.hh ├── epipolar_geometry.hh ├── fast_detector │ ├── fast.hh │ └── fast.hpp ├── filters │ └── scharr.hh ├── lbp │ ├── lbp_distance.hh │ └── lbp_transform.hh ├── line_tracker_4_sfm.hh ├── line_tracker_4_sfm │ ├── Readme.md │ ├── fast_dht.hh │ ├── fast_dht │ │ ├── cordic.hh │ │ ├── dense_one_to_one_hough.hh │ │ ├── dense_one_to_one_hough.hpp │ │ ├── fast_hough.hh │ │ └── fast_hough.hpp │ ├── hough_extruder.hh │ ├── hough_extruder │ │ ├── draw_line_hough.hh │ │ ├── draw_trajectories_hough.hh │ │ ├── feature_matching_hough.hh │ │ ├── feature_matching_hough.hpp │ │ ├── paint.hh │ │ ├── track.hh │ │ ├── track.hpp │ │ ├── unscented_kalman_filter.hh │ │ └── unscented_kalman_filter.hpp │ ├── miscellanous.hh │ ├── miscellanous │ │ ├── define.hh │ │ ├── lookup_tables.hh │ │ └── operations.hh │ ├── sfm.hh │ ├── sfm │ │ ├── plucker.hh │ │ ├── structure_from_motion.hh │ │ ├── structure_from_motion.hpp │ │ └── vanishing_point.hh │ └── symbols.hh ├── lucas_kanade.hh ├── lucas_kanade │ └── lucas_kanade.hpp ├── optical_flow.hh ├── optical_flow │ ├── dense_optical_flow.hpp │ ├── epipolar_match.hh │ ├── gradient_descent.hh │ ├── propagation.hh │ ├── semi_dense_optical_flow.hpp │ └── sparse_optical_flow.hh ├── pyrlk │ ├── lk.hh │ └── pyrlk_match.hh ├── slam │ └── triangulate.hh ├── symbols.hh ├── video_extruder.hh └── video_extruder │ ├── optical_flow_experiments.hh │ └── video_extruder.hpp ├── core ├── block_wise.hh ├── box2d.hh ├── boxNd.hh ├── boxNd_iterator.hh ├── boxNd_iterator.hpp ├── cast_to_float.hh ├── clone.hh ├── coding_style ├── colorspace_conversions.hh ├── const.hh ├── copy.hh ├── dige.hh ├── fill.hh ├── image2d.hh ├── image3d.hh ├── imageNd.hh ├── imageNd.hpp ├── imageNd_iterator.hh ├── keypoint_container.hh ├── keypoint_container.hpp ├── keypoint_trajectory.hh ├── liie.hh ├── make_array.hh ├── numbers.sb ├── patch.hh ├── pixel_wise.hh ├── pixel_wise.hpp ├── pyramid.hh ├── relative_accessor.hh ├── sum.hh ├── symbol_definitions.hh ├── symbols.hh ├── tuple_utils.hh ├── vector.hh ├── window.hh └── zero.hh ├── draw ├── draw.hh ├── draw_trajectories.hh ├── rgb_colors.hh ├── square.hh └── symbols.hh ├── utils ├── opencv_bridge.hh ├── opencv_utils.hh └── profiler.hh └── vpp.hh /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Compiled Dynamic libraries 8 | *.so 9 | *.dylib 10 | *.dll 11 | 12 | # Compiled Static libraries 13 | *.lai 14 | *.la 15 | *.a 16 | *.lib 17 | 18 | # Executables 19 | *.exe 20 | *.out 21 | *.app 22 | 23 | *~ 24 | build 25 | 26 | iod/ 27 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: cpp 2 | 3 | matrix: 4 | include: 5 | - os: osx 6 | osx_image: xcode7.3 7 | compiler: clang 8 | env: COMPILER=clang++ 9 | before_install: 10 | - brew update 11 | - brew tap homebrew/science 12 | - brew install eigen 13 | - brew install opencv --without-python --without-test --without-opencl 14 | - brew ln opencv --force 15 | - os: linux 16 | dist: trusty 17 | sudo: false 18 | compiler: gcc 19 | addons: 20 | apt: 21 | sources: ['ubuntu-toolchain-r-test', 'boost-latest'] 22 | packages: ['g++-6', 'libboost1.54-dev', 'libopencv-dev', 'libeigen3-dev'] 23 | env: COMPILER=g++-6 24 | - os: linux 25 | dist: trusty 26 | sudo: false 27 | compiler: clang 28 | addons: 29 | apt: 30 | sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-3.8', 'boost-latest'] 31 | packages: ['g++-6', 'clang-3.8', 'libboost1.54-dev', 'libopencv-dev', 'libeigen3-dev' ] 32 | env: COMPILER=clang++-3.8 33 | - os: linux 34 | dist: trusty 35 | sudo: false 36 | compiler: clang 37 | addons: 38 | apt: 39 | sources: 40 | - ubuntu-toolchain-r-test 41 | - boost-latest 42 | - sourceline: 'ppa:ubuntu-toolchain-r/test' 43 | - sourceline: 'deb http://apt.llvm.org/trusty/ llvm-toolchain-trusty-3.9 main' 44 | - key_url: 'http://apt.llvm.org/llvm-snapshot.gpg.key' 45 | packages: ['clang-3.9', 'g++-6', 'libboost1.54-dev', 'libopencv-dev', 'libeigen3-dev' ] 46 | env: COMPILER=clang++-3.9 47 | 48 | script: 49 | - export CXX=${COMPILER} 50 | - ${CXX} --version 51 | 52 | - export VPP_DIR=$PWD 53 | - git clone https://github.com/matt-42/iod 54 | - cd iod 55 | - mkdir -p ~/local 56 | - mkdir build && cd build && cmake .. -DCMAKE_INSTALL_PREFIX=~/local && make -j4 install; 57 | 58 | - cd $VPP_DIR 59 | - mkdir -p build && cd build 60 | - cmake .. -DIOD_INCLUDE_DIR=~/local/include && make -j4 61 | - cd tests 62 | - ctest --output-on-failure 63 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 2.8) 2 | 3 | project (vpp) 4 | 5 | find_package(PkgConfig) 6 | pkg_search_module(Eigen3 REQUIRED eigen3) 7 | include_directories(${Eigen3_INCLUDE_DIRS}) 8 | 9 | set(CMAKE_CXX_STANDARD 14) 10 | enable_testing() 11 | 12 | add_subdirectory(tests) 13 | #add_subdirectory(examples) 14 | 15 | install(DIRECTORY vpp DESTINATION include 16 | FILES_MATCHING PATTERN "*.hh") 17 | install(DIRECTORY vpp DESTINATION include 18 | FILES_MATCHING PATTERN "*.hpp") 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Matthieu Garrigues 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /benchmarks/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | project (vpp_benchmarks) 3 | 4 | find_package(OpenCV REQUIRED) 5 | 6 | include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..) 7 | include_directories(/usr/include/eigen3 $ENV{HOME}/local/include) 8 | 9 | link_directories($ENV{HOME}/local/lib) 10 | add_definitions(-O3 -std=c++1y -march=native -DNDEBUG) 11 | #add_definitions(-g -fno-omit-frame-pointer) # to profile 12 | 13 | if(${CMAKE_CXX_COMPILER} MATCHES ".*clang\\+\\+") 14 | SET(openmp_lib omp) 15 | ADD_DEFINITIONS(-fopenmp=libomp) 16 | else(${CMAKE_CXX_COMPILER} MATCHES ".*clang\\+\\+") 17 | SET(openmp_lib gomp) 18 | ADD_DEFINITIONS(-fopenmp) 19 | endif(${CMAKE_CXX_COMPILER} MATCHES ".*clang\\+\\+") 20 | 21 | set(CMAKE_VERBOSE_MAKEFILE ON) 22 | add_executable(boxNd_iterator boxNd_iterator.cc) 23 | add_executable(iteration_on_domains iteration_on_domains.cc) 24 | add_executable(image_iterations image_iterations.cc) 25 | add_executable(image_add image_add.cc) 26 | add_executable(image_add2 image_add2.cc) 27 | add_executable(box_filter box_filter.cc) 28 | add_executable(box_5x5_filter box_5x5_filter.cc) 29 | add_executable(box_5x5_filter2 box_5x5_filter2.cc) 30 | add_executable(box2d_filter box2d_filter.cc) 31 | add_executable(fast_detector fast_detector.cc) 32 | add_executable(for_fast for_fast.cc) 33 | add_executable(pyrlk_opencv_comparison pyrlk_opencv_comparison.cc) 34 | add_executable(liie liie.cc) 35 | add_executable(distance_transform distance_transform.cc) 36 | add_executable(descriptor_matcher descriptor_matcher.cc) 37 | #add_executable(lbp lbp.cc) 38 | 39 | target_link_libraries(image_iterations ${openmp_lib}) 40 | target_link_libraries(image_add ${openmp_lib} opencv_core) 41 | target_link_libraries(image_add2 pthread benchmark ${openmp_lib} opencv_core) 42 | target_link_libraries(box_filter ${openmp_lib}) 43 | target_link_libraries(box_5x5_filter ${openmp_lib} opencv_core opencv_imgproc) 44 | target_link_libraries(box_5x5_filter2 pthread ${openmp_lib} opencv_core opencv_imgproc benchmark) 45 | target_link_libraries(box2d_filter ${openmp_lib}) 46 | target_link_libraries(fast_detector ${OpenCV_LIBS} ${openmp_lib} benchmark pthread) 47 | target_link_libraries(for_fast ${OpenCV_LIBS} ${openmp_lib}) 48 | target_link_libraries(pyrlk_opencv_comparison ${OpenCV_LIBS} ${openmp_lib}) 49 | target_link_libraries(liie ${openmp_lib}) 50 | target_link_libraries(distance_transform ${openmp_lib} ${OpenCV_LIBS} gcov) 51 | target_link_libraries(descriptor_matcher benchmark pthread ${openmp_lib}) 52 | #target_link_libraries(lbp ${openmp_lib}) 53 | -------------------------------------------------------------------------------- /benchmarks/boxNd_iterator.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "get_time.hh" 5 | 6 | int main() 7 | { 8 | using namespace vpp; 9 | 10 | image2d img(1000,1000); 11 | 12 | // Cache warm up. 13 | for (int k = 0; k < 10; k++) 14 | for (auto p : img.domain()) 15 | img(p) = p[0] + p[1]; 16 | 17 | double time; 18 | 19 | time = get_time_in_seconds(); 20 | for (int k = 0; k < 10; k++) 21 | for (int r = 0; r < 1000; r++) 22 | for (int c = 0; c < 1000; c++) 23 | img(vint2(r, c)) = r + c; 24 | double ref_time = get_time_in_seconds() - time; 25 | 26 | 27 | time = get_time_in_seconds(); 28 | for (int k = 0; k < 10; k++) 29 | for (auto p : img.domain()) 30 | img(p) = p[0] + p[1]; 31 | double vpp_time = get_time_in_seconds() - time; 32 | 33 | std::cout << "Box iterator: " << std::endl; 34 | std::cout << "ref_time: " << ref_time << std::endl; 35 | std::cout << "vpp_time: " << vpp_time << std::endl; 36 | std::cout << "box iterator overhead: " << 100. * vpp_time / ref_time - 100. << "%" << std::endl; 37 | } 38 | -------------------------------------------------------------------------------- /benchmarks/box_5x5_filter2.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "get_time.hh" 9 | 10 | using namespace vpp; 11 | 12 | 13 | void raw_naive(image2d A, image2d B) 14 | { 15 | for (int r = 0; r < A.nrows(); r++) 16 | for (int c = 0; c < A.ncols(); c++) 17 | { 18 | int sum = 0; 19 | for (int d = -2; d <= 2; d++) 20 | for (int e = -2; e <= 2; e++) 21 | sum += B(r + d, c + e); 22 | A(r, c) = sum / 25; 23 | } 24 | } 25 | 26 | void check(image2d A, image2d B) 27 | { 28 | for (int r = 5; r < A.nrows() - 5; r++) 29 | for (int c = 5; c < A.ncols() - 5; c++) 30 | { 31 | 32 | int sum = 0; 33 | for (int d = -2; d <= 2; d++) 34 | for (int e = -2; e <= 2; e++) 35 | sum += B(r + d, c + e); 36 | 37 | if (A(r, c) != sum / 25) 38 | throw std::runtime_error("error!"); 39 | assert(A(r, c) == sum / 25); 40 | } 41 | } 42 | 43 | 44 | void raw_openmp_simd(image2d A, image2d B) 45 | { 46 | int nr = A.nrows(); 47 | 48 | #pragma omp parallel for 49 | for (int r = 0; r < nr; r++) 50 | { 51 | int* curA = &A(vint2(r, 0)); 52 | int nc = A.ncols(); 53 | 54 | int* rows[5]; 55 | for (int i = -2; i <= 2; i++) 56 | rows[i + 2] = &B(vint2(r + i, 0)); 57 | 58 | #pragma omp simd 59 | for (int c = 0; c < nc; c++) 60 | { 61 | int sum = 0; 62 | #pragma unroll 63 | for (int d = -2; d <= 2; d++) 64 | for (int e = -2; e <= 2; e++) 65 | sum += rows[d + 2][c + e]; 66 | curA[c] = sum / 25; 67 | } 68 | } 69 | } 70 | 71 | void vpp_pixel_wise(image2d B, image2d A) 72 | { 73 | vpp::pixel_wise(B, relative_access(A)) | [&] (int& b, auto a) 74 | { 75 | int sum = 0; 76 | for (int i = -2; i <= 2; i++) 77 | for (int j = -2; j <= 2; j++) 78 | sum += a(i, j); 79 | b = sum / 25; 80 | }; 81 | } 82 | 83 | void opencv(image2d A, image2d B) 84 | { 85 | cv::boxFilter(to_opencv(B), to_opencv(A), -1, cv::Size(5,5), cv::Point(-1, -1), true, cv::BORDER_CONSTANT); 86 | } 87 | 88 | 89 | static void BM_pixel_wise(benchmark::State& state) 90 | { 91 | image2d A(state.range(0), state.range(0), _border = 2); 92 | image2d B(state.range(0), state.range(0), _border = 2); 93 | 94 | fill(A, 1); 95 | fill(B, 2); 96 | while (state.KeepRunning()) 97 | { 98 | vpp_pixel_wise(A, B); 99 | } 100 | } 101 | 102 | static void BM_opencv(benchmark::State& state) 103 | { 104 | image2d A(state.range(0), state.range(0), _border = 2); 105 | image2d B(state.range(0), state.range(0), _border = 2); 106 | 107 | fill(A, 1); 108 | fill(B, 2); 109 | while (state.KeepRunning()) 110 | opencv(A, B); 111 | } 112 | 113 | static void BM_raw_openmp_simd(benchmark::State& state) 114 | { 115 | image2d A(state.range(0), state.range(0), _border = 2); 116 | image2d B(state.range(0), state.range(0), _border = 2); 117 | fill(A, 1); fill(B, 2); 118 | while (state.KeepRunning()) 119 | raw_openmp_simd(A, B); 120 | } 121 | 122 | BENCHMARK(BM_pixel_wise)->Range(100, 2000); 123 | BENCHMARK(BM_raw_openmp_simd)->Range(100, 2000); 124 | BENCHMARK(BM_opencv)->Range(100, 2000); 125 | 126 | BENCHMARK_MAIN(); 127 | -------------------------------------------------------------------------------- /benchmarks/fast_detector.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace vpp; 13 | typedef image2d I; 14 | 15 | static image2d init_input(benchmark::State& state) 16 | { 17 | image2d A(state.range(0), state.range(0), _border = 3); 18 | I src = clone(from_opencv(cv::imread("./img.jpg")), _border = 3); 19 | image2d src_gl = rgb_to_graylevel(src); 20 | 21 | for(vint2 p : A.domain()) 22 | A(p) = src_gl(p[0] % std::min(A.nrows(), src.nrows()), 23 | p[1] % std::min(A.ncols(), src.ncols())); 24 | 25 | fill_border_mirror(A); 26 | return A; 27 | } 28 | 29 | static void vpp_raw(benchmark::State& state) 30 | { 31 | image2d A = init_input(state); 32 | std::vector keypoints; 33 | 34 | const int th = state.range(1); 35 | 36 | while (state.KeepRunning()) 37 | { 38 | keypoints.clear(); 39 | keypoints = fast9(A, th); 40 | } 41 | } 42 | 43 | 44 | static void vpp_raw_lm(benchmark::State& state) 45 | { 46 | image2d A = init_input(state); 47 | std::vector keypoints; 48 | const int th = state.range(1); 49 | while (state.KeepRunning()) 50 | { 51 | keypoints.clear(); 52 | keypoints = fast9(A, th, _local_maxima); 53 | } 54 | } 55 | 56 | 57 | static void vpp_raw_bm(benchmark::State& state) 58 | { 59 | image2d A = init_input(state); 60 | std::vector keypoints; 61 | const int th = state.range(1); 62 | while (state.KeepRunning()) 63 | { 64 | keypoints.clear(); 65 | keypoints = fast9(A, th, _blockwise, _block_size = 10); 66 | } 67 | } 68 | 69 | 70 | static void vpp_opencv_lm(benchmark::State& state) 71 | { 72 | image2d A = init_input(state); 73 | 74 | cv::Mat cv_A = to_opencv(A); 75 | 76 | const int th = state.range(1); 77 | 78 | std::vector keypoints; 79 | while (state.KeepRunning()) 80 | { 81 | keypoints.clear(); 82 | FAST(cv_A, keypoints, th, true); 83 | } 84 | } 85 | 86 | 87 | static void vpp_opencv_raw(benchmark::State& state) 88 | { 89 | image2d A = init_input(state); 90 | 91 | cv::Mat cv_A = to_opencv(A); 92 | 93 | const int th = state.range(1); 94 | 95 | std::vector keypoints; 96 | while (state.KeepRunning()) 97 | { 98 | keypoints.clear(); 99 | FAST(cv_A, keypoints, th, false); 100 | } 101 | } 102 | 103 | static void CustomArguments(benchmark::internal::Benchmark* b) { 104 | for (int th = 1; th <= 100; th += 5) 105 | for (int w = 500; w <= 500; w += 300) 106 | b->ArgPair(w, th); 107 | } 108 | 109 | BENCHMARK(vpp_raw)->Apply(CustomArguments); 110 | BENCHMARK(vpp_raw_lm)->Apply(CustomArguments); 111 | BENCHMARK(vpp_raw_bm)->Range(300, 2000); 112 | BENCHMARK(vpp_opencv_lm)->Apply(CustomArguments); 113 | BENCHMARK(vpp_opencv_raw)->Apply(CustomArguments); 114 | BENCHMARK_MAIN(); 115 | -------------------------------------------------------------------------------- /benchmarks/fast_detector_draw_speedup.py: -------------------------------------------------------------------------------- 1 | #! /bin/python3 2 | 3 | 4 | import GPOF.strategies as gs 5 | import GPOF.runset as gr 6 | import GPOF.display as gd 7 | 8 | sets = gr.open_runset_from_google_benchmark('./fast_lm_benchmark3.txt') 9 | 10 | v1 = sets['vpp_raw'].view(('range_x', 'range_y', 'real_time')) 11 | v2 = sets['vpp_opencv_raw'].view(('range_x', 'range_y', 'real_time')) 12 | 13 | data=[] 14 | for r1, r2 in zip(v1.data, v2.data): 15 | data.append([r1[0], r1[1], r2[2] / r1[2]]) 16 | 17 | v=gr.RunSetView(('image_width', 'th', 'speedup'), data); 18 | 19 | gd.display_2d_heatmap(v) 20 | 21 | -------------------------------------------------------------------------------- /benchmarks/fast_detector_draw_speedup_1d.py: -------------------------------------------------------------------------------- 1 | #! /bin/python3 2 | 3 | 4 | import GPOF.strategies as gs 5 | import GPOF.runset as gr 6 | import GPOF.display as gd 7 | 8 | sets = gr.open_runset_from_google_benchmark('./fast_raw_bench.txt') 9 | 10 | v1 = sets['vpp_raw'].view(('range_y', 'real_time')) 11 | v2 = sets['vpp_opencv_raw'].view(('range_y', 'real_time')) 12 | 13 | data=[] 14 | for r1, r2 in zip(v1.data, v2.data): 15 | data.append([r1[0], r2[1] / r1[1]]) 16 | 17 | v=gr.RunSetView(('th', 'speedup'), data); 18 | 19 | gd.display_2d_points(v) 20 | 21 | -------------------------------------------------------------------------------- /benchmarks/fill.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace vpp; 5 | 6 | static void BM_fill(benchmark::State& state) { 7 | image2d A(200,200); 8 | while (state.KeepRunning()) 9 | { 10 | fill(A, 0); 11 | } 12 | } 13 | 14 | BENCHMARK(BM_fill); 15 | 16 | static void BM_memset(benchmark::State& state) { 17 | auto arr = new int[200 * 200]; 18 | while (state.KeepRunning()) 19 | { 20 | memset(arr, 0, sizeof(int) * 200 * 200); 21 | } 22 | delete arr; 23 | } 24 | 25 | // Register the function as a benchmark 26 | BENCHMARK(BM_memset); 27 | 28 | 29 | static void BM_fill_with_border(benchmark::State& state) { 30 | image2d A(190,190, _border = 5); 31 | while (state.KeepRunning()) 32 | { 33 | fill_with_border(A, 0); 34 | } 35 | } 36 | BENCHMARK(BM_fill_with_border); 37 | 38 | static void BM_fill_border_with_value(benchmark::State& state) { 39 | image2d A(190,190, _border = 5); 40 | while (state.KeepRunning()) 41 | { 42 | fill_border_with_value(A, 0); 43 | } 44 | } 45 | BENCHMARK(BM_fill_border_with_value); 46 | 47 | 48 | static void BM_fill_border_closest(benchmark::State& state) { 49 | image2d A(190,190, _border = 5); 50 | while (state.KeepRunning()) 51 | { 52 | fill_border_closest(A); 53 | } 54 | } 55 | BENCHMARK(BM_fill_border_closest); 56 | 57 | 58 | static void BM_fill_border_mirror(benchmark::State& state) { 59 | image2d A(190,190, _border = 5); 60 | while (state.KeepRunning()) 61 | { 62 | fill_border_mirror(A); 63 | } 64 | } 65 | BENCHMARK(BM_fill_border_mirror); 66 | 67 | BENCHMARK_MAIN(); 68 | -------------------------------------------------------------------------------- /benchmarks/get_time.hh: -------------------------------------------------------------------------------- 1 | 2 | inline double get_time_in_seconds() 3 | { 4 | timespec ts; 5 | clock_gettime(CLOCK_REALTIME, &ts); 6 | return double(ts.tv_sec) + double(ts.tv_nsec) / 1000000000.; 7 | } 8 | 9 | template 10 | double time(F f) 11 | { 12 | double t = get_time_in_seconds(); 13 | 14 | f(); 15 | 16 | return get_time_in_seconds() - t; 17 | } 18 | -------------------------------------------------------------------------------- /benchmarks/image_add2.cc: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace vpp; 8 | 9 | 10 | template 11 | void check(I A, I B, I C) 12 | { 13 | for (int r = 0; r < A.nrows(); r++) 14 | for (int c = 0; c < A.ncols(); c++) 15 | { 16 | if (A(r, c) != B(r, c) + C(r, c)) 17 | { 18 | std::cout << A(r, c) << " " << B(r, c) << " " << C(r, c) << std::endl; 19 | throw std::runtime_error("error."); 20 | } 21 | } 22 | } 23 | 24 | void raw_openmp_simd(image2d A, image2d B, image2d C) 25 | { 26 | const int nr = A.nrows(); 27 | const int nc = A.ncols(); 28 | 29 | #pragma omp parallel for 30 | for (int r = 0; r < nr; r++) 31 | { 32 | int* curA = &A(vint2(r, 0)); 33 | int* curB = &B(vint2(r, 0)); 34 | int* curC = &C(vint2(r, 0)); 35 | int* endA = curA + A.nrows(); 36 | 37 | #pragma omp simd aligned(curA, curB, curC : 8 * sizeof(int)) 38 | for (int i = 0; i < nc; i++) 39 | curA[i] = curB[i] + curC[i]; 40 | } 41 | } 42 | 43 | void opencv(image2d& A, image2d B, image2d C) 44 | { 45 | cv::add(to_opencv(C), to_opencv(B), to_opencv(A)); 46 | } 47 | 48 | void vpp_pixel_wise(image2d A, 49 | image2d B, 50 | image2d C) 51 | { 52 | vpp::pixel_wise(A, B, C) | [] (int& a, int b, int c) 53 | { 54 | a = b + c; 55 | }; 56 | } 57 | 58 | 59 | static void BM_pixel_wise(benchmark::State& state) 60 | { 61 | image2d A(state.range(0), state.range(0)); 62 | image2d B(state.range(0), state.range(0)); 63 | image2d C(state.range(0), state.range(0)); 64 | 65 | fill(A, 1); 66 | fill(B, 2); 67 | fill(C, 3); 68 | while (state.KeepRunning()) 69 | { 70 | vpp_pixel_wise(A, B, C); 71 | } 72 | check(A, B, C); 73 | } 74 | 75 | 76 | static void BM_opencv(benchmark::State& state) 77 | { 78 | image2d A(state.range(0), state.range(0)); 79 | image2d B(state.range(0), state.range(0)); 80 | image2d C(state.range(0), state.range(0)); 81 | 82 | fill(A, 1); 83 | fill(B, 2); 84 | fill(C, 3); 85 | while (state.KeepRunning()) 86 | opencv(A, B, C); 87 | check(A, B, C); 88 | } 89 | 90 | 91 | static void BM_raw_openmp_simd(benchmark::State& state) 92 | { 93 | image2d A(state.range(0), state.range(0)); 94 | image2d B(state.range(0), state.range(0)); 95 | image2d C(state.range(0), state.range(0)); 96 | 97 | fill(A, 1); 98 | fill(B, 2); 99 | fill(C, 3); 100 | while (state.KeepRunning()) 101 | { 102 | raw_openmp_simd(A, B, C); 103 | } 104 | check(A, B, C); 105 | } 106 | 107 | BENCHMARK(BM_pixel_wise)->Range(300, 2000); 108 | BENCHMARK(BM_opencv)->Range(300, 2000); 109 | BENCHMARK(BM_raw_openmp_simd)->Range(300, 2000); 110 | 111 | BENCHMARK_MAIN(); 112 | -------------------------------------------------------------------------------- /benchmarks/image_iterations.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "get_time.hh" 5 | 6 | using namespace vpp; 7 | 8 | 9 | void raw_naive(image2d img) 10 | { 11 | for (int r = 0; r < img.nrows(); r++) 12 | for (int c = 0; c < img.ncols(); c++) 13 | img(r, c) = r + c; 14 | } 15 | 16 | void check(image2d img) 17 | { 18 | for (int r = 0; r < img.nrows(); r++) 19 | for (int c = 0; c < img.ncols(); c++) 20 | { 21 | assert(img(r, c) == r + c); 22 | } 23 | } 24 | 25 | void raw_sequential(image2d img) 26 | { 27 | int nr = img.nrows(); 28 | for (int r = 0; r < nr; r++) 29 | { 30 | int* cur = &img(vint2(r, 0)); 31 | int* end = cur + img.nrows(); 32 | int c = 0; 33 | while (cur != end) 34 | { 35 | *cur = r + c; 36 | ++cur; 37 | c++; 38 | } 39 | } 40 | } 41 | 42 | void raw_openmp(image2d img) 43 | { 44 | int nr = img.nrows(); 45 | #pragma omp parallel for 46 | for (int r = 0; r < nr; r++) 47 | { 48 | int* cur = &img(vint2(r, 0)); 49 | int* end = cur + img.ncols(); 50 | int c = 0; 51 | while (cur != end) 52 | { 53 | *cur = r + c; 54 | ++cur; 55 | c++; 56 | } 57 | } 58 | } 59 | 60 | 61 | void raw_openmp_simd(image2d img) 62 | { 63 | int nr = img.nrows(); 64 | #pragma omp parallel for 65 | for (int r = 0; r < nr; r++) 66 | { 67 | int* cur = &img(vint2(r, 0)); 68 | int nc = img.ncols(); 69 | 70 | #pragma omp simd 71 | for (int i = 0; i < nc; i++) 72 | { 73 | cur[i] = r; 74 | } 75 | } 76 | } 77 | 78 | void vpp_pixel_wise(image2d img) 79 | { 80 | vpp::pixel_wise(img, img.domain()) | [] (auto& p, auto& c) 81 | { 82 | p = c[0] + c[1]; 83 | }; 84 | } 85 | 86 | int main() 87 | { 88 | ::sched_param sc_params; 89 | sc_params.sched_priority = 1; 90 | if (::sched_setscheduler(::getpid(), SCHED_FIFO, &sc_params)) 91 | ::fprintf(stderr, "sched_setscheduler(): %s\n", ::strerror(errno)); 92 | 93 | image2d img(1000,1000); 94 | 95 | int K = 400; 96 | double time; 97 | 98 | 99 | // Cache warm up. 100 | raw_naive(img); 101 | 102 | fill(img, 0); 103 | time = get_time_in_seconds(); 104 | for (int k = 0; k < K; k++) 105 | raw_naive(img); 106 | double raw_naive_time = get_time_in_seconds() - time; 107 | check(img); 108 | 109 | fill(img, 0); 110 | time = get_time_in_seconds(); 111 | for (int k = 0; k < K; k++) 112 | raw_sequential(img); 113 | double raw_sequential_time = get_time_in_seconds() - time; 114 | check(img); 115 | 116 | fill(img, 0); 117 | time = get_time_in_seconds(); 118 | for (int k = 0; k < K; k++) 119 | raw_openmp(img); 120 | double raw_openmp_time = get_time_in_seconds() - time; 121 | check(img); 122 | 123 | 124 | fill(img, 0); 125 | time = get_time_in_seconds(); 126 | for (int k = 0; k < K; k++) 127 | raw_openmp_simd(img); 128 | double raw_openmp_simd_time = get_time_in_seconds() - time; 129 | // check(img); 130 | 131 | fill(img, 0); 132 | time = get_time_in_seconds(); 133 | for (int k = 0; k < K; k++) 134 | vpp_pixel_wise(img); 135 | double pixel_wise_time = get_time_in_seconds() - time; 136 | check(img); 137 | 138 | std::cout << "time per iteration (ms) : " << std::endl; 139 | std::cout << "raw_naive_time: " << 1000. * raw_naive_time / K << std::endl; 140 | std::cout << "raw_sequential_time: " << 1000. * raw_sequential_time / K << std::endl; 141 | std::cout << "raw_openmp_time: " << 1000. * raw_openmp_time / K << std::endl; 142 | std::cout << "raw_openmp_simd_time: " << 1000. * raw_openmp_simd_time / K << std::endl; 143 | std::cout << "vpp_pixel_wise: " << 1000. * pixel_wise_time / K << std::endl; 144 | //std::cout << "domain iteration overhead: " << 100. * id_time / ref_time - 100. << "%" << std::endl; 145 | 146 | } 147 | -------------------------------------------------------------------------------- /benchmarks/image_iterator.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "get_time.hh" 6 | 7 | int main() 8 | { 9 | using namespace vpp; 10 | 11 | image2d img(1000,1000); 12 | 13 | // Cache warm up. 14 | for (auto p : img) 15 | p = 42; 16 | 17 | int K = 400; 18 | double time; 19 | 20 | time = get_time_in_seconds(); 21 | for (int k = 0; k < K; k++) 22 | { 23 | int* cur = &img(vint2(0, 0)); 24 | for (int r = 0; r < img.nrows(); r++) 25 | { 26 | int* end = cur + img.nrows(); 27 | int c = 0; 28 | while (cur != end) 29 | { 30 | *(cur++) = r + c; 31 | c++; 32 | } 33 | 34 | } 35 | } 36 | double ref_time = get_time_in_seconds() - time; 37 | 38 | time = get_time_in_seconds(); 39 | for (int k = 0; k < K; k++) 40 | for (auto p : img) 41 | p = p.coord()[0] + p.coord()[1]; 42 | double ii_time = get_time_in_seconds() - time; 43 | 44 | time = get_time_in_seconds(); 45 | for (int k = 0; k < K; k++) 46 | for (auto p : img.domain()) 47 | img(p) = p[0] + p[1]; 48 | double id_time = get_time_in_seconds() - time; 49 | 50 | std::cout << "image iterator: " << std::endl; 51 | std::cout << "ref_time (ms): " << 1000. * ref_time / K << std::endl; 52 | std::cout << "io_time (ms): " << 1000. * ii_time / K << std::endl; 53 | std::cout << "image iterator overhead: " << 100. * ii_time / ref_time - 100. << "%" << std::endl; 54 | std::cout << "id_time (ms): " << 1000. * id_time / K << std::endl; 55 | std::cout << "domain iteration overhead: " << 100. * id_time / ref_time - 100. << "%" << std::endl; 56 | 57 | } 58 | -------------------------------------------------------------------------------- /benchmarks/integral_images.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() 4 | { 5 | using namespace vpp; 6 | 7 | image2d A(1000, 1000); 8 | image2d B(1000, 1000, border(2)); 9 | image2d C(1000, 1000, border(2)); 10 | 11 | pixel_wise(A)(row_forward) < [] (auto& a) { a = 2; }; 12 | 13 | // auto Bnbh = make_box_nbh2d<2,2>(B); 14 | // auto Cnbh = make_box_nbh2d<2,2>(C); 15 | // pixel_wise(A, Bnbh, Cnbh, row_first, column_first) < [] (auto& a,auto& b,auto& c) { 16 | // b(0,0) = b(0,-1) + a; 17 | // c(0,0) = c(-1,0) + b(0,0); 18 | // }; 19 | 20 | // row_first, one_thread_per_row 21 | // iterate_on(A, B, C)(parallel, backward, colunm_wise, static_schedule = 5) < [] (auto& o) 22 | // { 23 | // o.a = o.b + o.c; 24 | // }; 25 | 26 | // for (int i = 0; i < A.nrows(); i++) { 27 | // A 28 | // } 29 | 30 | // col_wise(A, Bnbh) << [] (auto& a, auto& b) { b(0,0) = b(-1, 0) + a; }; 31 | // row_wise(B, Cnbh) << [] (auto& b, auto& c) { c(0,0) = c(0, -1) + b; }; 32 | 33 | // pixel_wise( 34 | // images = ( a = pixel_accessor(A), 35 | // b = pixel_accessor(B), 36 | // c = neighbor_accessor<5, 5>(C)), 37 | // parallel = true, 38 | // dependency = row_forward) | f; 39 | 40 | } 41 | -------------------------------------------------------------------------------- /benchmarks/iteration_on_domains.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "get_time.hh" 5 | 6 | int main() 7 | { 8 | using namespace vpp; 9 | 10 | image2d img(1000,1000); 11 | 12 | // Cache warm up. 13 | for (auto p : img.domain()) 14 | img(p) = p[0] + p[1]; 15 | 16 | double time; 17 | 18 | time = get_time_in_seconds(); 19 | for (int k = 0; k < 40; k++) 20 | { 21 | for (int r = 0; r < 1000; r++) 22 | { 23 | int* row = &img(vint2(r, 0)); 24 | int* end = &img(vint2(r, 1000)); 25 | int c = 0; 26 | while (row != end) 27 | { 28 | *(row++) = r + c; 29 | c++; 30 | } 31 | } 32 | } 33 | double ref_time = get_time_in_seconds() - time; 34 | 35 | time = get_time_in_seconds(); 36 | for (int k = 0; k < 40; k++) 37 | for (auto p : img.domain()) 38 | img(p) = p[0] + p[1]; 39 | double vpp_time = get_time_in_seconds() - time; 40 | 41 | std::cout << "iterator on domain: " << std::endl; 42 | std::cout << "ref_time: " << ref_time << std::endl; 43 | std::cout << "vpp_time: " << vpp_time << std::endl; 44 | std::cout << "iteration on domain overhead: " << 100. * vpp_time / ref_time - 100. << "%" << std::endl; 45 | } 46 | -------------------------------------------------------------------------------- /benchmarks/lbp.cc: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | #include "get_time.hh" 6 | 7 | using namespace vpp; 8 | 9 | template 10 | void lbp_transform2(image2d& A, image2d& B) 11 | { 12 | int nr = A.nrows(); 13 | #pragma omp parallel for 14 | for (int r = 0; r < nr; r++) 15 | { 16 | V* curA = &A(vint2(r, 0)); 17 | U* curB = &B(vint2(r, 0)); 18 | int nc = A.ncols(); 19 | 20 | V* rows[3]; 21 | for (int i = -1; i <= 1; i++) 22 | rows[i + 1] = (V*)&A(vint2(r + i, 0)); 23 | 24 | for (int i = 0; i < nc; i++) 25 | { 26 | curB[i] = 27 | ((rows[0][i - 1] > rows[1][i]) << 0) + 28 | ((rows[0][i ] > rows[1][i]) << 1) + 29 | ((rows[0][i + 1] > rows[1][i]) << 2) + 30 | 31 | ((rows[1][i - 1] > rows[1][i]) << 3) + 32 | ((rows[1][i + 1] > rows[1][i]) << 4) + 33 | 34 | ((rows[2][i - 1] > rows[1][i]) << 5) + 35 | ((rows[2][i ] > rows[1][i]) << 6) + 36 | ((rows[2][i + 1] > rows[1][i]) << 7); 37 | 38 | } 39 | } 40 | 41 | } 42 | 43 | int main() 44 | { 45 | using namespace vpp; 46 | 47 | 48 | //std::vector> result = benchmark_cpp(100, 1000, 10, [] (int w) { 49 | for (int i = 100; i < 4000; i+= 100) 50 | { 51 | 52 | image2d V(i, i, _Border = 1); 53 | image2d lbp(i, i); 54 | 55 | int K = 400; 56 | float t = time([&] () { 57 | for (int k = 0; k < K; k++) 58 | lbp_transform(V, lbp); 59 | }); 60 | std::cout << "LBP: " << i << ": " << 1e9 * t / (K * i * i) << "ns / pixels." << std::endl; 61 | 62 | t = time([&] () { 63 | for (int k = 0; k < K; k++) 64 | pixel_wise(V, lbp) | [] (auto& a, auto& b) { 65 | a = a + b; 66 | }; 67 | }); 68 | std::cout << "ADD: " << i << ": " << 1e9 * t / (K * i * i) << "ns / pixels." << std::endl; 69 | 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /benchmarks/liie.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "get_time.hh" 6 | 7 | using namespace vpp; 8 | using namespace vpp::liie; 9 | 10 | // void operator+(const image2d& l, const image2d& r) 11 | // { 12 | // std::cout << "A: " << l.data() << std::endl; 13 | // std::cout << "B: " << r.data() << std::endl; 14 | 15 | // } 16 | 17 | int main() 18 | { 19 | image2d A(1000,1000); 20 | image2d B(1000,1000); 21 | 22 | // A + B; 23 | fill(A, 1); 24 | fill(B, 2); 25 | 26 | auto time = get_time_in_seconds(); 27 | 28 | auto res = eval(_v(A) + _v(B)); 29 | for (int K = 0; K < 1000; K++) 30 | pixel_wise(res, A, B) | [] (auto& r, auto& a, auto& b) { r = a + b; }; 31 | 32 | std::cout << 1000 * (get_time_in_seconds() - time) << std::endl; 33 | 34 | time = get_time_in_seconds(); 35 | 36 | for (int K = 0; K < 1000; K++) 37 | pixel_wise(_v(res) = _v(A) + _v(B)); 38 | 39 | std::cout << 1000 * (get_time_in_seconds() - time) << std::endl; 40 | 41 | 42 | } 43 | -------------------------------------------------------------------------------- /benchmarks/parallel_for.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "get_time.hh" 6 | 7 | using namespace vpp; 8 | 9 | template 10 | void fast_pixel_wise(I img, F f) 11 | { 12 | int nr = img.nrows(); 13 | #pragma omp parallel for 14 | for (int r = 0; r < nr; r++) 15 | { 16 | int* cur = &img(vint2(r, 0)); 17 | // vint2 cur_(r,0); 18 | int* end = cur + img.nrows(); 19 | int c = 0; 20 | while (cur != end) 21 | { 22 | f(cur, r, c); 23 | //f(cur, cur_[0], cur_[1]); 24 | ++cur; 25 | // cur_[1]++; 26 | c++; 27 | } 28 | } 29 | 30 | } 31 | 32 | int main() 33 | { 34 | 35 | image2d img(2000,2000); 36 | 37 | int K = 400; 38 | double time; 39 | 40 | 41 | // check 42 | vpp::pixel_wise(img) << [] (auto&& p) 43 | { 44 | p = 42; 45 | }; 46 | 47 | for (auto p : img.domain()) 48 | { 49 | if (img(p) != 42) 50 | std::cout << "error at " << p.transpose() << " -> " << img(p) << std::endl; 51 | } 52 | 53 | // Cache warm up. 54 | for (int k = 0; k < K; k++) 55 | fast_pixel_wise(img, [] (int* p, int r, int c) 56 | { 57 | *p = r + c; 58 | }); 59 | 60 | time = get_time_in_seconds(); 61 | for (int k = 0; k < K; k++) 62 | { 63 | int nr = img.nrows(); 64 | #pragma omp parallel for 65 | for (int r = 0; r < nr; r++) 66 | { 67 | int* cur = &img(vint2(r, 0)); 68 | int* end = cur + img.nrows(); 69 | int c = 0; 70 | while (cur != end) 71 | { 72 | *cur = r + c; 73 | ++cur; 74 | c++; 75 | } 76 | 77 | } 78 | } 79 | double ref_time = get_time_in_seconds() - time; 80 | 81 | 82 | time = get_time_in_seconds(); 83 | for (int k = 0; k < K; k++) 84 | fast_pixel_wise(img, [] (int* p, int r, int c) 85 | { 86 | *p = r + c; 87 | }); 88 | double ref2_time = get_time_in_seconds() - time; 89 | 90 | time = get_time_in_seconds(); 91 | for (int k = 0; k < K; k++) 92 | for (auto& p : img) 93 | p = p.coord()[0] + p.coord()[1]; 94 | double ii_time = get_time_in_seconds() - time; 95 | 96 | time = get_time_in_seconds(); 97 | for (int k = 0; k < K; k++) 98 | vpp::pixel_wise(img, img.domain()) << [] (auto& p, auto& p2) 99 | { 100 | p = p2[0] + p2[1]; 101 | }; 102 | double pw_time = get_time_in_seconds() - time; 103 | 104 | std::cout << "image iterator: " << std::endl; 105 | std::cout << "ref_time (ms): " << 1000. * ref_time / K << std::endl; 106 | std::cout << "ref2_time (ms): " << 1000. * ref2_time / K << std::endl; 107 | std::cout << "ii_time (ms): " << 1000. * ii_time / K << std::endl; 108 | std::cout << "image iterator overhead: " << 100. * ii_time / ref_time - 100. << "%" << std::endl; 109 | std::cout << "pw_time (ms): " << 1000. * pw_time / K << std::endl; 110 | //std::cout << "domain iteration overhead: " << 100. * id_time / ref_time - 100. << "%" << std::endl; 111 | 112 | } 113 | -------------------------------------------------------------------------------- /benchmarks/pyrlk_opencv_comparison.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | using namespace vpp; 12 | 13 | int main(int argc, char* argv[]) 14 | { 15 | if (argc != 3) 16 | { 17 | std::cout << "Usage: " << argv[0] << " image1 image2" << std::endl; 18 | return 1; 19 | } 20 | 21 | // image2d i1 = (from_opencv(cv::imread(argv[1]))); 22 | // image2d i3 = rgb_to_graylevel(i1); 23 | image2d i1 = rgb_to_graylevel(from_opencv(cv::imread(argv[1]))); 24 | image2d i2 = rgb_to_graylevel(from_opencv(cv::imread(argv[2]))); 25 | 26 | i1 = clone(i1, _border = 5); 27 | i2 = clone(i2, _border = 5); 28 | image2d display = graylevel_to_rgb(i1); 29 | 30 | image2d fast_score(i1.domain()); 31 | pyrlk_keypoint_container keypoints(i1.domain()); 32 | 33 | fast_detector9(*(image2d*)&i1, fast_score, 40); 34 | fast9_scores(*(image2d*)&i1, fast_score, 40); 35 | //fast9_filter_localmaximas(fast_score); 36 | fast9_blockwise_maxima(fast_score, 20); 37 | 38 | std::vector pts; 39 | make_keypoint_vector(fast_score, pts); 40 | for (vint2 p : pts) keypoints.add(keypoint(p.cast()), 0); 41 | 42 | std::vector cv_keypoints; 43 | 44 | for (auto kp : keypoints.keypoints()) 45 | cv_keypoints.push_back(cv::Point2f(kp.position[1], kp.position[0])); 46 | 47 | int nscales = 4; 48 | 49 | pyramid2d pyramid1(i1.domain(), nscales, 2, border(3)); 50 | pyramid2d pyramid2(i1.domain(), nscales, 2, border(3)); 51 | pyramid2d pyramid1_grad(i1.domain(), nscales, 2, border(3)); 52 | 53 | copy(i1, pyramid1[0]); 54 | copy(i2, pyramid2[0]); 55 | 56 | 57 | pyramid1.propagate_level0(); 58 | pyramid2.propagate_level0(); 59 | scharr(pyramid1[0], pyramid1_grad[0]); 60 | pyramid1_grad.propagate_level0(); 61 | 62 | 63 | // Vpp Pyrlk. 64 | #define WINDOW_SIZE 11 65 | pyrlk_match(pyramid1, pyramid1_grad, pyramid2, keypoints, lk_match_point_square_win(), 0.0001, 500, 30, 0.01); 66 | 67 | image2d vpp_flow(i1.domain()); 68 | fill(vpp_flow, vfloat2{0.f,0.f}); 69 | for (auto& kp: keypoints.keypoints()) 70 | if (kp.age > 0 and vpp_flow.has(kp.position.cast())) 71 | vpp_flow((kp.position - kp.velocity).cast()) = kp.velocity; 72 | 73 | // Opencv Pyrlk. 74 | std::vector cv_keypoints2; 75 | std::vector status; 76 | cv::Mat err; 77 | calcOpticalFlowPyrLK(to_opencv(i1), to_opencv(i2), cv_keypoints, cv_keypoints2, status, err, 78 | cv::Size(WINDOW_SIZE, WINDOW_SIZE), nscales); 79 | 80 | image2d cv_flow(i1.domain()); 81 | fill(cv_flow, vfloat2{0.f,0.f}); 82 | for (int i = 0; i < cv_keypoints.size(); i++) 83 | { 84 | vfloat2 a(cv_keypoints[i].y, cv_keypoints[i].x); 85 | vfloat2 b(cv_keypoints2[i].y, cv_keypoints2[i].x); 86 | if (cv_flow.has(a.cast())) 87 | cv_flow(a.cast()) = b - a; 88 | } 89 | 90 | // Display vectors. 91 | for (vint2 p : cv_flow.domain()) 92 | { 93 | float err = ((cv_flow(p) - vpp_flow(p)).norm()); 94 | if (err > 0.5 && cv_flow(p) != vfloat2{0.f, 0.f}) 95 | draw::line2d(display, p, p + cv_flow(p).cast(), vuchar3{255, 0, 0}); 96 | if (err > 0.5 && vpp_flow(p) != vfloat2{0.f, 0.f}) 97 | draw::line2d(display, p, p + vpp_flow(p).cast(), vuchar3{0, 255, 0}); 98 | 99 | if (err < 0.5 && vpp_flow(p) != vfloat2{0.f, 0.f}) 100 | { 101 | draw::c9(display, p, vuchar3{0, 0, 255}); 102 | } 103 | } 104 | 105 | cv::imwrite("cv_vpp_flow.ppm", to_opencv(display)); 106 | } 107 | -------------------------------------------------------------------------------- /evaluation/semi_dense_optical_flow/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | 3 | find_package(OpenCV REQUIRED) 4 | 5 | set(CMAKE_CXX_STANDARD 14) 6 | set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fopenmp=libomp -march=native") 7 | 8 | include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../.. 9 | /usr/include/eigen3 10 | $ENV{HOME}/local/include) 11 | 12 | add_executable(KITTI KITTI.cc) 13 | target_link_libraries(KITTI ${OpenCV_LIBS}) 14 | -------------------------------------------------------------------------------- /evaluation/semi_dense_optical_flow/display.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import numpy as np 3 | 4 | import gpof 5 | 6 | from gpof.runset import RunSet 7 | 8 | 9 | rs=gpof.open_runset('./pareto.rs'); 10 | gpof.display.display_2d_colorpoints(rs.view(('errors', 'runtime', 'nkeypoints'))) 11 | 12 | -------------------------------------------------------------------------------- /evaluation/semi_dense_optical_flow/pareto_KITTI.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import numpy as np 3 | 4 | import gpof 5 | from gpof.strategies import GradientDescentConfig 6 | from gpof.strategies import Runner 7 | from gpof.runset import RunSet 8 | from gpof.strategies import RV 9 | 10 | # For each given FAST9 detection, look for the pareto front for the two objectives : 11 | # computational time and percentage of errors > 3px 12 | 13 | # The detector is FAST n = 9 used with the blockwise selection strategy. 14 | 15 | detector_configurations=[ 16 | [5, 3], 17 | [7, 3], 18 | [10, 3], 19 | [10, 5], 20 | [15, 6], 21 | [20, 7], 22 | [30, 10]] 23 | 24 | # Global score: average for all detector configuration, the area under the pareto front. 25 | 26 | # Starting point of the gradient descent. 27 | configuration={ 28 | 'nscales': 3, 29 | 'winsize': 9, 30 | 'propagation': 4, 31 | 'min_scale': 0, 32 | 'patchsize': 5, 33 | # fixed in the experiments 34 | 'detector_th': 10, 35 | 'block_size': 10 36 | } 37 | 38 | parameter_space = { 39 | 'nscales': np.arange(1,6, 1), 40 | 'winsize': np.arange(5, 15, 2), 41 | 'propagation': np.arange(0, 10, 1), 42 | 'patchsize': np.arange(3, 10, 1) 43 | } 44 | 45 | pareto_runs=gpof.open_runset("pareto.rs") 46 | 47 | runner=gpof.command_runner(("{} %config_file %result_file").format(' '.join(sys.argv[1:]))) 48 | 49 | for detector_config in detector_configurations: 50 | for alpha in np.arange(0, 1, 0.02): 51 | 52 | cost = lambda r: alpha * r['errors'] + (1 - alpha) * r['runtime'] / (1.0 * 1000) 53 | configuration['detector_th'] = detector_config[0]; 54 | configuration['block_size'] = detector_config[1]; 55 | 56 | gd_conf=GradientDescentConfig( 57 | max_iterations = 10, 58 | starting_point = configuration, 59 | parameters = parameter_space, 60 | iterator = 'linear_prediction', 61 | cost = cost) 62 | 63 | gpof.strategies.gradient_descent2(runner, gd_conf) 64 | run = gpof.runset.select_best_run(runner.runset, cost) 65 | pareto_runs.record(run) 66 | 67 | # Here, pareto.rs and pareto_runs contains all the best runsets 68 | # for each detector_config / alpha couple. 69 | -------------------------------------------------------------------------------- /evaluation/semi_dense_optical_flow/symbols.hh: -------------------------------------------------------------------------------- 1 | // Generated by iod_generate_symbols. 2 | #include 3 | #ifndef IOD_SYMBOL_block_size 4 | #define IOD_SYMBOL_block_size 5 | iod_define_symbol(block_size) 6 | #endif 7 | 8 | #ifndef IOD_SYMBOL_blockwise 9 | #define IOD_SYMBOL_blockwise 10 | iod_define_symbol(blockwise) 11 | #endif 12 | 13 | #ifndef IOD_SYMBOL_detector_th 14 | #define IOD_SYMBOL_detector_th 15 | iod_define_symbol(detector_th) 16 | #endif 17 | 18 | #ifndef IOD_SYMBOL_errors 19 | #define IOD_SYMBOL_errors 20 | iod_define_symbol(errors) 21 | #endif 22 | 23 | #ifndef IOD_SYMBOL_min_scale 24 | #define IOD_SYMBOL_min_scale 25 | iod_define_symbol(min_scale) 26 | #endif 27 | 28 | #ifndef IOD_SYMBOL_nkeypoints 29 | #define IOD_SYMBOL_nkeypoints 30 | iod_define_symbol(nkeypoints) 31 | #endif 32 | 33 | #ifndef IOD_SYMBOL_nscales 34 | #define IOD_SYMBOL_nscales 35 | iod_define_symbol(nscales) 36 | #endif 37 | 38 | #ifndef IOD_SYMBOL_propagation 39 | #define IOD_SYMBOL_propagation 40 | iod_define_symbol(propagation) 41 | #endif 42 | 43 | #ifndef IOD_SYMBOL_runtime 44 | #define IOD_SYMBOL_runtime 45 | iod_define_symbol(runtime) 46 | #endif 47 | 48 | #ifndef IOD_SYMBOL_winsize 49 | #define IOD_SYMBOL_winsize 50 | iod_define_symbol(winsize) 51 | #endif 52 | 53 | -------------------------------------------------------------------------------- /evaluation/utils/kitti.hh: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | namespace kitti 5 | { 6 | using namespace vpp; 7 | 8 | 9 | inline image2d load_flow(std::string filename) 10 | { 11 | image2d tmp 12 | = from_opencv(cv::imread(filename, CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_COLOR)); 13 | if (!tmp.has_data()) return image2d(); 14 | 15 | image2d out(tmp.domain()); 16 | 17 | pixel_wise(out.domain(), tmp) | [&] (vint2 p, vushort3 v) 18 | { 19 | out(p) = vfloat3{ (float(v[1]) - (1 << 15)) / 64.f, (float(v[2]) - (1 << 15)) / 64.f, float(v[0]) }; 20 | }; 21 | return out; 22 | } 23 | 24 | template 25 | void foreach_training_pair(std::string kitti_root, int N, F&& fun) 26 | { 27 | std::string images_root = kitti_root + "/training/image_0/"; 28 | std::string ref_root = kitti_root + "/training/flow_noc/"; 29 | 30 | for (int i = 0; i < N; i++) 31 | { 32 | std::stringstream ss; 33 | ss << std::setfill('0') << std::setw(6) << i; 34 | 35 | std::string i1_filename = images_root + ss.str() + "_10.png"; 36 | std::string i2_filename = images_root + ss.str() + "_11.png"; 37 | std::string ref_filename = ref_root + ss.str() + "_10.png"; 38 | 39 | image2d i1 = from_opencv(cv::imread(i1_filename)); 40 | image2d i2 = from_opencv(cv::imread(i2_filename)); 41 | 42 | if (!i1.has_data()) 43 | throw std::runtime_error(std::string("Cannot read image ") + i1_filename); 44 | if (!i2.has_data()) 45 | throw std::runtime_error(std::string("Cannot read image ") + i2_filename); 46 | 47 | image2d ref_flow = load_flow(ref_filename); 48 | 49 | fun(i1, i2, ref_flow); 50 | } 51 | } 52 | 53 | inline void write_flow(std::string filename, const image2d& flow, const image2d& has_flow) 54 | { 55 | image2d out(flow.domain()); 56 | 57 | fill(out, vushort3(0,0,0)); 58 | 59 | pixel_wise(out.domain(), flow) | [&] (vint2 p, vfloat2 flow) 60 | { 61 | if (has_flow(p)) 62 | { 63 | // red. 64 | out(p)[2] = (uint16_t)std::max(std::min(flow[1]*64.0f+32768.0f,65535.0f),0.0f); 65 | // green 66 | out(p)[1] = (uint16_t)std::max(std::min(flow[0]*64.0f+32768.0f,65535.0f),0.0f); 67 | // blue 68 | out(p)[0] = 1; 69 | } 70 | }; 71 | 72 | cv::imwrite(filename, to_opencv(out), { CV_IMWRITE_PNG_COMPRESSION, 0}); 73 | } 74 | 75 | inline auto flow_error_stats(const image2d& flow, const image2d& ref) 76 | { 77 | int n = 0; 78 | 79 | float error_sum = 0.f; 80 | 81 | std::vector errors; 82 | 83 | image2d errors_map(flow.domain()); 84 | fill(errors_map, 0); 85 | 86 | int cpt = 0; 87 | pixel_wise(flow.domain())(_no_threads) | [&] (vint2 p) 88 | { 89 | if (flow(p)[2] > 0.f) cpt++; 90 | if (flow(p)[2] > 0.f and ref(p)[2] > 0.f) 91 | { 92 | n++; 93 | float err = (flow(p).segment<2>(0) - ref(p).segment<2>(0)).norm(); 94 | error_sum += err; 95 | errors.push_back(err); 96 | errors_map(p) = std::min(err * 20.f, 255.f); 97 | } 98 | }; 99 | 100 | std::sort(errors.begin(), errors.end()); 101 | 102 | int n1 = 0; 103 | int n3 = 0; 104 | int n5 = 0; 105 | int n10 = 0; 106 | for (int i = 0; i < errors.size(); i++) 107 | { 108 | if (errors[i] > 1.f) n1++; 109 | if (errors[i] > 3.f) n3++; 110 | if (errors[i] > 5.f) n5++; 111 | if (errors[i] > 10.f) n10++; 112 | } 113 | 114 | struct R { 115 | float n1; 116 | float n3; 117 | float n5; 118 | float n10; 119 | float avg; 120 | std::vector errors; 121 | image2d errors_map; 122 | float density; 123 | }; 124 | 125 | 126 | return R{ 127 | n1 ? 100 * float(n1) / errors.size() : 0, 128 | n3 ? 100 * float(n3) / errors.size() : 0, 129 | n5 ? 100 * float(n5) / errors.size() : 0, 130 | n10 ? 100 * float(n10) / errors.size() : 0, 131 | error_sum / (errors.size() ? errors.size() : 1), 132 | errors, errors_map, 133 | 100.f * float(cpt) / (flow.nrows() * flow.ncols()) 134 | }; 135 | } 136 | 137 | } 138 | -------------------------------------------------------------------------------- /examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 2.8) 2 | 3 | SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} 4 | ${CMAKE_CURRENT_LIST_DIR}/cmake 5 | ${CMAKE_SOURCE_DIR}/cmake) 6 | 7 | 8 | find_package(OpenCV REQUIRED) 9 | 10 | find_package(OpenGL REQUIRED) 11 | 12 | 13 | include_directories(${CMAKE_CURRENT_SOURCE_DIR}/.. 14 | ${IOD_INCLUDE_DIR} 15 | ${GLEW_INCLUDE_DIR} 16 | ${DIGE_INCLUDE_DIR}) 17 | 18 | set(LIBS 19 | ${OpenGL_LIBS} 20 | ${OPENGL_gl_LIBRARY} 21 | ${OPENGL_glu_LIBRARY} 22 | ${QT_LIBRARIES}) 23 | 24 | link_directories(${THIRDPARTY}/lib) 25 | 26 | add_definitions(-std=c++1y -g) 27 | set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -Ofast -march=native -fopenmp -DNDEBUG") 28 | set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O1 -march=native") 29 | 30 | include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..) 31 | include_directories(/usr/include/eigen3) 32 | 33 | add_executable(box_filter box_filter.cc) 34 | target_link_libraries(box_filter ${OpenCV_LIBS} gomp) 35 | 36 | add_executable(fast_detector fast_detector.cc) 37 | target_link_libraries(fast_detector ${OpenCV_LIBS} gomp) 38 | 39 | add_executable(tutorial tutorial.cc) 40 | target_link_libraries(tutorial ${OpenCV_LIBS} ${LIBS} gomp) 41 | 42 | 43 | add_executable(video_extruder video_extruder.cc) 44 | target_link_libraries(video_extruder ${OpenCV_LIBS} ${LIBS} gomp) 45 | 46 | 47 | add_executable(video_extruder_paint video_extruder_paint.cc) 48 | target_link_libraries(video_extruder_paint ${OpenCV_LIBS} ${LIBS} gomp) 49 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | 2 | # Compilation 3 | 4 | ``` 5 | git clone https://github.com/matt-42/vpp.git 6 | cd vpp 7 | ./install.sh ./vpp_install 8 | cd examples 9 | mkdir build 10 | cd build 11 | cmake .. -DIOD_INCLUDE_DIR=$PWD/../../vpp_install/include -DCMAKE_BUILD_TYPE=Release 12 | make -j4 13 | ``` 14 | 15 | Replace vpp_install with your prefered vpp install location. 16 | -------------------------------------------------------------------------------- /examples/box_filter.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | 8 | int main(int argc, char* argv[]) 9 | { 10 | using namespace vpp; 11 | 12 | if (argc != 2) 13 | { 14 | std::cerr << "Usage : " << argv[0] << " image" << std::endl; 15 | return 1; 16 | } 17 | 18 | typedef image2d I; 19 | I A = clone(from_opencv(cv::imread(argv[1])), vpp::_border = 1); 20 | I B(A.domain()); 21 | 22 | // Parallel Loop over pixels of in and out. 23 | pixel_wise(relative_access(A), B) | [] (auto n, auto& b) { 24 | vint3 sum = vint3::Zero(); 25 | 26 | sum += n(0, -1).template cast(); 27 | sum += n(0, 0).template cast(); 28 | sum += n(0, 1).template cast(); 29 | 30 | // Write the sum to the output image. 31 | b = (sum / 3).cast(); 32 | }; 33 | 34 | cv::imwrite("b.ppm", to_opencv(B)); 35 | 36 | } 37 | -------------------------------------------------------------------------------- /examples/fast_detector.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | int main(int argc, char* argv[]) 10 | { 11 | using namespace vpp; 12 | 13 | if (argc != 3) 14 | { 15 | std::cerr << "Usage : " << argv[0] << " image threshold" << std::endl; 16 | return 1; 17 | } 18 | 19 | image2d A = rgb_to_graylevel(from_opencv(cv::imread(argv[1]))); 20 | A = clone(A, _border = 3); 21 | 22 | std::vector keypoints = fast9(A, atoi(argv[2]), _local_maxima); 23 | 24 | image2d B = graylevel_to_rgb(A); 25 | for (vint2 p : keypoints) B(p) = vuchar3(0,0,255); 26 | 27 | cv::imwrite("b.ppm", to_opencv(B)); 28 | } 29 | -------------------------------------------------------------------------------- /examples/hough_extruder_main.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "hough_extruder_example.hh" 4 | 5 | #include 6 | 7 | 8 | using namespace std; 9 | using namespace Eigen; 10 | using namespace cv; 11 | using namespace vpp; 12 | using namespace std::chrono; 13 | 14 | int main(int argc, char *argv[]) 15 | { 16 | // Start the computation of the time used by the function to compute 17 | high_resolution_clock::time_point t1 = high_resolution_clock::now(); 18 | /** 19 | * @brief fast_dht_matching 20 | * This function allows to perform fast dense one-to-one Hough Transform 21 | * The fisrt parameter represents the type media you want to use. you can use either an image or a video 22 | * The second parameter represents the value of theta you want to use. This parameter defines the height of the array accumulator 23 | * The third parameter represents the scaling which will be used for rho. This parameter can be used to reduced the size of the accumulator 24 | * The parameter Type_video_hough represents the way the user wants to use after the tracking 25 | * The parameter Type_Lines defines the way we describe lines. A line can be described by polar coordinates , the list of all points forming this lines , by the extremities of this lines 26 | * The parameter With_Kalman_Filter represents the facts if the user wants to use kalman filter to perform prediction 27 | * The parameter With_Transparency represents the way the user wants to print the trajectories with transpenrcy 28 | * The parameter With_Entries represents the fact if the user wants the tracking to be performed with entries 29 | */ 30 | 31 | fast_dht_matching(dense_ht,Theta_max::SMALL, Sclare_rho::SAME, 32 | Type_video_hough::ALL_POINTS, 33 | Type_output::ORIGINAL_VIDEO, 34 | Type_Lines::ONLY_POLAR, 35 | Frequence::ALL_FRAME, 36 | With_Kalman_Filter::NO, 37 | With_Transparency::YES, 38 | With_Entries::YES, 39 | _rayon_exclusion_theta = 15, 40 | _rayon_exclusion_rho = 12, 41 | _slot_hough = 1, 42 | _link_of_video_image = "m.png", 43 | _acc_threshold = 100, 44 | _m_first_lines = 5, 45 | _max_trajectory_length = 5, 46 | _nombre_max_frame_without_update =5);/**/ 47 | high_resolution_clock::time_point t2 = high_resolution_clock::now(); 48 | auto duration = duration_cast( t2 - t1 ).count(); 49 | //Show the time used to compute 50 | cout << "la duree " << duration << endl ; 51 | return 0; 52 | } 53 | -------------------------------------------------------------------------------- /examples/image_view.cc: -------------------------------------------------------------------------------- 1 | 2 | int main() 3 | { 4 | image2d rgb(100,100); 5 | 6 | auto red = image_view(rgb, [] (vint2 p) { return rgb(p)[0]; }); 7 | auto sub_red = image_view(rgb.subimage(vint2(0,0), vint2(10,10)), 8 | [] (vint2 p) { return rgb(p)[0]; }); 9 | 10 | } 11 | -------------------------------------------------------------------------------- /examples/keypoint_matching.cc: -------------------------------------------------------------------------------- 1 | 2 | int main() 3 | { 4 | 5 | std::vector descriptors, descriptors2; 6 | std::vector positions; 7 | 8 | std::vector<> matches; 9 | 10 | // Classical neareast neighbor search. 11 | match_keypoints( 12 | 13 | _distance = [] (int q, int t) { return (descriptors2[q] - descriptors[t]).norm(); }, 14 | _match = [] (int q, int t, float dist) { matches.push_back({q, t, dist}); }, 15 | 16 | // Only for bruteforce 17 | _size1 = descriptors1.size() 18 | _size2 = descriptors2.size() 19 | 20 | // For all methods except bruteforce 21 | _query = descriptors2, // or a lambda [] (int i) { return kps[i].descriptor; } 22 | _train = descriptors, 23 | 24 | 25 | _bruteforce 26 | _flann(_trees = 4, _nchecks = 10), 27 | _index1d(_approximation = 1), 28 | 29 | _local_search(_query_positions = positions2, 30 | _train_positions = positions1, 31 | _search_radius = 100) 32 | _ 33 | ); 34 | 35 | 36 | // Neareast neighbor search in a local neighborhood. 37 | local_match_keypoints_nearest( 38 | // Same than classical neighbor search plus: 39 | 40 | _query_positions = positions2, 41 | _train_positions = positions1, 42 | 43 | // Search radius. 44 | _search_radius = 12, 45 | ); 46 | 47 | } 48 | -------------------------------------------------------------------------------- /examples/optical_flow.cc: -------------------------------------------------------------------------------- 1 | int main() 2 | { 3 | 4 | optical_flow(i1, i2, 5 | _keypoints = kps, 6 | _flow = [] (int i, vfloat2 f, float distance) { ...}); 7 | 8 | optical_flow(i1, i2, 9 | _flow = [] (vint2 p, vfloat2 f) { ... }); 10 | 11 | epipolar_flow(i1, i2, 12 | _flow = [] (vint2 p, vfloat2 f) { ... }); 13 | 14 | } 15 | -------------------------------------------------------------------------------- /examples/symbols.hh: -------------------------------------------------------------------------------- 1 | // Generated by iod_generate_symbols. 2 | #include 3 | #ifndef IOD_SYMBOL_border 4 | #define IOD_SYMBOL_border 5 | iod_define_symbol(border) 6 | #endif 7 | 8 | #ifndef IOD_SYMBOL_detector_period 9 | #define IOD_SYMBOL_detector_period 10 | iod_define_symbol(detector_period) 11 | #endif 12 | 13 | #ifndef IOD_SYMBOL_detector_th 14 | #define IOD_SYMBOL_detector_th 15 | iod_define_symbol(detector_th) 16 | #endif 17 | 18 | #ifndef IOD_SYMBOL_keypoint_spacing 19 | #define IOD_SYMBOL_keypoint_spacing 20 | iod_define_symbol(keypoint_spacing) 21 | #endif 22 | 23 | #ifndef IOD_SYMBOL_local_maxima 24 | #define IOD_SYMBOL_local_maxima 25 | iod_define_symbol(local_maxima) 26 | #endif 27 | 28 | #ifndef IOD_SYMBOL_no_threads 29 | #define IOD_SYMBOL_no_threads 30 | iod_define_symbol(no_threads) 31 | #endif 32 | 33 | #ifndef IOD_SYMBOL_record_video 34 | #define IOD_SYMBOL_record_video 35 | iod_define_symbol(record_video) 36 | #endif 37 | 38 | #ifndef IOD_SYMBOL_video 39 | #define IOD_SYMBOL_video 40 | iod_define_symbol(video) 41 | #endif 42 | 43 | -------------------------------------------------------------------------------- /examples/tutorial.cc: -------------------------------------------------------------------------------- 1 | // Include the header-only library. 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | // import vpp into the current namespace. 8 | using namespace vpp; 9 | 10 | 11 | typedef vuchar3 V; // value type. 12 | typedef image2d I; // image type. 13 | 14 | // Declare a 2d image. 15 | I img; 16 | 17 | // Load an external image using opencv. 18 | img = from_opencv(cv::imread("image.jpg")); 19 | 20 | // Allocate a second image with the same definition domain. 21 | I out(img.domain()); 22 | 23 | // Iterate on img 24 | pixel_wise(img) | [&] (auto& i) { i += vuchar3(1,1,1); }; 25 | 26 | // Access to the neighborhood in pixel wise kernels : 27 | pixel_wise(relative_access(img), out) | [] (auto n, auto& b) { 28 | vint3 sum = vint3::Zero(); 29 | 30 | sum += n(0, -1).template cast(); 31 | sum += n(0, 0).template cast(); 32 | sum += n(0, 1).template cast(); 33 | 34 | b = (sum / 3).cast(); 35 | }; 36 | 37 | // Sum the rows. 38 | std::vector sums(img.nrows()); 39 | std::cout << img.nrows() << std::endl; 40 | 41 | row_wise(img, img.domain())(_no_threads) | [&] (auto row, auto coord) 42 | { 43 | vint3 sum = vint3::Zero(); 44 | pixel_wise(row) | [&] (vuchar3 p) { sum += p.cast(); }; 45 | sums[coord.p1()[0]] = sum; 46 | }; 47 | 48 | } 49 | -------------------------------------------------------------------------------- /examples/video_extruder.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "symbols.hh" 13 | 14 | using namespace iod; 15 | using namespace vpp; 16 | 17 | int main(int argc, const char* argv[]) 18 | { 19 | 20 | auto opts = parse_command_line(argc, argv, 21 | cl::positionals(_video, _detector_th, _keypoint_spacing), 22 | cl::required(_video), 23 | _video = std::string(), 24 | _detector_th = int(10), 25 | _keypoint_spacing = int(5), 26 | _record_video = std::string()); 27 | 28 | box2d domain = videocapture_domain(opts.video.c_str()); 29 | video_extruder_ctx ctx = video_extruder_init(domain); 30 | 31 | cv::VideoWriter output_video; 32 | if (opts.record_video.size()) 33 | { 34 | output_video.open(opts.record_video, cv::VideoWriter::fourcc('M','J','P','G'), 30.f, 35 | cv::Size(domain.ncols(), domain.nrows()), true); 36 | } 37 | 38 | image2d prev_frame(domain); 39 | 40 | bool first = true; 41 | int nframes = 0; 42 | 43 | int us_cpt = 0; 44 | foreach_videoframe(opts.video.c_str()) | [&] (const image2d& frame_cv) 45 | { 46 | auto frame = clone(frame_cv, _border = 3); 47 | fill_border_mirror(frame); 48 | auto frame_gl = rgb_to_graylevel(frame); 49 | timer t; 50 | t.start(); 51 | if (!first) 52 | video_extruder_update(ctx, prev_frame, frame_gl, 53 | _detector_th = opts.detector_th, 54 | _keypoint_spacing = opts.keypoint_spacing, 55 | _detector_period = 1, 56 | _max_trajectory_length = 100); 57 | else first = false; 58 | t.end(); 59 | 60 | us_cpt += t.us(); 61 | if (!(nframes%1000)) 62 | { 63 | std::cout << "Tracker time: " << (us_cpt / 1000000.f) << " ms/frame. " << ctx.trajectories.size() << " particles." << std::endl; 64 | us_cpt = 0; 65 | } 66 | 67 | vpp::copy(frame_gl, prev_frame); 68 | auto display = clone(frame); 69 | draw::draw_trajectories(display, ctx.trajectories, 200); 70 | cv::imshow("Trajectories", to_opencv(display)); 71 | cv::waitKey(1); 72 | 73 | if (output_video.isOpened()) 74 | output_video << to_opencv(display); 75 | 76 | nframes++; 77 | }; 78 | 79 | } 80 | -------------------------------------------------------------------------------- /examples/video_extruder_javascript/cpp/Makefile: -------------------------------------------------------------------------------- 1 | all: main.js 2 | 3 | main.js: main.cc Makefile 4 | emcc -O3 -DNDEBUG -std=c++1z -I ~/projects/vpp -I ~/projects/iod -I /usr/include/eigen3 main.cc -o main.js -s EXPORTED_FUNCTIONS="['_update', '_get_display_buffer', '_set_threshold']" -s TOTAL_MEMORY=163554432 5 | # -s USE_PTHREADS=1 6 | # -s ALLOW_MEMORY_GROWTH=1 7 | 8 | # -s ASSERTIONS=2 -s SAFE_HEAP=1 -s STACK_OVERFLOW_CHECK=1 9 | 10 | clean: 11 | rm main.js main.js.mem 12 | -------------------------------------------------------------------------------- /examples/video_extruder_javascript/cpp/symbols.hh: -------------------------------------------------------------------------------- 1 | // Generated by iod_generate_symbols. 2 | #include 3 | #ifndef IOD_SYMBOL_detector_period 4 | #define IOD_SYMBOL_detector_period 5 | iod_define_symbol(detector_period) 6 | #endif 7 | 8 | #ifndef IOD_SYMBOL_detector_th 9 | #define IOD_SYMBOL_detector_th 10 | iod_define_symbol(detector_th) 11 | #endif 12 | 13 | #ifndef IOD_SYMBOL_keypoint_spacing 14 | #define IOD_SYMBOL_keypoint_spacing 15 | iod_define_symbol(keypoint_spacing) 16 | #endif 17 | 18 | -------------------------------------------------------------------------------- /examples/video_extruder_javascript/gumwrapper.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * GumWrapper v0.13 3 | * By Daniel Davis under MIT License 4 | * https://github.com/tagawa/GumWrapper 5 | */ 6 | ;(function(n,t){"use strict";n.GumWrapper=function(i,r,u){function f(n){if(u){var t=new Error;t.message=n,u(t)}else console.error(n)}function e(){function o(t){u.mozSrcObject!==undefined?u.mozSrcObject=t:u.src=n.URL&&n.URL.createObjectURL(t)||t,u.play()}function e(){f("Unable to get webcam stream.")}var u=t.getElementById(i.video);if(!u){f("Unable to find the video element.");return}navigator.getUserMedia=navigator.getUserMedia||navigator.webkitGetUserMedia||navigator.mozGetUserMedia||navigator.msGetUserMedia,n.URL=n.URL||n.webkitURL||n.mozURL||n.msURL,navigator.getUserMedia?navigator.getUserMedia({video:!0},o,e):f("Native web camera streaming (getUserMedia) not supported in this browser."),u.addEventListener("loadeddata",function(){function t(){i>0?u.videoWidth>0&&u.videoHeight>0?r&&r(u):n.setTimeout(t,500):f("Unable to play video stream. Is webcam working?"),i--}var i=10;t()},!1)}return{play:e}}})(window,document); -------------------------------------------------------------------------------- /examples/video_extruder_javascript/test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Colorful Optical Flow 5 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /examples/video_extruder_javascript/test.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | // Wrap the C++ API. 4 | var cpp = { 5 | update: Module.cwrap('update', 'number', ['number', 'number', 'number']), 6 | get_display_buffer: Module.cwrap('get_display_buffer', 'number', []) 7 | }; 8 | 9 | function showSuccess() {} 10 | function showError(e) { alert(e); } 11 | 12 | // Start the webcam stream. 13 | var gum = new GumWrapper({video: 'video'}, showSuccess, showError); 14 | gum.play(); 15 | 16 | function draw_on_canvas(canvas, rgba_buffer) { 17 | 18 | var ctx = canvas.getContext('2d'); 19 | var imageData = ctx.createImageData(canvas.width, canvas.height); 20 | var data = imageData.data; 21 | 22 | for (var i = 0; i < data.length; i += 4) { 23 | data[i] = rgba_buffer[i]; // red 24 | data[i + 1] = rgba_buffer[i+1]; // green 25 | data[i + 2] = rgba_buffer[i+2]; // blue 26 | data[i + 3] = 255; // blue 27 | } 28 | ctx.putImageData(imageData, 0, 0); 29 | }; 30 | 31 | var frame_buffer = { data: null, size: 42, set: function (d, s) { this.data = d; this.size = s; } }; 32 | 33 | function update() 34 | { 35 | var video = document.getElementById('video'); 36 | var canvas1 = document.getElementById('canvas1'); 37 | var ctx1 = canvas1.getContext('2d'); 38 | var canvas3 = document.getElementById('canvas3'); 39 | var ctx3 = canvas3.getContext('2d'); 40 | 41 | // Put webcam image on canvas1 42 | ctx1.drawImage(video, 0, 0, canvas1.width, canvas1.height); 43 | 44 | // Canvas frame. 45 | var frame = ctx1.getImageData(0, 0, canvas1.width, canvas1.height); 46 | 47 | // Allocate 48 | size = frame.width * frame.height * 4; 49 | if (frame_buffer.size != size) 50 | { 51 | if (frame_buffer.data) Module._free(frame_buffer.data); 52 | frame_buffer.set(Module._malloc(size), size); 53 | } 54 | Module.HEAPU8.set(frame.data, frame_buffer.data); 55 | 56 | var start = Date.now(); 57 | var t = cpp.update(frame_buffer.data, frame.width, frame.height); 58 | var end = Date.now(); 59 | console.log(end - start, "ms"); 60 | 61 | if (cpp.get_display_buffer() != 0) 62 | { 63 | var display_buffer = new Uint8Array(Module.HEAPU8.buffer, cpp.get_display_buffer(), frame.width * frame.height * 4); 64 | draw_on_canvas(canvas1, display_buffer); 65 | ctx3.drawImage(canvas1, 0, 0, canvas1.width, canvas1.height, 0,0,canvas3.width, canvas3.height); 66 | } 67 | setTimeout(function() { update(); }, 0); 68 | } 69 | 70 | function run() 71 | { 72 | console.log("run!"); 73 | document.getElementById('video').addEventListener("playing", function() { 74 | setTimeout(function() { update(); }, 0); 75 | //setInterval(function() { update(); }, 1000/30); 76 | }, false); 77 | } 78 | -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | readlink_f() { # Recode readlink -f for mac osx 2 | 3 | # From http://stackoverflow.com/questions/1055671/how-can-i-get-the-behavior-of-gnus-readlink-f-on-a-mac 4 | TARGET_FILE=$1 5 | 6 | cd `dirname $TARGET_FILE` 7 | TARGET_FILE=`basename $TARGET_FILE` 8 | 9 | while [ -L "$TARGET_FILE" ] 10 | do 11 | TARGET_FILE=`readlink $TARGET_FILE` 12 | cd `dirname $TARGET_FILE` 13 | TARGET_FILE=`basename $TARGET_FILE` 14 | done 15 | 16 | PHYS_DIR=`pwd -P` 17 | RESULT=$PHYS_DIR/$TARGET_FILE 18 | echo $RESULT 19 | } 20 | 21 | check_for_executable() 22 | { 23 | command -v $1 >/dev/null 2>&1 || { echo "$1 is required."; exit 1; } 24 | } 25 | 26 | cmake_build_install_current_dir() 27 | { 28 | { mkdir -p vpp_build && cd vpp_build && cmake .. -DIOD_INCLUDE_DIR=$1/include -DCMAKE_INSTALL_PREFIX=$1 && make -j4 install; } || { echo "Cannot install $PWD."; exit 1; } 29 | } 30 | 31 | [ ! $# -eq 1 ] && echo "Usage: install.sh prefix" && exit 1 32 | 33 | check_for_executable cmake; 34 | check_for_executable git; 35 | 36 | ROOT=$PWD 37 | PREFIX=$(readlink_f $1) 38 | 39 | mkdir -p $PREFIX 40 | 41 | [ ! -d $1 ] && echo "The given prefix is not a directory" && exit 1 42 | 43 | mkdir externals; 44 | cd externals; 45 | 46 | git clone http://github.com/matt-42/iod.git 47 | cd iod 48 | cmake_build_install_current_dir $PREFIX 49 | 50 | cd $ROOT 51 | cmake_build_install_current_dir $PREFIX 52 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | 3 | find_package(OpenCV REQUIRED) 4 | 5 | find_package(PkgConfig) 6 | pkg_search_module(Eigen3 REQUIRED eigen3) 7 | include_directories(${Eigen3_INCLUDE_DIRS}) 8 | 9 | enable_testing() 10 | 11 | include_directories(${CMAKE_CURRENT_SOURCE_DIR}/.. 12 | ${IOD_INCLUDE_DIR} 13 | $ENV{HOME}/local/include 14 | ) 15 | 16 | add_definitions(-std=c++14 -g) 17 | 18 | add_executable(imageNd imageNd.cc) 19 | add_test(imageNd imageNd) 20 | 21 | add_executable(image2d image2d.cc) 22 | add_test(image2d image2d) 23 | 24 | add_executable(image3d image3d.cc) 25 | add_test(image3d image3d) 26 | 27 | add_executable(boxNd_iterator boxNd_iterator.cc) 28 | add_test(boxNd_iterator boxNd_iterator) 29 | 30 | add_executable(imageNd_iterator imageNd_iterator.cc) 31 | add_test(imageNd_iterator imageNd_iterator) 32 | 33 | add_executable(pixel_wise pixel_wise.cc) 34 | #target_link_libraries(pixel_wise gomp) 35 | add_test(pixel_wise pixel_wise) 36 | 37 | add_executable(sandbox sandbox.cc) 38 | add_test(sandbox sandbox) 39 | 40 | add_executable(window window.cc) 41 | #target_link_libraries(window gomp) 42 | add_test(window window) 43 | 44 | add_executable(opencv_bridge opencv_bridge.cc) 45 | add_test(opencv_bridge opencv_bridge) 46 | 47 | add_executable(fill fill.cc) 48 | add_test(fill fill) 49 | 50 | 51 | add_executable(border border.cc) 52 | add_test(border border) 53 | 54 | add_executable(pyramid pyramid.cc) 55 | add_test(pyramid pyramid) 56 | 57 | add_executable(cast cast.cc) 58 | add_test(cast cast) 59 | 60 | add_executable(sum sum.cc) 61 | add_test(sum sum) 62 | 63 | add_executable(tuple_utils tuple_utils.cc) 64 | add_test(tuple_utils tuple_utils) 65 | 66 | add_executable(block_wise block_wise.cc) 67 | #target_link_libraries(block_wise gomp) 68 | add_test(block_wise block_wise) 69 | 70 | add_executable(colorspace_conversions colorspace_conversions.cc) 71 | add_test(colorspace_conversions colorspace_conversions) 72 | 73 | add_executable(pyrlk pyrlk.cc) 74 | add_test(pyrlk pyrlk) 75 | 76 | 77 | #add_executable(liie liie.cc) 78 | #add_test(liie liie) 79 | 80 | 81 | add_executable(lbp lbp.cc) 82 | add_test(lbp lbp) 83 | 84 | target_link_libraries(pyrlk ${OpenCV_LIBS}) 85 | target_link_libraries(opencv_bridge ${OpenCV_LIBS}) 86 | #target_link_libraries(liie gomp) 87 | 88 | add_executable(descriptor_matcher descriptor_matcher.cc) 89 | add_test(descriptor_matcher descriptor_matcher) 90 | -------------------------------------------------------------------------------- /tests/block_wise.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace vpp; 5 | 6 | template 7 | bool equals(image2d& v, image2d& u) 8 | { 9 | int eq = true; 10 | pixel_wise(v, u) | [&] (V& a, U& b) { if (a != b) eq = false; }; 11 | return eq; 12 | } 13 | 14 | 15 | template 16 | void print(image2d& v) 17 | { 18 | for (int r = 0; r < v.nrows(); r++) 19 | { 20 | for (int c = 0; c < v.ncols(); c++) 21 | std::cout << v(r, c) << " "; 22 | std::cout << std::endl; 23 | } 24 | } 25 | 26 | int main() 27 | { 28 | 29 | image2d img(4,4); 30 | vint2 b(2,2); 31 | 32 | auto test_dependency = [&] (int* ref_data, auto dep, int dim) 33 | { 34 | image2d ref(img.domain(), _data = (int*)ref_data, _pitch = 4 * sizeof(int)); 35 | int cols[2] = {1,1}; 36 | block_wise(b, img, img, img.domain())(dep) 37 | | [&] (image2d I, image2d J, box2d d) 38 | { 39 | int& cpt = cols[d.p1()[dim] / 2]; 40 | fill(I, cpt); 41 | cpt++; 42 | }; 43 | 44 | std::cout << "ref: " << std::endl; 45 | print(ref); 46 | std::cout << "img: " << std::endl; 47 | print(img); 48 | assert(equals(ref, img)); 49 | }; 50 | 51 | { 52 | int ref_data[] = { 53 | 1,1,1,1, 54 | 1,1,1,1, 55 | 2,2,2,2, 56 | 2,2,2,2, 57 | }; 58 | 59 | test_dependency(ref_data, _top_to_bottom, 1); 60 | } 61 | 62 | fill(img, 9); 63 | { 64 | int ref_data[] = { 65 | 2,2,2,2, 66 | 2,2,2,2, 67 | 1,1,1,1, 68 | 1,1,1,1, 69 | }; 70 | 71 | test_dependency(ref_data, _bottom_to_top, 1); 72 | } 73 | 74 | fill(img, 9); 75 | { 76 | int ref_data[] = { 77 | 1,1,2,2, 78 | 1,1,2,2, 79 | 1,1,2,2, 80 | 1,1,2,2, 81 | }; 82 | 83 | test_dependency(ref_data, _left_to_right, 0); 84 | } 85 | 86 | fill(img, 9); 87 | { 88 | int ref_data[] = { 89 | 2,2,1,1, 90 | 2,2,1,1, 91 | 2,2,1,1, 92 | 2,2,1,1, 93 | }; 94 | 95 | test_dependency(ref_data, _right_to_left, 0); 96 | } 97 | 98 | // Check that blocks covers the whole image, and do 99 | // not overlap with image border. 100 | { 101 | image2d img(10,10, _border = 1); 102 | fill_border_with_value(img, 2); 103 | fill(img, 0); 104 | block_wise(vint2(3,3), img) | [] (auto si) { fill(si, 1); }; 105 | 106 | print (img); 107 | for (auto p : img.domain_with_border()) 108 | { 109 | if (img.has(p)) 110 | assert(img(p) == 1); 111 | else 112 | assert(img(p) == 2); 113 | } 114 | } 115 | 116 | } 117 | -------------------------------------------------------------------------------- /tests/border.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | using namespace vpp; 7 | 8 | image2d img1(5, 10, _border = 2, _aligned = 1); 9 | 10 | // Fill with border 11 | { 12 | fill_with_border(img1, 42); 13 | 14 | pixel_wise(img1.domain_with_border(), img1) | [&] (vint2 p, auto v) { 15 | assert(v == 42); 16 | }; 17 | } 18 | // Fill border with value. 19 | { 20 | fill(img1, 5); 21 | fill_border_with_value(img1, 6); 22 | 23 | for (int r = -2; r < 7; r++) 24 | { 25 | for (int c = -2; c < 12; c++) 26 | std::cout << img1(r, c) << " "; 27 | std::cout << std::endl; 28 | } 29 | 30 | pixel_wise(img1.domain_with_border(), img1) | [&] (vint2 p, auto v) { 31 | if (img1.domain().has(p)) assert(v == 5); 32 | else assert(v == 6); 33 | }; 34 | } 35 | 36 | // Fill border closest. 37 | { 38 | fill_with_border(img1, 0); 39 | 40 | pixel_wise(img1.domain(), img1) | [&] (vint2 p, auto& v) { 41 | v = (p[0] + p[1]) % 10; 42 | }; 43 | 44 | fill_border_closest(img1); 45 | 46 | std::cout << std::endl; 47 | for (int r = -2; r < 7; r++) 48 | { 49 | for (int c = -2; c < 12; c++) 50 | std::cout << img1(r, c) << " "; 51 | std::cout << std::endl; 52 | } 53 | 54 | pixel_wise(img1.domain_with_border(), img1) | [&] (vint2 p, auto& v) { 55 | int cc = std::max(std::min(img1.ncols() - 1, p[1]), 0); 56 | int cr = std::max(std::min(img1.nrows() - 1, p[0]), 0); 57 | assert(v == (cc + cr) % 10); 58 | }; 59 | 60 | } 61 | 62 | // Fill border mirror 63 | { 64 | fill_with_border(img1, 0); 65 | 66 | pixel_wise(img1.domain(), img1) | [&] (vint2 p, auto& v) { 67 | v = (p[0] + p[1]) % 10; 68 | }; 69 | 70 | fill_border_mirror(img1); 71 | 72 | std::cout << std::endl; 73 | for (int r = -2; r < 7; r++) 74 | { 75 | for (int c = -2; c < 12; c++) 76 | std::cout << img1(r, c) << " "; 77 | std::cout << std::endl; 78 | } 79 | 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /tests/boxNd_iterator.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | using vpp::boxNd_iterator; 7 | using vpp::box2d; 8 | using vpp::vint2; 9 | 10 | 11 | box2d b(vint2(10,5), vint2(12,7)); 12 | 13 | auto it = b.begin(); 14 | 15 | assert(*it == vint2(10, 5)); 16 | it.next(); 17 | assert(*it == vint2(10, 6)); 18 | it.next(); 19 | assert(*it == vint2(10, 7)); 20 | it.next(); 21 | assert(*it == vint2(11, 5)); 22 | it.next(); 23 | assert(*it == vint2(11, 6)); 24 | it.next(); 25 | assert(*it == vint2(11, 7)); 26 | it.next(); 27 | assert(*it == vint2(12, 5)); 28 | it.next(); 29 | assert(*it == vint2(12, 6)); 30 | it.next(); 31 | assert(*it == vint2(12, 7)); 32 | it.next(); 33 | assert(it == b.end()); 34 | 35 | vint2 ref[] = { 36 | vint2(10, 5), 37 | vint2(10, 6), 38 | vint2(10, 7), 39 | vint2(11, 5), 40 | vint2(11, 6), 41 | vint2(11, 7), 42 | vint2(12, 5), 43 | vint2(12, 6), 44 | vint2(12, 7) 45 | }; 46 | 47 | int i = 0; 48 | for (auto p : b) assert(p == ref[i++]); 49 | } 50 | -------------------------------------------------------------------------------- /tests/box_nbh2d.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | using namespace vpp; 7 | 8 | image2d A(3, 3); 9 | auto nbh = box_nbh2d(A, vint2{1, 1}); 10 | 11 | fill(A, 1); 12 | 13 | nbh.for_all([] (auto& p) { p = 2; }); 14 | nbh.north() = 3; 15 | nbh.east() = 4; 16 | nbh.south() = 5; 17 | nbh.west() = 6; 18 | 19 | assert(A(0,0) == 2); 20 | assert(A(0,1) == 3); 21 | assert(A(0,2) == 2); 22 | 23 | assert(A(1,0) == 6); 24 | assert(A(1,1) == 2); 25 | assert(A(1,2) == 4); 26 | 27 | assert(A(2,0) == 2); 28 | assert(A(2,1) == 5); 29 | assert(A(2,2) == 2); 30 | } 31 | -------------------------------------------------------------------------------- /tests/cast.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace vpp; 5 | 6 | int main() 7 | { 8 | //typename std::enable_if::SizeAtCompileTime != 1>::type xx = 2; 9 | 10 | vuchar3 p; 11 | const Eigen::MatrixBase& ref = p; 12 | 13 | assert(p == ref); 14 | 15 | std::cout << !std::is_base_of, vfloat1>::value << std::endl; 16 | vint3 v = cast(p); 17 | vint3 x = cast(p - p); 18 | vint1 y = cast(vfloat1(1)); 19 | 20 | int z = cast(vfloat1(1)); 21 | vint1 a = cast(float(1)); 22 | 23 | // vint1 xxx; xxx[0] = (20); 24 | // float y = cast(xxx); 25 | // assert(y == 20); 26 | 27 | // vint1 vi = cast(float(3.f)); 28 | // assert(vi[0] == 3); 29 | } 30 | -------------------------------------------------------------------------------- /tests/colorspace_conversions.cc: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | using namespace vpp; 8 | 9 | image2d i1(100, 100); 10 | 11 | unsigned char i = 0; 12 | for (vint2 p : i1.domain()) 13 | { 14 | i1(p) = vuchar3{i, i, i}; 15 | i++; 16 | } 17 | 18 | image2d i2 = rgb_to_graylevel(i1); 19 | i = 0; 20 | for (vint2 p : i1.domain()) 21 | { 22 | assert(i2(p)[0] == i); 23 | i++; 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /tests/descriptor_matcher.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | //#include 4 | #include 5 | 6 | template 7 | decltype(auto) image_as_array_of_rows(I& img) 8 | { 9 | return iod::array_view(img.nrows(), [&] (int i) { 10 | return iod::array_view(img.ncols(), img[i]); }); 11 | } 12 | 13 | int main() 14 | { 15 | using namespace vpp; 16 | 17 | vpp::image2d D1(100, 10); 18 | vpp::image2d D2(200, 10); 19 | 20 | pixel_wise(D1, D2) | [] (int& a, int& b) { a = rand() % 10000; b = rand() % 10000; }; 21 | 22 | struct match { int j; int d; }; 23 | std::vector matches(D1.nrows(), match{-1, -1}); 24 | 25 | // Bruteforce 26 | bruteforce_matcher(D1.nrows(), D2.nrows(), 27 | _distance = [&] (int i, int j, int d) { 28 | return sad_distance(D1.ncols(), D1[i], D2[j], d); }, 29 | _match = [&] (int i, int j, int d) { matches[i] = match{j, d}; }); 30 | 31 | for (int i = 0; i < D1.nrows(); i++) 32 | { 33 | int d = sad_distance(D1.ncols(), D1[i], D2[matches[i].j]); 34 | assert(d == matches[i].d); 35 | 36 | for (int j = 0; j < D2.nrows(); j++) 37 | assert(sad_distance(D1.ncols(), D1[i], D2[j]) >= d); 38 | } 39 | 40 | 41 | // Local index1d. 42 | matches = std::vector(D1.nrows(), match{-1, -1}); 43 | 44 | std::vector P1, P2; // keypoint positions. 45 | for (int i = 0; i < D1.nrows(); i++) 46 | P1.push_back(vint2(rand() % 1000, rand() % 1000)); 47 | for (int i = 0; i < D2.nrows(); i++) 48 | P2.push_back(vint2(rand() % 1000, rand() % 1000)); 49 | 50 | local_index1d_sad_descriptor_matcher 51 | (_query_positions = P1, 52 | _train_positions = P2, 53 | _query = image_as_array_of_rows(D1), 54 | _train = image_as_array_of_rows(D2), 55 | _approximation = 1, 56 | _search_radius = 10000, 57 | _cell_width = 300, 58 | _distance = [&] (int i, int j, int d) { 59 | assert(i < D1.nrows()); 60 | assert(j < D2.nrows()); 61 | return sad_distance(D1.ncols(), D1[i], D2[j], d); 62 | }, 63 | _match = [&] (int i, int j, int d) { matches[i] = match{j, d}; }); 64 | 65 | for (int i = 0; i < D1.nrows(); i++) 66 | { 67 | assert(matches[i].j < D2.nrows()); 68 | assert(matches[i].j >= 0); 69 | int d = sad_distance(D1.ncols(), D1[i], D2[matches[i].j]); 70 | assert(d == matches[i].d); 71 | 72 | for (int j = 0; j < D2.nrows(); j++) 73 | assert(sad_distance(D1.ncols(), D1[i], D2[j]) >= d); 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /tests/fill.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | using vpp::imageNd; 8 | using vpp::fill; 9 | 10 | imageNd img({100, 200}); 11 | 12 | fill(img, 42); 13 | 14 | for (auto& v : img) assert(v == 42); 15 | 16 | } 17 | -------------------------------------------------------------------------------- /tests/image2d.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | using namespace vpp; 7 | 8 | image2d img1(make_box2d(100, 200), _border = 3); 9 | image2d img2({100, 200}); 10 | 11 | assert(&img1(0,0) == &img1[0][0]); 12 | assert(&img1(0,0) == &(*img1.begin())); 13 | assert(img1.domain() == img2.domain()); 14 | 15 | assert(img1.nrows() == 100); 16 | assert(img1.ncols() == 200); 17 | 18 | { 19 | image2d img(make_box2d(5, 5), _border = 1); 20 | 21 | assert(&img(0,0) == img.address_of(vint2(0,0))); 22 | assert(&img(4,0) == img.address_of(vint2(4,0))); 23 | 24 | auto s1 = img.subimage(img.domain()); 25 | 26 | assert(&s1(0,0) == s1.address_of(vint2(0,0))); 27 | 28 | for (auto p : img.domain()) 29 | assert(img(p) == img[p[0]][p[1]]); 30 | for (auto p : img.domain()) 31 | assert(img(p) == s1[p[0]][p[1]]); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /tests/image3d.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | using namespace vpp; 7 | 8 | image3d img1(make_box3d(10, 20, 30)); 9 | image3d img2(10, 20, 30); 10 | 11 | assert(img1.domain() == img2.domain()); 12 | 13 | assert(img1.nslices() == 10); 14 | assert(img1.nrows() == 20); 15 | assert(img1.ncols() == 30); 16 | 17 | for (int s = 0; s < img1.nslices(); s++) 18 | for (int r = 0; r < img1.nrows(); r++) 19 | for (int c = 0; c < img1.ncols(); c++) 20 | { 21 | img1(s, r, c) = s * r * c; 22 | assert(img1(s, r, c) == (s * r * c)); 23 | } 24 | 25 | // Subimage 26 | { 27 | auto s1 = img1 | box3d(vint3(2,3,4), vint3(5,6,7)); 28 | assert(&s1(0,0,0) == &img1(vint3(2,3,4))); 29 | assert(&s1(0,1,1) == &img1(vint3(2,3,4) + vint3(0,1,1))); 30 | assert(&s1(1,1,1) == &img1(vint3(2,3,4) + vint3(1,1,1))); 31 | assert(&s1(2,2,2) == &img1(vint3(2,3,4) + vint3(2,2,2))); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /tests/imageNd.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace vpp; 5 | 6 | int main() 7 | { 8 | 9 | imageNd img_test({2,3}); 10 | 11 | 12 | std::vector dims = {100, 200}; 13 | 14 | 15 | imageNd img(dims); 16 | 17 | 18 | assert(img.domain().size(0) == dims[0]); 19 | assert(img.domain().size(1) == dims[1]); 20 | 21 | assert(&(*img.begin()) == &img(0,0)); 22 | 23 | for (int r = 0; r < img.domain().size(0); r++) 24 | for (int c = 0; c < img.domain().size(1); c++) 25 | { 26 | assert(img.coords_to_offset(vint2(r, c)) == img.pitch() * r + c * sizeof(int)); 27 | } 28 | 29 | for (int r = 0; r < img.domain().size(0); r++) 30 | for (int c = 0; c < img.domain().size(1); c++) 31 | { 32 | img(vint2(r, c)) = r * c; 33 | img(r, c) = r * c; 34 | } 35 | 36 | for (int r = 0; r < img.domain().size(0) - 1; r++) 37 | for (int c = 0; c < img.domain().size(1) - 1; c++) 38 | { 39 | assert(img(vint2(r, c)) == r * c); 40 | } 41 | 42 | 43 | // Test with border. 44 | 45 | int align_size = 256; 46 | imageNd img2(dims, _border = 1, _aligned = align_size); 47 | assert(&(*img2.begin()) == &img2(0,0)); 48 | assert(!(long(&img2(0,0)) % align_size)); 49 | assert(!(img2.pitch() % align_size)); 50 | assert((char*)(&img2(vint2(99,199))) == ((char*)&img2(0,0) + 99 * img2.pitch() + 199 * sizeof(int))); 51 | 52 | std::vector dim3 = {100, 200, 300}; 53 | imageNd img3(dim3, _border = 1); 54 | 55 | int i = 0; 56 | for (auto& p : img) p = i++; 57 | 58 | auto img_clone = clone(img); 59 | auto img_clone_border = clone(img, _border = 3); 60 | 61 | assert(&(*img_clone_border.begin()) == &img_clone_border(0,0)); 62 | assert(img.domain() == img_clone.domain()); 63 | assert(img.domain() == img_clone_border.domain()); 64 | 65 | assert(img.domain() == img_clone_border.domain()); 66 | 67 | for (auto p : img.domain()) 68 | { 69 | assert(img(p) == img_clone(p)); 70 | assert(img(p) == img_clone_border(p)); 71 | } 72 | 73 | // Subimage. 74 | { 75 | vint2 p1 = vint2(10,10); 76 | vint2 p2 = vint2(12,15); 77 | 78 | auto sub = img | box2d(p1, p2); 79 | assert(&(*sub.begin()) == &sub(0,0)); 80 | assert(&sub(0,0) == &img(p1)); 81 | assert(sub.nrows() == (p2[0] - p1[0] + 1)); 82 | assert(sub.ncols() == (p2[1] - p1[1] + 1)); 83 | } 84 | 85 | // Linear interpolation. 86 | { 87 | image2d test(2, 2, _border = 1); 88 | 89 | { 90 | vuchar1 m; m << 2; 91 | vint1 a = cast(m); 92 | assert(a[0] == 2); 93 | } 94 | 95 | { 96 | vint1 m; m << 2; 97 | vuchar1 a = cast(m); 98 | assert(a[0] == 2); 99 | } 100 | 101 | test(0,0)[0] = 0; 102 | test(0,1)[0] = 10; 103 | test(1,0)[0] = 20; 104 | test(1,1)[0] = 30; 105 | int v1 = (10+20+30)/4.f; 106 | // std::cout << int(test.linear_interpolate(vfloat2(0.5, 0.5))[0]) << std::endl; 107 | assert(test.linear_interpolate(vfloat2(0.5, 0.5))[0] == v1); 108 | // int v2 = (0.25 * 0.75) * 10 + (0.25 * 0.75) * 20 + (0.25 * 0.25) * 30; 109 | // assert(test.linear_interpolate(vfloat2(0.25, 0.25)) == v2); 110 | } 111 | 112 | // Move. 113 | { 114 | image2d i1(10, 10); 115 | int* buffer = i1.data(); 116 | image2d i2 = std::move(i1); 117 | assert(i2.data() == buffer); 118 | assert(!i1.has_data()); 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /tests/imageNd_iterator.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | using namespace vpp; 7 | 8 | image2d img(3, 3, _border = 1); 9 | 10 | vint2 ref[] = { 11 | vint2(0, 0), 12 | vint2(0, 1), 13 | vint2(0, 2), 14 | vint2(1, 0), 15 | vint2(1, 1), 16 | vint2(1, 2), 17 | vint2(2, 0), 18 | vint2(2, 1), 19 | vint2(2, 2) 20 | }; 21 | 22 | int i = 0; 23 | for (auto& p : img) 24 | { 25 | std::cout << long(&p - &img(0,0)) << " " << (&img(ref[i]) - &img(0,0)) << std::endl; 26 | assert(&p == &img(ref[i])); 27 | i++; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /tests/lbp.cc: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | int main() 7 | { 8 | using namespace vpp; 9 | 10 | image2d V(3,3, _border = 1); 11 | image2d lbp(3,3); 12 | 13 | V(1,1) = 1; 14 | 15 | V(0,0) = 0; 16 | V(0,1) = 2; 17 | V(0,2) = 2; 18 | 19 | V(1,0) = 2; 20 | V(1,2) = 0; 21 | 22 | V(2,0) = 2; 23 | V(2,1) = 0; 24 | V(2,2) = 2; 25 | 26 | unsigned char x = 0b10101110; 27 | 28 | lbp_transform(V, lbp); 29 | 30 | unsigned char y = lbp(1,1); 31 | for (int i = 0; i <= 8; i++) 32 | std::cout << ((y & (1 << i)) >> i); 33 | std::cout << std::endl; 34 | 35 | for (int i = 0; i <= 8; i++) 36 | std::cout << ((x & (1 << i)) >> i); 37 | std::cout << std::endl; 38 | 39 | assert(lbp(1,1) == x); 40 | 41 | assert(lbp_hamming_distance(0b01010101, 0b01010101) == 0); 42 | assert(lbp_hamming_distance(0b11010101, 0b01010101) == 1); 43 | assert(lbp_hamming_distance(0b11111111, 0b00000000) == 8); 44 | } 45 | -------------------------------------------------------------------------------- /tests/liie.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | 14 | using namespace vpp; 15 | using namespace vpp::liie; 16 | using namespace s; 17 | 18 | int main() 19 | { 20 | image2d A(10,10); 21 | image2d B(10,10); 22 | const image2d C(10,10); 23 | 24 | // A + B; 25 | fill(A, 1); 26 | fill(B, 2); 27 | 28 | A(5,5) = 1000; 29 | 30 | auto X = pixel_wise(A, B).eval(_v(A) = _v(A) + _v(_2)); 31 | 32 | auto Y = pixel_wise(A, B).eval(_v(A) = _v(A) - _v(_2)); 33 | auto Z = pixel_wise(A, B).eval(_v(A) = _v(A) * _v(_2) + _v(A) + _v(A) + _v(A) + _v(A) + _v(A) + _v(A)); 34 | auto U = pixel_wise(A, B).eval(_v(A) = _v(A) * _v(_2) + _v(A) - _v(A) - _v(A) - _v(A) - _v(A) - _v(A)); 35 | 36 | 37 | // assert(eval(A, B, A, _argmax(_v(A))) == vint2(5,5)); 38 | // assert(eval(_argmax(_v(A))) == vint2(5,5)); 39 | // assert(eval(A, _argmax(_v(_1))) == vint2(5,5)); 40 | 41 | // fill(A, 1); fill(B, 2); 42 | // X = eval(_v(A) + _v(B)); 43 | // assert(X(0,0) == 3); 44 | 45 | // eval(_v(X) = _v(B) * 2); 46 | // assert(X(0,0) == 4); 47 | 48 | // eval(X, _v(_1) = _v(B) * 2); 49 | // assert(X(0,0) == 4); 50 | 51 | // A(5,5) = 1000; 52 | // A(2,5) = -11; 53 | // assert(eval(_max(A)) == 1000); 54 | // assert(eval(_min(A)) == -11); 55 | } 56 | -------------------------------------------------------------------------------- /tests/opencv_bridge.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void check_cv_refcount(const cv::Mat& m, int i) 6 | { 7 | #if (((defined(CV_VERSION_MAJOR) && CV_VERSION_MAJOR >= 3))) 8 | assert((m.u->refcount) == i); 9 | #else 10 | assert(*(m.refcount) == i); 11 | #endif 12 | 13 | } 14 | 15 | int main() 16 | { 17 | using vpp::image2d; 18 | using vpp::vint2; 19 | using vpp::make_box2d; 20 | 21 | // from_opencv, opencv releases memory. 22 | { 23 | cv::Mat_ m(100, 200); 24 | 25 | { 26 | image2d v = vpp::from_opencv(m); 27 | 28 | assert(v.nrows() == 100); 29 | assert(v.ncols() == 200); 30 | 31 | check_cv_refcount(m, 2); 32 | 33 | } 34 | check_cv_refcount(m, 1); 35 | } 36 | 37 | // from_opencv, vpp releases memory. 38 | { 39 | image2d v; 40 | 41 | { 42 | cv::Mat_ m(100, 200); 43 | v = vpp::from_opencv(m); 44 | 45 | assert(v.nrows() == 100); 46 | assert(v.ncols() == 200); 47 | 48 | m.at(50, 50) = 41; 49 | 50 | check_cv_refcount(m, 2); 51 | } 52 | 53 | assert(v(50, 50) == 41); 54 | for (auto& p : v) p = 42; 55 | for (auto& p : v) assert(p == 42); 56 | } 57 | 58 | // To opencv, vpp releases memory. 59 | { 60 | image2d v(100, 200); 61 | 62 | { 63 | cv::Mat m = vpp::to_opencv(v); 64 | 65 | assert(m.rows == 100); 66 | assert(m.cols == 200); 67 | 68 | v(50, 50) = 0;; 69 | m.at(50, 50) = 41; 70 | assert(v(50, 50) == 41); 71 | } 72 | 73 | v(50, 51) = 42; 74 | assert(v(50, 50) == 41); 75 | assert(v(50, 51) == 42); 76 | 77 | // for (auto& p : v) p = 42; 78 | // for (auto& p : v) assert(p == 42); 79 | } 80 | 81 | // To opencv, opencv releases memory. 82 | // Does not work because cv::fastFree cannot release 83 | // a buffer given by malloc. 84 | // { 85 | // cv::Mat_ m; 86 | 87 | // { 88 | // image2d v(100, 200); 89 | // m = vpp::to_opencv(v); 90 | 91 | // assert(m.rows == 100); 92 | // assert(m.cols == 200); 93 | // m.at(50, 50) = 41; 94 | 95 | // assert(v(50, 50) == 41); 96 | 97 | // for (auto& p : v) p = 42; 98 | // for (auto& p : v) assert(p == 42); 99 | 100 | // } 101 | 102 | // m.at(10,10) = 42; 103 | // assert(m.at(10,10) == 42); 104 | // // for (auto& p : make_box2d(100, 200)) m.at(p[0], p[1]) = 42; 105 | // // for (auto& p : make_box2d(100, 200)) assert(m.at(p[0], p[1]) == 42); 106 | 107 | // assert(*(m.refcount) == 1); 108 | // } 109 | 110 | } 111 | -------------------------------------------------------------------------------- /tests/pixel_wise.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace vpp; 5 | 6 | int main() 7 | { 8 | using namespace vpp; 9 | 10 | //image2d img2(50, 300, border(1)); 11 | image2d img2(10, 10, _border = 1); 12 | 13 | vpp::pixel_wise(img2) | [&] (auto& p) { p = 42; }; 14 | 15 | for (auto p : img2.domain()) 16 | assert(img2(p) == 42); 17 | 18 | fill(img2, 0); 19 | vpp::pixel_wise(img2) | [&] (auto& p) { p = 43; }; 20 | for (auto p : img2.domain()) { assert(img2(p) == 43); } 21 | 22 | // On domain. 23 | box2d domain = vpp::make_box2d(10, 10); 24 | auto it = domain.begin(); 25 | vpp::pixel_wise(domain)(_left_to_right, _top_to_bottom, _no_threads) | [&] (auto p) { 26 | assert(*it == p); 27 | it.next(); 28 | }; 29 | 30 | fill_with_border(img2, 0); 31 | 32 | // Row forward. 33 | fill(img2, 1); 34 | vpp::pixel_wise(img2, relative_access(img2))(_left_to_right) | [&] (auto& o, auto nbh) { 35 | o = o + nbh(0, -1); 36 | }; 37 | for (auto p : img2.domain()) { 38 | assert(img2(p) == p[1] + 1); 39 | } 40 | 41 | // Row backward. 42 | fill(img2, 1); 43 | vpp::pixel_wise(img2, relative_access(img2))(_right_to_left) | [&] (auto& o, auto nbh) { 44 | o = o + nbh(0, 1); 45 | }; 46 | for (auto p : img2.domain()) { assert(img2(p) == (img2.ncols() - p[1])); } 47 | 48 | // Col forward. 49 | fill(img2, 1); 50 | vpp::pixel_wise(img2, relative_access(img2), img2.domain())(_top_to_bottom) | [&] (auto& o, auto nbh, vint2 p) { 51 | o = o + nbh(-1, 0); 52 | }; 53 | for (auto p : img2.domain()) { assert(img2(p) == (p[0] + 1)); } 54 | 55 | // Col forward. 56 | fill(img2, 1); 57 | vpp::pixel_wise(img2, relative_access(img2), img2.domain())(_bottom_to_top) | [&] (auto& o, auto nbh, vint2 p) { 58 | o = o + nbh(1, 0); 59 | }; 60 | for (auto p : img2.domain()) { assert(img2(p) == (img2.nrows() - p[0])); } 61 | 62 | // Image construction. 63 | auto img3 = pixel_wise(img2) | [] (auto& x) { return x; }; 64 | for (auto p : img2.domain()) { assert(img2(p) == img3(p)); } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /tests/pyramid.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | using namespace vpp; 8 | 9 | image2d img(4, 4); 10 | 11 | // Todo. 12 | } 13 | -------------------------------------------------------------------------------- /tests/pyrlk.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | using namespace vpp; 11 | 12 | int main(int argc, char* argv[]) 13 | { 14 | image2d i1(100,100); 15 | image2d i2(100,100); 16 | 17 | image2d i1_blur(100,100); 18 | image2d i2_blur(100,100); 19 | 20 | fill(i1, 0); 21 | fill(i2, 0); 22 | 23 | draw::square(i1, _center = vint2{50,50}, _width = 5, _fill = 255); 24 | draw::square(i2, _center = vint2{52,52}, _width = 5, _fill = 255); 25 | 26 | cv::GaussianBlur(to_opencv(i1), to_opencv(i1_blur), cv::Size(9,9), 3, 5, cv::BORDER_REPLICATE); 27 | cv::GaussianBlur(to_opencv(i2), to_opencv(i2_blur), cv::Size(9,9), 3, 5, cv::BORDER_REPLICATE); 28 | 29 | std::vector keypoints; 30 | keypoints.push_back(vfloat2(50, 50)); 31 | 32 | if (argc > 1 && std::string(argv[1]) == "--verbose") 33 | { 34 | std::cout << "Writing i1.jpg and i2.jpg" << std::endl; 35 | cv::imwrite("i1.jpg", to_opencv(i1_blur)); 36 | cv::imwrite("i2.jpg", to_opencv(i2_blur)); 37 | } 38 | 39 | lucas_kanade(i1_blur, i2_blur, 40 | _keypoints = keypoints, 41 | _niterations = 50, 42 | _winsize = 5, 43 | _min_ev = 0.001, 44 | _delta = 0.01, 45 | _nscales = 2, 46 | _flow = [] (vfloat2 p, vfloat2 f, int d) 47 | { 48 | assert(p == vfloat2(50.f, 50.f)); 49 | assert((f - vfloat2(2.f, 2.f)).norm() < 0.05); 50 | }); 51 | } 52 | -------------------------------------------------------------------------------- /tests/sandbox.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | using namespace vpp; 7 | } 8 | -------------------------------------------------------------------------------- /tests/sum.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | using namespace vpp; 8 | 9 | image2d img(100, 200); 10 | 11 | int s = 0; 12 | char i = 0; 13 | for (char& c : img) { c = i++; s += c; } 14 | 15 | assert(sum(img) == s); 16 | 17 | } 18 | -------------------------------------------------------------------------------- /tests/tuple_utils.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int sum(int a, int b) 5 | { 6 | return a + b; 7 | } 8 | 9 | int main() 10 | { 11 | using namespace vpp; 12 | 13 | auto t1 = std::make_tuple(1, 2); 14 | 15 | internals::apply_args(t1, sum); 16 | internals::apply_args_transform(t1, sum, [] (int x) { return x + 1; } ); 17 | 18 | } 19 | -------------------------------------------------------------------------------- /tests/window.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | using namespace vpp; 7 | 8 | image2d A(100, 100); 9 | 10 | auto win = make_window([] () { 11 | return make_array( 12 | vint2{-1, -1}, vint2{-1, 0}, vint2{-1, 1}, 13 | vint2{0, -1}, vint2{0, 0}, vint2{0, 1}, 14 | vint2{1, -1}, vint2{1, 0}, vint2{1, 1}); }); 15 | 16 | int& pix = A(5, 5); 17 | 18 | vint2 ref[] = { 19 | vint2(4, 4), 20 | vint2(4, 5), 21 | vint2(4, 6), 22 | vint2(5, 4), 23 | vint2(5, 5), 24 | vint2(5, 6), 25 | vint2(6, 4), 26 | vint2(6, 5), 27 | vint2(6, 6) 28 | }; 29 | 30 | int i = 0; 31 | auto ra = relative_accessor(A, vint2(5,5)); 32 | 33 | foreach(win, [&] (vint2 n) { ra(n) = i++; }); 34 | 35 | i = 0; 36 | for (int dr = 4; dr <= 6; dr++) 37 | for (int dc = 4; dc <= 6; dc++) 38 | { 39 | assert(A(dr, dc) == i); 40 | i++; 41 | } 42 | 43 | assert(i == 9); 44 | } 45 | 46 | 47 | -------------------------------------------------------------------------------- /vpp/algorithms/descriptor_matcher.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace vpp 6 | { 7 | using namespace s; 8 | 9 | // Match two set of descritors. 10 | 11 | 12 | // Options: 13 | 14 | // For all matchers: 15 | // 16 | // _distance = function(i, j, best_distance) 17 | // compute the distance between the ith and jth descritors. 18 | // _match = function(i, j, distance) 19 | // called if there a match between the ith and jth descritor. 20 | // 21 | // For the bruteforce matcher only: 22 | // 23 | // _query_size: Size of the first set 24 | // _train_size: Size of the second set 25 | // 26 | // For the _flann and _index1d indexes: 27 | // 28 | // _query = descriptors1, // or a lambda [] (int i) { return kps[i].descriptor; } 29 | // _train = descriptors2, 30 | // 31 | // Methods selection: 32 | // 33 | // _bruteforce 34 | // _index1d(_approximation = 2) TODO 35 | // _flann(_trees = 4, _nchecks = 50) TODO 36 | 37 | // Spatial indexes: 38 | // _grid_index(_query_positions = positions1, 39 | // _train_positions = positions2, 40 | // _search_radius = 100) 41 | // 42 | 43 | template 44 | void descriptor_matcher(OPTS&&... opts); 45 | 46 | template 47 | void bruteforce_matcher(int query_size, int train_size, 48 | OPTS... opts); 49 | 50 | template 51 | void local_index1d_sad_descriptor_matcher(OPTS... opts); 52 | 53 | // Todo 54 | // template 55 | // void flann_descriptor_matcher(int query_size, 56 | // int train_size, 57 | // OPTS... opts); 58 | 59 | } 60 | 61 | //#include "descriptor_matcher/dispatch.hh" 62 | #include "descriptor_matcher/bruteforce_matcher.hh" 63 | #include "descriptor_matcher/distances.hh" 64 | #include "descriptor_matcher/local_index1d_sad_descriptor_matcher.hh" 65 | -------------------------------------------------------------------------------- /vpp/algorithms/descriptor_matcher/bruteforce_matcher.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace vpp 8 | { 9 | 10 | template 11 | void bruteforce_matcher(int query_size, int train_size, 12 | OPTS... opts) 13 | { 14 | auto options = D(opts...); 15 | typedef decltype(options) O; 16 | 17 | static_assert(iod::has_symbol::value, "bruteforce_matcher: _distance options missing."); 18 | static_assert(iod::has_symbol::value, "bruteforce_matcher: _match callback is missing."); 19 | 20 | int set1_size = query_size; 21 | int set2_size = train_size; 22 | 23 | auto distance = options.distance; 24 | auto match = options.match; 25 | 26 | typedef decltype(distance(0, 0, 0)) distance_t; 27 | 28 | #pragma omp parallel for 29 | for (int i = 0; i < set1_size; i++) 30 | { 31 | int best_j = 0; 32 | distance_t best_distance = distance(i, 0, std::numeric_limits::max()); 33 | 34 | for (int j = 1; j < set2_size; j++) 35 | { 36 | distance_t d = distance(i, j, best_distance); 37 | if (d < best_distance) 38 | { 39 | best_j = j; 40 | best_distance = d; 41 | } 42 | } 43 | 44 | #pragma omp critical 45 | match(i, best_j, best_distance); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /vpp/algorithms/descriptor_matcher/dispatch.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | //#include 4 | #include 5 | #include 6 | #include 7 | //#include 8 | #include 9 | 10 | namespace vpp 11 | { 12 | 13 | using s::_bruteforce; 14 | using s::_local_search; 15 | using s::_index1d; 16 | using s::_flann; 17 | using s::_match; 18 | using s::_distance; 19 | using s::_size1; 20 | using s::_size2; 21 | 22 | template 23 | void descriptor_matcher(OPTS&&... opts) 24 | { 25 | //auto options = iod::options(opts...); 26 | auto options = iod::D(opts...); 27 | typedef decltype(options) O; 28 | static_assert(iod::has_symbol::value, "descriptor_matcher: _distance options missing."); 29 | static_assert(iod::has_symbol::value, "descriptor_matcher: _match callback is missing."); 30 | 31 | constexpr bool is_bruteforce = iod::has_symbol::value; 32 | constexpr bool is_index1d = iod::has_symbol::value; 33 | constexpr bool is_local_search = iod::has_symbol::value; 34 | constexpr bool is_flann = iod::has_symbol::value; 35 | static_assert(is_bruteforce || is_index1d, "descritor_matcher: Missing matching strategy. Use _bruteforce or _index1d."); 36 | 37 | // Index strategy selection. 38 | auto index = iod::static_if 39 | ([&] (auto o) { return bruteforce_matcher_caller; }, // Bruteforce 40 | [&] (auto) { 41 | 42 | // Index1d. 43 | return iod::static_if 44 | ([&] (auto o) { return index1d(o.index1d); }, // Index1d 45 | [] (auto) { 46 | 47 | // Flann 48 | // return iod::static_if 49 | // ([&] (auto o) { return flann_matcher(opts...); }, // Flann 50 | // [] (auto) {}, options); 51 | 52 | }, options); 53 | 54 | }, options); 55 | 56 | // Search. 57 | auto F = iod::static_if 58 | ([&] (auto o) { return local_search(index, o.local_search); }, 59 | [] (auto o) { return global_search(index); }, 60 | options); 61 | 62 | } 63 | 64 | 65 | } 66 | 67 | 68 | -------------------------------------------------------------------------------- /vpp/algorithms/descriptor_matcher/distances.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace vpp 8 | { 9 | 10 | template 11 | D sad_distance(F&& i1, F&& i2, D th) 12 | { 13 | const int RS = 128; 14 | D err = 0; 15 | for (int r = 0; r < (i1.size())/RS and err <= th; r++) 16 | { 17 | for (int i = 0; i < RS; i++) 18 | err += std::abs((i1[r * RS + i]) - (i2[r * RS + i])); 19 | } 20 | 21 | 22 | if (err <= th) 23 | { 24 | for (int i = (((i1.size())/RS)*RS); i < i1.size(); i++) 25 | err += std::abs((i1[i]) - (i2[i])); 26 | } 27 | 28 | // // for (int i = 0; i < i1.size(); i++) 29 | // // err += std::abs((i1[i]) - (i2[i])); 30 | 31 | return err; 32 | } 33 | 34 | template 35 | D sad_distance(int size, F&& i1, F&& i2, D th) 36 | { 37 | return sad_distance(iod::array_view(size, i1), iod::array_view(size, i2), th); 38 | } 39 | 40 | template 41 | D sad_distance(int size, F&& i1, F&& i2) 42 | { 43 | return sad_distance(iod::array_view(size, i1), iod::array_view(size, i2), 44 | std::numeric_limits::max()); 45 | } 46 | 47 | template 48 | D sad_distance(F&& i1, F&& i2) 49 | { 50 | return sad_distance(i1, i2, std::numeric_limits::max()); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /vpp/algorithms/descriptor_matcher/global_search.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace vpp 4 | { 5 | 6 | template 7 | void global_search(I& index, int query_size, int train_size, 8 | D distance) 9 | { 10 | for (int i = 0; i < query_size; i++) 11 | index.search( 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /vpp/algorithms/descriptor_matcher/grid_index.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace vpp 8 | { 9 | 10 | template 11 | struct grid_index 12 | { 13 | 14 | template 15 | grid_index(O&& o) : 16 | s(o.get(s::_cell_width, 300)), 17 | search_radius(o.get(s::_search_radius, 300)) 18 | { 19 | vint2 pmax(0,0); 20 | for (vint2 p : o.train_positions) 21 | { 22 | pmax[0] = std::max(pmax[0], p[0]); 23 | pmax[1] = std::max(pmax[1], p[1]); 24 | } 25 | 26 | idx = vpp::image2d(int(std::ceil((1 + pmax[0]) / float(s))), 27 | int(std::ceil((1 + pmax[1]) / float(s)))); 28 | 29 | for (vint2 p : o.train_positions) 30 | assert(idx.has(p / s)); 31 | 32 | pixel_wise(idx) | [&] (SI& si) 33 | { 34 | new (&si) SI(o); 35 | }; 36 | } 37 | 38 | template 39 | void index(O&& o) 40 | { 41 | assert(idx.has(o.position / s)); 42 | idx(o.position / s).index(o); 43 | } 44 | 45 | void finalize() 46 | { 47 | 48 | pixel_wise(idx) | [&] (SI& si) 49 | { 50 | si.finalize(); 51 | }; 52 | 53 | } 54 | 55 | template 56 | auto search(O&& o, F distance) 57 | { 58 | vint2 prediction = o.position; 59 | 60 | vint2 begin = (prediction - vint2(search_radius, search_radius)) / s; 61 | vint2 end = (prediction + vint2(search_radius, search_radius)) / s; 62 | 63 | typedef decltype(distance(0, 0, 0)) distance_t; 64 | 65 | int best_idx = -1; 66 | distance_t best_distance = std::numeric_limits::max(); 67 | 68 | for (vint2 n : box2d(begin, end)) 69 | { 70 | if (idx.has(n) and idx(n).size() > 0) 71 | { 72 | auto& b = idx(n); 73 | auto m = b.search(o, distance); 74 | if (m.distance < best_distance) 75 | { 76 | best_distance = m.distance; 77 | best_idx = m.idx; 78 | } 79 | } 80 | } 81 | 82 | return iod::D(_distance = best_distance, _idx = best_idx); 83 | } 84 | 85 | vpp::image2d idx; 86 | int s; // scale 87 | int search_radius; 88 | }; 89 | 90 | } 91 | -------------------------------------------------------------------------------- /vpp/algorithms/descriptor_matcher/index.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | namespace vpp 5 | { 6 | 7 | // An index must provide: 8 | 9 | // index_init(subindex, options); 10 | // index.index_descriptors(descriptors); 11 | // index.search(descriptor) -> match{int match_idx, int distance}; 12 | 13 | index1.index_descriptors 14 | 15 | spatial_index_init(options, bruteforce_index()); 16 | } 17 | -------------------------------------------------------------------------------- /vpp/algorithms/descriptor_matcher/index1d.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace vpp 6 | { 7 | 8 | struct index1d 9 | { 10 | struct kp_info 11 | { 12 | int id; 13 | int projection; 14 | }; 15 | 16 | 17 | template 18 | index1d(O&& o) 19 | { 20 | approximation_ = o.get(_approximation, 1); 21 | } 22 | 23 | int size() const { return points_.size(); } 24 | 25 | template 26 | int project(const O& o) 27 | { 28 | int projection = 0; 29 | for (int i = 0; i < o.size(); i++) 30 | projection += o[i]; 31 | return projection; 32 | } 33 | 34 | template 35 | void index(O&& o) 36 | { 37 | int projection = project(o.descriptor); 38 | points_.push_back(kp_info{o.idx, projection}); 39 | } 40 | 41 | void finalize() 42 | { 43 | std::sort(points_.begin(), points_.end(), 44 | [] (auto x, auto y) { return x.projection < y.projection; }); 45 | } 46 | 47 | int position_of_projection(int proj) 48 | { 49 | // Dichotomic search. 50 | int inf = 0; 51 | int sup = points_.size() - 1; 52 | 53 | while (((inf + 1) < sup) and points_[inf].projection < points_[sup].projection) 54 | { 55 | int pivot = (inf + sup) / 2; 56 | if (points_[pivot].projection < proj) 57 | inf = pivot; 58 | else sup = pivot; 59 | 60 | if (points_[inf].projection == proj) sup = inf; 61 | if (points_[sup].projection == proj) inf = sup; 62 | } 63 | 64 | return inf; 65 | } 66 | 67 | template 68 | auto search(O&& o, F distance, int distance_th = std::numeric_limits::max()) 69 | { 70 | int projection = project(o.descriptor); 71 | int projection_idx = position_of_projection(projection); 72 | 73 | int best_idx = points_[projection_idx].id; 74 | int best_distance = distance(o.idx, best_idx, distance_th); 75 | distance_th = std::min(distance_th, best_distance); 76 | 77 | auto test_ith = [&] (int i) 78 | { 79 | int dist = distance(o.idx, i, best_distance); 80 | if (best_distance > dist) 81 | { 82 | best_distance = dist; 83 | best_idx = i; 84 | distance_th = std::min(distance_th, best_distance); 85 | } 86 | }; 87 | 88 | bool done = false; 89 | for (int i = projection_idx - 1, j = projection_idx + 1; !done; i--, j++) 90 | { 91 | done = true; 92 | if (i >= 0 and (approximation_ * (projection - points_[i].projection)) <= best_distance) 93 | { 94 | done = false; 95 | test_ith(points_[i].id); 96 | } 97 | 98 | if (j < points_.size() and (approximation_ * (points_[j].projection - projection)) <= best_distance) 99 | { 100 | done = false; 101 | test_ith(points_[j].id); 102 | } 103 | } 104 | return D(_idx = best_idx, _distance = best_distance); 105 | } 106 | 107 | private: 108 | int approximation_; 109 | std::vector points_; 110 | std::vector projection_index_; 111 | }; 112 | 113 | } 114 | -------------------------------------------------------------------------------- /vpp/algorithms/descriptor_matcher/local_index1d_sad_descriptor_matcher.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "grid_index.hh" 4 | #include "index1d.hh" 5 | #include 6 | 7 | namespace vpp 8 | { 9 | 10 | template 11 | void local_index1d_sad_descriptor_matcher(OPTS... opts) 12 | { 13 | 14 | auto options = iod::D(opts...); 15 | typedef decltype(options) O; 16 | 17 | grid_index idx(options); 18 | 19 | static_assert(iod::has_symbol::value, "descriptor_matcher: _train options missing."); 20 | static_assert(iod::has_symbol::value, "descriptor_matcher: _query is missing."); 21 | 22 | static_assert(iod::has_symbol::value, "descriptor_matcher: _train_positions options missing."); 23 | static_assert(iod::has_symbol::value, "descriptor_matcher: _query_positions options missing."); 24 | 25 | static_assert(iod::has_symbol::value, "descriptor_matcher: _distance options missing."); 26 | static_assert(iod::has_symbol::value, "descriptor_matcher: _match callback is missing."); 27 | 28 | assert(options.train.size() == options.train_positions.size()); 29 | assert(options.query.size() == options.query_positions.size()); 30 | 31 | for (int i = 0; i < options.train.size(); i++) 32 | idx.index(iod::D(_idx = i, 33 | _position = options.train_positions[i], 34 | _descriptor = options.train[i])); 35 | 36 | idx.finalize(); 37 | #pragma omp parallel for 38 | for (int i = 0; i < options.query.size(); i++) 39 | { 40 | auto m = idx.search(iod::D(_position = options.query_positions[i], 41 | _descriptor = options.query[i], 42 | _idx = i), 43 | options.distance); 44 | 45 | if (m.idx >= 0) 46 | { 47 | options.match(i, m.idx, m.distance); 48 | } 49 | } 50 | 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /vpp/algorithms/descriptor_matcher/local_search.hh: -------------------------------------------------------------------------------- 1 | 2 | namespace vpp 3 | { 4 | 5 | template 6 | struct grid_index 7 | { 8 | 9 | template 10 | grid_index(O&& o) 11 | { 12 | search_radius = o.search_radius; 13 | grid_width = o.grid_width; 14 | // Fixme build index 15 | } 16 | 17 | template 18 | void index(O&& o) 19 | { 20 | idx(o.position / s).index(o); 21 | } 22 | 23 | template 24 | void search(O&& o, F distance) 25 | { 26 | vint2 prediction = o.position; 27 | vint2 descriptor = o.descriptor; 28 | 29 | vint2 begin = (prediction - vint2(search_radius, search_radius)) / s; 30 | vint2 end = (prediction + vint2(search_radius, search_radius)) / s; 31 | for (vint2 n : box2d(begin, end)) 32 | { 33 | if (idx.has(n) and idx(n).size() > 0) 34 | { 35 | auto& b = idx(n); 36 | b.search(descriptor, prediction, distance); 37 | } 38 | } 39 | } 40 | 41 | const int S; 42 | vpp::image2d idx; 43 | int s; // scale 44 | int search_radius; 45 | }; 46 | 47 | } 48 | -------------------------------------------------------------------------------- /vpp/algorithms/epipolar_geometry.hh: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | namespace vpp 5 | { 6 | 7 | // http://www.cse.psu.edu/~rcollins/CSE486/lecture19_6pp.pdf 8 | // Page 5. 9 | inline vfloat2 epipole_left(const Eigen::Matrix3f& F) 10 | { 11 | // F e_l = 0. 12 | Eigen::EigenSolver es(F.cast().transpose() * F.cast()); 13 | 14 | auto values = es.eigenvalues(); 15 | auto vectors = es.eigenvectors(); 16 | vdouble2 epipole; 17 | double min_ev = FLT_MAX; 18 | for (int i = 0; i < values.size(); i++) 19 | if (values[i].real() < min_ev) 20 | { 21 | min_ev = values[i].real(); 22 | auto vc = vectors.col(i); 23 | epipole[0] = vc[0].real(); 24 | epipole[1] = vc[1].real(); 25 | epipole /= double(vc[2].real()); 26 | } 27 | 28 | return epipole.cast(); 29 | } 30 | 31 | // http://www.cse.psu.edu/~rcollins/CSE486/lecture19_6pp.pdf 32 | // Page 5. 33 | inline vfloat2 epipole_right(const Eigen::Matrix3f& F) 34 | { 35 | // e_r F = 0. 36 | Eigen::EigenSolver es(F.cast() * F.cast().transpose()); 37 | 38 | 39 | auto values = es.eigenvalues(); 40 | auto vectors = es.eigenvectors(); 41 | vdouble2 epipole; 42 | double min_ev = FLT_MAX; 43 | for (int i = 0; i < values.size(); i++) 44 | if (values[i].real() < min_ev) 45 | { 46 | min_ev = values[i].real(); 47 | auto vc = vectors.col(i); 48 | epipole[0] = vc[0].real(); 49 | epipole[1] = vc[1].real(); 50 | epipole /= double(vc[2].real()); 51 | } 52 | 53 | return epipole.cast(); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /vpp/algorithms/fast_detector/fast.hh: -------------------------------------------------------------------------------- 1 | #ifndef VPP_FAST9_DETECTOR_HH_ 2 | # define VPP_FAST9_DETECTOR_HH_ 3 | 4 | # include 5 | 6 | # include 7 | 8 | namespace vpp 9 | { 10 | 11 | // FAST9 detector. 12 | 13 | // Options : 14 | // _local_maxima: Local maxima keypoint selection. 15 | // _blockwise: blockwise keypoint selection (one kp per block) 16 | // _blockwise_rank: blockwise rank selection (several kp per block). 17 | // 18 | // _block_size = int(): block size ised by _blockwise and _blockwise_rank. 19 | // _max_points_per_block = int(): block size used by _blockwise and _blockwise_rank. 20 | // _mask = image2d 21 | // _scores = &std::vector 22 | // 23 | // example: fast_detector9(image, th, _local_maxima, _mask = mask_image); 24 | // 25 | template 26 | std::vector fast9(const image2d& A, 27 | int th, 28 | OPTS... opts); 29 | 30 | template 31 | void fast9_scores(const image2d& A, 32 | int th, 33 | const KPS& keypoints, 34 | std::vector& scores); 35 | 36 | template 37 | int fast9_score(const image2d& A, 38 | int th, 39 | vint2 p); 40 | 41 | // Old API only used internally. 42 | 43 | template 44 | std::vector fast_detector9(const image2d& A, 45 | int th, 46 | const image2d& mask, 47 | std::vector* scores = 0); 48 | 49 | template 50 | std::vector fast_detector9_blockwise_maxima(const image2d& A, 51 | int th, 52 | int block_size, 53 | const image2d& mask, 54 | std::vector* scores = 0); 55 | 56 | template 57 | std::vector fast_detector9_blockwise_rank(const image2d& A, 58 | int th, 59 | int block_size, 60 | int max_point_per_block, 61 | const image2d& mask, 62 | std::vector* scores = 0); 63 | 64 | template 65 | std::vector fast_detector9_local_maxima(const image2d& A, 66 | int th, 67 | const image2d& mask, 68 | std::vector* scores = 0); 69 | 70 | } 71 | 72 | # include 73 | 74 | #endif 75 | -------------------------------------------------------------------------------- /vpp/algorithms/filters/scharr.hh: -------------------------------------------------------------------------------- 1 | #ifndef VPP_ALGORITHMS_FILTERS_SCHARR_HH_ 2 | # define VPP_ALGORITHMS_FILTERS_SCHARR_HH_ 3 | 4 | # include 5 | # include 6 | 7 | namespace vpp 8 | { 9 | 10 | template 11 | auto scharr(const image2d& in, vint2 p) 12 | { 13 | assert(in.border() >= 1); 14 | 15 | int r = p[0]; 16 | int c = p[1]; 17 | 18 | const U* row1 = &in(r - 1, 0); 19 | const U* row2 = &in(r, 0); 20 | const U* row3 = &in(r + 1, 0); 21 | 22 | return vector( 23 | 24 | (3 * int(row3[c - 1]) + 25 | 10 * int(row3[c]) + 26 | 3 * int(row3[c + 1]) 27 | - 28 | 3 * int(row1[c - 1]) - 29 | 10 * int(row1[c ]) - 30 | 3 * int(row1[c + 1])) / 32.f 31 | 32 | , 33 | 34 | (3 * int(row1[c + 1]) + 35 | 10 * int(row2[c + 1]) + 36 | 3 * int(row3[c + 1]) 37 | - 38 | 3 * int(row1[c - 1]) - 39 | 10 * int(row2[c - 1]) - 40 | 3 * int(row3[c - 1])) / 32.f 41 | ); 42 | 43 | } 44 | 45 | template 46 | void scharr(const image2d& in, image2d>& out) 47 | { 48 | assert(in.border() >= 1); 49 | 50 | int nr = out.nrows(); 51 | int nc = out.ncols(); 52 | 53 | #pragma omp parallel for 54 | for (int r = 0; r < nr; r++) 55 | { 56 | vector* out_row = &out(r, 0); 57 | const U* row1 = &in(r - 1, 0); 58 | const U* row2 = &in(r, 0); 59 | const U* row3 = &in(r + 1, 0); 60 | 61 | #pragma omp simd 62 | for (int c = 0; c < nc; c++) 63 | { 64 | out_row[c] = vector( 65 | 66 | (3 * V(row3[c - 1]) + 67 | 10 * V(row3[c]) + 68 | 3 * V(row3[c + 1]) 69 | - 70 | 3 * V(row1[c - 1]) - 71 | 10 * V(row1[c ]) - 72 | 3 * V(row1[c + 1])) / 32.f 73 | 74 | , 75 | 76 | (3 * V(row1[c + 1]) + 77 | 10 * V(row2[c + 1]) + 78 | 3 * V(row3[c + 1]) 79 | - 80 | 3 * V(row1[c - 1]) - 81 | 10 * V(row2[c - 1]) - 82 | 3 * V(row3[c - 1])) / 32.f 83 | ); 84 | } 85 | } 86 | 87 | } 88 | 89 | template 90 | void scharr(const image2d>& in, image2d>& out) 91 | { 92 | scharr(*(const image2d*)&in, out); 93 | } 94 | 95 | }; 96 | 97 | #endif 98 | -------------------------------------------------------------------------------- /vpp/algorithms/lbp/lbp_distance.hh: -------------------------------------------------------------------------------- 1 | namespace vpp 2 | { 3 | 4 | inline int lbp_hamming_distance(unsigned char a, unsigned b) 5 | { 6 | unsigned char val = a ^ b; 7 | int dist = 0; 8 | while(val) 9 | { 10 | ++dist; 11 | val &= val - 1; // why? 12 | } 13 | return dist; 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /vpp/algorithms/lbp/lbp_transform.hh: -------------------------------------------------------------------------------- 1 | 2 | 3 | namespace vpp 4 | { 5 | 6 | template 7 | void lbp_transform(image2d& A, image2d& B) 8 | { 9 | int nr = A.nrows(); 10 | #pragma omp parallel for 11 | for (int r = 0; r < nr; r++) 12 | { 13 | U* curB = &B(vint2(r, 0)); 14 | int nc = A.ncols(); 15 | 16 | V* rows[3]; 17 | for (int i = -1; i <= 1; i++) 18 | rows[i + 1] = (V*)&A(vint2(r + i, 0)); 19 | 20 | #pragma omp simd 21 | for (int i = 0; i < nc; i++) 22 | { 23 | curB[i] = 24 | ((rows[0][i - 1] > rows[1][i]) << 0) + 25 | ((rows[0][i ] > rows[1][i]) << 1) + 26 | ((rows[0][i + 1] > rows[1][i]) << 2) + 27 | 28 | ((rows[1][i - 1] > rows[1][i]) << 3) + 29 | ((rows[1][i + 1] > rows[1][i]) << 4) + 30 | 31 | ((rows[2][i - 1] > rows[1][i]) << 5) + 32 | ((rows[2][i ] > rows[1][i]) << 6) + 33 | ((rows[2][i + 1] > rows[1][i]) << 7); 34 | 35 | } 36 | } 37 | 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /vpp/algorithms/line_tracker_4_sfm.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include "line_tracker_4_sfm/hough_extruder.hh" 18 | #include "line_tracker_4_sfm/fast_dht.hh" 19 | #include "line_tracker_4_sfm/sfm.hh" 20 | #include "line_tracker_4_sfm/miscellanous.hh" 21 | 22 | -------------------------------------------------------------------------------- /vpp/algorithms/line_tracker_4_sfm/fast_dht.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "fast_dht/cordic.hh" 4 | #include "fast_dht/dense_one_to_one_hough.hh" 5 | #include "fast_dht/fast_hough.hh" 6 | -------------------------------------------------------------------------------- /vpp/algorithms/line_tracker_4_sfm/fast_dht/cordic.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | using namespace vpp; 7 | using namespace std; 8 | using namespace Eigen; 9 | 10 | #define cordic_1K 0x26DD3B6A 11 | #define half_pi 0x6487ED51 12 | #define MUL 1073741824.000000 13 | #define CORDIC_NTAB 32 14 | int cordic_ctab [] = {0x3243F6A8, 0x1DAC6705, 0x0FADBAFC, 0x07F56EA6, 0x03FEAB76, 0x01FFD55B, 15 | 0x00FFFAAA, 0x007FFF55, 0x003FFFEA, 0x001FFFFD, 0x000FFFFF, 0x0007FFFF, 0x0003FFFF, 16 | 0x0001FFFF, 0x0000FFFF, 0x00007FFF, 0x00003FFF, 0x00001FFF, 0x00000FFF, 0x000007FF, 17 | 0x000003FF, 0x000001FF, 0x000000FF, 0x0000007F, 0x0000003F, 0x0000001F, 0x0000000F, 18 | 0x00000008, 0x00000004, 0x00000002, 0x00000001, 0x00000000, }; 19 | 20 | 21 | -------------------------------------------------------------------------------- /vpp/algorithms/line_tracker_4_sfm/fast_dht/fast_hough.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "dense_one_to_one_hough.hh" 13 | #include "vpp/algorithms/line_tracker_4_sfm.hh" 14 | #include "vpp/algorithms/line_tracker_4_sfm/miscellanous/define.hh" 15 | 16 | 17 | 18 | using namespace vpp; 19 | using namespace std; 20 | using namespace Eigen; 21 | using namespace iod; 22 | using namespace cv; 23 | 24 | namespace vpp{ 25 | 26 | float get_vector_val(std::vector t_array, int vert,int hori,int i ,int j); 27 | void hough_accumulator(image2d img, int T_theta, Mat &bv, float acc_threshold); 28 | cv::Mat hough_accumulator_video_map_and_clusters(image2d img, int mode , int T_theta, 29 | std::vector& t_accumulator, std::list& interestedPoints, 30 | float rhomax); 31 | cv::Mat hough_accumulator_video_clusters(image2d img, int mode , int T_theta, 32 | std::vector& t_accumulator,std::list& interestedPoints, 33 | float rhomax); 34 | int get_theta_max(Theta_max discr); 35 | cv::Mat accumulator_to_frame(std::vector t_accumulator, float max, int rhomax, int T_theta); 36 | cv::Mat accumulator_to_frame(std::list interestedPoints, int rhomax, int T_theta); 37 | void hough_image(int T_theta, float acc_threshold); 38 | 39 | /* 40 | template 41 | void Capture_Image(int mode, Theta_max discr , Sclare_rho scale 42 | ,Type_video_hough type_video 43 | , Type_output type_sortie, 44 | Type_Lines type_line,Frequence freq,Mode mode_type, 45 | OPTS... options);*/ 46 | 47 | } 48 | 49 | #include "fast_hough.hpp" 50 | 51 | -------------------------------------------------------------------------------- /vpp/algorithms/line_tracker_4_sfm/hough_extruder.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | #include "hough_extruder/draw_trajectories_hough.hh" 5 | #include "symbols.hh" 6 | #include "hough_extruder/paint.hh" 7 | #include "hough_extruder/feature_matching_hough.hh" 8 | -------------------------------------------------------------------------------- /vpp/algorithms/line_tracker_4_sfm/hough_extruder/draw_line_hough.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace vpp 9 | { 10 | using namespace vpp; 11 | using namespace draw; 12 | 13 | 14 | template 15 | /** 16 | * @brief line2d_hough : draw a line in a grascale gradient image 17 | * @param a 18 | * @param b 19 | * @param paint 20 | * @param paint_border 21 | * @param grad 22 | * @param line_width 23 | */ 24 | void line2d_hough(vint2 a, vint2 b, V paint, U paint_border,image2d grad , int line_width = 5) 25 | { 26 | int x0 = a[1]; int y0 = a[0]; 27 | int x1 = b[1]; int y1 = b[0]; 28 | 29 | int steep = ::abs(y1 - y0) > ::abs(x1 - x0); 30 | 31 | if (steep) 32 | { 33 | std::swap(x0, y0); 34 | std::swap(x1, y1); 35 | } 36 | 37 | if (x0 > x1) 38 | { 39 | std::swap(x0, x1); 40 | std::swap(y0, y1); 41 | } 42 | 43 | int deltax = x1 - x0; 44 | int deltay = ::abs(y1 - y0); 45 | float error = 0.f; 46 | float deltaerr = deltay / float(deltax); 47 | int ystep; 48 | int y = y0; 49 | if (y0 < y1) ystep = 1; else ystep = -1; 50 | 51 | for (int x = x0 + 1; x <= x1; x++) 52 | { 53 | vint2 to_plot; 54 | vint2 d1,d2; // line border. 55 | if (steep) 56 | { 57 | to_plot = vint2{x, y}; 58 | d1 = vint2{0, -1}; 59 | d2 = vint2{0, +1}; 60 | } 61 | else 62 | { 63 | to_plot = vint2{y, x}; 64 | d1 = vint2{-1, 0}; 65 | d2 = vint2{+1, 0}; 66 | } 67 | 68 | if(grad(to_plot) < 10) 69 | continue; 70 | 71 | float interp = float(x - x0) / (x1 - x0); 72 | paint(to_plot, interp); 73 | for (int bi = 1; bi < line_width / 2; bi++) 74 | { 75 | paint_border(to_plot + bi * d1, interp, bi); 76 | paint_border(to_plot + bi * d2, interp, bi); 77 | } 78 | 79 | error = error + deltaerr; 80 | if (error >= 0.5) 81 | { 82 | y = y + ystep; 83 | error = error - 1.0; 84 | } 85 | } 86 | } 87 | 88 | 89 | } 90 | -------------------------------------------------------------------------------- /vpp/algorithms/line_tracker_4_sfm/hough_extruder/unscented_kalman_filter.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Eigen/Dense" 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | using Eigen::MatrixXd; 10 | using Eigen::VectorXd; 11 | using namespace vpp; 12 | 13 | class unscented_kalman_filter { 14 | public: 15 | bool is_initialized_; 16 | 17 | int state_dimension; 18 | 19 | int augmented_state_dimension; 20 | 21 | int measurement_dimension; 22 | 23 | double sigma_point_spreading_parameter; 24 | 25 | VectorXd state_vector; 26 | 27 | MatrixXd covariance_matrix; 28 | 29 | MatrixXd predicted_sigmas_matrix; 30 | 31 | long long previous_timestamp_; 32 | 33 | double standard_deviation_longit_acc; 34 | 35 | double standard_deviation_yaw; 36 | 37 | double standard_deviation_noise1; 38 | 39 | double standard_deviation_noise2; 40 | 41 | 42 | VectorXd weights_; 43 | 44 | /** 45 | * Constructor 46 | */ 47 | unscented_kalman_filter(); 48 | 49 | /** 50 | * Destructor 51 | */ 52 | virtual ~unscented_kalman_filter(); 53 | 54 | void add_new_dectection(const vint2 values, float dt); 55 | 56 | void initialize_the_track(const vint2 values, float dt); 57 | 58 | void only_update_track(float dt); 59 | 60 | void augmented_sigma_points(MatrixXd &Xsig_out); 61 | 62 | void sigma_point_prediction(const MatrixXd &Xsig_aug, const double delta_t, MatrixXd &Xsig_out); 63 | 64 | void predict_mean_and_covariance(const MatrixXd &Xsig_pred, VectorXd &x_out, MatrixXd &P_out); 65 | 66 | void predict_measurement(VectorXd &z_out, MatrixXd &S_out, MatrixXd &Tc_out); 67 | 68 | void prediction(double delta_t); 69 | 70 | void update(vint2 values,float dt, VectorXd &z_pred, MatrixXd &Tc, MatrixXd &S); 71 | 72 | }; 73 | 74 | #include "unscented_kalman_filter.hpp" 75 | 76 | 77 | -------------------------------------------------------------------------------- /vpp/algorithms/line_tracker_4_sfm/miscellanous.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "miscellanous/define.hh" 4 | #include "miscellanous/lookup_tables.hh" 5 | #include "miscellanous/operations.hh" 6 | -------------------------------------------------------------------------------- /vpp/algorithms/line_tracker_4_sfm/miscellanous/define.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | using namespace Eigen; 9 | 10 | using namespace vpp; 11 | 12 | 13 | 14 | 15 | double execution_time = 0; 16 | double execution_t= 0; 17 | 18 | 19 | 20 | 21 | enum class Theta_max : int32_t { XXSMALL = 67 , XSMALL = 127 , SMALL = 255, MEDIUM = 500, LARGE = 1000 , XLARGE = 1500}; 22 | enum class Sclare_rho : int32_t { ONE_QUART = 3, HALF = 2 , THREE_QUART = 1 , SAME = 0}; 23 | enum class Type_video_hough : int8_t { ONLY_CLUSTERS = 1 , ALL_POINTS = 2 }; 24 | enum class Type_capture : int16_t { webcam = 0 , photo = 1 , video = 3 } ; 25 | enum class Type_tracking : int16_t { no_tracking = 0 , lucas_kanade = 1 , kalman_track = 2 , video_extruder_vid = 3}; 26 | enum class Type_output : int16_t { VIDEO_HOUGH = 0 , ORIGINAL_VIDEO = 1 , GRADIENT_VIDEO = 2,ORIGINAL_AND_HOUGH_VIDEO = 3 }; 27 | enum class Type_Lines : int8_t { EXTREMITE = 0 , ALL_POINTS = 1 , ONLY_POLAR = 2 }; 28 | enum class Frequence : int8_t { ALL_FRAME = 0 , NOT_ALL = 1 }; 29 | enum class Mode : int8_t { ONLY_VPP = 0 , OPTIMIZED = 1 }; 30 | enum class With_Kalman_Filter : int8_t { YES = 1 , NO = 0 }; 31 | enum class With_Transparency : int8_t { YES = 1 , NO = 0 }; 32 | enum class With_Entries : int8_t { YES = 1 , NO = 0 }; 33 | 34 | float motion_threshold = 100; 35 | #define dense_ht 2 36 | #define feature_matching 7 37 | Matrix GySobel3x3; 38 | Matrix GxSobel3x3; 39 | Matrix GySobel5x5; 40 | Matrix GxSobel5x5; 41 | Matrix GySobel7x7; 42 | Matrix GxSobel7x7; 43 | Matrix GySobel9x9; 44 | Matrix GxSobel9x9; 45 | 46 | 47 | -------------------------------------------------------------------------------- /vpp/algorithms/line_tracker_4_sfm/sfm.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "sfm/plucker.hh" 4 | #include "sfm/structure_from_motion.hh" 5 | #include "sfm/vanishing_point.hh" 6 | -------------------------------------------------------------------------------- /vpp/algorithms/line_tracker_4_sfm/sfm/plucker.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | using namespace vpp; 16 | using namespace std; 17 | using namespace cv; 18 | using namespace Eigen; 19 | 20 | // Inhomogeneous coordinates 21 | class point_3d 22 | { 23 | public: double x,y,z; 24 | 25 | point_3d() 26 | {x=y=z=0.0;} 27 | 28 | point_3d(double xx, double yy, double zz) 29 | {x=xx;y=yy;z=zz;} 30 | 31 | friend ostream & operator << (ostream & os, const point_3d p) 32 | { 33 | os<<"["< 4 | #include 5 | 6 | #include 7 | #include "vpp/algorithms/line_tracker_4_sfm/miscellanous/operations.hh" 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | 14 | using namespace vpp; 15 | using namespace std; 16 | using namespace Eigen; 17 | using namespace iod; 18 | using namespace cv; 19 | 20 | namespace vpp 21 | { 22 | 23 | //from http://www.mip.informatik.uni-kiel.de/tiki-index.php?page=Lilian+Zhang 24 | 25 | struct structure_from_motion_ctx { 26 | structure_from_motion_ctx(box2d domain) : keypoints(domain) {} 27 | 28 | // Keypoint container. 29 | // ctx.keypoint[i] to access the ith keypoint. 30 | keypoint_container, int> keypoints; 31 | 32 | std::vector start_points; 33 | std::vector end_points; 34 | std::vector directions; 35 | }; 36 | 37 | structure_from_motion_ctx structure_from_motion_init(box2d domain); 38 | 39 | void initialize_rotation_matrix(); 40 | void initialize_translation_matrix(); 41 | void pose_estimation_from_line_correspondence(MatrixXf start_points, MatrixXf end_points, 42 | MatrixXf directions, MatrixXf points, 43 | MatrixXf &rot_cw, VectorXf &pos_cw); 44 | inline 45 | void cal_campose(MatrixXf XXc, MatrixXf XXw, int n, MatrixXf &R2, VectorXf &t2); 46 | inline 47 | void r_and_t(MatrixXf &rot_cw, VectorXf &pos_cw,MatrixXf start_points, MatrixXf end_points, 48 | MatrixXf P1w,MatrixXf P2w,MatrixXf initRot_cw,VectorXf initPos_cw, 49 | int maxIterNum,float TerminateTh,int nargin); 50 | 51 | inline 52 | vfloat3 x_cross(vfloat3 a,vfloat3 b); 53 | 54 | 55 | void triangulation(); 56 | void bundle_adjustement(); 57 | 58 | 59 | } 60 | 61 | #include "structure_from_motion.hpp" 62 | 63 | -------------------------------------------------------------------------------- /vpp/algorithms/line_tracker_4_sfm/symbols.hh: -------------------------------------------------------------------------------- 1 | // Generated by iod_generate_symbols. 2 | #include 3 | #ifndef IOD_SYMBOL_border 4 | #define IOD_SYMBOL_border 5 | iod_define_symbol(border) 6 | #endif 7 | 8 | #ifndef IOD_SYMBOL_detector_period 9 | #define IOD_SYMBOL_detector_period 10 | iod_define_symbol(detector_period) 11 | #endif 12 | 13 | #ifndef IOD_SYMBOL_detector_th 14 | #define IOD_SYMBOL_detector_th 15 | iod_define_symbol(detector_th) 16 | #endif 17 | 18 | #ifndef IOD_SYMBOL_keypoint_spacing 19 | #define IOD_SYMBOL_keypoint_spacing 20 | iod_define_symbol(keypoint_spacing) 21 | #endif 22 | 23 | #ifndef IOD_SYMBOL_local_maxima 24 | #define IOD_SYMBOL_local_maxima 25 | iod_define_symbol(local_maxima) 26 | #endif 27 | 28 | #ifndef IOD_SYMBOL_no_threads 29 | #define IOD_SYMBOL_no_threads 30 | iod_define_symbol(no_threads) 31 | #endif 32 | 33 | #ifndef IOD_SYMBOL_record_video 34 | #define IOD_SYMBOL_record_video 35 | iod_define_symbol(record_video) 36 | #endif 37 | 38 | #ifndef IOD_SYMBOL_video 39 | #define IOD_SYMBOL_video 40 | iod_define_symbol(video) 41 | #endif 42 | 43 | #ifndef IOD_SYMBOL_type_of_distance 44 | #define IOD_SYMBOL_type_of_distance 45 | iod_define_symbol(type_of_distance) 46 | #endif 47 | 48 | #ifndef IOD_SYMBOL_type_of_kalman_filter 49 | #define IOD_SYMBOL_type_of_kalman_filter 50 | iod_define_symbol(type_of_kalman_filter) 51 | #endif 52 | 53 | #ifndef IOD_SYMBOL_life_time_threshold 54 | #define IOD_SYMBOL_life_time_threshold 55 | iod_define_symbol(life_time_threshold) 56 | #endif 57 | 58 | #ifndef IOD_SYMBOL_distance_threshold 59 | #define IOD_SYMBOL_distance_threshold 60 | iod_define_symbol(distance_threshold) 61 | #endif 62 | 63 | #ifndef IOD_SYMBOL_missed_frame_threshold 64 | #define IOD_SYMBOL_missed_frame_threshold 65 | iod_define_symbol(missed_frame_threshold) 66 | #endif 67 | 68 | #ifndef IOD_SYMBOL_magnitude_acceleration_noise 69 | #define IOD_SYMBOL_magnitude_acceleration_noise 70 | iod_define_symbol(magnitude_acceleration_noise) 71 | #endif 72 | 73 | #ifndef IOD_SYMBOL_life_time_supression_threshold 74 | #define IOD_SYMBOL_life_time_supression_threshold 75 | iod_define_symbol(life_time_supression_threshold) 76 | #endif 77 | 78 | #ifndef IOD_SYMBOL_age_supression_threshold 79 | #define IOD_SYMBOL_age_supression_threshold 80 | iod_define_symbol(age_supression_threshold) 81 | #endif 82 | 83 | #ifndef IOD_SYMBOL_type_hough_video 84 | #define IOD_SYMBOL_type_hough_video 85 | iod_define_symbol(type_hough_video) 86 | #endif 87 | 88 | 89 | #ifndef IOD_SYMBOL_type_gradient_video 90 | #define IOD_SYMBOL_type_gradient_video 91 | iod_define_symbol(type_gradient_video) 92 | #endif 93 | 94 | #ifndef IOD_SYMBOL_type_original_video 95 | #define IOD_SYMBOL_type_original_video 96 | iod_define_symbol(type_original_video) 97 | #endif 98 | 99 | #ifndef IOD_SYMBOL_link_of_video_image 100 | #define IOD_SYMBOL_link_of_video_image 101 | iod_define_symbol(link_of_video_image) 102 | #endif 103 | 104 | #ifndef IOD_SYMBOL_gaussian_noise 105 | #define IOD_SYMBOL_gaussian_noise 106 | iod_define_symbol(gaussian_noise) 107 | #endif 108 | 109 | #ifndef IOD_SYMBOL_rayon_exclusion_theta 110 | #define IOD_SYMBOL_rayon_exclusion_theta 111 | iod_define_symbol(rayon_exclusion_theta) 112 | #endif 113 | 114 | #ifndef IOD_SYMBOL_rayon_exclusion_rho 115 | #define IOD_SYMBOL_rayon_exclusion_rho 116 | iod_define_symbol(rayon_exclusion_rho) 117 | #endif 118 | 119 | 120 | #ifndef IOD_SYMBOL_slot_hough 121 | #define IOD_SYMBOL_slot_hough 122 | iod_define_symbol(slot_hough) 123 | #endif 124 | 125 | #ifndef IOD_SYMBOL_m_first_lines 126 | #define IOD_SYMBOL_m_first_lines 127 | iod_define_symbol(m_first_lines) 128 | #endif 129 | 130 | #ifndef IOD_SYMBOL_acc_threshold 131 | #define IOD_SYMBOL_acc_threshold 132 | iod_define_symbol(acc_threshold) 133 | #endif 134 | 135 | #ifndef IOD_SYMBOL_nombre_max_frame_without_update 136 | #define IOD_SYMBOL_nombre_max_frame_without_update 137 | iod_define_symbol(nombre_max_frame_without_update) 138 | #endif 139 | 140 | 141 | 142 | 143 | -------------------------------------------------------------------------------- /vpp/algorithms/lucas_kanade.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace vpp 6 | { 7 | 8 | // lucas_kanade(i1, i2, 9 | // _keypoints = K1, 10 | // _niterations = lk_iterations, 11 | // _winsize = winsize, 12 | // _nscales = 3, 13 | // _prediction = flow, 14 | // _flow = [&] (int i, vfloat2 f) { 15 | // auto d2 = extract_patch(K1[i].template cast() + f, i2, winsize); 16 | // auto dist = sparse_of_iternals::sad_distance(D1[i], d2); 17 | // options.flow(K1[i], f, dist); 18 | // } 19 | // ); 20 | 21 | template 22 | void lucas_kanade(const image2d& i1, 23 | const image2d& i2, 24 | OPTS... opts); 25 | 26 | } 27 | 28 | #include 29 | -------------------------------------------------------------------------------- /vpp/algorithms/optical_flow.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace vpp 4 | { 5 | 6 | // Compute a semi dense flow field with the following assumptions : 7 | // - The keypoint set should be dense enough to let the estimation rely on spatial regularity. 8 | // - The nscales and winsize parameters should be large enough to recover the motion. 9 | // 10 | // Parameters: 11 | // nscales = 3: The number of scales used by multiscales approaches. 12 | // winsize = 9: The window size support for SSD computation 13 | // patchsize = 3: Suppose that every NxN cell contains the same motion. 14 | // propagation = 2: The number of propagation iterations. 15 | // min_scale = 1: Minimum scale used to estimate the flow. 16 | // 17 | // Todo parameters: 18 | // _epipolar_flow: Guide the motion estimation with the epipolar lines. 19 | // _epipolar_line_filter: Activate the epipolar line filter. 20 | // _fundamental_matrix: Fundamental matrix. 21 | // _qr_ratio = 0-1: From 0 for maximum speed to 1 for maximum 22 | // quality. The best appropriate optical flow 23 | // method will be selected depending of this 24 | // parameter. Note : evaluation is done on public 25 | // optical flow datasets (KITTI, middlebury, ...). 26 | // 27 | // _regularisation ? 28 | // 29 | template 30 | inline void 31 | semi_dense_optical_flow(const K& keypoints, 32 | F match_callback, 33 | const image2d& i1, 34 | const image2d& i2, 35 | OPTS... options); 36 | 37 | 38 | // Todo. 39 | 40 | // Compute the dense optical flow from two images. 41 | // Parameters: 42 | // semi_dense_optical_flow parameters 43 | // mask: if (mask(p)) compute the flow 44 | // Todo. 45 | // template 46 | // inline void 47 | // dense_optical_flow(F flow_callback, 48 | // const image2d& i1, 49 | // const image2d& i2, 50 | // OPTS... options); 51 | 52 | // Computes the flow vectors of a sparse set of keypoints. This 53 | // relies on detecting FAST keypoints in \i1 and \i2 and matching 54 | // them with the set of keypoint. 55 | // 56 | // Parameters: 57 | // search_radius = 100 58 | // winsize = 11 59 | template 60 | inline void 61 | sparse_optical_flow(const K& keypoints, 62 | F match_callback, 63 | const image2d& i1, 64 | const image2d& i2, 65 | OPTS... options); 66 | 67 | template 68 | inline void 69 | sparse_optical_flow(const image2d& i1, 70 | const image2d& i2, 71 | OPTS... options); 72 | 73 | } 74 | 75 | #include 76 | #include 77 | #include 78 | -------------------------------------------------------------------------------- /vpp/algorithms/optical_flow/epipolar_match.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace vpp 6 | { 7 | 8 | inline vfloat2 line2d_to_direction_vector(const vfloat3& line) 9 | { 10 | vfloat2 dv; 11 | if (line[1] == 0) 12 | dv = vfloat2(0, 1); 13 | else 14 | { 15 | dv = vfloat2(1, -line[0]/line[1]); 16 | dv.normalize(); 17 | } 18 | 19 | return dv; 20 | } 21 | 22 | template 23 | auto epipolar_match(vector p1, vector prediction, vfloat2 epipole, 24 | Eigen::Matrix3f F, D distance) 25 | { 26 | vfloat2 v = line2d_to_direction_vector(F * p1.template cast().homogeneous()); 27 | float d = (prediction.template cast() - epipole).dot(v); 28 | 29 | float cost = distance(p1, (epipole + d * v).template cast(), INT_MAX); 30 | float costA = distance(p1, (epipole + (d + 1.5) * v).template cast(), INT_MAX); 31 | float costB = distance(p1, (epipole + (d - 1.5) * v).template cast(), INT_MAX); 32 | 33 | if (cost >= costA or cost >= costB) 34 | { 35 | float dir = costA < costB ? +1.5 : -1.5; 36 | float new_cost = std::min(costA, costB); 37 | 38 | while (new_cost <= cost and cost != FLT_MAX) 39 | { 40 | d += dir; 41 | cost = new_cost; 42 | new_cost = distance(p1, (epipole + (d + dir) * v).template cast(), cost); 43 | } 44 | } 45 | 46 | return iod::D(_flow = (epipole + d * v).template cast(), 47 | _distance = cost); 48 | 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /vpp/algorithms/optical_flow/gradient_descent.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace vpp 6 | { 7 | 8 | template 9 | inline 10 | auto gradient_descent_match(const vint2 p, 11 | vint2 prediction, 12 | D distance, 13 | int max_iteration = 10) 14 | { 15 | typedef std::pair ret; 16 | vint2 match = prediction; 17 | int match_distance = distance(p, prediction, INT_MAX); 18 | unsigned match_i = 8; 19 | 20 | const int c8_it[9][2] = 21 | { 22 | /* 23 | 0 1 2 24 | 7 3 25 | 6 5 4 26 | */ 27 | 28 | {6, 3}, // 0 29 | {0, 3}, // 1 30 | {0, 5}, // 2 31 | {2, 5}, // 3 32 | {2, 7}, // 4 33 | {4, 7}, // 5 34 | {4, 1}, // 6 35 | {6, 1}, // 7 36 | {0, 0} // 8 37 | }; 38 | 39 | const int c8[8][2] = 40 | { 41 | {-1, 1}, {0, 1}, {1, 1}, 42 | {-1, 0}, {1, 0}, 43 | {-1, -1}, {0, -1}, {1, -1} 44 | }; 45 | 46 | for (int search = 0; search < max_iteration; search++) 47 | { 48 | int i = c8_it[match_i][0]; 49 | int end = c8_it[match_i][1]; 50 | 51 | // First lookup 52 | { 53 | vint2 n(prediction + vint2(c8[i])); 54 | 55 | int d = distance(p, n, match_distance); 56 | if (d < match_distance) 57 | { 58 | match = n; 59 | match_i = i; 60 | match_distance = d; 61 | } 62 | i = (i + 1) & 7; 63 | } 64 | 65 | 66 | // Loop over the non visited neighbors 67 | #pragma unroll 4 68 | for(; i != end; i = (i + 1) & 7) 69 | { 70 | vint2 n(prediction + vint2(c8[i])); 71 | int d = distance(p, n, match_distance); 72 | if (d < match_distance) 73 | { 74 | match = n; 75 | match_i = i; 76 | match_distance = d; 77 | //break; 78 | } 79 | } 80 | 81 | if (vint2(prediction) == vint2(match)) 82 | break; // Local minimum found. 83 | else 84 | prediction = match; 85 | 86 | } 87 | 88 | return iod::D(_flow = vint2(match - p), _distance = match_distance); 89 | } 90 | 91 | 92 | } 93 | -------------------------------------------------------------------------------- /vpp/algorithms/optical_flow/propagation.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace vpp 4 | { 5 | 6 | // Parameters: 7 | // optimize = [] (vint2 p, vfloat2 flow) { ... return make_pair(flow, distance); } 8 | // Optimize the \flow at point \p. 9 | // 10 | // criteria = [] (vint2 p, vint2 n) { return true/false; } 11 | // Tell if the flow should propagate from p to n. 12 | // 13 | // flow = [] (vint2 p, vfloat2 flow) { } 14 | // Register the new flow for point p. 15 | 16 | void flow_propagation(image2d& flow, 17 | image2d& distance, 18 | D distance) 19 | { 20 | 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /vpp/algorithms/optical_flow/sparse_optical_flow.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | 7 | namespace vpp 8 | { 9 | 10 | namespace sparse_of_iternals 11 | { 12 | 13 | template 14 | auto sad_distance(const F& i1, const F& i2, int size, int th = INT_MAX) 15 | { 16 | const int RS = 128; 17 | int err = 0; 18 | for (int r = 0; r < (size)/RS and err <= th; r++) 19 | { 20 | #pragma omp simd 21 | for (int i = 0; i < RS; i++) 22 | err += std::abs((i1[r * RS + i]) - (i2[r * RS + i])); 23 | } 24 | 25 | if (err <= th) 26 | { 27 | #pragma omp simd 28 | for (int i = (((size)/RS)*RS); i < size; i++) 29 | err += std::abs((i1[i]) - (i2[i])); 30 | } 31 | 32 | return err; 33 | } 34 | } 35 | 36 | #if 0 // FIXME: Reactivate when it compiles. 37 | 38 | template 39 | inline void 40 | sparse_optical_flow(const image2d& i1, 41 | const image2d& i2, 42 | OPTS... opts) 43 | { 44 | auto options = D(opts...); 45 | const int block_size = options.get(_block_size, 5); 46 | const int detector_th = options.get(_detector_th, 5); 47 | constexpr int is_subpixelic = options.get(_subpixelic, 5); 48 | const int lk_iterations = options.get(_lk_iterations, 5); 49 | const int winsize = options.get(_winsize, 11); 50 | 51 | auto flow_callback = options.flow; 52 | std::vector K1 = fast9(i1, 53 | detector_th, 54 | _blockwise, 55 | _block_size = block_size); 56 | 57 | std::vector K2 = fast9(i2, 58 | detector_th, 59 | _blockwise, 60 | _block_size = block_size); 61 | 62 | auto D1 63 | = extract_patches(K1, i1, winsize); 64 | auto D2 65 | = extract_patches(K2, i2, winsize); 66 | 67 | if (is_subpixelic) 68 | { 69 | match_descritors 70 | (_query = D1, 71 | _train = D2, 72 | _distance = sparse_of_iternals::sad_distance, 73 | _match = [&] (int q, int t, int d) { options.flow(K1[q], K2[t] - K1[q], d); }, 74 | 75 | _index1d(_approximation = 2), 76 | _local_search(_query_positions = K1, 77 | _train_positions = K2, 78 | _radius = 100) 79 | ); 80 | } 81 | else 82 | { 83 | std::vector flow(K1.size()); 84 | fill(flow, vint2(0,0)); 85 | 86 | match_descritors 87 | (_query = D1, 88 | _train = D2, 89 | _distance = sparse_optical_flow::sad_distance, 90 | _match = [&] (int q, int t, int d) { flow[q] = vint2(K2[t] - K1[q]); }, 91 | 92 | _index1d(_approximation = 2), 93 | _local_search(_query_positions = K1, 94 | _train_positions = K2, 95 | _radius = 100) 96 | ); 97 | 98 | lucas_kanade(i1, i2, 99 | _keypoints = K1, 100 | _niterations = lk_iterations, 101 | _winsize = winsize, 102 | _prediction = flow, 103 | _flow = [&] (int i, vfloat2 f) { 104 | auto d2 = extract_patch(K1[i].template cast() + f, i2, winsize); 105 | auto dist = sparse_of_iternals::sad_distance(D1[i], d2); 106 | options.flow(K1[i], f, dist); 107 | } 108 | ); 109 | } 110 | } 111 | 112 | #endif 113 | } 114 | -------------------------------------------------------------------------------- /vpp/algorithms/pyrlk/pyrlk_match.hh: -------------------------------------------------------------------------------- 1 | #ifndef VPP_ALGORITHMS_PYRLK_HH_ 2 | # define VPP_ALGORITHMS_PYRLK_HH_ 3 | 4 | # include 5 | # include 6 | # include 7 | # include 8 | 9 | namespace vpp 10 | { 11 | 12 | typedef keypoint_container, int> pyrlk_keypoint_container; 13 | 14 | template 15 | void pyrlk_match(const pyramid2d& pyramid_prev, 16 | const pyramid2d>& pyramid_prev_grad, 17 | const pyramid2d& pyramid_next, 18 | C& keypoints, 19 | M matcher, 20 | float min_ev, float max_err, 21 | float max_iteration, float convergence_delta, int min_scale = 0) 22 | { 23 | keypoints.prepare_matching(); 24 | #pragma omp parallel for 25 | for(int i = 0; i < keypoints.size(); i++) 26 | { 27 | auto& kp = keypoints[i]; 28 | if (kp.alive()) 29 | { 30 | vfloat2 tr = vfloat2{0.f,0.f}; 31 | float dist = 0.f; 32 | for(int S = pyramid_prev.size() - 1; S >= min_scale; S--) 33 | { 34 | tr *= pyramid_prev.factor(); 35 | auto match = matcher(kp.position / std::pow(2, S), tr, pyramid_prev[S], pyramid_next[S], pyramid_prev_grad[S], min_ev, max_iteration, convergence_delta); 36 | 37 | if (match.second < max_err) 38 | { 39 | tr = match.first; 40 | } 41 | dist = match.second; 42 | } 43 | 44 | if (dist > max_err || !pyramid_prev[0].domain().has(cast(kp.position + tr))) 45 | { 46 | remove_keypoint: 47 | keypoints.remove(i); 48 | } 49 | else 50 | keypoints.move(i, kp.position + tr); 51 | } 52 | nextpoint: 53 | continue; 54 | } 55 | } 56 | 57 | } 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /vpp/algorithms/slam/triangulate.hh: -------------------------------------------------------------------------------- 1 | #ifndef VPP_SLAM_TRIANGULATE_HH_ 2 | # define VPP_SLAM_TRIANGULATE_HH_ 3 | 4 | # include 5 | # include 6 | 7 | namespace vpp 8 | { 9 | 10 | // Triangulate a 3d point given 2 projections. 11 | inline vfloat3 triangulate(vfloat3 x, 12 | vfloat3 y, 13 | Eigen::Matrix4f A, 14 | Eigen::Matrix4f B) 15 | { 16 | using namespace Eigen; 17 | 18 | MatrixXf S(6, 4); 19 | 20 | S.block<1, 4>(0,0) = x[1] * A.block<1, 4>(2,0) - x[2] * A.block<1, 4>(1,0); 21 | S.block<1, 4>(1,0) = x[2] * A.block<1, 4>(0,0) - x[0] * A.block<1, 4>(2,0); 22 | S.block<1, 4>(2,0) = x[0] * A.block<1, 4>(1,0) - x[1] * A.block<1, 4>(0,0); 23 | S.block<1, 4>(3,0) = y[1] * B.block<1, 4>(2,0) - y[2] * B.block<1, 4>(1,0); 24 | S.block<1, 4>(4,0) = y[2] * B.block<1, 4>(0,0) - y[0] * B.block<1, 4>(2,0); 25 | S.block<1, 4>(5,0) = y[0] * B.block<1, 4>(1,0) - y[1] * B.block<1, 4>(0,0); 26 | 27 | JacobiSVD svd(S, ComputeFullV); 28 | return (svd.matrixV().block<3, 1>(0, 3) / svd.matrixV()(3, 3)); 29 | } 30 | 31 | }; 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /vpp/algorithms/video_extruder.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace vpp 8 | { 9 | // Video extruder context. 10 | struct video_extruder_ctx 11 | { 12 | video_extruder_ctx(box2d domain) : keypoints(domain), frame_id(0) {} 13 | 14 | // Keypoint container. 15 | // ctx.keypoint[i] to access the ith keypoint. 16 | keypoint_container, int> keypoints; 17 | 18 | // Trajectory container. 19 | // ctx.trajectory[i].position_at_frame(j) to access the ith keypoint position at frame j. 20 | std::vector trajectories; 21 | 22 | // Current frame id. 23 | int frame_id; 24 | }; 25 | 26 | // Initialize the video extruder context. 27 | // \param domain: The video domain. 28 | video_extruder_ctx video_extruder_init(box2d domain); 29 | 30 | // Update the video extruder with a new video frame. 31 | // 32 | // Options : 33 | // _detector_th: FAST detector threshold. 34 | // _keypoint_spacing: Keypoint spacing in pixels. 1 for maximum density. 35 | // _max_trajectory_length: Maximum length of trajectories. 36 | // _winsize: Window size used by the optical flow ssd distance 37 | // _nscales: Number of scales 38 | // _regularization: Number of iterations of the regularisation 39 | 40 | template 41 | void video_extruder_update(video_extruder_ctx& ctx, 42 | const image2d& frame1, 43 | const image2d& frame2, 44 | OPTS... options); 45 | 46 | // Synchronize an array of tr 47 | // template 48 | // void sync_trajectory_attributes(video_extruder_ctx& ctx, 49 | // T& attrs, 50 | // OPTS... options); 51 | 52 | } 53 | 54 | // Implementation 55 | #include "video_extruder/video_extruder.hpp" 56 | -------------------------------------------------------------------------------- /vpp/core/block_wise.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace vpp 6 | { 7 | template 8 | class block_wise_runner 9 | { 10 | public: 11 | typedef block_wise_runner self; 12 | 13 | block_wise_runner(vint2 block_size, std::tuple t, OPTS options = iod::D()) 14 | : block_size_(block_size), ranges_(t), options_(options) {} 15 | 16 | 17 | template 18 | auto operator()(A... _options) 19 | { 20 | auto new_options = iod::D(_options...); 21 | return block_wise_runner 22 | (block_size_, ranges_, new_options); 23 | } 24 | 25 | template 26 | void operator|(F fun) 27 | { 28 | auto p1 = std::get<0>(ranges_).first_point_coordinates(); 29 | auto p2 = std::get<0>(ranges_).last_point_coordinates(); 30 | 31 | int rstart = p1[0]; 32 | int rend = p2[0]; 33 | 34 | int cstart = p1[1]; 35 | int cend = p2[1]; 36 | 37 | int nr = std::ceil((1 + rend - rstart) / float(block_size_[0])); 38 | int nc = std::ceil((1 + cend - cstart) / float(block_size_[1])); 39 | 40 | box2d grid(vint2(0, 0), 41 | vint2(nr - 1, nc - 1)); 42 | 43 | pixel_wise(grid)(options_) | [&] (vint2 block) 44 | { 45 | int r1 = rstart + block[0] * block_size_[0]; 46 | int r2 = std::min(rstart + (block[0] + 1) * block_size_[0] - 1, rend); 47 | 48 | int c1 = cstart + block[1] * block_size_[1]; 49 | int c2 = std::min(cstart + (block[1] + 1) * block_size_[1] - 1, cend); 50 | 51 | box2d b(vint2{std::min(r1, r2), std::min(c1, c2)}, 52 | vint2{std::max(r1, r2), std::max(c1, c2)}); 53 | 54 | internals::apply_args_transform(this->ranges_, fun, [&b] (auto& i) { return i | b; }); 55 | }; 56 | } 57 | 58 | private: 59 | vint2 block_size_; 60 | std::tuple ranges_; 61 | OPTS options_; 62 | }; 63 | 64 | template 65 | auto block_wise(vint2 block_size, PS&&... params) 66 | { 67 | return block_wise_runner, PS...>(block_size, std::forward_as_tuple(params...)); 68 | } 69 | 70 | template 71 | auto row_wise(P0&& a0, PS&&... params) 72 | { 73 | auto p1 = a0.first_point_coordinates(); 74 | auto p2 = a0.last_point_coordinates(); 75 | 76 | return block_wise(vint2(1, 1 + p2[1] - p1[1]), 77 | std::forward(a0), std::forward(params)...); 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /vpp/core/box2d.hh: -------------------------------------------------------------------------------- 1 | #ifndef VPP_BOX2D_HH__ 2 | # define VPP_BOX2D_HH__ 3 | 4 | namespace vpp 5 | { 6 | 7 | class box2d 8 | { 9 | public: 10 | 11 | box2d(vint2 a, vint2 b); 12 | 13 | private: 14 | 15 | vint2 first_; 16 | vint2 last_; 17 | }; 18 | 19 | 20 | }; 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /vpp/core/boxNd.hh: -------------------------------------------------------------------------------- 1 | #ifndef VPP_Boxnd_HH__ 2 | # define VPP_Boxnd_HH__ 3 | 4 | # include 5 | # include 6 | 7 | namespace vpp 8 | { 9 | 10 | template 11 | class boxNd 12 | { 13 | public: 14 | typedef vector coord_type; 15 | typedef boxNd_iterator iterator; 16 | typedef boxNd_row_iterator row_iterator; 17 | typedef boxNd_row_iterator const_row_iterator; 18 | 19 | inline boxNd() : p1_(), p2_() {} 20 | 21 | inline boxNd(coord_type p1, coord_type p2) 22 | : p1_(p1), 23 | p2_(p2) 24 | { 25 | for (unsigned i = 0; i < N; i++) 26 | size_[i] = compute_size(i); 27 | } 28 | 29 | inline bool has(const coord_type& p) const 30 | { 31 | for (unsigned i = 0; i < N; i++) 32 | if (p[i] < p1_[i] || p[i] > p2_[i]) 33 | return false; 34 | return true; 35 | } 36 | 37 | inline boxNd_iterator begin() const 38 | { 39 | return boxNd_iterator(p1_, *this); 40 | } 41 | 42 | inline boxNd_iterator end() const 43 | { 44 | coord_type e = p1_; 45 | e[0] = p2_[0] + 1; 46 | return boxNd_iterator(e, *this); 47 | } 48 | 49 | inline const coord_type& first_point_coordinates() const { return p1_; } 50 | inline const coord_type& last_point_coordinates() const { return p2_; } 51 | 52 | inline const coord_type& p1() const { return p1_; } 53 | inline const coord_type& p2() const { return p2_; } 54 | 55 | inline int compute_size(int d) const { 56 | assert(d >= 0); 57 | assert(d < N); 58 | return p2_[d] - p1_[d] + 1; 59 | } 60 | 61 | inline const int& size(int d) const { 62 | assert(d >= 0); 63 | assert(d < N); 64 | return size_[d]; 65 | } 66 | 67 | inline const int& ncols() const { return size_[N - 1]; } 68 | inline const int& nrows() const { return size_[N - 2]; } 69 | 70 | private: 71 | coord_type size_; 72 | coord_type p1_; 73 | coord_type p2_; 74 | }; 75 | 76 | template 77 | bool operator==(const boxNd& a, const boxNd& b) 78 | { 79 | return a.p1() == b.p1() && a.p2() == b.p2(); 80 | } 81 | 82 | template 83 | bool operator!=(const boxNd& a, const boxNd& b) 84 | { 85 | return !(a == b); 86 | } 87 | 88 | typedef boxNd<1> box1d; 89 | typedef boxNd<2> box2d; 90 | typedef boxNd<3> box3d; 91 | typedef boxNd<4> box4d; 92 | 93 | inline box1d make_box1d(int nc) 94 | { 95 | vint1 a; a[0] = 0; 96 | vint1 b; b[0] = nc - 1; 97 | return box1d(a, b); 98 | } 99 | 100 | inline box2d make_box2d(int nr, int nc) 101 | { 102 | return box2d(vint2(0, 0), vint2(nr - 1, nc - 1)); 103 | } 104 | 105 | inline box3d make_box3d(int ns, int nr, int nc) 106 | { 107 | return box3d(vint3(0, 0, 0), vint3(ns - 1, nr - 1, nc - 1)); 108 | } 109 | 110 | class border 111 | { 112 | public: 113 | inline border(int n) : size_(n) {} 114 | inline int size() const { return size_; } 115 | private: 116 | int size_; 117 | }; 118 | 119 | template 120 | boxNd operator-(const boxNd& b, const border& border) 121 | { 122 | auto p1 = b.p1(); 123 | auto p2 = b.p2(); 124 | for (int n = 0; n < N; n++) 125 | { 126 | p1[n] += border.size(); 127 | p2[n] -= border.size(); 128 | } 129 | 130 | return boxNd(p1, p2); 131 | } 132 | 133 | 134 | template 135 | boxNd operator+(const boxNd& b, const border& border) 136 | { 137 | auto p1 = b.p1(); 138 | auto p2 = b.p2(); 139 | for (int n = 0; n < N; n++) 140 | { 141 | p1[n] -= border.size(); 142 | p2[n] += border.size(); 143 | } 144 | 145 | return boxNd(p1, p2); 146 | } 147 | 148 | template 149 | auto operator|(const boxNd& a, const boxNd& b) { return b; } 150 | 151 | }; 152 | 153 | #endif 154 | -------------------------------------------------------------------------------- /vpp/core/boxNd_iterator.hh: -------------------------------------------------------------------------------- 1 | #ifndef VPP_BOXND_ITERATOR_HH_ 2 | # define VPP_BOXND_ITERATOR_HH_ 3 | 4 | namespace vpp 5 | { 6 | 7 | template 8 | class boxNd; 9 | 10 | template 11 | class boxNd_iterator 12 | { 13 | public: 14 | typedef vector coord_type; 15 | typedef boxNd_iterator self; 16 | 17 | inline boxNd_iterator() {} 18 | inline boxNd_iterator(const coord_type cur, const boxNd& box); 19 | 20 | inline boxNd_iterator(const self& o) 21 | { box_ = o.box_; cur_ = o.cur_; } 22 | 23 | inline boxNd_iterator& next(); 24 | inline boxNd_iterator& operator++() { return next(); } 25 | 26 | inline operator coord_type() const; 27 | inline const coord_type& operator*() const; 28 | 29 | private: 30 | const boxNd* box_; 31 | coord_type cur_; 32 | //int line_end_; 33 | // C& last_c_; 34 | }; 35 | 36 | template 37 | inline bool operator==(const boxNd_iterator& a, const boxNd_iterator& b) 38 | { 39 | return *a == *b; 40 | } 41 | 42 | template 43 | inline bool operator!=(const boxNd_iterator& a, const boxNd_iterator& b) 44 | { 45 | return *a != *b; 46 | } 47 | 48 | 49 | template 50 | class boxNd_row_iterator 51 | { 52 | public: 53 | typedef vector coord_type; 54 | typedef boxNd_row_iterator self; 55 | 56 | inline boxNd_row_iterator() {} 57 | inline boxNd_row_iterator(const coord_type cur, const boxNd&) : cur_(cur) {} 58 | 59 | inline boxNd_row_iterator(const self& o) 60 | { cur_ = o.cur_; } 61 | 62 | inline boxNd_row_iterator& next() { cur_[N-1]++; return *this; } 63 | inline boxNd_row_iterator& prev() { cur_[N-1]--; return *this; } 64 | inline boxNd_row_iterator& operator++() { return next(); } 65 | inline boxNd_row_iterator& operator--() { return prev(); } 66 | 67 | inline operator coord_type() const { return cur_; } 68 | inline const coord_type& operator*() const { return cur_; } 69 | 70 | private: 71 | coord_type cur_; 72 | }; 73 | 74 | template 75 | inline bool operator==(const boxNd_row_iterator& a, const boxNd_row_iterator& b) 76 | { 77 | return *a == *b; 78 | } 79 | 80 | template 81 | inline bool operator!=(const boxNd_row_iterator& a, const boxNd_row_iterator& b) 82 | { 83 | return *a != *b; 84 | } 85 | 86 | }; 87 | 88 | # include 89 | 90 | #endif 91 | -------------------------------------------------------------------------------- /vpp/core/boxNd_iterator.hpp: -------------------------------------------------------------------------------- 1 | #ifndef VPP_BOXND_ITERATOR_HPP_ 2 | # define VPP_BOXND_ITERATOR_HPP_ 3 | 4 | namespace vpp 5 | { 6 | 7 | template 8 | boxNd_iterator::boxNd_iterator(const coord_type cur, const boxNd& box) 9 | : box_(&box), cur_(cur) 10 | {} 11 | 12 | template 13 | boxNd_iterator& 14 | boxNd_iterator::next() 15 | { 16 | cur_[N - 1]++; 17 | if (cur_[N - 1] == (box_->p2()[N - 1] + 1)) 18 | { 19 | int n = N; 20 | while (--n > 0 and cur_[n] == (box_->p2()[n] + 1)) 21 | { 22 | cur_[n] = box_->p1()[n]; 23 | cur_[n - 1]++; 24 | } 25 | } 26 | 27 | return *this; 28 | } 29 | 30 | template 31 | boxNd_iterator::operator coord_type() const 32 | { 33 | return cur_; 34 | } 35 | 36 | 37 | template 38 | const typename boxNd_iterator::coord_type& 39 | boxNd_iterator::operator*() const 40 | { 41 | return cur_; 42 | } 43 | 44 | 45 | }; 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /vpp/core/cast_to_float.hh: -------------------------------------------------------------------------------- 1 | #ifndef VPP_CAST_TO_FLOAT_HH__ 2 | # define VPP_CAST_TO_FLOAT_HH__ 3 | 4 | # include 5 | 6 | namespace vpp 7 | { 8 | 9 | template 10 | struct cast_to_float_ 11 | { 12 | typedef float ret; 13 | }; 14 | 15 | template 16 | struct cast_to_float_> 17 | { 18 | typedef Eigen::Matrix ret; 19 | }; 20 | 21 | template 22 | using cast_to_float = typename cast_to_float_::ret; 23 | }; 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /vpp/core/clone.hh: -------------------------------------------------------------------------------- 1 | #ifndef VPP_CLONE_HH__ 2 | # define VPP_CLONE_HH__ 3 | 4 | # include 5 | 6 | namespace vpp 7 | { 8 | 9 | template 10 | I clone(I img, const O&... options) 11 | { 12 | auto o = iod::D(options...); 13 | int border = o.has(_border) ? o.get(_border, 0) : img.border(); 14 | int aligned = o.has(_aligned) ? o.get(_aligned, 0) : img.alignment(); 15 | assert(aligned != 0); 16 | I n(img.domain(), _border = border, _aligned = aligned); 17 | copy_with_border(img, n); 18 | return n; 19 | } 20 | 21 | }; 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /vpp/core/coding_style: -------------------------------------------------------------------------------- 1 | 2 | File extention : 3 | 4 | *.hh : headers. 5 | *.hpp : template implementations. 6 | *.cc : implementations. 7 | 8 | Naming : 9 | 10 | Every identifiers folows : foo_bar. 11 | -------------------------------------------------------------------------------- /vpp/core/colorspace_conversions.hh: -------------------------------------------------------------------------------- 1 | #ifndef VPP_CORE_COLORSPACE_CONVERSIONS_HH__ 2 | # define VPP_CORE_COLORSPACE_CONVERSIONS_HH__ 3 | 4 | # include 5 | 6 | namespace vpp 7 | { 8 | 9 | template 10 | void rgb_to_graylevel(const vector& i, vector& o) 11 | { 12 | o[0] = (i[0] + i[1] + i[2]) / 3; 13 | } 14 | 15 | 16 | template 17 | void rgb_to_graylevel(const vector& i, T& o) 18 | { 19 | o = (i[0] + i[1] + i[2]) / 3; 20 | } 21 | 22 | template 23 | imageNd rgb_to_graylevel(const imageNd, N>& in) 24 | { 25 | typedef T out_type; 26 | typedef vector in_type; 27 | imageNd out(in.domain(), _border = in.border(), _aligned = in.alignment()); 28 | pixel_wise(in.domain_with_border(), in, out) | [] (vint2, const in_type& i, out_type& o) 29 | { 30 | rgb_to_graylevel(i, o); 31 | }; 32 | return out; 33 | } 34 | 35 | template 36 | imageNd rgb_to_graylevel(const imageNd, N>& in) 37 | { 38 | typedef T out_type; 39 | typedef vector in_type; 40 | imageNd out(in.domain(), _border = in.border(), _aligned = in.alignment()); 41 | pixel_wise(in.domain_with_border(), in, out) | [] (vint2, const in_type& i, out_type& o) 42 | { 43 | vector tmp = i.template segment<3>(0); 44 | rgb_to_graylevel(tmp, o); 45 | }; 46 | return out; 47 | } 48 | 49 | template 50 | imageNd graylevel_to_rgb(const imageNd& in) 51 | { 52 | typedef T out_type; 53 | typedef U in_type; 54 | imageNd out(in.domain(), _border = in.border(), _aligned = in.alignment()); 55 | pixel_wise(in.domain_with_border(), in, out) | [] (vint2, const in_type& i, out_type& o) 56 | { 57 | o = out_type(i, i, i); 58 | }; 59 | 60 | return out; 61 | } 62 | 63 | inline vuchar3 hsv_to_rgb(int h, float s, float v) 64 | { 65 | float c = s * v; 66 | float h2 = h / 60.f; 67 | float x = c * (1 - fabs(fmod(h2, 2) - 1)); 68 | 69 | unsigned char C = c * 255; 70 | unsigned char X = x * 255; 71 | if (h2 < 1) 72 | return vuchar3(C, X, 0); 73 | else if (h2 < 2) 74 | return vuchar3(X, C, 0); 75 | else if (h2 < 3) 76 | return vuchar3(0, C, X); 77 | else if (h2 < 4) 78 | return vuchar3(0, X, C); 79 | else if (h2 < 5) 80 | return vuchar3(X, 0, C); 81 | else if (h2 < 6) 82 | return vuchar3(C, 0, X); 83 | else 84 | return vuchar3(0,0,0); 85 | } 86 | 87 | }; 88 | 89 | #endif 90 | -------------------------------------------------------------------------------- /vpp/core/const.hh: -------------------------------------------------------------------------------- 1 | #ifndef VPP_CORE_CONST_HH__ 2 | # define VPP_CORE_CONST_HH__ 3 | 4 | # include 5 | 6 | namespace vpp 7 | { 8 | template 9 | using unconstify = typename std::remove_const::type; 10 | template 11 | using constify = typename std::add_const::type; 12 | }; 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /vpp/core/copy.hh: -------------------------------------------------------------------------------- 1 | #ifndef VPP_COPY_HH__ 2 | # define VPP_COPY_HH__ 3 | 4 | namespace vpp 5 | { 6 | //struct pixel_wise_functor; 7 | //pixel_wise_functor pixel_wise; 8 | 9 | template 10 | void copy(const I& src, J& dst) 11 | { 12 | pixel_wise(src, dst) | [] (const auto& in, auto& out) { out = in; }; 13 | } 14 | 15 | template 16 | void copy(const I& src, J&& dst) 17 | { 18 | pixel_wise(src, dst) | [] (const auto& in, auto& out) { out = in; }; 19 | } 20 | 21 | template 22 | void copy_with_border(const I& src, J&& dst) 23 | { 24 | assert(src.domain() == dst.domain()); 25 | assert(src.border() <= dst.border()); 26 | pixel_wise(src.domain_with_border(), src, dst) | [] (vint2, const auto& in, auto& out) { out = in; }; 27 | } 28 | 29 | }; 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /vpp/core/dige.hh: -------------------------------------------------------------------------------- 1 | #ifndef VPP_CORE_DIGE_HH_ 2 | # define VPP_CORE_DIGE_HH_ 3 | 4 | # include 5 | # include 6 | 7 | namespace dg 8 | { 9 | 10 | inline image 11 | adapt(const vpp::image2d& i) 12 | { 13 | return image 14 | (i.ncols() + 2*i.border(), i.nrows() + 2*i.border(), (unsigned char*)&i(0,0)); 15 | } 16 | 17 | inline image 18 | adapt(const vpp::image2d& i) 19 | { 20 | return image 21 | (i.ncols() + 2*i.border(), i.nrows() + 2*i.border(), (unsigned char*)i.data()); 22 | } 23 | 24 | 25 | inline image 26 | adapt(const vpp::image2d& i) 27 | { 28 | return image 29 | (i.ncols() + 2*i.border(), i.nrows() + 2*i.border(), (unsigned char*)i.data()); 30 | } 31 | 32 | }; 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /vpp/core/image2d.hh: -------------------------------------------------------------------------------- 1 | #ifndef VPP_IMAGE2D_HH__ 2 | # define VPP_IMAGE2D_HH__ 3 | 4 | # include 5 | 6 | namespace vpp 7 | { 8 | 9 | template 10 | using image2d = imageNd; 11 | 12 | } 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /vpp/core/image3d.hh: -------------------------------------------------------------------------------- 1 | #ifndef VPP_IMAGE3D_HH__ 2 | # define VPP_IMAGE3D_HH__ 3 | 4 | # include 5 | 6 | namespace vpp 7 | { 8 | template 9 | using image3d = imageNd; 10 | 11 | }; 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /vpp/core/imageNd_iterator.hh: -------------------------------------------------------------------------------- 1 | #ifndef VPP_IMAGEND_ITERATOR_HH_ 2 | # define VPP_IMAGEND_ITERATOR_HH_ 3 | 4 | # include 5 | 6 | namespace vpp 7 | { 8 | 9 | template 10 | class imageNd; 11 | template class Const> 12 | class imageNd_iterator; 13 | 14 | template class Const> 15 | class imageNd_row_iterator 16 | { 17 | public: 18 | typedef imageNd I; 19 | typedef typename I::coord_type coord_type; 20 | typedef Const value_type; 21 | 22 | typedef typename I::domain_type::row_iterator bi_type; 23 | typedef imageNd_row_iterator self; 24 | 25 | inline imageNd_row_iterator() 26 | {} 27 | 28 | inline imageNd_row_iterator(const self& o) 29 | { 30 | *this = o; 31 | } 32 | 33 | inline self& operator=(const self& o) 34 | { 35 | cur_ = o.cur_; 36 | return *this; 37 | } 38 | 39 | inline imageNd_row_iterator(const coord_type& cur, Const& image) 40 | : cur_(image.address_of(cur)) 41 | {} 42 | 43 | inline void next() { ++cur_; } 44 | inline void prev() { --cur_; } 45 | 46 | inline self& operator++() { next(); return *this; } 47 | inline self& operator--() { next(); return *this; } 48 | 49 | inline value_type& operator*() const { return *cur_; } 50 | inline value_type* operator->() const { return cur_; } 51 | 52 | private: 53 | value_type* cur_; 54 | }; 55 | 56 | template class Const> 57 | inline bool operator==(const imageNd_row_iterator& a, const imageNd_row_iterator& b) 58 | { 59 | return &*a == &*b; 60 | } 61 | 62 | template class Const> 63 | inline bool operator!=(const imageNd_row_iterator& a, const imageNd_row_iterator& b) 64 | { 65 | return !(a == b); 66 | } 67 | 68 | 69 | template class Const> 70 | class imageNd_iterator 71 | { 72 | public: 73 | typedef imageNd I; 74 | typedef typename I::coord_type coord_type; 75 | typedef Const value_type; 76 | 77 | typedef typename I::domain_type::iterator bi_type; 78 | typedef imageNd_iterator self; 79 | 80 | inline imageNd_iterator() 81 | {} 82 | 83 | inline imageNd_iterator(const self& o) 84 | { 85 | *this = o; 86 | } 87 | 88 | inline self& operator=(const self& o) 89 | { 90 | pitch_ = o.pitch_; 91 | row_spacing_ = o.row_spacing_; 92 | cur_ = o.cur_; 93 | eor_ = o.eor_; 94 | return *this; 95 | } 96 | 97 | inline imageNd_iterator(const coord_type& cur, Const& image) 98 | : pitch_(image.pitch()), 99 | row_spacing_(image.pitch() - image.ncols() * sizeof(V)), 100 | cur_(image.address_of(cur)), 101 | eor_(cur_ + image.ncols()) 102 | {} 103 | 104 | inline void next() 105 | { 106 | cur_++; 107 | if (cur_ == eor_) 108 | { 109 | cur_ = (value_type*)((Const*) cur_ + row_spacing_); 110 | eor_ = (value_type*)((Const*) eor_ + pitch_); 111 | } 112 | } 113 | 114 | inline self& operator++() { next(); return *this; } 115 | 116 | inline value_type& operator*() const { return *cur_; } 117 | inline value_type* operator->() const { return cur_; } 118 | 119 | private: 120 | int pitch_; 121 | int row_spacing_; 122 | value_type* cur_; 123 | value_type* eor_; 124 | }; 125 | 126 | template class Const> 127 | inline bool operator==(const imageNd_iterator& a, const imageNd_iterator& b) 128 | { 129 | return &*a == &*b; 130 | } 131 | 132 | template class Const> 133 | inline bool operator!=(const imageNd_iterator& a, const imageNd_iterator& b) 134 | { 135 | return !(a == b); 136 | } 137 | 138 | }; 139 | 140 | #endif 141 | -------------------------------------------------------------------------------- /vpp/core/keypoint_container.hh: -------------------------------------------------------------------------------- 1 | #ifndef VPP_CORE_KEYPOINT_CONTAINER_HH_ 2 | # define VPP_CORE_KEYPOINT_CONTAINER_HH_ 3 | 4 | # include 5 | # include 6 | # include 7 | 8 | 9 | namespace vpp 10 | { 11 | 12 | template 13 | struct keypoint 14 | { 15 | keypoint() : age(0) {} 16 | keypoint(vector pos) : position(pos), velocity(0,0), 17 | age(1) {} 18 | 19 | vector position; 20 | vector velocity; 21 | int age; 22 | 23 | void die() { age = 0; } 24 | bool alive() { return age > 0; } 25 | }; 26 | 27 | template 28 | struct keypoint_container 29 | { 30 | typedef P keypoint_type; 31 | typedef F feature_type; 32 | 33 | typedef std::vector

keypoint_vector_type; 34 | typedef std::vector feature_vector_type; 35 | 36 | keypoint_container(const box2d& d); 37 | 38 | void compact(); 39 | void prepare_matching(); 40 | 41 | struct no_op 42 | { 43 | template 44 | void operator()(T& t) {} 45 | }; 46 | 47 | template 48 | void sync_attributes(T& container, typename T::value_type new_value = typename T::value_type(), 49 | D die_fun = D()) const; 50 | 51 | template 52 | void sync_attributes(T& container, 53 | typename T::value_type new_value, 54 | std::vector& dead_vector) const; 55 | 56 | void add(const vfloat2& p); 57 | void add(const keypoint_type& p, const feature_type& f = feature_type()); 58 | void remove(int i); 59 | void remove(vint2 pos); 60 | 61 | template 62 | void move(int i, T pos); 63 | void update(unsigned i, const keypoint_type& p, const feature_type& f); 64 | 65 | keypoint_vector_type& keypoints() { return keypoint_vector_; } 66 | const keypoint_vector_type& keypoints() const { return keypoint_vector_; } 67 | image2d& index2d() { return index2d_; } 68 | const image2d& index2d() const { return index2d_; } 69 | 70 | int index_of(vint2& p) const { return index2d_(p); } 71 | 72 | keypoint_type& operator[] (unsigned i) { return keypoint_vector_[i]; } 73 | const keypoint_type& operator[] (unsigned i) const { return keypoint_vector_[i]; } 74 | 75 | keypoint_type& operator() (vint2 p) { return keypoint_vector_[index2d_(p)]; } 76 | const keypoint_type& operator() (vint2 p) const { return keypoint_vector_[index2d_(p)]; } 77 | 78 | int size() const; 79 | 80 | void update_index(unsigned i, const vint2& p); 81 | 82 | bool has(vint2 p) const; 83 | 84 | private: 85 | std::vector matches_; 86 | image2d index2d_; 87 | keypoint_vector_type keypoint_vector_; 88 | feature_vector_type feature_vector_; 89 | bool compact_has_run_; 90 | }; 91 | 92 | } 93 | 94 | # include 95 | 96 | #endif 97 | -------------------------------------------------------------------------------- /vpp/core/keypoint_trajectory.hh: -------------------------------------------------------------------------------- 1 | #ifndef VPP_CORE_KEYPOINT_TRAJECTORY_HH_ 2 | # define VPP_CORE_KEYPOINT_TRAJECTORY_HH_ 3 | 4 | # include 5 | # include 6 | # include 7 | 8 | namespace vpp 9 | { 10 | 11 | struct keypoint_trajectory 12 | { 13 | keypoint_trajectory() : alive_(true) {} 14 | keypoint_trajectory(int frame_cpt) 15 | : start_frame_(frame_cpt), 16 | alive_(true) 17 | { 18 | } 19 | 20 | void die() 21 | { 22 | alive_ = false; 23 | } 24 | 25 | bool alive() 26 | { 27 | return alive_; 28 | } 29 | 30 | vfloat2 position() const 31 | { 32 | assert(size() > 0); 33 | return history_.front(); 34 | } 35 | 36 | int size() const 37 | { 38 | return history_.size(); 39 | } 40 | 41 | vfloat2 position_at_frame(int frame_cpt) 42 | { 43 | assert(frame_cpt < (start_frame_ + history_.size())); 44 | assert(frame_cpt >= (start_frame_)); 45 | int i = history_.size() - 1 - (frame_cpt - start_frame_); 46 | return history_[i]; 47 | } 48 | 49 | void move_to(vfloat2 p) 50 | { 51 | history_.push_front(p); 52 | } 53 | 54 | void pop_oldest_position() 55 | { 56 | history_.pop_back(); 57 | } 58 | 59 | vfloat2 operator[](unsigned i) const { return history_[i]; } 60 | 61 | const std::deque& positions() const { return history_; } 62 | 63 | int start_frame() const { return start_frame_; } 64 | int end_frame() const { return start_frame_ + history_.size() - 1; } 65 | 66 | private: 67 | int start_frame_; 68 | bool alive_; 69 | std::deque history_; 70 | }; 71 | 72 | }; 73 | 74 | #endif 75 | -------------------------------------------------------------------------------- /vpp/core/make_array.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace vpp 7 | { 8 | template 9 | decltype(auto) make_array(T1&& t1, T&&... t) 10 | { 11 | return std::array 12 | {{std::forward(t1), 13 | std::forward(t)...}}; 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /vpp/core/numbers.sb: -------------------------------------------------------------------------------- 1 | // Convert the symbol file into a C++ header using sed, or another text processing tool 2 | // with the equivalent command: 3 | // sed -e 's/^\([a-zA-Z1-9_]\+\)\/#ifndef IOD_SYMBOL__\1\n\#define IOD_SYMBOL__\1\n iod_define_symbol_number(\1)\n#endif/' numbers.sb > number_symbols_definitions.hh 4 | 5 | sed -e 's/^\([a-zA-Z1-9_]\+\)/#ifndef IOD_SYMBOL_\#define IOD_SYMBOL__\1\n iod_define_symbol_number(\1)\n#endif/' numbers.sb 6 | 7 | 1 8 | 2 9 | 3 10 | 4 11 | 5 12 | 6 13 | 7 14 | 8 15 | 9 16 | 9 17 | 10 18 | 11 19 | 12 20 | 13 21 | 14 22 | 15 23 | 16 -------------------------------------------------------------------------------- /vpp/core/patch.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace vpp 9 | { 10 | 11 | // Store a single patch of pixels. 12 | // Faster than imageNd because it uses unique_ptr instead of smart_ptr. 13 | // Non copyable. 14 | // 15 | // Note: image2d is still faster to store a set of patches because it 16 | // only call malloc once for all descritors. 17 | template 18 | struct patch 19 | { 20 | patch(int nrows, int ncols) : size_(nrows * ncols), pixels(new V[size_]) {} 21 | patch(box2d d) : size_(d.nrows() * d.ncols()), pixels(new V[size_]) {} 22 | 23 | int size() { return size_; } 24 | decltype(auto) operator[](int i) { return pixels[i]; } 25 | 26 | // No copy allowed. 27 | int size_; 28 | std::unique_ptr pixels; 29 | }; 30 | 31 | template 32 | auto extract_patches(const std::vector& kps, 33 | const image2d& img, int winsize) 34 | { 35 | image2d patches(kps.size(), winsize * winsize); 36 | for (int ki = 0; ki < kps.size(); ki++) 37 | { 38 | vint2 pos = kps[ki]; 39 | auto ra = relative_accessor(img, pos); 40 | const int h = winsize / 2; 41 | for (int r = -h; r < -h + winsize; r++) 42 | #pragma omp simd 43 | for (int c = -h; c < -h + winsize; c++) 44 | patches[ki][r * winsize + c] = ra(r, c); 45 | } 46 | 47 | return patches; 48 | } 49 | 50 | template 51 | auto extract_patch(const vint2& pos, 52 | const image2d& img, int winsize) 53 | { 54 | auto ra = relative_accessor(img, pos); 55 | patch patch(winsize, winsize); 56 | const int h = winsize / 2; 57 | for (int r = -h; r < -h + winsize; r++) 58 | #pragma omp simd 59 | for (int c = -h; c < -h + winsize; c++) 60 | patch[r * winsize + c] = ra(r, c); 61 | 62 | return patch; 63 | } 64 | 65 | template 66 | auto extract_patch(const vpp::vfloat2& pos, 67 | const image2d& img, int winsize) 68 | { 69 | // Fixme add interpolation. 70 | auto ra = relative_accessor(img, pos.template cast()); 71 | patch patch(winsize, winsize); 72 | const int h = winsize / 2; 73 | for (int r = -h; r < -h + winsize; r++) 74 | #pragma omp simd 75 | for (int c = -h; c < -h + winsize; c++) 76 | patch[r * winsize + c] = ra(r, c); 77 | 78 | return patch; 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /vpp/core/pixel_wise.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | namespace vpp 17 | { 18 | 19 | // pixel_wise is an abstraction that simplify writing of fast dense 20 | // local image processing. To accelerate the processing, it spans 21 | // the executions on multicore and let the compiler vectorise the 22 | // loops with SIMD vector instructions. 23 | // 24 | // Usage: 25 | // pixel_wise(img1, ..., imgN)(options...) | [] (auto pixel1, ... auto pixelN) { process the pixels here }; 26 | // 27 | // Avalaible options: 28 | // 29 | // _right_to_left: forward iteration on rows. 30 | // _left_to_right (default): backward iteration on rows. 31 | // _top_to_bottom (default): forward iteration on rows. 32 | // _bottom_to_top: backward iteration on rows. 33 | // _no_threads: disable multithreading but still let the compiler vectorise the code if possible. 34 | // 35 | // Example: pixel_wise(img) | [] (int& i) { i += 1; } // Increment all pixels. 36 | // 37 | 38 | template 39 | struct pixel_wise_impl; 40 | 41 | struct pixel_wise_caller 42 | { 43 | template 44 | inline decltype(auto) operator()(T&&... t) 45 | { 46 | return pixel_wise_impl, T...>(std::forward_as_tuple(t...), iod::sio<>()); 47 | } 48 | }; 49 | 50 | static pixel_wise_caller pixel_wise; 51 | } 52 | 53 | 54 | #include 55 | -------------------------------------------------------------------------------- /vpp/core/relative_accessor.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace vpp 6 | { 7 | 8 | template 9 | struct relative_access_kernel; 10 | 11 | // Provides a fast access to the neighborhood of a point. 12 | // Easily vectorized by the compiler if used inside a loop. 13 | // 14 | // Example: 15 | // auto ra = relative_accessor(img, vint2(10, 10)); 16 | // auto nw = ra(-1, -1); // North west neighbor. 17 | template 18 | auto relative_accessor(const image2d& img, vint2 p) 19 | { 20 | auto line= &img[p[0]]; 21 | int col = p[1]; 22 | return relative_access_kernel{line, col}; 23 | }; 24 | 25 | template 26 | struct relative_access_kernel 27 | { 28 | decltype(auto) operator() (int dr, int dc) { return line[dr][col+dc]; }; 29 | decltype(auto) operator() (vint2 p) { return line[p[0]][col+p[1]]; }; 30 | 31 | V line; 32 | int col; 33 | }; 34 | 35 | } 36 | -------------------------------------------------------------------------------- /vpp/core/sum.hh: -------------------------------------------------------------------------------- 1 | #ifndef VPP_SUM_HH__ 2 | # define VPP_SUM_HH__ 3 | 4 | # include 5 | # include 6 | # include 7 | 8 | namespace vpp 9 | { 10 | 11 | template 12 | plus_promotion sum(const imageNd& img) 13 | { 14 | typedef plus_promotion S; 15 | S res = zero(); 16 | pixel_wise(img)(_no_threads) | [&res] (auto v) { res += v; }; 17 | return res; 18 | 19 | } 20 | }; 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /vpp/core/symbol_definitions.hh: -------------------------------------------------------------------------------- 1 | // Generated by iod_generate_symbols. 2 | #include 3 | #ifndef IOD_SYMBOL_1 4 | #define IOD_SYMBOL_1 5 | iod_define_number_symbol(1) 6 | #endif 7 | 8 | #ifndef IOD_SYMBOL_2 9 | #define IOD_SYMBOL_2 10 | iod_define_number_symbol(2) 11 | #endif 12 | 13 | #ifndef IOD_SYMBOL_N 14 | #define IOD_SYMBOL_N 15 | iod_define_symbol(N) 16 | #endif 17 | 18 | #ifndef IOD_SYMBOL_aligned 19 | #define IOD_SYMBOL_aligned 20 | iod_define_symbol(aligned) 21 | #endif 22 | 23 | #ifndef IOD_SYMBOL_argmax 24 | #define IOD_SYMBOL_argmax 25 | iod_define_symbol(argmax) 26 | #endif 27 | 28 | #ifndef IOD_SYMBOL_argmin 29 | #define IOD_SYMBOL_argmin 30 | iod_define_symbol(argmin) 31 | #endif 32 | 33 | #ifndef IOD_SYMBOL_avg 34 | #define IOD_SYMBOL_avg 35 | iod_define_symbol(avg) 36 | #endif 37 | 38 | #ifndef IOD_SYMBOL_block_size 39 | #define IOD_SYMBOL_block_size 40 | iod_define_symbol(block_size) 41 | #endif 42 | 43 | #ifndef IOD_SYMBOL_border 44 | #define IOD_SYMBOL_border 45 | iod_define_symbol(border) 46 | #endif 47 | 48 | #ifndef IOD_SYMBOL_bottom_to_top 49 | #define IOD_SYMBOL_bottom_to_top 50 | iod_define_symbol(bottom_to_top) 51 | #endif 52 | 53 | #ifndef IOD_SYMBOL_col_order 54 | #define IOD_SYMBOL_col_order 55 | iod_define_symbol(col_order) 56 | #endif 57 | 58 | #ifndef IOD_SYMBOL_ctx 59 | #define IOD_SYMBOL_ctx 60 | iod_define_symbol(ctx) 61 | #endif 62 | 63 | #ifndef IOD_SYMBOL_data 64 | #define IOD_SYMBOL_data 65 | iod_define_symbol(data) 66 | #endif 67 | 68 | #ifndef IOD_SYMBOL_exp 69 | #define IOD_SYMBOL_exp 70 | iod_define_symbol(exp) 71 | #endif 72 | 73 | #ifndef IOD_SYMBOL_if_ 74 | #define IOD_SYMBOL_if_ 75 | iod_define_symbol(if_) 76 | #endif 77 | 78 | #ifndef IOD_SYMBOL_left_to_right 79 | #define IOD_SYMBOL_left_to_right 80 | iod_define_symbol(left_to_right) 81 | #endif 82 | 83 | #ifndef IOD_SYMBOL_max 84 | #define IOD_SYMBOL_max 85 | iod_define_symbol(max) 86 | #endif 87 | 88 | #ifndef IOD_SYMBOL_mem_backward 89 | #define IOD_SYMBOL_mem_backward 90 | iod_define_symbol(mem_backward) 91 | #endif 92 | 93 | #ifndef IOD_SYMBOL_mem_forward 94 | #define IOD_SYMBOL_mem_forward 95 | iod_define_symbol(mem_forward) 96 | #endif 97 | 98 | #ifndef IOD_SYMBOL_min 99 | #define IOD_SYMBOL_min 100 | iod_define_symbol(min) 101 | #endif 102 | 103 | #ifndef IOD_SYMBOL_nbh 104 | #define IOD_SYMBOL_nbh 105 | iod_define_symbol(nbh) 106 | #endif 107 | 108 | #ifndef IOD_SYMBOL_no_threads 109 | #define IOD_SYMBOL_no_threads 110 | iod_define_symbol(no_threads) 111 | #endif 112 | 113 | #ifndef IOD_SYMBOL_options 114 | #define IOD_SYMBOL_options 115 | iod_define_symbol(options) 116 | #endif 117 | 118 | #ifndef IOD_SYMBOL_pitch 119 | #define IOD_SYMBOL_pitch 120 | iod_define_symbol(pitch) 121 | #endif 122 | 123 | #ifndef IOD_SYMBOL_right_to_left 124 | #define IOD_SYMBOL_right_to_left 125 | iod_define_symbol(right_to_left) 126 | #endif 127 | 128 | #ifndef IOD_SYMBOL_row_order 129 | #define IOD_SYMBOL_row_order 130 | iod_define_symbol(row_order) 131 | #endif 132 | 133 | #ifndef IOD_SYMBOL_sum 134 | #define IOD_SYMBOL_sum 135 | iod_define_symbol(sum) 136 | #endif 137 | 138 | #ifndef IOD_SYMBOL_test 139 | #define IOD_SYMBOL_test 140 | iod_define_symbol(test) 141 | #endif 142 | 143 | #ifndef IOD_SYMBOL_then 144 | #define IOD_SYMBOL_then 145 | iod_define_symbol(then) 146 | #endif 147 | 148 | #ifndef IOD_SYMBOL_tie_arguments 149 | #define IOD_SYMBOL_tie_arguments 150 | iod_define_symbol(tie_arguments) 151 | #endif 152 | 153 | #ifndef IOD_SYMBOL_top_to_bottom 154 | #define IOD_SYMBOL_top_to_bottom 155 | iod_define_symbol(top_to_bottom) 156 | #endif 157 | 158 | #ifndef IOD_SYMBOL_v 159 | #define IOD_SYMBOL_v 160 | iod_define_symbol(v) 161 | #endif 162 | 163 | -------------------------------------------------------------------------------- /vpp/core/symbols.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace vpp 7 | { 8 | using s::_border; 9 | using s::_aligned; 10 | using s::_tie_arguments; 11 | using s::_mem_forward; 12 | using s::_mem_backward; 13 | using s::_no_threads; 14 | using s::_block_size; 15 | using s::_data; 16 | using s::_pitch; 17 | 18 | using namespace s; 19 | } 20 | -------------------------------------------------------------------------------- /vpp/core/tuple_utils.hh: -------------------------------------------------------------------------------- 1 | #ifndef VPP_TUPLE_UTILS_HH_ 2 | # define VPP_TUPLE_UTILS_HH_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace vpp 10 | { 11 | namespace internals 12 | { 13 | 14 | template 15 | inline void apply_args_impl(std::tuple& t, std::integer_sequence, F&& f) 16 | { 17 | f(std::forward(std::get(t))...); 18 | } 19 | 20 | template 21 | inline void apply_args(std::tuple& t, F&& f) 22 | { 23 | apply_args_impl(t, std::make_integer_sequence{}, f); 24 | } 25 | 26 | 27 | template 28 | inline void apply_args_star_impl(std::tuple& t, std::integer_sequence, F&& f) 29 | { 30 | f(*std::get(t)...); 31 | } 32 | 33 | template 34 | inline void apply_args_star(std::tuple& t, F&& f) 35 | { 36 | apply_args_star_impl(t, std::make_integer_sequence{}, f); 37 | } 38 | 39 | template 40 | inline void apply_args_transform_impl(std::tuple& t, std::integer_sequence, 41 | F f, G g) 42 | { 43 | f(g(std::get(t))...); 44 | } 45 | 46 | template 47 | inline void apply_args_transform(std::tuple& t, F f, G g) 48 | { 49 | apply_args_transform_impl(t, std::make_integer_sequence{}, f, g); 50 | } 51 | 52 | 53 | template 54 | inline F tuple_map(std::tuple& t, F f, std::index_sequence) 55 | { 56 | return (void)std::initializer_list{((void)f(std::get(t)), 0)...}, f; 57 | } 58 | 59 | template 60 | inline void tuple_map(std::tuple& t, F f) 61 | { 62 | tuple_map(t, f, std::index_sequence_for{}); 63 | } 64 | 65 | template 66 | inline decltype(auto) tuple_transform(T&& t, F f, std::index_sequence) 67 | { 68 | return std::make_tuple(f(std::get(std::forward(t)))...); 69 | } 70 | 71 | template 72 | inline decltype(auto) tuple_transform(T&& t, F f) 73 | { 74 | return tuple_transform(std::forward(t), f, 75 | std::make_index_sequence>{}>{}); 76 | } 77 | 78 | } 79 | } 80 | 81 | #endif 82 | -------------------------------------------------------------------------------- /vpp/core/vector.hh: -------------------------------------------------------------------------------- 1 | #ifndef VPP_VECTOR_HH__ 2 | # define VPP_VECTOR_HH__ 3 | 4 | # include 5 | 6 | namespace vpp 7 | { 8 | 9 | template 10 | using vector = Eigen::Matrix; 11 | 12 | #define VPP_ALIAS_DECL(T1, T2) \ 13 | template \ 14 | using v##T2 = vector; \ 15 | typedef v##T2<1> v##T2##1; \ 16 | typedef v##T2<2> v##T2##2; \ 17 | typedef v##T2<3> v##T2##3; \ 18 | typedef v##T2<4> v##T2##4; \ 19 | typedef v##T2<8> v##T2##8; \ 20 | typedef v##T2<16> v##T2##16; 21 | 22 | VPP_ALIAS_DECL(char, char); 23 | VPP_ALIAS_DECL(short, short); 24 | VPP_ALIAS_DECL(int, int); 25 | VPP_ALIAS_DECL(float, float); 26 | VPP_ALIAS_DECL(double, double); 27 | 28 | VPP_ALIAS_DECL(unsigned char, uchar); 29 | VPP_ALIAS_DECL(unsigned short, ushort); 30 | VPP_ALIAS_DECL(unsigned int, uint); 31 | 32 | #undef VPP_ALIAS_DECL 33 | 34 | // Promote a type to avoid addition overflow. Scalar version. 35 | template 36 | struct plus_promotion_ 37 | { 38 | typedef decltype(T() + T()) type; 39 | }; 40 | 41 | // Promote a type to avoid addition overflow. Vector version. 42 | template 43 | struct plus_promotion_> 44 | { 45 | typedef Eigen::Matrix type; 46 | }; 47 | 48 | // plus_promotion_ helper. 49 | template 50 | using plus_promotion = typename plus_promotion_::type; 51 | 52 | 53 | // Cast a value from V to U. Scalar version. 54 | template 55 | struct cast_ 56 | { 57 | static U run(const V& v) { return v; } 58 | }; 59 | 60 | // Cast an Eigen matrix to U. 61 | template 62 | struct cast_, typename std::enable_if::value>::type 63 | > 64 | { 65 | static U run(const Eigen::MatrixBase& v) { 66 | return v.template cast(); 67 | } 68 | }; 69 | 70 | // Cast an Eigen matrix of size 1 to U. Handle convertion to scalar types likes float or int. 71 | template 72 | struct cast_, typename std::enable_if::SizeAtCompileTime == 1 && 73 | std::is_scalar::value>::type> 74 | { 75 | static U run(const Eigen::MatrixBase& v) { 76 | return U(v[0]); 77 | } 78 | }; 79 | 80 | // Cast a scalar to an Eigen matrix of size 1. 81 | template 82 | struct cast_, V, 83 | typename std::enable_if::value>::type> 84 | { 85 | static vector run(const V& v) { 86 | vector res; 87 | res[0] = v; 88 | return res; 89 | } 90 | }; 91 | 92 | // template 93 | // struct cast_, vector> 94 | // { 95 | // static vector run(const vector& v) { 96 | // vector res; 97 | // res[0] = v[0]; 98 | // return res; 99 | // } 100 | // }; 101 | 102 | // Cast helper. 103 | template 104 | typename std::enable_if, V>::value, U>::type 105 | cast(const V& v) { return cast_::run(v); } 106 | 107 | template 108 | typename std::enable_if, V>::value, U>::type 109 | cast(const V& v) { return cast_>::run(v); } 110 | 111 | // template 112 | // typename std::enable_if, U>::value, U>::type 113 | // cast(const V& v) { return cast_, V>::run(v); } 114 | 115 | }; 116 | 117 | #endif 118 | -------------------------------------------------------------------------------- /vpp/core/window.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace vpp 8 | { 9 | 10 | template 11 | struct window 12 | { 13 | window(N n) : offsets(n) {} 14 | 15 | decltype(auto) operator()() { return offsets(); } 16 | N offsets; 17 | }; 18 | 19 | // Apply a function on a set of relative coordinates. 20 | // 21 | // Example: 22 | // 23 | // pixel_wise(relative_access(img)) | [] (auto& a) { 24 | // foreach(c4, [&] (vint2 n) { a(n) += a(0,0); }); 25 | // }; 26 | template 27 | auto foreach(window n, F f) 28 | { 29 | for (int i = 0; i < n().size(); i++) 30 | f(vint2(n()[i][0], n()[i][1])); 31 | } 32 | 33 | template 34 | auto make_window(F f) { return window(f); } 35 | 36 | // Define window with lambda function to allow inlining 37 | // of neighbor offsets. 38 | 39 | auto c9 = make_window 40 | ([] () { return vpp::make_array 41 | (vint2{-1,-1}, vint2{-1, 0}, vint2{-1, 1}, 42 | vint2{ 0, -1}, vint2{ 0, 0}, vint2{0, 1}, 43 | vint2{1,-1}, vint2{1, 0}, vint2{1, 1}); }); 44 | 45 | auto c8 = make_window 46 | ([] { return make_array 47 | (vint2{-1,-1}, vint2{-1, 0}, vint2{-1, 1}, 48 | vint2{ 0, -1}, vint2{0, 1}, 49 | vint2{1,-1}, vint2{1, 0}, vint2{1, 1}); }); 50 | 51 | auto c5 = make_window 52 | ([] { return make_array 53 | (vint2{-1, 0}, 54 | vint2{ 0, -1}, vint2{ 0, 0}, vint2{0, 1}, 55 | vint2{1, 0}); }); 56 | 57 | auto c4 = make_window 58 | ([] { return make_array 59 | (vint2{-1, 0}, 60 | vint2{ 0, -1}, vint2{0, 1}, 61 | vint2{1, 0}); }); 62 | 63 | }; 64 | -------------------------------------------------------------------------------- /vpp/core/zero.hh: -------------------------------------------------------------------------------- 1 | #ifndef VPP_ZERO_HH__ 2 | # define VPP_ZERO_HH__ 3 | 4 | namespace vpp 5 | { 6 | 7 | template 8 | struct zero 9 | { 10 | operator V() { return 0; } 11 | }; 12 | 13 | template <> 14 | struct zero 15 | { 16 | operator float() { return 0.f; } 17 | }; 18 | 19 | template 20 | struct zero> 21 | { 22 | operator Eigen::Matrix() { return Eigen::Matrix::Zero(); } 23 | }; 24 | 25 | }; 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /vpp/draw/draw_trajectories.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace vpp 9 | { 10 | 11 | template 12 | void draw_trajectories(image2d& out, std::vector& trs, 13 | int max_trajectory_len, 14 | OPTS... opts) 15 | { 16 | auto options = iod::D(opts...); 17 | 18 | auto trajectory_color = options.get(_trajectory_color, [] (int i) { 19 | return vuchar3(255, 255, 0); }); 20 | 21 | if (max_trajectory_len == -1) 22 | max_trajectory_len = INT_MAX; 23 | 24 | std::vector sorted_idx; 25 | for (auto& t : trs) sorted_idx.push_back(sorted_idx.size()); 26 | 27 | std::sort(sorted_idx.begin(), sorted_idx.end(), [&] (auto i, auto j) { return trs[i].start_frame() > trs[j].start_frame(); }); 28 | 29 | #pragma omp parallel for 30 | for (int ti = 0; ti < trs.size(); ti++) 31 | { 32 | keypoint_trajectory& t = trs[sorted_idx[ti]]; 33 | if (!t.alive() or t.size() == 0) continue; 34 | 35 | vint2 p1 = t.position_at_frame(t.end_frame()).template cast(); 36 | vint2 p2 = t.position_at_frame(t.end_frame() - std::min(10, int(t.size()) - 1)).template cast(); 37 | 38 | vuchar3 pt_color = hsv_to_rgb((M_PI + atan2(p2[0] - p1[0], p2[1] - p1[1])) * 180.f / M_PI, 1.f, 1.f); 39 | 40 | int last_frame_id = std::max(t.end_frame() - max_trajectory_len, t.start_frame()); 41 | if ((p1 - t.position_at_frame(last_frame_id).template cast()).norm() < 4) 42 | continue; 43 | 44 | for (int i = t.end_frame(); i >= std::max(t.end_frame() - max_trajectory_len, t.start_frame()) + 1; i--) 45 | { 46 | vint2 p1 = t.position_at_frame(i).template cast(); 47 | vint2 p2 = t.position_at_frame(i - 1).template cast(); 48 | vuchar4 color; 49 | color.segment<3>(0) = pt_color; 50 | color[3] = 0.4f*(255.f - 255.f * (t.end_frame() - i) / max_trajectory_len); 51 | 52 | color = vuchar4(0,255,0,255); 53 | draw::line2d(out, p1, p2, 54 | color 55 | ); 56 | } 57 | 58 | //draw::c9(out, t.position().template cast(), pt_color); 59 | draw::c9(out, t.position().template cast(), vuchar3(0,0,255)); 60 | 61 | } 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /vpp/draw/rgb_colors.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace vpp 6 | { 7 | namespace rgb_colors 8 | { 9 | vuchar3 blue(0,0,255); 10 | vuchar3 green(0,255,0); 11 | vuchar3 red(255,0,0); 12 | 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /vpp/draw/square.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | 7 | namespace vpp 8 | { 9 | 10 | using s::_width; 11 | using s::_stroke; 12 | using s::_fill; 13 | using s::_center; 14 | 15 | namespace draw 16 | { 17 | template 18 | void square(image2d img, OPTS... opts) 19 | { 20 | auto options = D(opts...); 21 | 22 | vint2 center = options.center; 23 | int width = options.width; 24 | 25 | if (options.has(_fill)) 26 | { 27 | vint2 hdiag(width / 2, width / 2); 28 | box2d bb(center - hdiag, center + hdiag); 29 | 30 | pixel_wise(img | bb) | [&] (auto& p) { 31 | p = options.get(_fill, V()); 32 | }; 33 | 34 | } 35 | else 36 | if (options.has(_stroke)) 37 | { 38 | // FIXME. 39 | } 40 | } 41 | } 42 | } 43 | 44 | -------------------------------------------------------------------------------- /vpp/draw/symbols.hh: -------------------------------------------------------------------------------- 1 | // Generated by iod_generate_symbols. 2 | #include 3 | #ifndef IOD_SYMBOL_center 4 | #define IOD_SYMBOL_center 5 | iod_define_symbol(center) 6 | #endif 7 | 8 | #ifndef IOD_SYMBOL_fill 9 | #define IOD_SYMBOL_fill 10 | iod_define_symbol(fill) 11 | #endif 12 | 13 | #ifndef IOD_SYMBOL_stroke 14 | #define IOD_SYMBOL_stroke 15 | iod_define_symbol(stroke) 16 | #endif 17 | 18 | #ifndef IOD_SYMBOL_trajectory_color 19 | #define IOD_SYMBOL_trajectory_color 20 | iod_define_symbol(trajectory_color) 21 | #endif 22 | 23 | #ifndef IOD_SYMBOL_width 24 | #define IOD_SYMBOL_width 25 | iod_define_symbol(width) 26 | #endif 27 | 28 | -------------------------------------------------------------------------------- /vpp/utils/opencv_bridge.hh: -------------------------------------------------------------------------------- 1 | #ifndef VPP_OPENCV_BRIDGE_HH__ 2 | # define VPP_OPENCV_BRIDGE_HH__ 3 | 4 | # include 5 | # include 6 | 7 | namespace vpp 8 | { 9 | 10 | template 11 | struct opencv_typeof; 12 | 13 | #define OPENCV_TYPEOF(T, V) \ 14 | template <> \ 15 | struct opencv_typeof \ 16 | { \ 17 | enum { ret = V }; \ 18 | }; 19 | 20 | #define OPENCV_TYPEOF_(BT, T, CV) \ 21 | OPENCV_TYPEOF(BT, CV_##CV##C1); \ 22 | OPENCV_TYPEOF(v##T##1, CV_##CV##C1); \ 23 | OPENCV_TYPEOF(v##T##2, CV_##CV##C2); \ 24 | OPENCV_TYPEOF(v##T##3, CV_##CV##C3); \ 25 | OPENCV_TYPEOF(v##T##4, CV_##CV##C4); 26 | 27 | OPENCV_TYPEOF_(unsigned char, uchar, 8U); 28 | OPENCV_TYPEOF_(char, char, 8S); 29 | OPENCV_TYPEOF_(unsigned short, ushort, 16U); 30 | OPENCV_TYPEOF_(short, short, 16S); 31 | OPENCV_TYPEOF_(float, float, 32F); 32 | OPENCV_TYPEOF_(int, int, 32S); 33 | 34 | struct opencv_data_holder 35 | { 36 | int* refcount; 37 | void* data; 38 | }; 39 | 40 | static void opencv_data_deleter(void* data) 41 | { 42 | opencv_data_holder* d = (opencv_data_holder*) data; 43 | 44 | if (d->refcount and *(d->refcount) > 1) 45 | *(d->refcount) -= 1; 46 | else if (d->refcount and *(d->refcount) == 1) 47 | cv::fastFree(d->data); 48 | delete d; 49 | } 50 | 51 | template 52 | image2d from_opencv(cv::Mat m) 53 | { 54 | if (!m.data) return image2d(); 55 | 56 | image2d res(make_box2d(m.rows, m.cols), _data = m.data, _pitch = m.step); 57 | 58 | #if (((defined(CV_VERSION_MAJOR) && CV_VERSION_MAJOR >= 3))) 59 | res.set_external_data_holder(new opencv_data_holder{&m.u->refcount, m.data}, opencv_data_deleter); 60 | #else 61 | res.set_external_data_holder(new opencv_data_holder{m.refcount, m.data}, opencv_data_deleter); 62 | #endif 63 | 64 | m.addref(); 65 | return res; 66 | } 67 | 68 | template 69 | cv::Mat to_opencv(image2d& v) 70 | { 71 | if (!v.has_data()) return cv::Mat(); 72 | 73 | cv::Mat m(v.nrows(), v.ncols(), opencv_typeof::ret, (void*) v.address_of(vint2(0,0)), v.pitch()); 74 | return m; 75 | } 76 | 77 | template 78 | cv::Mat to_opencv(image2d&& v) 79 | { 80 | if (!v.has_data()) return cv::Mat(); 81 | 82 | // v is a rvalue (won't survive after the function call) 83 | // so we need to copy its buffer. 84 | cv::Mat m(v.nrows(), v.ncols(), opencv_typeof::ret); 85 | 86 | image2d out = from_opencv(m); 87 | copy(v, out); 88 | 89 | return m; 90 | } 91 | 92 | }; 93 | 94 | #endif 95 | -------------------------------------------------------------------------------- /vpp/utils/opencv_utils.hh: -------------------------------------------------------------------------------- 1 | #ifndef VPP_OPENCV_UTILS_HH_ 2 | # define VPP_OPENCV_UTILS_HH_ 3 | 4 | # include 5 | # include 6 | # include 7 | # include 8 | # include 9 | # include 10 | 11 | inline bool open_videocapture(const char* str, cv::VideoCapture& cap) 12 | { 13 | if (std::regex_match(str, std::regex("[0-9]+"))) 14 | cap.open(atoi(str)); 15 | else cap.open(str); 16 | 17 | if (!cap.isOpened()) 18 | { 19 | std::cerr << "Error: Cannot open " << str << std::endl; 20 | return false; 21 | } 22 | 23 | return true; 24 | } 25 | 26 | inline vpp::box2d videocapture_domain(cv::VideoCapture& cap) 27 | { 28 | #if (((defined(CV_VERSION_MAJOR) && CV_VERSION_MAJOR >= 4))) 29 | return vpp::make_box2d(cap.get(cv::CAP_PROP_FRAME_HEIGHT), 30 | cap.get(cv::CAP_PROP_FRAME_WIDTH)); 31 | #else 32 | return vpp::make_box2d(cap.get(CV_CAP_PROP_FRAME_HEIGHT), 33 | cap.get(CV_CAP_PROP_FRAME_WIDTH)); 34 | #endif 35 | } 36 | 37 | inline vpp::box2d videocapture_domain(const char* f) 38 | { 39 | cv::VideoCapture cap; 40 | open_videocapture(f, cap); 41 | #if (((defined(CV_VERSION_MAJOR) && CV_VERSION_MAJOR >= 4))) 42 | return vpp::make_box2d(cap.get(cv::CAP_PROP_FRAME_HEIGHT), 43 | cap.get(cv::CAP_PROP_FRAME_WIDTH)); 44 | #else 45 | return vpp::make_box2d(cap.get(CV_CAP_PROP_FRAME_HEIGHT), 46 | cap.get(CV_CAP_PROP_FRAME_WIDTH)); 47 | #endif 48 | } 49 | 50 | struct foreach_videoframe 51 | { 52 | 53 | foreach_videoframe(const char* f) 54 | { 55 | open_videocapture(f, cap_); 56 | frame_ = vpp::image2d(videocapture_domain(cap_)); 57 | cvframe_ = to_opencv(frame_); 58 | } 59 | 60 | template 61 | void operator| (F f) 62 | { 63 | while (cap_.read(cvframe_)) f(frame_); 64 | } 65 | 66 | private: 67 | cv::Mat cvframe_; 68 | vpp::image2d frame_; 69 | cv::VideoCapture cap_; 70 | }; 71 | #endif 72 | -------------------------------------------------------------------------------- /vpp/vpp.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include 4 | # include 5 | # include 6 | 7 | # include 8 | # include 9 | 10 | # include 11 | 12 | # include 13 | # include 14 | # include 15 | # include 16 | # include 17 | # include 18 | # include 19 | # include 20 | 21 | # include 22 | 23 | # include 24 | 25 | # include 26 | 27 | # include 28 | # include 29 | 30 | # include 31 | # include 32 | # include 33 | 34 | 35 | # include 36 | 37 | # include 38 | //# include 39 | --------------------------------------------------------------------------------