├── virtual_scanner ├── python │ └── ocnn │ │ ├── __init__.py │ │ └── virtualscanner │ │ ├── __init__.py │ │ ├── _virtualscanner_extern.pxd │ │ ├── CMakeLists.txt │ │ ├── _virtualscanner.pyx │ │ ├── scanner_settings.py │ │ └── directory_tree_scanner.py ├── prebuilt_binaries │ ├── VirtualScanner.exe │ ├── CGAL-vc140-mt-4.13-I-900.dll │ ├── boost_system-vc141-mt-x64-1_68.dll │ └── boost_filesystem-vc141-mt-x64-1_68.dll ├── setup.py ├── CMakeLists.txt ├── cpp │ ├── libvirtualscanner │ │ ├── cmake │ │ │ ├── VirtualScannerConfig.cmake.in │ │ │ ├── FindCGAL.cmake │ │ │ └── FindEigen3.cmake │ │ ├── include │ │ │ └── virtual_scanner │ │ │ │ ├── virtual_scanner.h │ │ │ │ └── points.h │ │ ├── CMakeLists.txt │ │ ├── libvirtualscanner.vcxproj.filters │ │ ├── src │ │ │ ├── points.cpp │ │ │ └── virtual_scanner.cpp │ │ └── libvirtualscanner.vcxproj │ └── virtualscanner │ │ ├── virtualscanner.vcxproj.filters │ │ ├── CMakeLists.txt │ │ ├── src │ │ └── main.cpp │ │ └── virtualscanner.vcxproj ├── VirtualScanner.sln └── README.md ├── README.md ├── .github └── FUNDING.yml ├── densecrf ├── README.md ├── examples │ ├── common.h │ ├── dense_inference.cpp │ ├── common.cpp │ └── dense_learning.cpp ├── include │ └── densecrf.h └── src │ ├── densecrf.cpp │ └── permutohedral.cpp └── .gitignore /virtual_scanner/python/ocnn/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /virtual_scanner/prebuilt_binaries/VirtualScanner.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wang-ps/O-CNN/HEAD/virtual_scanner/prebuilt_binaries/VirtualScanner.exe -------------------------------------------------------------------------------- /virtual_scanner/prebuilt_binaries/CGAL-vc140-mt-4.13-I-900.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wang-ps/O-CNN/HEAD/virtual_scanner/prebuilt_binaries/CGAL-vc140-mt-4.13-I-900.dll -------------------------------------------------------------------------------- /virtual_scanner/prebuilt_binaries/boost_system-vc141-mt-x64-1_68.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wang-ps/O-CNN/HEAD/virtual_scanner/prebuilt_binaries/boost_system-vc141-mt-x64-1_68.dll -------------------------------------------------------------------------------- /virtual_scanner/prebuilt_binaries/boost_filesystem-vc141-mt-x64-1_68.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wang-ps/O-CNN/HEAD/virtual_scanner/prebuilt_binaries/boost_filesystem-vc141-mt-x64-1_68.dll -------------------------------------------------------------------------------- /virtual_scanner/python/ocnn/virtualscanner/__init__.py: -------------------------------------------------------------------------------- 1 | from ocnn.virtualscanner._virtualscanner import VirtualScanner 2 | from ocnn.virtualscanner.directory_tree_scanner import DirectoryTreeScanner 3 | from ocnn.virtualscanner.scanner_settings import ScannerSettings 4 | -------------------------------------------------------------------------------- /virtual_scanner/python/ocnn/virtualscanner/_virtualscanner_extern.pxd: -------------------------------------------------------------------------------- 1 | # distutils: language = c++ 2 | 3 | from libcpp.string cimport string 4 | from libcpp cimport bool 5 | 6 | cdef extern from "virtual_scanner/virtual_scanner.h" nogil: 7 | cdef cppclass VirtualScanner: 8 | bool scanning(const string&, int, bool, bool) 9 | bool save_binary(const string&) 10 | bool save_ply(const string&) 11 | -------------------------------------------------------------------------------- /virtual_scanner/setup.py: -------------------------------------------------------------------------------- 1 | from skbuild import setup 2 | 3 | setup( 4 | name="ocnn.virtualscanner", 5 | version="18.09.05", 6 | description="Virtual scanner utilities", 7 | author='Microsoft', 8 | author_email="dapisani@microsoft.com", 9 | packages=['ocnn', 'ocnn.virtualscanner'], 10 | zip_safe=False, 11 | install_requires=['Cython', 'pyyaml'], 12 | package_dir={'': 'python'}, 13 | package_data={'ocnn.virtualscanner': ['*.pxd']} 14 | ) 15 | -------------------------------------------------------------------------------- /virtual_scanner/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.3) 2 | 3 | if(SKBUILD) 4 | project(python_ocnn VERSION 18.10.09) 5 | find_package(PythonExtensions REQUIRED) 6 | find_package(Cython REQUIRED) 7 | add_subdirectory(python/ocnn/virtualscanner) 8 | else() 9 | project(virtualscannerexe VERSION 18.10.09 LANGUAGES CXX) 10 | add_subdirectory(cpp/libvirtualscanner "${CMAKE_CURRENT_BINARY_DIR}/_libvirtualscanner") 11 | add_subdirectory(cpp/virtualscanner/ "${CMAKE_CURRENT_BINARY_DIR}/_virtualscanner") 12 | endif() 13 | -------------------------------------------------------------------------------- /virtual_scanner/cpp/libvirtualscanner/cmake/VirtualScannerConfig.cmake.in: -------------------------------------------------------------------------------- 1 | get_filename_component(VirtualScanner_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) 2 | include(CMakeFindDependencyMacro) 3 | 4 | if(NOT VCPKG_TOOLCHAIN) 5 | list(APPEND CMAKE_MODULE_PATH ${VirtualScanner_CMAKE_DIR}) 6 | endif() 7 | 8 | find_package(Boost REQUIRED COMPONENTS filesystem system) 9 | find_package(Eigen3 REQUIRED) 10 | find_package(CGAL REQUIRED) 11 | 12 | if(NOT VCPKG_TOOLCHAIN) 13 | list(REMOVE_AT CMAKE_MODULE_PATH -1) 14 | endif() 15 | 16 | if(NOT TARGET OCNN::VirtualScanner) 17 | include("${VirtualScanner_CMAKE_DIR}/VirtualScannerTargets.cmake") 18 | endif() 19 | 20 | set(VirtualScanner_LIBRARIES OCNN::VirtualScanner) 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # O-CNN: Octree-based Convolutional Neural Networks 2 | 3 | This repository contains the code of some tools used in our [O-CNN](http://wang-ps.github.io/O-CNN.html) project. 4 | The core code is contained in [this repository](https://github.com/Microsoft/O-CNN). 5 | 6 | If you use our code, please cite our paper. 7 | 8 | @article {Wang-2017-OCNN, 9 | title = {O-CNN: Octree-based Convolutional Neural Networks for 3D Shape Analysis}, 10 | author = {Wang, Peng-Shuai and Liu, Yang and Guo, Yu-Xiao and Sun, Chun-Yu and Tong, Xin}, 11 | journal = {ACM Transactions on Graphics (SIGGRAPH)}, 12 | volume = {36}, 13 | number = {4}, 14 | year = {2017}, 15 | } 16 | 17 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /virtual_scanner/python/ocnn/virtualscanner/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | find_package(VirtualScanner) 2 | if(NOT TARGET OCNN::VirtualScanner) 3 | message("VirtualScanner library not found") 4 | add_subdirectory(../../../cpp/libvirtualscanner "${CMAKE_CURRENT_BINARY_DIR}/_libvirtualscanner") 5 | endif() 6 | 7 | add_cython_target(_virtualscanner CXX) 8 | 9 | add_library(_virtualscanner MODULE ${_virtualscanner}) 10 | python_extension_module(_virtualscanner) 11 | 12 | if (VCPKG_TOOLCHAIN) 13 | find_package(CGAL) 14 | get_target_property(CGAL_DLL CGAL::CGAL IMPORTED_LOCATION_RELEASE) 15 | install(FILES ${CGAL_DLL} DESTINATION python/ocnn/virtualscanner) 16 | endif() 17 | target_link_libraries(_virtualscanner OCNN::VirtualScanner) 18 | install(TARGETS _virtualscanner LIBRARY DESTINATION python/ocnn/virtualscanner) 19 | -------------------------------------------------------------------------------- /virtual_scanner/cpp/virtualscanner/virtualscanner.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | -------------------------------------------------------------------------------- /virtual_scanner/cpp/libvirtualscanner/include/virtual_scanner/virtual_scanner.h: -------------------------------------------------------------------------------- 1 | #ifndef _VIRTUAL_SCANNER_ 2 | #define _VIRTUAL_SCANNER_ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "points.h" 9 | 10 | using std::string; 11 | using std::vector; 12 | using Eigen::Vector3f; 13 | using Eigen::MatrixXf; 14 | using Eigen::MatrixXi; 15 | 16 | class VirtualScanner { 17 | public: 18 | bool scanning(const string& filename, int view_num, bool flags, bool normalize); 19 | bool save_binary(const string& filename); 20 | bool save_ply(const string& filename); 21 | 22 | protected: 23 | bool save_binary_legacy(const string& filename); 24 | void calc_views(); 25 | 26 | protected: 27 | MatrixXf V_; 28 | MatrixXi F_; 29 | MatrixXf N_; 30 | Vector3f bbMin_, bbMax_; 31 | vector view_center_; 32 | vector view_dir_; 33 | vector dx_; 34 | vector dy_; 35 | 36 | vector pts_; 37 | vector normals_; 38 | vector flags_; // indicate whether the normal is reversed 39 | 40 | Points point_cloud_; 41 | 42 | const int resolution_ = 127; 43 | const int total_view_num_ = 14; 44 | 45 | }; 46 | 47 | #endif // _VIRTUAL_SCANNER_ 48 | -------------------------------------------------------------------------------- /densecrf/README.md: -------------------------------------------------------------------------------- 1 | # DenseCRF for the refinement of 3D shape part segmentation result 2 | 3 | This folder contains the code for the refinement of 3D shape part segmentation in our [O-CNN](http://wang-ps.github.io/O-CNN.html) paper. The mathematical details are presented in the Section 5.3 of our paper. 4 | 5 | The instructions to build the code are as follows: 6 | 7 | - Download the original [DenseCRF](http://graphics.stanford.edu/projects/drf) library first. 8 | - Download the code in current folder and use it to override the original [DenseCRF](http://graphics.stanford.edu/projects/drf) code. 9 | - Follow the instructions in the [DenseCRF](http://graphics.stanford.edu/projects/drf) to finish the build, and produce the executive files `dense_learning.exe` and `dense_inference.exe`. 10 | 11 | 12 | If you use our code, please cite our paper. 13 | 14 | @article {Wang-2017-OCNN, 15 | title = {O-CNN: Octree-based Convolutional Neural Networks for 3D Shape Analysis}, 16 | author = {Wang, Peng-Shuai and Liu, Yang and Guo, Yu-Xiao and Sun, Chun-Yu and Tong, Xin}, 17 | journal = {ACM Transactions on Graphics (SIGGRAPH)}, 18 | volume = {36}, 19 | number = {4}, 20 | year = {2017}, 21 | } 22 | 23 | -------------------------------------------------------------------------------- /virtual_scanner/cpp/libvirtualscanner/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.3) 2 | project(libvirtualscanner VERSION 18.10.09 LANGUAGES CXX) 3 | 4 | if(NOT VCPKG_TOOLCHAIN) 5 | list(INSERT CMAKE_MODULE_PATH 0 ${CMAKE_CURRENT_SOURCE_DIR}/cmake) 6 | endif() 7 | 8 | ################################################## 9 | # Dependencies 10 | find_package(Boost REQUIRED COMPONENTS system) 11 | find_package(Eigen3 REQUIRED) 12 | find_package(CGAL REQUIRED) 13 | ################################################## 14 | 15 | add_library(virtualscanner 16 | src/virtual_scanner.cpp 17 | src/points.cpp) 18 | 19 | add_library(OCNN::VirtualScanner ALIAS virtualscanner) 20 | 21 | target_include_directories(virtualscanner 22 | PUBLIC 23 | $ 24 | $ 25 | PRIVATE 26 | ${CMAKE_CURRENT_SOURCE_DIR}/src) 27 | 28 | target_compile_features(virtualscanner PUBLIC cxx_nullptr) 29 | target_compile_options(virtualscanner 30 | PRIVATE 31 | $<$:-Wall -fPIC -Wno-sign-compare -Wno-uninitialized -frounding-math> 32 | $<$: /Wall>) 33 | 34 | target_link_libraries(virtualscanner 35 | PUBLIC 36 | Eigen3::Eigen 37 | PRIVATE 38 | Boost::system 39 | CGAL::CGAL) 40 | -------------------------------------------------------------------------------- /virtual_scanner/cpp/virtualscanner/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.3) 2 | 3 | add_definitions(-DCGAL_DISABLE_ROUNDING_MATH_CHECK) 4 | 5 | add_executable(virtualscannerexe src/main.cpp) 6 | 7 | target_compile_features(virtualscannerexe PRIVATE cxx_auto_type) 8 | 9 | find_package(Boost REQUIRED COMPONENTS filesystem) 10 | find_package(OpenMP REQUIRED) 11 | 12 | set_target_properties(virtualscannerexe PROPERTIES 13 | OUTPUT_NAME "virtualscanner" 14 | RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" 15 | ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}") 16 | 17 | target_compile_options(virtualscannerexe 18 | PRIVATE 19 | $<$:-Wall -fPIC -Wno-sign-compare -Wno-uninitialized -frounding-math> 20 | $<$: /Wall>) 21 | 22 | if(NOT TARGET OpenMP::OpenMP_CXX) 23 | find_package(Threads REQUIRED) 24 | add_library(OpenMP::OpenMP_CXX IMPORTED INTERFACE) 25 | set_property(TARGET OpenMP::OpenMP_CXX 26 | PROPERTY INTERFACE_COMPILE_OPTIONS ${OpenMP_CXX_FLAGS}) 27 | # Only works if the same flag is passed to the linker; use CMake 3.9+ otherwise (Intel, AppleClang) 28 | set_property(TARGET OpenMP::OpenMP_CXX 29 | PROPERTY INTERFACE_LINK_LIBRARIES ${OpenMP_CXX_FLAGS} Threads::Threads) 30 | endif() 31 | 32 | target_link_libraries(virtualscannerexe 33 | PRIVATE 34 | OpenMP::OpenMP_CXX 35 | Boost::filesystem 36 | OCNN::VirtualScanner) 37 | 38 | -------------------------------------------------------------------------------- /virtual_scanner/cpp/libvirtualscanner/libvirtualscanner.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | {0abfb204-0fb6-43df-bb78-6d1761606f28} 18 | 19 | 20 | 21 | 22 | Header Files\virtual_scanner 23 | 24 | 25 | Header Files\virtual_scanner 26 | 27 | 28 | 29 | 30 | Source Files 31 | 32 | 33 | Source Files 34 | 35 | 36 | -------------------------------------------------------------------------------- /virtual_scanner/python/ocnn/virtualscanner/_virtualscanner.pyx: -------------------------------------------------------------------------------- 1 | from ocnn.virtualscanner cimport _virtualscanner_extern 2 | from libcpp.string cimport string 3 | from libcpp cimport bool 4 | from ocnn.virtualscanner.scanner_settings import ScannerSettings 5 | 6 | cdef class VirtualScanner: 7 | """ 8 | Creates points/normals file from obj or off files 9 | """ 10 | cdef _virtualscanner_extern.VirtualScanner c_scanner 11 | 12 | def __cinit__(self, filepath, int view_num=6, bool flags=False, bool normalize=False): 13 | """ 14 | Scans obj/off file into a points/normal format 15 | 16 | Args: 17 | filepath (str): File path of obj/off file to convert. 18 | view_num (int): The number of views for scanning 19 | flags (bool): Indicate whether to output normal flipping flag 20 | normalize (bool): Indicate whether to normalize input mesh 21 | """ 22 | 23 | cdef string stl_string = filepath.encode('UTF-8') 24 | with nogil: 25 | self.c_scanner.scanning(stl_string, view_num, flags, normalize) 26 | 27 | @classmethod 28 | def from_scanner_settings(self, filepath, scanner_settings): 29 | """ 30 | Scans obj/off file into a points/normal format 31 | 32 | Args: 33 | filepath (str): File path of obj/off file to convert. 34 | scanner_settings (ScannerSettings): Virtual scanner settings. 35 | """ 36 | return VirtualScanner(filepath=filepath, 37 | view_num=scanner_settings.view_num, 38 | flags=scanner_settings.flags, 39 | normalize=scanner_settings.normalize) 40 | 41 | def save(self, output_path): 42 | """ 43 | Saves out to points/normals file. 44 | 45 | Args: 46 | output_path (str): Path where to save points file. 47 | """ 48 | 49 | cdef string stl_string = output_path.encode('UTF-8') 50 | with nogil: 51 | self.c_scanner.save_binary(stl_string) 52 | -------------------------------------------------------------------------------- /densecrf/examples/common.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2013, Philipp Krähenbühl 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * Neither the name of the Stanford University nor the 13 | names of its contributors may be used to endorse or promote products 14 | derived from this software without specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY Philipp Krähenbühl ''AS IS'' AND ANY 17 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL Philipp Krähenbühl BE LIABLE FOR ANY 20 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | #pragma once 28 | 29 | #include "densecrf.h" 30 | VectorXs getLabeling( const unsigned char * im, int N, int M ); 31 | unsigned char * colorize( const VectorXs & labeling, int W, int H ); 32 | void load_pointcloud(MatrixXf& pt, MatrixXf& normal, 33 | VectorXs& label, const std::string& filename); 34 | void load_prob(MatrixXf& prob, const std::string& filename); 35 | void save_label(const VectorXs& map, const std::string& filename); 36 | void get_all_filenames(std::vector& _all_filenames, std::string _filename); 37 | -------------------------------------------------------------------------------- /virtual_scanner/python/ocnn/virtualscanner/scanner_settings.py: -------------------------------------------------------------------------------- 1 | """ Module to manage ScannerSettings """ 2 | 3 | from __future__ import absolute_import 4 | from __future__ import division 5 | from __future__ import print_function 6 | 7 | import yaml 8 | 9 | class ScannerSettings: 10 | """ Loads, writes and compares ScannerSettings """ 11 | def __init__(self, 12 | view_num=6, 13 | flags=False, 14 | normalize=False): 15 | """ Initializes ScannerSettings 16 | Args: 17 | view_num (int): The number of view points to scan from. 18 | flags (bool): Indicate whether to ouput normal flipping flag. 19 | normalize (bool): Normalize maximum extents of mesh to 1. 20 | """ 21 | self.view_num = view_num 22 | self.flags = flags 23 | self.normalize = normalize 24 | 25 | @classmethod 26 | def from_yaml(cls, yml_filepath): 27 | """ Creates ScannerSettings from YAML 28 | Args: 29 | yml_filepath: Path to yml config file. 30 | """ 31 | with open(yml_filepath, 'r') as yml_file: 32 | config = yaml.load(yml_file) 33 | 34 | parameters = config['scanner_settings'] 35 | return cls(view_num=parameters['view_num'], 36 | flags=parameters['flags'], 37 | normalize=parameters['normalize']) 38 | 39 | def write_yaml(self, yml_filepath): 40 | """ Writes ScannerSettings to YAML 41 | Args: 42 | yml_filepath: Filepath to output settings 43 | """ 44 | data = {'scanner_settings': { 45 | 'view_num': self.view_num, 46 | 'flags': self.flags, 47 | 'normalize': self.normalize}} 48 | with open(yml_filepath, 'w') as yml_file: 49 | yaml.dump(data, yml_file, default_flow_style=False) 50 | 51 | def __eq__(self, other): 52 | if self.__class__ is other.__class__: 53 | return (self.view_num == other.view_num and 54 | self.flags == other.flags and 55 | self.normalize == other.normalize) 56 | return NotImplemented 57 | 58 | def __ne__(self, other): 59 | return not self == other 60 | -------------------------------------------------------------------------------- /virtual_scanner/cpp/libvirtualscanner/include/virtual_scanner/points.h: -------------------------------------------------------------------------------- 1 | #ifndef _OCTREE_POINTS_ 2 | #define _OCTREE_POINTS_ 3 | 4 | #include 5 | #include 6 | 7 | using std::vector; 8 | using std::string; 9 | 10 | class PtsInfo { 11 | public: 12 | enum PropType { kPoint = 1, kNormal = 2, kFeature = 4, kLabel = 8 }; 13 | static const int kPTypeNum = 4; 14 | static const char kMagicStr[16]; 15 | 16 | public: 17 | PtsInfo() { reset(); } 18 | void reset(); 19 | bool check_format(string& msg) const; 20 | bool has_property(PropType ptype) const { 21 | return (content_flags_ & ptype) != 0; 22 | } 23 | 24 | int pt_num() const { return pt_num_; } 25 | int channel(PropType ptype) const; 26 | int ptr_dis(PropType ptype) const; 27 | int sizeof_points() const { return ptr_dis_[kPTypeNum]; } 28 | 29 | void set_pt_num(int num) { pt_num_ = num; } 30 | void set_channel(PropType ptype, const int ch); 31 | void set_ptr_dis(); 32 | 33 | protected: 34 | int property_index(PropType ptype) const; 35 | 36 | protected: 37 | char magic_str_[16]; 38 | int pt_num_; 39 | int content_flags_; 40 | int channels_[8]; 41 | int ptr_dis_[8]; 42 | }; 43 | 44 | 45 | class Points { 46 | public: 47 | Points() : info_(nullptr), buffer_() {} 48 | bool is_empty() const { return info_ == nullptr || info_->pt_num() == 0; } 49 | 50 | // the pts must not be empty, the labels may be empty, 51 | // the normals & features must not be empty at the same time. 52 | bool set_points(const vector& pts, const vector& normals, 53 | const vector& features = vector(), 54 | const vector& labels = vector()); 55 | void set_points(vector& data); // swap data and buffer_ 56 | 57 | bool read_points(const string& filename); 58 | bool write_points(const string& filename) const; 59 | bool write_ply(const string& filename) const; 60 | 61 | const PtsInfo& info() const { return *info_; } 62 | const float* ptr(PtsInfo::PropType ptype) const; 63 | float* mutable_ptr(PtsInfo::PropType ptype); 64 | 65 | void centralize(const float* center); 66 | void displace(const float dis); 67 | void rotate(const float angle, const float* axis); 68 | 69 | protected: 70 | PtsInfo* info_; 71 | vector buffer_; 72 | }; 73 | 74 | #endif // _OCTREE_POINTS_ -------------------------------------------------------------------------------- /virtual_scanner/cpp/virtualscanner/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "virtual_scanner/virtual_scanner.h" 6 | 7 | using namespace std; 8 | 9 | void get_all_filenames(vector& _all_filenames, string _filename); 10 | 11 | int main(int argc, char* argv[]) { 12 | if (argc < 2) { 13 | cout << "Usage: VirtualScanner.exe " 14 | "[view_num] [flags] [normalize]" << endl; 15 | return 0; 16 | } 17 | string filename(argv[1]); 18 | 19 | int view_num = 6; // scanning view number 20 | if (argc >= 3) view_num = atoi(argv[2]); 21 | 22 | bool flag = false; // output normal flipping flag 23 | if (argc >= 4) flag = atoi(argv[3]); 24 | 25 | bool normalize = false; // normalize input meshes 26 | if (argc >= 5) normalize = atoi(argv[4]); 27 | 28 | vector all_files; 29 | get_all_filenames(all_files, filename); 30 | 31 | #pragma omp parallel for 32 | for (int i = 0; i < all_files.size(); i++) { 33 | clock_t t1 = clock(); 34 | VirtualScanner scanner; 35 | scanner.scanning(all_files[i], view_num, flag, normalize); 36 | string out_path = all_files[i].substr(0, all_files[i].rfind('.')); 37 | scanner.save_binary(out_path+ ".points"); 38 | clock_t t2 = clock(); 39 | 40 | string messg = all_files[i].substr(all_files[i].rfind('\\') + 1) + 41 | " done! Time: " + to_string(t2 - t1) + "\n"; 42 | #pragma omp critical 43 | cout << messg; 44 | } 45 | 46 | return 0; 47 | } 48 | 49 | bool is_convertable_file(string extension) { 50 | return extension.compare(".off") == 0 || extension.compare(".obj") == 0; 51 | } 52 | 53 | void get_all_filenames(vector& _all_filenames, string _filename) { 54 | using namespace boost::filesystem; 55 | 56 | if (is_regular_file(_filename)) { 57 | _all_filenames.push_back(_filename); 58 | } else if (is_directory(_filename)) { 59 | for (auto& file : recursive_directory_iterator(_filename)) { 60 | auto extension = file.path().extension().string(); 61 | std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower); 62 | if (is_regular_file(file) && is_convertable_file(extension)) { 63 | _all_filenames.push_back(file.path().string()); 64 | } 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /virtual_scanner/VirtualScanner.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27703.2035 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libvirtualscanner", "cpp\libvirtualscanner\libvirtualscanner.vcxproj", "{132C8DB6-16EE-48B2-9D52-0A6D5777854E}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "virtualscanner", "cpp\virtualscanner\virtualscanner.vcxproj", "{8C7CF56A-4830-4858-A90E-5DA7BE887951}" 9 | ProjectSection(ProjectDependencies) = postProject 10 | {132C8DB6-16EE-48B2-9D52-0A6D5777854E} = {132C8DB6-16EE-48B2-9D52-0A6D5777854E} 11 | EndProjectSection 12 | EndProject 13 | Global 14 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 15 | Debug|x64 = Debug|x64 16 | Debug|x86 = Debug|x86 17 | Release|x64 = Release|x64 18 | Release|x86 = Release|x86 19 | EndGlobalSection 20 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 21 | {132C8DB6-16EE-48B2-9D52-0A6D5777854E}.Debug|x64.ActiveCfg = Debug|x64 22 | {132C8DB6-16EE-48B2-9D52-0A6D5777854E}.Debug|x64.Build.0 = Debug|x64 23 | {132C8DB6-16EE-48B2-9D52-0A6D5777854E}.Debug|x86.ActiveCfg = Debug|Win32 24 | {132C8DB6-16EE-48B2-9D52-0A6D5777854E}.Debug|x86.Build.0 = Debug|Win32 25 | {132C8DB6-16EE-48B2-9D52-0A6D5777854E}.Release|x64.ActiveCfg = Release|x64 26 | {132C8DB6-16EE-48B2-9D52-0A6D5777854E}.Release|x64.Build.0 = Release|x64 27 | {132C8DB6-16EE-48B2-9D52-0A6D5777854E}.Release|x86.ActiveCfg = Release|Win32 28 | {132C8DB6-16EE-48B2-9D52-0A6D5777854E}.Release|x86.Build.0 = Release|Win32 29 | {8C7CF56A-4830-4858-A90E-5DA7BE887951}.Debug|x64.ActiveCfg = Debug|x64 30 | {8C7CF56A-4830-4858-A90E-5DA7BE887951}.Debug|x64.Build.0 = Debug|x64 31 | {8C7CF56A-4830-4858-A90E-5DA7BE887951}.Debug|x86.ActiveCfg = Debug|Win32 32 | {8C7CF56A-4830-4858-A90E-5DA7BE887951}.Debug|x86.Build.0 = Debug|Win32 33 | {8C7CF56A-4830-4858-A90E-5DA7BE887951}.Release|x64.ActiveCfg = Release|x64 34 | {8C7CF56A-4830-4858-A90E-5DA7BE887951}.Release|x64.Build.0 = Release|x64 35 | {8C7CF56A-4830-4858-A90E-5DA7BE887951}.Release|x86.ActiveCfg = Release|Win32 36 | {8C7CF56A-4830-4858-A90E-5DA7BE887951}.Release|x86.Build.0 = Release|Win32 37 | EndGlobalSection 38 | GlobalSection(SolutionProperties) = preSolution 39 | HideSolutionNode = FALSE 40 | EndGlobalSection 41 | GlobalSection(ExtensibilityGlobals) = postSolution 42 | SolutionGuid = {DABA4831-F74D-45E8-8285-D16D5959FF61} 43 | EndGlobalSection 44 | EndGlobal 45 | -------------------------------------------------------------------------------- /virtual_scanner/cpp/libvirtualscanner/cmake/FindCGAL.cmake: -------------------------------------------------------------------------------- 1 | # - Find CGAL 2 | # Find the CGAL includes and client library 3 | # This module defines 4 | # CGAL_INCLUDE_DIR, where to find CGAL.h 5 | # CGAL_LIBRARIES, the libraries needed to use CGAL. 6 | # CGAL_FOUND, If false, do not try to use CGAL. 7 | 8 | if(CGAL_INCLUDE_DIR AND CGAL_LIBRARIES AND BOOST_THREAD_LIBRARIES AND GMP_LIBRARIES) 9 | set(CGAL_FOUND TRUE) 10 | 11 | else(CGAL_INCLUDE_DIR AND CGAL_LIBRARIES AND BOOST_THREAD_LIBRARIES AND GMP_LIBRARIES) 12 | 13 | FIND_PATH(CGAL_INCLUDE_DIR CGAL/basic.h 14 | ${CGAL_ROOT}/include 15 | /usr/include 16 | /usr/local/include 17 | $ENV{ProgramFiles}/CGAL/*/include 18 | $ENV{SystemDrive}/CGAL/*/include 19 | ) 20 | 21 | find_library(CGAL_LIBRARIES NAMES CGAL libCGAL 22 | PATHS 23 | ${CGAL_ROOT}/lib 24 | /usr/lib 25 | /usr/local/lib 26 | /usr/lib/CGAL 27 | /usr/lib64 28 | /usr/local/lib64 29 | /usr/lib64/CGAL 30 | $ENV{ProgramFiles}/CGAL/*/lib 31 | $ENV{SystemDrive}/CGAL/*/lib 32 | ) 33 | 34 | # set(Boost_DEBUG ON) 35 | find_package(Boost COMPONENTS thread REQUIRED) 36 | if(Boost_FOUND) 37 | set(BOOST_THREAD_LIBRARIES ${Boost_LIBRARIES}) 38 | endif(Boost_FOUND) 39 | 40 | # check boost version we may need other components 41 | if("${Boost_VERSION}" VERSION_GREATER "104900") 42 | find_package(Boost COMPONENTS thread system REQUIRED) 43 | if(Boost_FOUND) 44 | set(BOOST_THREAD_LIBRARIES ${Boost_LIBRARIES}) 45 | endif(Boost_FOUND) 46 | endif("${Boost_VERSION}" VERSION_GREATER "104900") 47 | 48 | find_library(GMP_LIBRARIES NAMES gmp libgmp 49 | PATHS 50 | ${GMP_ROOT}/lib 51 | /usr/lib 52 | /usr/local/lib 53 | /usr/lib/gmp 54 | /usr/lib64 55 | /usr/local/lib64 56 | /usr/lib64/gmp 57 | $ENV{ProgramFiles}/gmp/*/lib 58 | $ENV{SystemDrive}/gmp/*/lib 59 | ) 60 | 61 | message(STATUS "CGAL_INCLUDE_DIR=${CGAL_INCLUDE_DIR}") 62 | message(STATUS "CGAL_LIBRARIES=${CGAL_LIBRARIES}") 63 | message(STATUS "BOOST_THREAD_LIBRARIES=${BOOST_THREAD_LIBRARIES}") 64 | message(STATUS "GMP_LIBRARIES=${GMP_LIBRARIES}") 65 | 66 | if(CGAL_INCLUDE_DIR AND CGAL_LIBRARIES AND BOOST_THREAD_LIBRARIES AND GMP_LIBRARIES) 67 | set(CGAL_FOUND TRUE) 68 | message(STATUS "Found CGAL: ${CGAL_INCLUDE_DIR}, ${CGAL_LIBRARIES}, ${BOOST_THREAD_LIBRARIES}, ${GMP_LIBRARIES}") 69 | INCLUDE_DIRECTORIES(${CGAL_INCLUDE_DIR} $ENV{CGAL_CFG}) 70 | else(CGAL_INCLUDE_DIR AND CGAL_LIBRARIES AND BOOST_THREAD_LIBRARIES AND GMP_LIBRARIES) 71 | set(CGAL_FOUND FALSE) 72 | message(STATUS "CGAL not found.") 73 | endif(CGAL_INCLUDE_DIR AND CGAL_LIBRARIES AND BOOST_THREAD_LIBRARIES AND GMP_LIBRARIES) 74 | 75 | mark_as_advanced(CGAL_INCLUDE_DIR CGAL_LIBRARIES BOOST_THREAD_LIBRARIES GMP_LIBRARIES) 76 | 77 | endif(CGAL_INCLUDE_DIR AND CGAL_LIBRARIES AND BOOST_THREAD_LIBRARIES AND GMP_LIBRARIES) 78 | 79 | if (CGAL_FOUND AND NOT TARGET CGAL::CGAL) 80 | add_library(CGAL::CGAL SHARED IMPORTED) 81 | set_target_properties(CGAL::CGAL PROPERTIES 82 | INTERFACE_INCLUDE_DIRECTORIES "${CGAL_INCLUDE_DIR}" 83 | IMPORTED_LOCATION "${CGAL_LIBRARIES}" 84 | ) 85 | endif() 86 | -------------------------------------------------------------------------------- /densecrf/examples/dense_inference.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "densecrf.h" 8 | #include "common.h" 9 | using namespace std; 10 | int class_num = 4; // The class number 11 | string data_path = ""; // "The path of training data" 12 | string parameter_path = ""; 13 | 14 | bool load_parameters(VectorXf& unary, VectorXf& pairwise, 15 | VectorXf& kernel, const string parameter_path) 16 | { 17 | ifstream infile(parameter_path); 18 | if (!infile) return false; 19 | 20 | char str[512]; 21 | vector vec_unary, vec_pairwise, vec_kernel; 22 | while (infile.getline(str, 512)) 23 | { 24 | char* pch; 25 | float tmp; 26 | pch = strtok(str, ": "); 27 | if (0 == strcmp(pch, "Unary")) 28 | { 29 | pch = strtok(NULL, ": "); // eat the word "parameters 30 | pch = strtok(NULL, ": "); 31 | while (pch != NULL) 32 | { 33 | tmp = atof(pch); 34 | vec_unary.push_back(tmp); 35 | } 36 | } 37 | else if (0 == strcmp(pch, "Pairwise")) 38 | { 39 | pch = strtok(NULL, ": "); 40 | pch = strtok(NULL, ": "); 41 | while (pch != NULL) 42 | { 43 | tmp = atof(pch); 44 | vec_pairwise.push_back(tmp); 45 | pch = strtok(NULL, ": "); 46 | 47 | } 48 | } 49 | else if (0 == strcmp(pch, "Kernel")) 50 | { 51 | pch = strtok(NULL, ": "); 52 | pch = strtok(NULL, ": "); 53 | while (pch != NULL) 54 | { 55 | tmp = atof(pch); 56 | vec_kernel.push_back(tmp); 57 | pch = strtok(NULL, ": "); 58 | } 59 | } 60 | } 61 | 62 | 63 | int n = vec_unary.size(); 64 | unary.resize(n); 65 | memcpy(unary.data(), vec_unary.data(), n * sizeof(float)); 66 | 67 | n = vec_pairwise.size(); 68 | pairwise.resize(n); 69 | memcpy(pairwise.data(), vec_pairwise.data(), n * sizeof(float)); 70 | 71 | n = vec_kernel.size(); 72 | kernel.resize(n); 73 | memcpy(kernel.data(), vec_kernel.data(), n * sizeof(float)); 74 | 75 | infile.close(); 76 | return true; 77 | } 78 | 79 | void CRFInference() 80 | { 81 | const int NIT = 5; 82 | 83 | vector all_files; 84 | get_all_filenames(all_files, data_path + "\\*.points"); 85 | 86 | VectorXf unary, pairwise, kernel; 87 | bool has_parameter = load_parameters(unary, pairwise, kernel, parameter_path); 88 | 89 | int n = all_files.size(); 90 | cout << "Inference ... "; 91 | #pragma omp parallel for 92 | for (int i = 0; i < n; ++i) 93 | { 94 | cout << "Processing: " << all_files[i] + "\n"; 95 | VectorXs label; 96 | MatrixXf pt, normal, prob; 97 | load_pointcloud(pt, normal, label, all_files[i]); 98 | 99 | string filename_prob = all_files[i]; 100 | filename_prob.replace(filename_prob.rfind('.') + 1, string::npos, "probo.txt"); 101 | load_prob(prob, filename_prob); 102 | float* ptr = prob.data(); 103 | for (int j = 0; j < prob.size(); ++j) 104 | { 105 | ptr[j] = -log(ptr[j] + 0.01f); 106 | } 107 | 108 | // build crf 109 | int num = prob.cols(); 110 | int ch = prob.rows(); 111 | PointCloudCRF pcCRF(num, ch); 112 | pcCRF.setUnaryEnergy(prob); 113 | pcCRF.addPairwiseGaussian(2, 2, 2, pt.data(), new PottsCompatibility(3)); 114 | pcCRF.addPairwiseBilateral(4, 4, 4, 0.3, 0.3, 0.3, pt.data(), normal.data(), 115 | new MatrixCompatibility(MatrixXf::Identity(ch, ch))); 116 | 117 | // set paramters 118 | if (unary.size()) pcCRF.setUnaryParameters(unary); 119 | if (pairwise.size()) pcCRF.setLabelCompatibilityParameters(pairwise); 120 | if (kernel.size()) pcCRF.setKernelParameters(kernel); 121 | 122 | // inference 123 | VectorXs map = pcCRF.map(NIT); 124 | string filename = all_files[i] + ".crf.txt"; 125 | save_label(map, filename); 126 | } 127 | 128 | cout << "Done!" << endl; 129 | } 130 | 131 | int main(int argc, char* argv[]) 132 | { 133 | if (argc < 3) 134 | { 135 | cout << "Usage: deanse_learning.exe [parameter file]"; 136 | return 0; 137 | } 138 | 139 | data_path = argv[1]; 140 | class_num = atoi(argv[2]); 141 | if (argc > 3) parameter_path = argv[3]; 142 | 143 | CRFInference(); 144 | 145 | return 0; 146 | } 147 | -------------------------------------------------------------------------------- /virtual_scanner/python/ocnn/virtualscanner/directory_tree_scanner.py: -------------------------------------------------------------------------------- 1 | """ Module to output virtual scan a whole directory. """ 2 | 3 | from __future__ import absolute_import 4 | from __future__ import division 5 | from __future__ import print_function 6 | 7 | try: 8 | from Queue import Queue 9 | except ModuleNotFoundError: 10 | from queue import Queue 11 | 12 | import os 13 | 14 | from ocnn.virtualscanner.scanner_settings import ScannerSettings 15 | from ocnn.virtualscanner._virtualscanner import VirtualScanner 16 | from threading import Thread 17 | 18 | class DirectoryTreeScanner: 19 | """ Walks a directory and converts off/obj files to points files. """ 20 | 21 | def __init__(self, view_num=6, flags=False, normalize=False): 22 | """ Initializes DirectoryTreeScanner 23 | Args: 24 | view_num (int): The number of view points to scan from. 25 | flags (bool): Indicate whether to ouput normal flipping flag. 26 | normalize (bool): Normalize maximum extents of mesh to 1. 27 | """ 28 | self.scanner_settings = ScannerSettings(view_num=view_num, 29 | flags=flags, 30 | normalize=normalize) 31 | self.scan_queue = Queue() 32 | 33 | def _scan(self): 34 | """ Creates VirtualScanner object and creates points file from obj/off """ 35 | while True: 36 | input_path, output_path = self.scan_queue.get() 37 | 38 | print('Scanning {0}'.format(input_path)) 39 | scanner = VirtualScanner.from_scanner_settings( 40 | input_path, 41 | self.scanner_settings) 42 | scanner.save(output_path) 43 | self.scan_queue.task_done() 44 | 45 | @classmethod 46 | def from_scanner_settings(cls, scanner_settings): 47 | """ Create DirectoryTreeScanner from ScannerSettings object 48 | Args: 49 | scanner_settings (ScannerSettings): ScannerSettings object 50 | """ 51 | return cls(view_num=scanner_settings.view_num, 52 | flags=scanner_settings.flags, 53 | normalize=scanner_settings.normalize) 54 | 55 | def scan_tree(self, 56 | input_base_folder, 57 | output_base_folder, 58 | num_threads=1, 59 | output_yaml_filename=''): 60 | """ Walks directory looking for obj/off files. Outputs points files for 61 | found obj/off files. 62 | 63 | Args: 64 | input_base_folder (str): Base folder to scan 65 | output_base_folder (str): Base folder to output points files in 66 | mirrored directory structure. 67 | num_threads (int): Number of threads to use to convert obj/off 68 | to points 69 | output_yaml_filename (str): If specified, saves scanner 70 | settings to given filename in base folder. 71 | """ 72 | 73 | if not os.path.exists(output_base_folder): 74 | os.mkdir(output_base_folder) 75 | elif os.listdir(output_base_folder): 76 | raise RuntimeError('Ouput folder {0} must be empty'.format( 77 | output_base_folder)) 78 | 79 | if output_yaml_filename: 80 | self.scanner_settings.write_yaml( 81 | os.path.join(output_base_folder, output_yaml_filename)) 82 | 83 | for _ in range(num_threads): 84 | scan_thread = Thread(target=self._scan) 85 | scan_thread.daemon = True 86 | scan_thread.start() 87 | 88 | for root, _, files in os.walk(input_base_folder): 89 | rel_path = os.path.relpath(root, input_base_folder) 90 | 91 | output_folder = os.path.join(output_base_folder, rel_path) 92 | if not os.path.exists(output_folder): 93 | os.mkdir(output_folder) 94 | 95 | for filename in files: 96 | basename, extension = os.path.splitext(filename) 97 | extension = extension.lower() 98 | if extension == '.obj' or extension == '.off': 99 | outfilename = basename + '.points' 100 | input_path = os.path.join(root, filename) 101 | output_path = os.path.join(output_folder, outfilename) 102 | self.scan_queue.put((input_path, output_path)) 103 | self.scan_queue.join() 104 | -------------------------------------------------------------------------------- /densecrf/examples/common.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2013, Philipp Krähenbühl 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * Neither the name of the Stanford University nor the 13 | names of its contributors may be used to endorse or promote products 14 | derived from this software without specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY Philipp Krähenbühl ''AS IS'' AND ANY 17 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL Philipp Krähenbühl BE LIABLE FOR ANY 20 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | #include "common.h" 28 | #include 29 | #include 30 | #include 31 | using namespace std; 32 | 33 | 34 | // Store the colors we read, so that we can write them again. 35 | int nColors = 0; 36 | int colors[255]; 37 | int getColor( const unsigned char * c ){ 38 | return c[0] + 256*c[1] + 256*256*c[2]; 39 | } 40 | void putColor( unsigned char * c, int cc ){ 41 | c[0] = cc&0xff; c[1] = (cc>>8)&0xff; c[2] = (cc>>16)&0xff; 42 | } 43 | // Produce a color image from a bunch of labels 44 | unsigned char * colorize( const VectorXs & labeling, int W, int H ){ 45 | unsigned char * r = new unsigned char[ W*H*3 ]; 46 | for( int k=0; k buffer(n); 90 | infile.read((char*)buffer.data(), sizeof(int)*n); 91 | for (int i = 0; i < n; ++i) 92 | { 93 | label[i] = buffer[i]; 94 | } 95 | 96 | infile.close(); 97 | } 98 | 99 | void load_prob(MatrixXf& prob, const string& filename) 100 | { 101 | ifstream infile(filename, ios::binary); 102 | if (!infile) cout << "Open file error: " << filename << endl; 103 | 104 | int c, n; 105 | infile.read((char*)(&c), sizeof(int)); 106 | infile.read((char*)(&n), sizeof(int)); 107 | 108 | prob.resize(c, n); 109 | infile.read((char*)prob.data(), sizeof(int)*prob.size()); 110 | 111 | infile.close(); 112 | } 113 | 114 | void save_label(const VectorXs& map, const string& filename) 115 | { 116 | ofstream outfile(filename); 117 | for (int i = 0; i < map.size(); ++i) 118 | { 119 | outfile << map[i] << endl; 120 | } 121 | outfile.close(); 122 | } 123 | 124 | void get_all_filenames(vector& _all_filenames, string _filename) 125 | { 126 | // reset data 127 | _all_filenames.clear(); 128 | 129 | // find 130 | size_t p0 = _filename.rfind('\\') + 1; 131 | size_t p1 = _filename.rfind('.'); 132 | 133 | // file path 134 | string file_path(_filename, 0, p0); 135 | 136 | // get the regular expression 137 | _filename.replace(p0, p1 - p0, "*"); 138 | 139 | // find all the file 140 | _finddata_t c_file; 141 | intptr_t hFile = _findfirst(_filename.c_str(), &c_file); 142 | do 143 | { 144 | if (hFile == -1) break; 145 | _all_filenames.push_back(file_path + std::string(c_file.name)); 146 | } while (_findnext(hFile, &c_file) == 0); 147 | _findclose(hFile); 148 | } 149 | -------------------------------------------------------------------------------- /virtual_scanner/README.md: -------------------------------------------------------------------------------- 1 | # Virtual scanner for converting 3D model to point cloud 2 | 3 | 4 | This folder contains the code for converting the 3D models to dense point clouds with normals (\*.points). As detailed in our paper, we build a virtual scanner and shoot rays to calculate the intersection point and oriented normal. 5 | 6 | The code is based on [Boost](https://www.boost.org/), [CGAL](http://www.cgal.org/) and the [Eigen](http://eigen.tuxfamily.org/index.php?title=Main_Page) libraries. After configuring these three libraries properly, the code can be built with visual studio easily. 7 | 8 | `Note`: 9 | 1. Sometimes, the executive file might collapse when the scale of the mesh is very large. This is one bug of CGAL. In order to mitigate this you can run VirtualScanner with the normalize flag set to 1. 10 | 2. The format of some off files in the `ModelNet40` is invalid. Before running the virtual scanner, fix the `ModelNet40` with this [script](https://github.com/Microsoft/O-CNN/blob/master/ocnn/octree/python/ocnn/utils/off_utils.py). 11 | 12 | 13 | ## Running Virtual Scanner 14 | ### Executable 15 | The pre-built executive file is contained in the folder `prebuilt_binaries`, which has been test on the Win10 x64 system. 16 | 17 | Usage: 18 | VirtualScanner.exe [nviews] [flags] [normalize] 19 | file_name: the name of the file (*.obj; *.off) to be processed. 20 | nviews: the number of views for scanning. Default: 6 21 | flags: Indicate whether to output normal flipping flag. Default: 0 22 | normalize: Indicate whether to normalize input mesh. Default: 0 23 | Example: 24 | VirtualScanner.exe input.obj 14 // process the file input.obj 25 | VirtualScanner.exe D:\data\ 14 // process all the obj/off files under the folder D:\Data 26 | 27 | 28 | ### Python 29 | You can also use python to convert 'off' and 'obj' files. 30 | 31 | Example usage (single file): 32 | # Converts obj/off file to points 33 | from ocnn.virtualscanner import VirtualScanner 34 | scanner = VirtualScanner(filepath="input.obj", view_num=14, flags=False, normalize=True) 35 | scanner.save(output_path="output.points") 36 | 37 | Example usage (directory tree): 38 | # Converts all obj/off files in directory tree to points 39 | from ocnn.virtualscanner import DirectoryTreeScanner 40 | scanner = DirectoryTreeScanner(view_num=6, flags=False, normalize=True) 41 | scanner.scan_tree(input_base_folder='/ModelNet10', output_base_folder='/ModelNet10Points', num_threads=8) 42 | 43 | 44 | ## Output of Virtual Scanner 45 | The result is in the format of `points`, which can be parsed with the following: 46 | 47 | ### CPP 48 | ```cpp 49 | #include "virtual_scanner/points.h" 50 | 51 | // ... 52 | // Specify the filename of the points 53 | string filename = "your_pointcloud.points"; 54 | 55 | // Load points 56 | Points points; 57 | points.read_points(filename) 58 | 59 | // Point number 60 | int n = points.info().pt_num(); 61 | 62 | // Whether does the file contain point coordinates? 63 | bool has_points = points.info().has_property(PtsInfo::kPoint); 64 | // Get the pointer to points: x_1, y_1, z_1, ..., x_n, y_n, z_n 65 | const float* ptr_points = points.ptr(PtsInfo::kPoint); 66 | 67 | // Whether does the file contain normals? 68 | bool has_normals = points.info().has_property(PtsInfo::kNormal); 69 | // Get the pointer to normals: nx_1, ny_1, nz_1, ..., nx_n, ny_n, nz_n 70 | const float* ptr_points = points.ptr(PtsInfo::kNormal); 71 | 72 | // Whether does the file contain per-point labels? 73 | bool has_labels = points.info().has_property(PtsInfo::kLabel); 74 | // Get the pointer to labels: label_1, label_2, ..., label_n 75 | const float* ptr_labels = points.ptr(PtsInfo::kLabel); 76 | ``` 77 | 78 | ### Python 79 | The Microsoft repo [O-CNN](https://github.com/Microsoft/O-CNN) contains the `ocnn.ocnn_base` package which defines a `Points` class under `ocnn.octree`. You can use this class to manipulate the points files and generate octrees. 80 | 81 | ## Building/Installing 82 | ### Building On Windows 83 | To build in Windows you can, 84 | 85 | 1. Edit the project files to point to Boost, Eigen and CGAL, 86 | 87 | or 88 | 89 | 2. Use [Vcpkg](https://github.com/Microsoft/vcpkg) to install/build all the dependencies (note this takes a long time). 90 | ``` 91 | git clone https://github.com/Microsoft/vcpkg 92 | cd vcpkg 93 | .\bootstrap-vcpkg.bat 94 | .\vcpkg integrate install 95 | .\vcpkg install cgal eigen3 boost-system boost-filesystem --triplet x64-windows 96 | ``` 97 | Then to build, you can use the supplied solution file VirtualScanner.sln 98 | 99 | 100 | ### Building On Ubuntu 101 | To build with ubuntu, you can use apt for the dependencies. 102 | ``` 103 | apt-get install -y --no-install-recommends libboost-all-dev libcgal-dev libeigen3-dev 104 | ``` 105 | Then you can use cmake to build the executable 106 | From this project's directory, 107 | ``` 108 | mkdir build 109 | cd build 110 | cmake -DCMAKE_BUILD_TYPE=Release .. 111 | make 112 | ``` 113 | ### Installing Python Package 114 | To install the python package you need to ensure that Eigen and CGAL can be found by cmake. If you used Vcpkg or apt-get to retrieve those libraries it should automatically find it. 115 | 116 | With that ensured, 117 | 118 | **Dependencies install via VCPKG** 119 | ``` 120 | pip install scikit-build cmake Cython 121 | pip install --install-option="--" --install-option="-DCMAKE_TOOLCHAIN_FILE=\scripts\buildsystems\vcpkg.cmake" . 122 | ``` 123 | Where is the directory you install VCPKG. 124 | 125 | **Dependencies install via apt-get** 126 | ``` 127 | pip install scikit-build cmake Cython 128 | pip install . 129 | ``` 130 | 131 | If you use our code, please cite our paper. 132 | 133 | @article {Wang-2017-OCNN, 134 | title = {O-CNN: Octree-based Convolutional Neural Networks for 3D Shape Analysis}, 135 | author = {Wang, Peng-Shuai and Liu, Yang and Guo, Yu-Xiao and Sun, Chun-Yu and Tong, Xin}, 136 | journal = {ACM Transactions on Graphics (SIGGRAPH)}, 137 | volume = {36}, 138 | number = {4}, 139 | year = {2017}, 140 | } 141 | 142 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.suo 8 | *.user 9 | *.userosscache 10 | *.sln.docstates 11 | 12 | # User-specific files (MonoDevelop/Xamarin Studio) 13 | *.userprefs 14 | 15 | # Build results 16 | [Dd]ebug/ 17 | [Dd]ebugPublic/ 18 | [Rr]elease/ 19 | [Rr]eleases/ 20 | x64/ 21 | x86/ 22 | bld/ 23 | [Bb]in/ 24 | [Oo]bj/ 25 | [Ll]og/ 26 | 27 | # Visual Studio 2015 cache/options directory 28 | .vs/ 29 | # Uncomment if you have tasks that create the project's static files in wwwroot 30 | #wwwroot/ 31 | 32 | # MSTest test Results 33 | [Tt]est[Rr]esult*/ 34 | [Bb]uild[Ll]og.* 35 | 36 | # NUNIT 37 | *.VisualState.xml 38 | TestResult.xml 39 | 40 | # Build Results of an ATL Project 41 | [Dd]ebugPS/ 42 | [Rr]eleasePS/ 43 | dlldata.c 44 | 45 | # .NET Core 46 | project.lock.json 47 | project.fragment.lock.json 48 | artifacts/ 49 | **/Properties/launchSettings.json 50 | 51 | *_i.c 52 | *_p.c 53 | *_i.h 54 | *.ilk 55 | *.meta 56 | *.obj 57 | *.pch 58 | *.pdb 59 | *.pgc 60 | *.pgd 61 | *.rsp 62 | *.sbr 63 | *.tlb 64 | *.tli 65 | *.tlh 66 | *.tmp 67 | *.tmp_proj 68 | *.log 69 | *.vspscc 70 | *.vssscc 71 | .builds 72 | *.pidb 73 | *.svclog 74 | *.scc 75 | 76 | # Chutzpah Test files 77 | _Chutzpah* 78 | 79 | # Visual C++ cache files 80 | ipch/ 81 | *.aps 82 | *.ncb 83 | *.opendb 84 | *.opensdf 85 | *.sdf 86 | *.cachefile 87 | *.VC.db 88 | *.VC.VC.opendb 89 | 90 | # Visual Studio profiler 91 | *.psess 92 | *.vsp 93 | *.vspx 94 | *.sap 95 | 96 | # TFS 2012 Local Workspace 97 | $tf/ 98 | 99 | # Guidance Automation Toolkit 100 | *.gpState 101 | 102 | # ReSharper is a .NET coding add-in 103 | _ReSharper*/ 104 | *.[Rr]e[Ss]harper 105 | *.DotSettings.user 106 | 107 | # JustCode is a .NET coding add-in 108 | .JustCode 109 | 110 | # TeamCity is a build add-in 111 | _TeamCity* 112 | 113 | # DotCover is a Code Coverage Tool 114 | *.dotCover 115 | 116 | # Visual Studio code coverage results 117 | *.coverage 118 | *.coveragexml 119 | 120 | # NCrunch 121 | _NCrunch_* 122 | .*crunch*.local.xml 123 | nCrunchTemp_* 124 | 125 | # MightyMoose 126 | *.mm.* 127 | AutoTest.Net/ 128 | 129 | # Web workbench (sass) 130 | .sass-cache/ 131 | 132 | # Installshield output folder 133 | [Ee]xpress/ 134 | 135 | # DocProject is a documentation generator add-in 136 | DocProject/buildhelp/ 137 | DocProject/Help/*.HxT 138 | DocProject/Help/*.HxC 139 | DocProject/Help/*.hhc 140 | DocProject/Help/*.hhk 141 | DocProject/Help/*.hhp 142 | DocProject/Help/Html2 143 | DocProject/Help/html 144 | 145 | # Click-Once directory 146 | publish/ 147 | 148 | # Publish Web Output 149 | *.[Pp]ublish.xml 150 | *.azurePubxml 151 | # TODO: Comment the next line if you want to checkin your web deploy settings 152 | # but database connection strings (with potential passwords) will be unencrypted 153 | *.pubxml 154 | *.publishproj 155 | 156 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 157 | # checkin your Azure Web App publish settings, but sensitive information contained 158 | # in these scripts will be unencrypted 159 | PublishScripts/ 160 | 161 | # NuGet Packages 162 | *.nupkg 163 | # The packages folder can be ignored because of Package Restore 164 | **/packages/* 165 | # except build/, which is used as an MSBuild target. 166 | !**/packages/build/ 167 | # Uncomment if necessary however generally it will be regenerated when needed 168 | #!**/packages/repositories.config 169 | # NuGet v3's project.json files produces more ignorable files 170 | *.nuget.props 171 | *.nuget.targets 172 | 173 | # Microsoft Azure Build Output 174 | csx/ 175 | *.build.csdef 176 | 177 | # Microsoft Azure Emulator 178 | ecf/ 179 | rcf/ 180 | 181 | # Windows Store app package directories and files 182 | AppPackages/ 183 | BundleArtifacts/ 184 | Package.StoreAssociation.xml 185 | _pkginfo.txt 186 | 187 | # Visual Studio cache files 188 | # files ending in .cache can be ignored 189 | *.[Cc]ache 190 | # but keep track of directories ending in .cache 191 | !*.[Cc]ache/ 192 | 193 | # Others 194 | ClientBin/ 195 | ~$* 196 | *~ 197 | *.dbmdl 198 | *.dbproj.schemaview 199 | *.jfm 200 | *.pfx 201 | *.publishsettings 202 | orleans.codegen.cs 203 | 204 | # Since there are multiple workflows, uncomment next line to ignore bower_components 205 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 206 | #bower_components/ 207 | 208 | # RIA/Silverlight projects 209 | Generated_Code/ 210 | 211 | # Backup & report files from converting an old project file 212 | # to a newer Visual Studio version. Backup files are not needed, 213 | # because we have git ;-) 214 | _UpgradeReport_Files/ 215 | Backup*/ 216 | UpgradeLog*.XML 217 | UpgradeLog*.htm 218 | 219 | # SQL Server files 220 | *.mdf 221 | *.ldf 222 | *.ndf 223 | 224 | # Business Intelligence projects 225 | *.rdl.data 226 | *.bim.layout 227 | *.bim_*.settings 228 | 229 | # Microsoft Fakes 230 | FakesAssemblies/ 231 | 232 | # GhostDoc plugin setting file 233 | *.GhostDoc.xml 234 | 235 | # Node.js Tools for Visual Studio 236 | .ntvs_analysis.dat 237 | node_modules/ 238 | 239 | # Typescript v1 declaration files 240 | typings/ 241 | 242 | # Visual Studio 6 build log 243 | *.plg 244 | 245 | # Visual Studio 6 workspace options file 246 | *.opt 247 | 248 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 249 | *.vbw 250 | 251 | # Visual Studio LightSwitch build output 252 | **/*.HTMLClient/GeneratedArtifacts 253 | **/*.DesktopClient/GeneratedArtifacts 254 | **/*.DesktopClient/ModelManifest.xml 255 | **/*.Server/GeneratedArtifacts 256 | **/*.Server/ModelManifest.xml 257 | _Pvt_Extensions 258 | 259 | # Paket dependency manager 260 | .paket/paket.exe 261 | paket-files/ 262 | 263 | # FAKE - F# Make 264 | .fake/ 265 | 266 | # JetBrains Rider 267 | .idea/ 268 | *.sln.iml 269 | 270 | # CodeRush 271 | .cr/ 272 | 273 | # Python Tools for Visual Studio (PTVS) 274 | __pycache__/ 275 | *.pyc 276 | 277 | # Cake - Uncomment if you are using it 278 | # tools/** 279 | # !tools/packages.config 280 | 281 | # Telerik's JustMock configuration file 282 | *.jmconfig 283 | 284 | # BizTalk build output 285 | *.btp.cs 286 | *.btm.cs 287 | *.odx.cs 288 | *.xsd.cs 289 | *.html 290 | -------------------------------------------------------------------------------- /densecrf/include/densecrf.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2013, Philipp Krähenbühl 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * Neither the name of the Stanford University nor the 13 | names of its contributors may be used to endorse or promote products 14 | derived from this software without specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY Philipp Krähenbühl ''AS IS'' AND ANY 17 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL Philipp Krähenbühl BE LIABLE FOR ANY 20 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #pragma once 29 | #include "unary.h" 30 | #include "labelcompatibility.h" 31 | #include "objective.h" 32 | #include "pairwise.h" 33 | #include 34 | 35 | /**** DenseCRF ****/ 36 | class DenseCRF{ 37 | protected: 38 | // Number of variables and labels 39 | int N_, M_; 40 | 41 | // Store the unary term 42 | UnaryEnergy * unary_; 43 | 44 | // Store all pairwise potentials 45 | std::vector pairwise_; 46 | 47 | // Don't copy this object, bad stuff will happen 48 | DenseCRF( DenseCRF & o ){} 49 | public: 50 | // Create a dense CRF model of size N with M labels 51 | DenseCRF( int N, int M ); 52 | virtual ~DenseCRF(); 53 | 54 | // Add a pairwise potential defined over some feature space 55 | // The potential will have the form: w*exp(-0.5*|f_i - f_j|^2) 56 | // The kernel shape should be captured by transforming the 57 | // features before passing them into this function 58 | // (ownership of LabelCompatibility will be transfered to this class) 59 | void addPairwiseEnergy( const MatrixXf & features, LabelCompatibility * function, KernelType kernel_type=DIAG_KERNEL, NormalizationType normalization_type=NORMALIZE_SYMMETRIC ); 60 | 61 | // Add your own favorite pairwise potential (ownership will be transfered to this class) 62 | void addPairwiseEnergy( PairwisePotential* potential ); 63 | 64 | // Set the unary potential (ownership will be transfered to this class) 65 | void setUnaryEnergy( UnaryEnergy * unary ); 66 | // Add a constant unary term 67 | void setUnaryEnergy( const MatrixXf & unary ); 68 | // Add a logistic unary term 69 | void setUnaryEnergy( const MatrixXf & L, const MatrixXf & f ); 70 | 71 | // Run inference and return the probabilities 72 | MatrixXf inference( int n_iterations ) const; 73 | 74 | // Run MAP inference and return the map for each pixel 75 | VectorXs map( int n_iterations ) const; 76 | 77 | // Step by step inference 78 | MatrixXf startInference() const; 79 | void stepInference( MatrixXf & Q, MatrixXf & tmp1, MatrixXf & tmp2 ) const; 80 | VectorXs currentMap( const MatrixXf & Q ) const; 81 | 82 | // Learning functions 83 | // Compute the gradient of the objective function over mean-field marginals with 84 | // respect to the model parameters 85 | double gradient( int n_iterations, const ObjectiveFunction & objective, VectorXf * unary_grad, VectorXf * lbl_cmp_grad, VectorXf * kernel_grad=NULL ) const; 86 | public: /* Debugging functions */ 87 | // Compute the unary energy of an assignment l 88 | VectorXf unaryEnergy( const VectorXs & l ); 89 | 90 | // Compute the pairwise energy of an assignment l (half of each pairwise potential is added to each of it's endpoints) 91 | VectorXf pairwiseEnergy( const VectorXs & l, int term=-1 ); 92 | 93 | // Compute the KL-divergence of a set of marginals 94 | double klDivergence( const MatrixXf & Q ) const; 95 | 96 | public: /* Parameters */ 97 | VectorXf unaryParameters() const; 98 | void setUnaryParameters( const VectorXf & v ); 99 | VectorXf labelCompatibilityParameters() const; 100 | void setLabelCompatibilityParameters( const VectorXf & v ); 101 | VectorXf kernelParameters() const; 102 | void setKernelParameters( const VectorXf & v ); 103 | }; 104 | 105 | class DenseCRF2D:public DenseCRF{ 106 | protected: 107 | // Width, height of the 2d grid 108 | int W_, H_; 109 | public: 110 | // Create a 2d dense CRF model of size W x H with M labels 111 | DenseCRF2D( int W, int H, int M ); 112 | virtual ~DenseCRF2D(); 113 | // Add a Gaussian pairwise potential with standard deviation sx and sy 114 | void addPairwiseGaussian( float sx, float sy, LabelCompatibility * function=NULL, KernelType kernel_type=DIAG_KERNEL, NormalizationType normalization_type=NORMALIZE_SYMMETRIC ); 115 | 116 | // Add a Bilateral pairwise potential with spacial standard deviations sx, sy and color standard deviations sr,sg,sb 117 | void addPairwiseBilateral( float sx, float sy, float sr, float sg, float sb, const unsigned char * im, LabelCompatibility * function=NULL, KernelType kernel_type=DIAG_KERNEL, NormalizationType normalization_type=NORMALIZE_SYMMETRIC ); 118 | 119 | // Set the unary potential for a specific variable 120 | using DenseCRF::setUnaryEnergy; 121 | }; 122 | 123 | class PointCloudCRF :public DenseCRF { 124 | public: 125 | // Create a 2d dense CRF model of size W x H with M labels 126 | PointCloudCRF(int N, int M); 127 | virtual ~PointCloudCRF(); 128 | // Add a Gaussian pairwise potential with standard deviation sx and sy 129 | void addPairwiseGaussian(float sx, float sy, float sz, const float* pt, LabelCompatibility * function = NULL, 130 | KernelType kernel_type = DIAG_KERNEL, NormalizationType normalization_type = NORMALIZE_SYMMETRIC); 131 | 132 | // Add a Bilateral pairwise potential with spacial standard deviations sx, sy and color standard deviations sr,sg,sb 133 | void addPairwiseBilateral(float sx, float sy, float sz, float sr, float sg, float sb, const float* pt, 134 | const float* normal, LabelCompatibility * function = NULL, 135 | KernelType kernel_type = DIAG_KERNEL, NormalizationType normalization_type = NORMALIZE_SYMMETRIC); 136 | 137 | // Set the unary potential for a specific variable 138 | using DenseCRF::setUnaryEnergy; 139 | }; -------------------------------------------------------------------------------- /virtual_scanner/cpp/libvirtualscanner/src/points.cpp: -------------------------------------------------------------------------------- 1 | #include "virtual_scanner/points.h" 2 | 3 | #include 4 | #include 5 | 6 | //////////////////////// 7 | const char PtsInfo::kMagicStr[16] = "_POINTS_1.0_"; 8 | 9 | void PtsInfo::reset() { 10 | memset(this, 0, sizeof(PtsInfo)); 11 | strcpy(magic_str_, kMagicStr); 12 | } 13 | 14 | bool PtsInfo::check_format(string& msg) const { 15 | msg.clear(); 16 | if (strcmp(kMagicStr, magic_str_) != 0) { 17 | msg += "The version of points format is not " + string(kMagicStr) + ".\n"; 18 | } 19 | if (pt_num_ < 0) { 20 | msg += "The pt_num_ should be larger than 0.\n"; 21 | } 22 | // todo: add more checks 23 | 24 | // the PtsInfo is valid when no error message is produced 25 | return msg.empty(); 26 | } 27 | 28 | int PtsInfo::channel(PropType ptype) const { 29 | int i = property_index(ptype); 30 | if (!has_property(ptype)) return 0; 31 | return channels_[i]; 32 | } 33 | 34 | void PtsInfo::set_channel(PropType ptype, const int ch) { 35 | // note: the channel and content_flags_ are consisent. 36 | // If channels_[i] != 0, then the i^th bit of content_flags_ is 1. 37 | int i = property_index(ptype); 38 | channels_[i] = ch; 39 | content_flags_ |= ptype; 40 | } 41 | 42 | int PtsInfo::ptr_dis(PropType ptype) const { 43 | int i = property_index(ptype); 44 | if (!has_property(ptype)) return -1; 45 | return ptr_dis_[i]; 46 | } 47 | 48 | void PtsInfo::set_ptr_dis() { 49 | // the accumulated pointer displacement 50 | ptr_dis_[0] = sizeof(PtsInfo); 51 | for (int i = 1; i <= kPTypeNum; ++i) { // note the " <= " is used here 52 | ptr_dis_[i] = ptr_dis_[i - 1] + sizeof(float) * pt_num_ * channels_[i - 1]; 53 | } 54 | } 55 | 56 | int PtsInfo::property_index(PropType ptype) const { 57 | int k = 0, p = ptype; 58 | for (int i = 0; i < kPTypeNum; ++i) { 59 | if (0 != (p & (1 << i))) { 60 | k = i; break; 61 | } 62 | } 63 | return k; 64 | } 65 | 66 | //////////////////////// 67 | bool Points::read_points(const string& filename) { 68 | std::ifstream infile(filename, std::ios::binary); 69 | if (!infile) return false; 70 | 71 | infile.seekg(0, infile.end); 72 | size_t len = infile.tellg(); 73 | infile.seekg(0, infile.beg); 74 | 75 | buffer_.resize(len); 76 | infile.read(buffer_.data(), len); 77 | info_ = reinterpret_cast(buffer_.data()); 78 | 79 | infile.close(); 80 | return true; 81 | } 82 | 83 | bool Points::write_points(const string& filename) const { 84 | std::ofstream outfile(filename, std::ios::binary); 85 | if (!outfile) return false; 86 | outfile.write(buffer_.data(), buffer_.size()); 87 | outfile.close(); 88 | return true; 89 | } 90 | 91 | bool Points::write_ply(const string & filename) const { 92 | std::ofstream outfile(filename, std::ios::binary); 93 | if (!outfile) return false; 94 | 95 | // write header 96 | int n = info_->pt_num(); 97 | outfile << "ply\nformat ascii 1.0\nelement vertex " << n 98 | << "\nproperty float x\nproperty float y\nproperty float z\n" 99 | << "property float nx\nproperty float ny\nproperty float nz\n" 100 | << "element face 0\nproperty list uchar int vertex_indices\n" 101 | << "end_header" << std::endl; 102 | 103 | // wirte contents 104 | const int len = 128; 105 | vector str(n * len, 0); 106 | char* pstr = str.data(); 107 | const float* pts = ptr(PtsInfo::kPoint); 108 | const float* normals = ptr(PtsInfo::kNormal); 109 | for (int i = 0; i < n; ++i) { 110 | sprintf(pstr + i * len, 111 | "%.6f %.6f %.6f %.6f %.6f %.6f\n", 112 | pts[3 * i], pts[3 * i + 1], pts[3 * i + 2], 113 | normals[3 * i], normals[3 * i + 1], normals[3 * i + 2]); 114 | } 115 | int k = 0; 116 | for (int i = 0; i < n; ++i) { 117 | for (int j = len * i; j < len * (i + 1); ++j) { 118 | if (str[j] == 0) break; 119 | str[k++] = str[j]; 120 | } 121 | } 122 | outfile.write(str.data(), k); 123 | 124 | outfile.close(); 125 | return false; 126 | } 127 | 128 | const float* Points::ptr(PtsInfo::PropType ptype) const { 129 | const float* p = nullptr; 130 | int dis = info_->ptr_dis(ptype); 131 | if (-1 != dis) { 132 | p = reinterpret_cast(buffer_.data() + dis); 133 | } 134 | return p; 135 | } 136 | 137 | float* Points::mutable_ptr(PtsInfo::PropType ptype) { 138 | return const_cast(ptr(ptype)); 139 | } 140 | 141 | bool Points::set_points(const vector& pts, const vector& normals, 142 | const vector& features, const vector& labels) { 143 | /// set info 144 | int num = pts.size() / 3; 145 | // !!! Empty input is not allowed 146 | if (num == 0) return false; 147 | PtsInfo info; 148 | info.set_pt_num(num); 149 | info.set_channel(PtsInfo::kPoint, 3); 150 | 151 | if (!normals.empty()) { 152 | int c = normals.size() / num; 153 | int r = normals.size() % num; 154 | // !!! The channel of normal has to be 3 155 | if (3 != c || 0 != r) return false; 156 | info.set_channel(PtsInfo::kNormal, c); 157 | } 158 | 159 | if (!features.empty()) { 160 | int c = features.size() / num; 161 | int r = features.size() % num; 162 | // !!! The channel of normal has to larger than 0 163 | if (0 == c || 0 != r) return false; 164 | info.set_channel(PtsInfo::kFeature, c); 165 | } 166 | 167 | if (!labels.empty()) { 168 | int c = labels.size() / num; 169 | int r = labels.size() % num; 170 | // !!! The channel of label has to be 1 171 | if (1 != c || 0 != r) return false; 172 | info.set_channel(PtsInfo::kLabel, c); 173 | } 174 | 175 | info.set_ptr_dis(); 176 | 177 | /// set buffer 178 | int sz = info.sizeof_points(); 179 | buffer_.resize(sz); 180 | memcpy(buffer_.data(), &info, sizeof(PtsInfo)); 181 | info_ = reinterpret_cast(buffer_.data()); 182 | copy(pts.begin(), pts.end(), mutable_ptr(PtsInfo::kPoint)); 183 | if (!normals.empty()) { 184 | copy(normals.begin(), normals.end(), mutable_ptr(PtsInfo::kNormal)); 185 | } 186 | if (!features.empty()) { 187 | copy(features.begin(), features.end(), mutable_ptr(PtsInfo::kFeature)); 188 | } 189 | if (!labels.empty()) { 190 | copy(labels.begin(), labels.end(), mutable_ptr(PtsInfo::kLabel)); 191 | } 192 | 193 | return true; 194 | } 195 | 196 | void Points::set_points(vector& data) { 197 | buffer_.swap(data); 198 | info_ = reinterpret_cast(buffer_.data()); 199 | } 200 | 201 | //void Points::set_bbox(float* bbmin, float* bbmax) { 202 | // const int dim = 3; 203 | // for (int i = 0; i < dim; ++i) { 204 | // bbmin_[i] = bbmin[i]; 205 | // bbmax_[i] = bbmax[i]; 206 | // } 207 | //} 208 | // 209 | //void Points::set_bbox() { 210 | // const int dim = 3, npt = info_->pt_num(); 211 | // const float* pt = mutable_ptr(PtsInfo::kPoint); 212 | // if (npt < 1) { 213 | // for (int c = 0; c < dim; ++c) { 214 | // bbmin_[c] = bbmax_[c] = 0.0f; 215 | // } 216 | // return; 217 | // } 218 | // 219 | // for (int c = 0; c < dim; ++c) { 220 | // bbmin_[c] = bbmax_[c] = pt[c]; 221 | // } 222 | // for (int i = 1; i < npt; ++i) { 223 | // int i3 = i * 3; 224 | // for (int j = 0; j < dim; ++j) { 225 | // float tmp = pt[i3 + j]; 226 | // if (tmp < bbmin_[j]) bbmin_[j] = tmp; 227 | // if (tmp > bbmax_[j]) bbmax_[j] = tmp; 228 | // } 229 | // } 230 | //} 231 | 232 | void Points::centralize(const float* center) { 233 | const int dim = 3, npt = info_->pt_num(); 234 | float* pt = mutable_ptr(PtsInfo::kPoint); 235 | for (int i = 0; i < npt; ++i) { 236 | int i3 = i * 3; 237 | for (int m = 0; m < dim; ++m) { 238 | pt[i3 + m] -= center[m]; 239 | } 240 | } 241 | } 242 | 243 | void Points::displace(const float dis) { 244 | const int dim = 3, npt = info_->pt_num(); 245 | float* pt = mutable_ptr(PtsInfo::kPoint); 246 | float* normal = mutable_ptr(PtsInfo::kNormal); 247 | if (normal == nullptr) return; 248 | 249 | for (int i = 0; i < npt; ++i) { 250 | int i3 = i * 3; 251 | for (int m = 0; m < 3; ++m) { 252 | pt[i3 + m] += normal[i3 + m] * dis; 253 | } 254 | } 255 | } 256 | 257 | //void Points::rotate(const float angle, const float* axis) { 258 | // float rot[9]; 259 | // rotation_matrix(rot, angle, axis); 260 | // 261 | // int npt = info_->pt_num(); 262 | // vector tmp(3 * npt); 263 | // matrix_prod(tmp.data(), rot, mutable_ptr(PtsInfo::kPoint), 3, npt, 3); 264 | // copy(tmp.begin(), tmp.end(), mutable_ptr(PtsInfo::kPoint)); 265 | // 266 | // if (this->info().has_property(PtsInfo::kNormal)) { 267 | // matrix_prod(tmp.data(), rot, this->mutable_ptr(PtsInfo::kNormal), 3, npt, 3); 268 | // copy(tmp.begin(), tmp.end(), mutable_ptr(PtsInfo::kNormal)); 269 | // } 270 | //} 271 | -------------------------------------------------------------------------------- /virtual_scanner/cpp/libvirtualscanner/libvirtualscanner.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | {132C8DB6-16EE-48B2-9D52-0A6D5777854E} 31 | Win32Proj 32 | libvirtualscanner 33 | libvirtualscanner 34 | 8.1 35 | 36 | 37 | 38 | StaticLibrary 39 | true 40 | v140 41 | Unicode 42 | 43 | 44 | StaticLibrary 45 | true 46 | v140 47 | Unicode 48 | 49 | 50 | StaticLibrary 51 | false 52 | v140 53 | true 54 | Unicode 55 | 56 | 57 | StaticLibrary 58 | false 59 | v140 60 | true 61 | Unicode 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | true 81 | 82 | 83 | true 84 | 85 | 86 | false 87 | $(SolutionDir)build\$(Configuration)\ 88 | 89 | 90 | false 91 | $(SolutionDir)build\$(Platform)\$(Configuration)\ 92 | 93 | 94 | 95 | 96 | 97 | Level3 98 | Disabled 99 | WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) 100 | $(ProjectDir)include;%(AdditionalIncludeDirectories) 101 | 102 | 103 | Console 104 | true 105 | 106 | 107 | 108 | 109 | 110 | 111 | Level3 112 | Disabled 113 | WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) 114 | $(ProjectDir)include;%(AdditionalIncludeDirectories) 115 | 116 | 117 | Console 118 | true 119 | 120 | 121 | 122 | 123 | Level3 124 | 125 | 126 | MaxSpeed 127 | true 128 | true 129 | WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) 130 | $(ProjectDir)include;%(AdditionalIncludeDirectories) 131 | 132 | 133 | Console 134 | true 135 | true 136 | true 137 | 138 | 139 | 140 | 141 | Level3 142 | 143 | 144 | MaxSpeed 145 | true 146 | true 147 | WIN32;NDEBUG;_CONSOLE;_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) 148 | true 149 | $(ProjectDir)include;%(AdditionalIncludeDirectories) 150 | 151 | 152 | Console 153 | true 154 | true 155 | true 156 | 157 | 158 | 159 | 160 | 161 | 162 | -------------------------------------------------------------------------------- /virtual_scanner/cpp/virtualscanner/virtualscanner.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | {132c8db6-16ee-48b2-9d52-0a6d5777854e} 27 | 28 | 29 | 30 | {8C7CF56A-4830-4858-A90E-5DA7BE887951} 31 | Win32Proj 32 | virtualscanner 33 | virtualscanner 34 | 8.1 35 | 36 | 37 | 38 | Application 39 | true 40 | v140 41 | Unicode 42 | 43 | 44 | Application 45 | true 46 | v140 47 | Unicode 48 | 49 | 50 | Application 51 | false 52 | v140 53 | true 54 | Unicode 55 | 56 | 57 | Application 58 | false 59 | v140 60 | true 61 | Unicode 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | true 81 | $(SolutionDir)build\$(Configuration)\ 82 | 83 | 84 | true 85 | $(SolutionDir)build\$(Platform)\$(Configuration)\ 86 | 87 | 88 | false 89 | $(SolutionDir)build\$(Configuration)\ 90 | 91 | 92 | false 93 | $(SolutionDir)build\$(Platform)\$(Configuration)\ 94 | 95 | 96 | 97 | 98 | 99 | Level3 100 | Disabled 101 | WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) 102 | $(SolutionDir)\cpp\libvirtualscanner\include;%(AdditionalIncludeDirectories) 103 | 104 | 105 | Console 106 | true 107 | 108 | 109 | 110 | 111 | 112 | 113 | Level3 114 | Disabled 115 | WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) 116 | $(SolutionDir)\cpp\libvirtualscanner\include;%(AdditionalIncludeDirectories) 117 | 118 | 119 | Console 120 | true 121 | 122 | 123 | 124 | 125 | Level3 126 | 127 | 128 | MaxSpeed 129 | true 130 | true 131 | WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) 132 | $(SolutionDir)\cpp\libvirtualscanner\include;%(AdditionalIncludeDirectories) 133 | 134 | 135 | Console 136 | true 137 | true 138 | true 139 | 140 | 141 | 142 | 143 | Level3 144 | 145 | 146 | MaxSpeed 147 | true 148 | true 149 | WIN32;NDEBUG;_CONSOLE;_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) 150 | true 151 | $(SolutionDir)\cpp\libvirtualscanner\include;%(AdditionalIncludeDirectories) 152 | 153 | 154 | Console 155 | true 156 | true 157 | true 158 | 159 | 160 | 161 | 162 | 163 | 164 | -------------------------------------------------------------------------------- /densecrf/examples/dense_learning.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2013, Philipp Krähenbühl 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * Neither the name of the Stanford University nor the 13 | names of its contributors may be used to endorse or promote products 14 | derived from this software without specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY Philipp Krähenbühl ''AS IS'' AND ANY 17 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL Philipp Krähenbühl BE LIABLE FOR ANY 20 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #include "densecrf.h" 29 | #include "optimization.h" 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include "ppm.h" 36 | #include "common.h" 37 | using namespace std; 38 | int class_num = 4; // The class number 39 | string data_path = ""; // "The path of training data" 40 | 41 | 42 | class CRFEnergy : public EnergyFunction { 43 | protected: 44 | VectorXf initial_u_param_, initial_lbl_param_, initial_knl_param_; 45 | DenseCRF & crf_; 46 | const ObjectiveFunction& objective_; 47 | int NIT_; 48 | bool unary_, pairwise_, kernel_; 49 | float l2_norm_; 50 | public: 51 | CRFEnergy(DenseCRF & crf, const ObjectiveFunction & objective, int NIT, bool unary = 1, 52 | bool pairwise = 1, bool kernel = 1) :crf_(crf), objective_(objective), NIT_(NIT), unary_(unary), 53 | pairwise_(pairwise), kernel_(kernel), l2_norm_(0.f) { 54 | initial_u_param_ = crf_.unaryParameters(); 55 | initial_lbl_param_ = crf_.labelCompatibilityParameters(); 56 | initial_knl_param_ = crf_.kernelParameters(); 57 | } 58 | void setL2Norm(float norm) { 59 | l2_norm_ = norm; 60 | } 61 | virtual VectorXf initialValue() { 62 | VectorXf p(unary_*initial_u_param_.rows() + pairwise_*initial_lbl_param_.rows() + kernel_*initial_knl_param_.rows()); 63 | p << (unary_ ? initial_u_param_ : VectorXf()), (pairwise_ ? initial_lbl_param_ : VectorXf()), (kernel_ ? initial_knl_param_ : VectorXf()); 64 | return p; 65 | } 66 | virtual double gradient(const VectorXf & x, VectorXf & dx) { 67 | int p = 0; 68 | if (unary_) { 69 | crf_.setUnaryParameters(x.segment(p, initial_u_param_.rows())); 70 | p += initial_u_param_.rows(); 71 | } 72 | if (pairwise_) { 73 | crf_.setLabelCompatibilityParameters(x.segment(p, initial_lbl_param_.rows())); 74 | p += initial_lbl_param_.rows(); 75 | } 76 | if (kernel_) 77 | crf_.setKernelParameters(x.segment(p, initial_knl_param_.rows())); 78 | 79 | VectorXf du = 0 * initial_u_param_, dl = 0 * initial_u_param_, dk = 0 * initial_knl_param_; 80 | double r = crf_.gradient(NIT_, objective_, unary_ ? &du : NULL, pairwise_ ? &dl : NULL, kernel_ ? &dk : NULL); 81 | dx.resize(unary_*du.rows() + pairwise_*dl.rows() + kernel_*dk.rows()); 82 | dx << -(unary_ ? du : VectorXf()), -(pairwise_ ? dl : VectorXf()), -(kernel_ ? dk : VectorXf()); 83 | r = -r; 84 | if (l2_norm_ > 0) { 85 | dx += l2_norm_ * x; 86 | r += 0.5*l2_norm_ * (x.dot(x)); 87 | } 88 | 89 | return r; 90 | } 91 | }; 92 | 93 | class CRFEnergys : public EnergyFunction 94 | { 95 | public: 96 | vector pEnergys; 97 | ~CRFEnergys() 98 | { 99 | cleanCRFEnerges(); 100 | } 101 | void setCRFEnerges(vector& crfs, 102 | vector& objectives, int NIT, 103 | bool unary = 1, bool pairwise = 1, bool kernel = 1) 104 | { 105 | cleanCRFEnerges(); 106 | int n = crfs.size(); 107 | pEnergys.resize(n); 108 | for (int i = 0; i < n; ++i) 109 | { 110 | pEnergys[i] = new CRFEnergy(*crfs[i], *objectives[i], 111 | NIT, unary, pairwise, kernel); 112 | } 113 | } 114 | 115 | void cleanCRFEnerges() 116 | { 117 | for (int i = 0; i < pEnergys.size(); ++i) 118 | { 119 | delete pEnergys[i]; 120 | } 121 | } 122 | 123 | void setL2Norm(float Norm) 124 | { 125 | for (int i = 0; i < pEnergys.size(); ++i) 126 | { 127 | pEnergys[i]->setL2Norm(Norm); 128 | } 129 | } 130 | virtual VectorXf initialValue() 131 | { 132 | return pEnergys[0]->initialValue(); 133 | } 134 | 135 | virtual double gradient(const VectorXf & x, VectorXf & dx) 136 | { 137 | int n = pEnergys.size(); 138 | vector rs(n); 139 | vector dxs(n); 140 | #pragma omp parallel for 141 | for (int i = 0; i < n; ++i) 142 | { 143 | rs[i] = pEnergys[i]->gradient(x, dxs[i]); 144 | } 145 | 146 | dx = dxs[0]; 147 | double r = rs[0]; 148 | for (int i = 1; i < n; ++i) 149 | { 150 | dx += dxs[i]; 151 | r += rs[i]; 152 | } 153 | 154 | dx /= (double)n; 155 | return r / double(n); 156 | } 157 | }; 158 | 159 | void CRFLearning() 160 | { 161 | vector all_files; 162 | get_all_filenames(all_files, data_path + "\\*.points"); 163 | 164 | int n = all_files.size(); 165 | vector pcCRFs(n); 166 | vector objectives(n); 167 | cout << "Load data ..."; 168 | #pragma omp parallel for 169 | for (int i = 0; i < n; ++i) 170 | { 171 | VectorXs label; 172 | MatrixXf pt, normal, prob; 173 | load_pointcloud(pt, normal, label, all_files[i]); 174 | 175 | string filename_prob = all_files[i]; 176 | filename_prob.replace(filename_prob.rfind('.') + 1, string::npos, "probo.txt"); 177 | load_prob(prob, filename_prob); 178 | float* ptr = prob.data(); 179 | for (int j = 0; j < prob.size(); ++j) 180 | { 181 | ptr[j] = -log(ptr[j] + 0.01f); 182 | } 183 | 184 | int num = prob.cols(); 185 | int ch = prob.rows(); 186 | pcCRFs[i] = new PointCloudCRF(num, ch); 187 | pcCRFs[i]->setUnaryEnergy(prob); 188 | pcCRFs[i]->addPairwiseGaussian(4, 4, 4, pt.data(), new PottsCompatibility(3)); 189 | pcCRFs[i]->addPairwiseBilateral(8, 8, 8, 0.3, 0.3, 0.3, pt.data(), normal.data(), 190 | new MatrixCompatibility(MatrixXf::Identity(ch, ch))); 191 | 192 | objectives[i] = new IntersectionOverUnion(label); 193 | } 194 | 195 | int NIT = 5; 196 | const bool verbose = true; 197 | 198 | MatrixXf learning_params(2, 3); 199 | // Optimize the CRF in 3 phases: 200 | // * pairwise 201 | // * Full CRF 202 | learning_params << 1, 1, 0, 1, 1, 1; 203 | cout << "Optimize ..."; 204 | for (int i = 0; i < learning_params.rows(); i++) 205 | { 206 | cout << "Phase : " << i << endl; 207 | // Setup the energy 208 | CRFEnergys energy; 209 | energy.setCRFEnerges(pcCRFs, objectives, NIT, 210 | learning_params(i, 0), learning_params(i, 1), learning_params(i, 2)); 211 | energy.setL2Norm(1e-3); 212 | 213 | // Minimize the energy 214 | VectorXf p = minimizeLBFGS(energy, 2, true); 215 | 216 | // Save the values 217 | for (int k = 0; k < pcCRFs.size(); ++k) 218 | { 219 | int id = 0; 220 | PointCloudCRF& crf = *pcCRFs[k]; 221 | if (learning_params(i, 0)) 222 | { 223 | crf.setUnaryParameters(p.segment(id, crf.unaryParameters().rows())); 224 | id += crf.unaryParameters().rows(); 225 | } 226 | 227 | if (learning_params(i, 1)) 228 | { 229 | crf.setLabelCompatibilityParameters(p.segment(id, crf.labelCompatibilityParameters().rows())); 230 | id += crf.labelCompatibilityParameters().rows(); 231 | } 232 | 233 | if (learning_params(i, 2)) 234 | { 235 | crf.setKernelParameters(p.segment(id, crf.kernelParameters().rows())); 236 | } 237 | } 238 | } 239 | // Return the parameters 240 | PointCloudCRF& crf = *pcCRFs[0]; 241 | std::cout << "Unary parameters: " << crf.unaryParameters().transpose() << std::endl; 242 | std::cout << "Pairwise parameters: " << crf.labelCompatibilityParameters().transpose() << std::endl; 243 | std::cout << "Kernel parameters: " << crf.kernelParameters().transpose() << std::endl; 244 | 245 | // Do map inference 246 | for (int i = 0; i < n; ++i) 247 | { 248 | VectorXs map = pcCRFs[i]->map(NIT); 249 | string filename = all_files[i] + ".crf.txt"; 250 | save_label(map, filename); 251 | } 252 | 253 | for (int i = 0; i < pcCRFs.size(); ++i) 254 | { 255 | delete pcCRFs[i]; 256 | delete objectives[i]; 257 | } 258 | } 259 | 260 | int main(int argc, char* argv[]) 261 | { 262 | 263 | if (argc < 3) 264 | { 265 | cout << "Usage: deanse_learning.exe "; 266 | return 0; 267 | } 268 | 269 | data_path = argv[1]; 270 | class_num = atoi(argv[2]); 271 | 272 | CRFLearning(); 273 | 274 | return 0; 275 | } 276 | -------------------------------------------------------------------------------- /densecrf/src/densecrf.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2013, Philipp Krähenbühl 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * Neither the name of the Stanford University nor the 13 | names of its contributors may be used to endorse or promote products 14 | derived from this software without specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY Philipp Krähenbühl ''AS IS'' AND ANY 17 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL Philipp Krähenbühl BE LIABLE FOR ANY 20 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #include "densecrf.h" 29 | #include "permutohedral.h" 30 | #include "util.h" 31 | #include "pairwise.h" 32 | #include 33 | #include 34 | #include 35 | 36 | ///////////////////////////// 37 | ///// Alloc / Dealloc ///// 38 | ///////////////////////////// 39 | DenseCRF::DenseCRF(int N, int M) : N_(N), M_(M), unary_(0) { 40 | } 41 | DenseCRF::~DenseCRF() { 42 | if (unary_) 43 | delete unary_; 44 | for( unsigned int i=0; iget(); 156 | expAndNormalize( Q, -unary ); 157 | 158 | for( int it=0; itapply( tmp2, Q ); 162 | tmp1 -= tmp2; 163 | } 164 | expAndNormalize( Q, tmp1 ); 165 | } 166 | return Q; 167 | } 168 | VectorXs DenseCRF::map ( int n_iterations ) const { 169 | // Run inference 170 | MatrixXf Q = inference( n_iterations ); 171 | // Find the map 172 | return currentMap( Q ); 173 | } 174 | /////////////////// 175 | ///// Debug ///// 176 | /////////////////// 177 | VectorXf DenseCRF::unaryEnergy(const VectorXs & l) { 178 | assert( l.cols() == N_ ); 179 | VectorXf r( N_ ); 180 | r.fill(0.f); 181 | if( unary_ ) { 182 | MatrixXf unary = unary_->get(); 183 | 184 | for( int i=0; iapply( Q, Q ); 207 | for( int i=0; iget() ); 221 | return Q; 222 | } 223 | void DenseCRF::stepInference( MatrixXf & Q, MatrixXf & tmp1, MatrixXf & tmp2 ) const{ 224 | tmp1.resize( Q.rows(), Q.cols() ); 225 | tmp1.fill(0); 226 | if( unary_ ) 227 | tmp1 -= unary_->get(); 228 | 229 | // Add up all pairwise potentials 230 | for( unsigned int k=0; kapply( tmp2, Q ); 232 | tmp1 -= tmp2; 233 | } 234 | 235 | // Exponentiate and normalize 236 | expAndNormalize( Q, tmp1 ); 237 | } 238 | VectorXs DenseCRF::currentMap( const MatrixXf & Q ) const{ 239 | VectorXs r(Q.cols()); 240 | // Find the map 241 | for( int i=0; iget(); 259 | for( int i=0; iapply( tmp, Q ); 268 | kl += (Q.array()*tmp.array()).sum(); 269 | } 270 | return kl; 271 | } 272 | 273 | // Gradient computations 274 | double DenseCRF::gradient( int n_iterations, const ObjectiveFunction & objective, VectorXf * unary_grad, VectorXf * lbl_cmp_grad, VectorXf * kernel_grad) const { 275 | // Run inference 276 | std::vector< MatrixXf > Q(n_iterations+1); 277 | MatrixXf tmp1, unary( M_, N_ ), tmp2; 278 | unary.fill(0); 279 | if( unary_ ) 280 | unary = unary_->get(); 281 | expAndNormalize( Q[0], -unary ); 282 | for( int it=0; itapply( tmp2, Q[it] ); 286 | tmp1 -= tmp2; 287 | } 288 | expAndNormalize( Q[it+1], tmp1 ); 289 | } 290 | 291 | // Compute the objective value 292 | MatrixXf b( M_, N_ ); 293 | double r = objective.evaluate( b, Q[n_iterations] ); 294 | sumAndNormalize( b, b, Q[n_iterations] ); 295 | 296 | // Compute the gradient 297 | if(unary_grad && unary_) 298 | *unary_grad = unary_->gradient( b ); 299 | if( lbl_cmp_grad ) 300 | *lbl_cmp_grad = 0*labelCompatibilityParameters(); 301 | if( kernel_grad ) 302 | *kernel_grad = 0*kernelParameters(); 303 | 304 | for( int it=n_iterations-1; it>=0; it-- ) { 305 | // Do the inverse message passing 306 | tmp1.fill(0); 307 | int ip = 0, ik = 0; 308 | // Add up all pairwise potentials 309 | for( unsigned int k=0; kgradient( b, Q[it] ); 313 | lbl_cmp_grad->segment( ip, pg.rows() ) += pg; 314 | ip += pg.rows(); 315 | } 316 | // Compute the kernel gradient expression 317 | if( kernel_grad ) { 318 | VectorXf pg = pairwise_[k]->kernelGradient( b, Q[it] ); 319 | kernel_grad->segment( ik, pg.rows() ) += pg; 320 | ik += pg.rows(); 321 | } 322 | // Compute the new b 323 | pairwise_[k]->applyTranspose( tmp2, b ); 324 | tmp1 += tmp2; 325 | } 326 | sumAndNormalize( b, tmp1.array()*Q[it].array(), Q[it] ); 327 | 328 | // Add the gradient 329 | if(unary_grad && unary_) 330 | *unary_grad += unary_->gradient( b ); 331 | } 332 | return r; 333 | } 334 | VectorXf DenseCRF::unaryParameters() const { 335 | if( unary_ ) 336 | return unary_->parameters(); 337 | return VectorXf(); 338 | } 339 | void DenseCRF::setUnaryParameters( const VectorXf & v ) { 340 | if( unary_ ) 341 | unary_->setParameters( v ); 342 | } 343 | VectorXf DenseCRF::labelCompatibilityParameters() const { 344 | std::vector< VectorXf > terms; 345 | for( unsigned int k=0; kparameters() ); 347 | int np=0; 348 | for( unsigned int k=0; k n; 359 | for( unsigned int k=0; kparameters().rows() ); 361 | int np=0; 362 | for( unsigned int k=0; ksetParameters( v.segment( i, n[k] ) ); 367 | i += n[k]; 368 | } 369 | } 370 | VectorXf DenseCRF::kernelParameters() const { 371 | std::vector< VectorXf > terms; 372 | for( unsigned int k=0; kkernelParameters() ); 374 | int np=0; 375 | for( unsigned int k=0; k n; 386 | for( unsigned int k=0; kkernelParameters().rows() ); 388 | int np=0; 389 | for( unsigned int k=0; ksetKernelParameters( v.segment( i, n[k] ) ); 394 | i += n[k]; 395 | } 396 | } 397 | -------------------------------------------------------------------------------- /virtual_scanner/cpp/libvirtualscanner/cmake/FindEigen3.cmake: -------------------------------------------------------------------------------- 1 | # Ceres Solver - A fast non-linear least squares minimizer 2 | # Copyright 2015 Google Inc. All rights reserved. 3 | # http://ceres-solver.org/ 4 | # 5 | # Redistribution and use in source and binary forms, with or without 6 | # modification, are permitted provided that the following conditions are met: 7 | # 8 | # * Redistributions of source code must retain the above copyright notice, 9 | # this list of conditions and the following disclaimer. 10 | # * Redistributions in binary form must reproduce the above copyright notice, 11 | # this list of conditions and the following disclaimer in the documentation 12 | # and/or other materials provided with the distribution. 13 | # * Neither the name of Google Inc. nor the names of its contributors may be 14 | # used to endorse or promote products derived from this software without 15 | # specific prior written permission. 16 | # 17 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 21 | # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 | # POSSIBILITY OF SUCH DAMAGE. 28 | # 29 | # Author: alexs.mac@gmail.com (Alex Stewart) 30 | # 31 | 32 | # FindEigen.cmake - Find Eigen library, version >= 3. 33 | # 34 | # This module defines the following variables: 35 | # 36 | # EIGEN_FOUND: TRUE iff Eigen is found. 37 | # EIGEN_INCLUDE_DIRS: Include directories for Eigen. 38 | # EIGEN_VERSION: Extracted from Eigen/src/Core/util/Macros.h 39 | # EIGEN_WORLD_VERSION: Equal to 3 if EIGEN_VERSION = 3.2.0 40 | # EIGEN_MAJOR_VERSION: Equal to 2 if EIGEN_VERSION = 3.2.0 41 | # EIGEN_MINOR_VERSION: Equal to 0 if EIGEN_VERSION = 3.2.0 42 | # FOUND_INSTALLED_EIGEN_CMAKE_CONFIGURATION: True iff the version of Eigen 43 | # found was built & installed / 44 | # exported as a CMake package. 45 | # 46 | # The following variables control the behaviour of this module: 47 | # 48 | # EIGEN_PREFER_EXPORTED_EIGEN_CMAKE_CONFIGURATION: TRUE/FALSE, iff TRUE then 49 | # then prefer using an exported CMake configuration 50 | # generated by Eigen over searching for the 51 | # Eigen components manually. Otherwise (FALSE) 52 | # ignore any exported Eigen CMake configurations and 53 | # always perform a manual search for the components. 54 | # Default: TRUE iff user does not define this variable 55 | # before we are called, and does NOT specify 56 | # EIGEN_INCLUDE_DIR_HINTS, otherwise FALSE. 57 | # EIGEN_INCLUDE_DIR_HINTS: List of additional directories in which to 58 | # search for eigen includes, e.g: /timbuktu/eigen3. 59 | # 60 | # The following variables are also defined by this module, but in line with 61 | # CMake recommended FindPackage() module style should NOT be referenced directly 62 | # by callers (use the plural variables detailed above instead). These variables 63 | # do however affect the behaviour of the module via FIND_[PATH/LIBRARY]() which 64 | # are NOT re-called (i.e. search for library is not repeated) if these variables 65 | # are set with valid values _in the CMake cache_. This means that if these 66 | # variables are set directly in the cache, either by the user in the CMake GUI, 67 | # or by the user passing -DVAR=VALUE directives to CMake when called (which 68 | # explicitly defines a cache variable), then they will be used verbatim, 69 | # bypassing the HINTS variables and other hard-coded search locations. 70 | # 71 | # EIGEN_INCLUDE_DIR: Include directory for CXSparse, not including the 72 | # include directory of any dependencies. 73 | 74 | # Called if we failed to find Eigen or any of it's required dependencies, 75 | # unsets all public (designed to be used externally) variables and reports 76 | # error message at priority depending upon [REQUIRED/QUIET/] argument. 77 | macro(EIGEN_REPORT_NOT_FOUND REASON_MSG) 78 | unset(EIGEN_FOUND) 79 | unset(EIGEN_INCLUDE_DIRS) 80 | unset(FOUND_INSTALLED_EIGEN_CMAKE_CONFIGURATION) 81 | # Make results of search visible in the CMake GUI if Eigen has not 82 | # been found so that user does not have to toggle to advanced view. 83 | mark_as_advanced(CLEAR EIGEN_INCLUDE_DIR) 84 | # Note _FIND_[REQUIRED/QUIETLY] variables defined by FindPackage() 85 | # use the camelcase library name, not uppercase. 86 | if (Eigen_FIND_QUIETLY) 87 | message(STATUS "Failed to find Eigen - " ${REASON_MSG} ${ARGN}) 88 | elseif (Eigen_FIND_REQUIRED) 89 | message(FATAL_ERROR "Failed to find Eigen - " ${REASON_MSG} ${ARGN}) 90 | else() 91 | # Neither QUIETLY nor REQUIRED, use no priority which emits a message 92 | # but continues configuration and allows generation. 93 | message("-- Failed to find Eigen - " ${REASON_MSG} ${ARGN}) 94 | endif () 95 | return() 96 | endmacro(EIGEN_REPORT_NOT_FOUND) 97 | 98 | # Protect against any alternative find_package scripts for this library having 99 | # been called previously (in a client project) which set EIGEN_FOUND, but not 100 | # the other variables we require / set here which could cause the search logic 101 | # here to fail. 102 | unset(EIGEN_FOUND) 103 | 104 | # ----------------------------------------------------------------- 105 | # By default, if the user has expressed no preference for using an exported 106 | # Eigen CMake configuration over performing a search for the installed 107 | # components, and has not specified any hints for the search locations, then 108 | # prefer an exported configuration if available. 109 | if (NOT DEFINED EIGEN_PREFER_EXPORTED_EIGEN_CMAKE_CONFIGURATION 110 | AND NOT EIGEN_INCLUDE_DIR_HINTS) 111 | message(STATUS "No preference for use of exported Eigen CMake configuration " 112 | "set, and no hints for include directory provided. " 113 | "Defaulting to preferring an installed/exported Eigen CMake configuration " 114 | "if available.") 115 | set(EIGEN_PREFER_EXPORTED_EIGEN_CMAKE_CONFIGURATION TRUE) 116 | endif() 117 | 118 | if (EIGEN_PREFER_EXPORTED_EIGEN_CMAKE_CONFIGURATION) 119 | # Try to find an exported CMake configuration for Eigen. 120 | # 121 | # We search twice, s/t we can invert the ordering of precedence used by 122 | # find_package() for exported package build directories, and installed 123 | # packages (found via CMAKE_SYSTEM_PREFIX_PATH), listed as items 6) and 7) 124 | # respectively in [1]. 125 | # 126 | # By default, exported build directories are (in theory) detected first, and 127 | # this is usually the case on Windows. However, on OS X & Linux, the install 128 | # path (/usr/local) is typically present in the PATH environment variable 129 | # which is checked in item 4) in [1] (i.e. before both of the above, unless 130 | # NO_SYSTEM_ENVIRONMENT_PATH is passed). As such on those OSs installed 131 | # packages are usually detected in preference to exported package build 132 | # directories. 133 | # 134 | # To ensure a more consistent response across all OSs, and as users usually 135 | # want to prefer an installed version of a package over a locally built one 136 | # where both exist (esp. as the exported build directory might be removed 137 | # after installation), we first search with NO_CMAKE_PACKAGE_REGISTRY which 138 | # means any build directories exported by the user are ignored, and thus 139 | # installed directories are preferred. If this fails to find the package 140 | # we then research again, but without NO_CMAKE_PACKAGE_REGISTRY, so any 141 | # exported build directories will now be detected. 142 | # 143 | # To prevent confusion on Windows, we also pass NO_CMAKE_BUILDS_PATH (which 144 | # is item 5) in [1]), to not preferentially use projects that were built 145 | # recently with the CMake GUI to ensure that we always prefer an installed 146 | # version if available. 147 | # 148 | # [1] http://www.cmake.org/cmake/help/v2.8.11/cmake.html#command:find_package 149 | find_package(Eigen3 QUIET 150 | NO_MODULE 151 | NO_CMAKE_PACKAGE_REGISTRY 152 | NO_CMAKE_BUILDS_PATH) 153 | if (EIGEN3_FOUND) 154 | message(STATUS "Found installed version of Eigen: ${Eigen3_DIR}") 155 | else() 156 | # Failed to find an installed version of Eigen, repeat search allowing 157 | # exported build directories. 158 | message(STATUS "Failed to find installed Eigen CMake configuration, " 159 | "searching for Eigen build directories exported with CMake.") 160 | # Again pass NO_CMAKE_BUILDS_PATH, as we know that Eigen is exported and 161 | # do not want to treat projects built with the CMake GUI preferentially. 162 | find_package(Eigen3 QUIET 163 | NO_MODULE 164 | NO_CMAKE_BUILDS_PATH) 165 | if (EIGEN3_FOUND) 166 | message(STATUS "Found exported Eigen build directory: ${Eigen3_DIR}") 167 | endif() 168 | endif() 169 | if (EIGEN3_FOUND) 170 | set(FOUND_INSTALLED_EIGEN_CMAKE_CONFIGURATION TRUE) 171 | set(EIGEN_FOUND ${EIGEN3_FOUND}) 172 | set(EIGEN_INCLUDE_DIR "${EIGEN3_INCLUDE_DIR}" CACHE STRING 173 | "Eigen include directory" FORCE) 174 | else() 175 | message(STATUS "Failed to find an installed/exported CMake configuration " 176 | "for Eigen, will perform search for installed Eigen components.") 177 | endif() 178 | endif() 179 | 180 | if (NOT EIGEN_FOUND) 181 | # Search user-installed locations first, so that we prefer user installs 182 | # to system installs where both exist. 183 | list(APPEND EIGEN_CHECK_INCLUDE_DIRS 184 | /usr/local/include 185 | /usr/local/homebrew/include # Mac OS X 186 | /opt/local/var/macports/software # Mac OS X. 187 | /opt/local/include 188 | /usr/include) 189 | # Additional suffixes to try appending to each search path. 190 | list(APPEND EIGEN_CHECK_PATH_SUFFIXES 191 | eigen3 # Default root directory for Eigen. 192 | Eigen/include/eigen3 # Windows (for C:/Program Files prefix) < 3.3 193 | Eigen3/include/eigen3 ) # Windows (for C:/Program Files prefix) >= 3.3 194 | 195 | # Search supplied hint directories first if supplied. 196 | find_path(EIGEN_INCLUDE_DIR 197 | NAMES Eigen/Core 198 | HINTS ${EIGEN_INCLUDE_DIR_HINTS} 199 | PATHS ${EIGEN_CHECK_INCLUDE_DIRS} 200 | PATH_SUFFIXES ${EIGEN_CHECK_PATH_SUFFIXES}) 201 | 202 | if (NOT EIGEN_INCLUDE_DIR OR 203 | NOT EXISTS ${EIGEN_INCLUDE_DIR}) 204 | eigen_report_not_found( 205 | "Could not find eigen3 include directory, set EIGEN_INCLUDE_DIR to " 206 | "path to eigen3 include directory, e.g. /usr/local/include/eigen3.") 207 | endif (NOT EIGEN_INCLUDE_DIR OR 208 | NOT EXISTS ${EIGEN_INCLUDE_DIR}) 209 | 210 | # Mark internally as found, then verify. EIGEN_REPORT_NOT_FOUND() unsets 211 | # if called. 212 | set(EIGEN_FOUND TRUE) 213 | endif() 214 | 215 | # Extract Eigen version from Eigen/src/Core/util/Macros.h 216 | if (EIGEN_INCLUDE_DIR) 217 | set(EIGEN_VERSION_FILE ${EIGEN_INCLUDE_DIR}/Eigen/src/Core/util/Macros.h) 218 | if (NOT EXISTS ${EIGEN_VERSION_FILE}) 219 | eigen_report_not_found( 220 | "Could not find file: ${EIGEN_VERSION_FILE} " 221 | "containing version information in Eigen install located at: " 222 | "${EIGEN_INCLUDE_DIR}.") 223 | else (NOT EXISTS ${EIGEN_VERSION_FILE}) 224 | file(READ ${EIGEN_VERSION_FILE} EIGEN_VERSION_FILE_CONTENTS) 225 | 226 | string(REGEX MATCH "#define EIGEN_WORLD_VERSION [0-9]+" 227 | EIGEN_WORLD_VERSION "${EIGEN_VERSION_FILE_CONTENTS}") 228 | string(REGEX REPLACE "#define EIGEN_WORLD_VERSION ([0-9]+)" "\\1" 229 | EIGEN_WORLD_VERSION "${EIGEN_WORLD_VERSION}") 230 | 231 | string(REGEX MATCH "#define EIGEN_MAJOR_VERSION [0-9]+" 232 | EIGEN_MAJOR_VERSION "${EIGEN_VERSION_FILE_CONTENTS}") 233 | string(REGEX REPLACE "#define EIGEN_MAJOR_VERSION ([0-9]+)" "\\1" 234 | EIGEN_MAJOR_VERSION "${EIGEN_MAJOR_VERSION}") 235 | 236 | string(REGEX MATCH "#define EIGEN_MINOR_VERSION [0-9]+" 237 | EIGEN_MINOR_VERSION "${EIGEN_VERSION_FILE_CONTENTS}") 238 | string(REGEX REPLACE "#define EIGEN_MINOR_VERSION ([0-9]+)" "\\1" 239 | EIGEN_MINOR_VERSION "${EIGEN_MINOR_VERSION}") 240 | 241 | # This is on a single line s/t CMake does not interpret it as a list of 242 | # elements and insert ';' separators which would result in 3.;2.;0 nonsense. 243 | set(EIGEN_VERSION "${EIGEN_WORLD_VERSION}.${EIGEN_MAJOR_VERSION}.${EIGEN_MINOR_VERSION}") 244 | endif (NOT EXISTS ${EIGEN_VERSION_FILE}) 245 | endif (EIGEN_INCLUDE_DIR) 246 | 247 | # Set standard CMake FindPackage variables if found. 248 | if (EIGEN_FOUND) 249 | set(EIGEN_INCLUDE_DIRS ${EIGEN_INCLUDE_DIR}) 250 | endif (EIGEN_FOUND) 251 | 252 | # Handle REQUIRED / QUIET optional arguments and version. 253 | include(FindPackageHandleStandardArgs) 254 | find_package_handle_standard_args(Eigen 255 | REQUIRED_VARS EIGEN_INCLUDE_DIRS 256 | VERSION_VAR EIGEN_VERSION) 257 | 258 | # Only mark internal variables as advanced if we found Eigen, otherwise 259 | # leave it visible in the standard GUI for the user to set manually. 260 | if (EIGEN_FOUND) 261 | mark_as_advanced(FORCE EIGEN_INCLUDE_DIR 262 | Eigen3_DIR) # Autogenerated by find_package(Eigen3) 263 | endif (EIGEN_FOUND) 264 | 265 | if (EIGEN_FOUND AND NOT TARGET Eigen3::Eigen) 266 | add_library(Eigen3::Eigen INTERFACE IMPORTED) 267 | set_target_properties(Eigen3::Eigen PROPERTIES 268 | INTERFACE_INCLUDE_DIRECTORIES "${EIGEN_INCLUDE_DIR}" 269 | ) 270 | endif() 271 | -------------------------------------------------------------------------------- /virtual_scanner/cpp/libvirtualscanner/src/virtual_scanner.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "virtual_scanner/virtual_scanner.h" 5 | 6 | // CGAL 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | using std::cout; 13 | using std::endl; 14 | using std::ofstream; 15 | using Eigen::VectorXf; 16 | using Eigen::VectorXi; 17 | using Eigen::Matrix3f; 18 | 19 | typedef Eigen::Matrix VectorXb; 20 | typedef CGAL::Simple_cartesian K; 21 | typedef K::FT FT; 22 | typedef K::Ray_3 Ray; 23 | typedef K::Line_3 Line; 24 | typedef K::Point_3 Point; 25 | typedef K::Triangle_3 Triangle; 26 | typedef std::vector::iterator Iterator; 27 | typedef CGAL::AABB_triangle_primitive Primitive; 28 | typedef CGAL::AABB_traits AABB_triangle_traits; 29 | typedef CGAL::AABB_tree Tree; 30 | typedef Tree::Point_and_primitive_id Point_and_primitive_id; 31 | typedef boost::optional::Type> Ray_intersection; 32 | 33 | const float EPS = 1.0e-20; 34 | 35 | #ifdef _MSC_VER 36 | inline char *strtok_r(char *str, const char *delim, char **saveptr) 37 | { 38 | return strtok(str, delim); 39 | } 40 | #endif 41 | 42 | bool read_obj(const string& filename, MatrixXf& V, MatrixXi& F) { 43 | std::ifstream infile(filename, std::ifstream::binary); 44 | if (!infile) { 45 | std::cout << "Open OBJ file error!" << std::endl; 46 | return false; 47 | } 48 | 49 | // get length of file 50 | infile.seekg(0, infile.end); 51 | int len = infile.tellg(); 52 | infile.seekg(0, infile.beg); 53 | 54 | // load the file into memory 55 | char* buffer = new char[len + 1]; 56 | infile.read(buffer, len); 57 | buffer[len] = 0; 58 | infile.close(); 59 | 60 | // parse buffer data 61 | std::vector pVline, pFline; 62 | char* save; 63 | char* pch = strtok_r(buffer, "\n", &save); 64 | while (pch != nullptr) { 65 | if (pch[0] == 'v' && pch[1] == ' ') { 66 | pVline.push_back(pch + 2); 67 | } else if (pch[0] == 'f' && pch[1] == ' ') { 68 | pFline.push_back(pch + 2); 69 | } 70 | 71 | pch = strtok_r(nullptr, "\n", &save); 72 | } 73 | 74 | // load V 75 | V.resize(3, pVline.size()); 76 | //#pragma omp parallel for 77 | for (int i = 0; i < pVline.size(); i++) { 78 | char* p = strtok_r(pVline[i], " ", &save); 79 | for (int j = 0; j < 3; j++) { 80 | V(j, i) = atof(p); 81 | p = strtok_r(nullptr, " ", &save); 82 | } 83 | } 84 | 85 | // load F 86 | F.resize(3, pFline.size()); 87 | //#pragma omp parallel for 88 | for (int i = 0; i < pFline.size(); i++) { 89 | char* p = strtok_r(pFline[i], " ", &save); 90 | for (int j = 0; j < 3; j++) { 91 | F(j, i) = atoi(p) - 1; 92 | p = strtok_r(nullptr, " ", &save); 93 | } 94 | } 95 | 96 | // release 97 | delete[] buffer; 98 | return true; 99 | } 100 | 101 | bool read_off(const string& filename, MatrixXf& V, MatrixXi& F) { 102 | std::ifstream infile(filename, std::ios::binary); 103 | if (!infile) { 104 | std::cout << "Open " + filename + " error!" << std::endl; 105 | return false; 106 | } 107 | 108 | // face/vertex number 109 | int nv, nf, ne; 110 | char head[256]; 111 | bool succ = true; 112 | char* save; 113 | infile >> head; // eat head 114 | if (head[0] == 'O' && head[1] == 'F' && head[2] == 'F') { 115 | if (head[3] == 0) { 116 | infile >> nv >> nf >> ne; 117 | } else if (head[3] == ' ') { 118 | vector tokens; 119 | char* pch = strtok_r(head + 3, " ", &save); 120 | while (pch != nullptr) { 121 | tokens.push_back(pch); 122 | pch = strtok_r(nullptr, " ", &save); 123 | } 124 | if (tokens.size() != 3) { 125 | std::cout << filename + " is not an OFF file!" << std::endl; 126 | return false; 127 | } 128 | nv = atoi(tokens[0]); 129 | nf = atoi(tokens[1]); 130 | ne = atoi(tokens[2]); 131 | } else { 132 | std::cout << filename + " is not an OFF file!" << std::endl; 133 | return false; 134 | } 135 | } else { 136 | std::cout << filename + " is not an OFF file!" << std::endl; 137 | return false; 138 | } 139 | 140 | // get length of file 141 | int p1 = infile.tellg(); 142 | infile.seekg(0, infile.end); 143 | int p2 = infile.tellg(); 144 | infile.seekg(p1, infile.beg); 145 | int len = p2 - p1; 146 | 147 | // load the file into memory 148 | char* buffer = new char[len + 1]; 149 | infile.read(buffer, len); 150 | buffer[len] = 0; 151 | 152 | // close file 153 | infile.close(); 154 | 155 | // parse buffer data 156 | std::vector pV; 157 | pV.reserve(3 * nv); 158 | char* pch = strtok_r(buffer, " \r\n", &save); 159 | pV.push_back(pch); 160 | for (int i = 1; i < 3 * nv; i++) { 161 | pch = strtok_r(nullptr, " \r\n", &save); 162 | pV.push_back(pch); 163 | } 164 | std::vector pF; 165 | pF.reserve(3 * nf); 166 | for (int i = 0; i < nf; i++) { 167 | // eat the first data 168 | pch = strtok_r(nullptr, " \r\n", &save); 169 | for (int j = 0; j < 3; j++) { 170 | pch = strtok_r(nullptr, " \r\n", &save); 171 | pF.push_back(pch); 172 | } 173 | } 174 | 175 | // load vertex 176 | V.resize(3, nv); 177 | float* p = V.data(); 178 | // #pragma omp parallel for 179 | for (int i = 0; i < 3 * nv; i++) { 180 | *(p + i) = atof(pV[i]); 181 | } 182 | 183 | // load face 184 | F.resize(3, nf); 185 | int* q = F.data(); 186 | // #pragma omp parallel for 187 | for (int i = 0; i < 3 * nf; i++) { 188 | *(q + i) = atoi(pF[i]); 189 | } 190 | 191 | //release 192 | delete[] buffer; 193 | return true; 194 | } 195 | 196 | bool read_mesh(const string& filename, MatrixXf& V, MatrixXi& F) { 197 | size_t found = filename.rfind('.'); 198 | if (found != string::npos) { 199 | string suffix(filename, found + 1); 200 | std::transform(suffix.begin(), suffix.end(), suffix.begin(), ::tolower); 201 | 202 | bool succ = false; 203 | if (suffix == "obj") { 204 | succ = read_obj(filename, V, F); 205 | } else if (suffix == "off") { 206 | succ = read_off(filename, V, F); 207 | } else { 208 | cout << "Error : Unsupported file formate!" << std::endl; 209 | } 210 | return succ; 211 | } 212 | return false; 213 | } 214 | 215 | void compute_face_normal(MatrixXf& Nf, VectorXf& f_areas, 216 | const MatrixXf& V, const MatrixXi& F) { 217 | size_t nf = F.cols(); 218 | Nf.resize(3, nf); 219 | f_areas.resize(nf); 220 | 221 | //#pragma omp parallel for 222 | for (int i = 0; i < nf; i++) { 223 | Vector3f p01 = V.col(F(1, i)) - V.col(F(0, i)); 224 | Vector3f p02 = V.col(F(2, i)) - V.col(F(0, i)); 225 | Vector3f n = p01.cross(p02); 226 | 227 | float d = n.norm(); 228 | if (d < EPS) d = EPS; 229 | n /= d; 230 | 231 | f_areas[i] = d * 0.5; 232 | Nf.col(i) = n; 233 | } 234 | } 235 | 236 | void delete_faces(MatrixXf& V, MatrixXi& F, const VectorXb& valid_f) { 237 | int nf = F.cols(); 238 | int nv = V.cols(); 239 | 240 | // valid F idx 241 | int nvf = 0; 242 | VectorXi fi = VectorXi::Constant(F.cols(), -1); 243 | for (int i = 0; i < F.cols(); i++) { 244 | if (valid_f[i] == 1) { 245 | fi[i] = nvf++; 246 | } 247 | } 248 | 249 | // valid V idx 250 | VectorXb valid_v = VectorXb::Constant(nv, false); 251 | for (int i = 0; i < nf; ++i) { 252 | if (valid_f[i]) { 253 | for (int j = 0; j < 3; ++j) { 254 | valid_v[F(j, i)] = true; 255 | } 256 | } 257 | } 258 | int nvv = 0; 259 | VectorXi vi = VectorXi::Constant(V.cols(), -1); 260 | for (int i = 0; i < V.cols(); i++) { 261 | if (valid_v[i]) { 262 | vi[i] = nvv++; 263 | } 264 | } 265 | 266 | // valid F 267 | for (int i = 0; i < nf; i++) { 268 | if (valid_f[i]) { 269 | F.col(fi[i]) << vi[F(0, i)], vi[F(1, i)], vi[F(2, i)]; 270 | } 271 | } 272 | F.conservativeResize(3, nvf); 273 | 274 | // valid V 275 | for (int i = 0; i < nv; i++) { 276 | if (valid_v[i]) { 277 | V.col(vi[i]) = V.col(i); 278 | } 279 | } 280 | V.conservativeResize(3, nvv); 281 | } 282 | 283 | void remove_zero_faces(MatrixXf& V, MatrixXi& F) { 284 | MatrixXf N; 285 | VectorXf f_area; 286 | compute_face_normal(N, f_area, V, F); 287 | 288 | int k = 0; 289 | int nf = F.cols(); 290 | VectorXb valid_f = VectorXb::Constant(nf, true); 291 | for (int j = 0; j < nf; ++j) { 292 | if (f_area[j] < 1.0e-15) { 293 | valid_f[j] = false; 294 | k++; 295 | } 296 | } 297 | if (k > 0) { 298 | delete_faces(V, F, valid_f); 299 | } 300 | } 301 | 302 | void normalize_mesh(MatrixXf& V) { 303 | int size = V.size(); 304 | auto buffer = V.data(); 305 | float maxExtent = 0.0; 306 | for (int j = 0; j < size; ++j) { 307 | float vertexExtent = fabs(buffer[j]); 308 | if (vertexExtent > maxExtent) { 309 | maxExtent = vertexExtent; 310 | } 311 | } 312 | for (int j = 0; j < size; ++j) { 313 | buffer[j] /= maxExtent; 314 | } 315 | } 316 | 317 | bool VirtualScanner::scanning(const string& filename, int view_num, bool flags, bool normalize) { 318 | if (view_num < 1) view_num = 1; 319 | if (view_num > total_view_num_) view_num = total_view_num_; 320 | 321 | // load mesh 322 | bool succ = read_mesh(filename, V_, F_); 323 | if (!succ) return false; 324 | 325 | if (normalize) { normalize_mesh(V_); } 326 | 327 | // remove zero-area faces and unreferenced vertices, 328 | // otherwise, CGAL will collapse 329 | remove_zero_faces(V_, F_); 330 | 331 | // calc normal 332 | VectorXf f_area; 333 | compute_face_normal(N_, f_area, V_, F_); 334 | 335 | // calc views 336 | bbMin_ = V_.rowwise().minCoeff(); 337 | bbMax_ = V_.rowwise().maxCoeff(); 338 | calc_views(); 339 | 340 | // data type conversion 341 | vector vecP; vecP.reserve(V_.cols()); 342 | for (int i = 0; i < V_.cols(); i++) { 343 | vecP.push_back(Point(V_(0, i), V_(1, i), V_(2, i))); 344 | } 345 | vector vecF; vecF.reserve(F_.cols()); 346 | for (int i = 0; i < F_.cols(); i++) { 347 | vecF.push_back(Triangle(vecP[F_(0, i)], vecP[F_(1, i)], vecP[F_(2, i)])); 348 | } 349 | 350 | // constructs AABB tree 351 | Tree tree(vecF.begin(), vecF.end()); 352 | auto start_iteration = vecF.begin(); 353 | 354 | // scanning 355 | int W = 2 * resolution_ + 1; 356 | int Num = view_num * W * W; 357 | MatrixXf buffer_pt(3, Num), buffer_n(3, Num); 358 | VectorXi buffer_flag = VectorXi::Constant(Num, 0); 359 | //#pragma omp parallel for 360 | for (int i = 0; i < Num; ++i) { 361 | int y = i % W - resolution_; 362 | int j = i / W; 363 | int x = j % W - resolution_; 364 | int v = j / W; 365 | 366 | Vector3f pt = view_center_[v] + 367 | float(x) * dx_[v] + float(y) * dy_[v]; 368 | 369 | Point p0(pt[0], pt[1], pt[2]); 370 | Point p1(pt[0] - view_dir_[v][0], 371 | pt[1] - view_dir_[v][1], pt[2] - view_dir_[v][2]); 372 | Ray ray_query(p0, p1); // ray with source p0 and passing through p1 373 | std::list intersections; 374 | tree.all_intersections(ray_query, std::back_inserter(intersections)); 375 | //Ray_intersection intersection = tree.first_intersection(ray_query); 376 | 377 | if (!intersections.empty()) { 378 | Vector3f rst(-1.0e30, -1.0e30, -1.0e30); 379 | int id = -1; 380 | float distance = 1.0e30; 381 | for (auto& intersection : intersections) { 382 | // gets intersection object 383 | Point* pPt = boost::get(&(intersection->first)); 384 | if (!pPt) continue; 385 | 386 | Vector3f tmp(pPt->x(), pPt->y(), pPt->z()); 387 | float dis = (tmp - pt).squaredNorm(); 388 | if (dis < distance) { 389 | distance = dis; 390 | rst = tmp; 391 | id = std::distance(start_iteration, intersection->second); 392 | } 393 | } 394 | if (id < 0 || rst[0] < bbMin_[0] - 1 || rst[0] > bbMax_[0] + 1 || 395 | rst[1] < bbMin_[1] - 1 || rst[1] > bbMax_[1] + 1 || 396 | rst[2] < bbMin_[2] - 1 || rst[2] > bbMax_[2] + 1) continue; 397 | 398 | // normal 399 | Vector3f normal = N_.col(id); 400 | int flag = 1; 401 | if (normal.dot(view_dir_[v]) < 0) { 402 | normal = -normal; 403 | flag = -1; 404 | } 405 | 406 | // save to buffer 407 | buffer_pt.col(i) = rst; 408 | buffer_n.col(i) = normal; 409 | buffer_flag(i) = flag; 410 | } 411 | } 412 | 413 | // get points and normals 414 | pts_.clear(); 415 | pts_.reserve(Num * 3); 416 | normals_.clear(); 417 | normals_.reserve(Num * 3); 418 | flags_.clear(); 419 | flags_.reserve(Num * 3); 420 | 421 | for (int i = 0; i < Num; ++i) { 422 | if (buffer_flag(i) != 0) { 423 | for (int j = 0; j < 3; ++j) { 424 | pts_.push_back(buffer_pt(j, i)); 425 | normals_.push_back(buffer_n(j, i)); 426 | } 427 | if (flags) { 428 | flags_.push_back(buffer_flag(i)); 429 | } 430 | } 431 | } 432 | 433 | 434 | // save 435 | //save_ply(filename_pc + "_pc.ply"); 436 | return true; 437 | } 438 | 439 | void VirtualScanner::calc_views() { 440 | view_center_.resize(total_view_num_); 441 | view_dir_.resize(total_view_num_); 442 | dx_.resize(total_view_num_); 443 | dy_.resize(total_view_num_); 444 | Vector3f center = (bbMin_ + bbMax_) * 0.5; 445 | float len = (bbMax_ - bbMin_).norm() * 0.5; 446 | 447 | // view directions 448 | view_dir_[0] << 0.0, 0.0, 1.0; 449 | view_dir_[1] << 1.0, 0.0, 0.0; 450 | view_dir_[2] << -1.0, 0.0, 0.0; 451 | view_dir_[3] << 0.0, 1.0, 0.0; 452 | view_dir_[4] << 0.0, -1.0, 0.0; 453 | view_dir_[5] << 0.0, 0.0, -1.0; 454 | view_dir_[6] = (Vector3f(bbMax_[0], bbMax_[1], bbMax_[2]) - center).normalized(); 455 | view_dir_[7] = (Vector3f(bbMax_[0], bbMin_[1], bbMax_[2]) - center).normalized(); 456 | view_dir_[8] = (Vector3f(bbMin_[0], bbMax_[1], bbMax_[2]) - center).normalized(); 457 | view_dir_[9] = (Vector3f(bbMin_[0], bbMin_[1], bbMax_[2]) - center).normalized(); 458 | view_dir_[10] = (Vector3f(bbMax_[0], bbMax_[1], bbMin_[2]) - center).normalized(); 459 | view_dir_[11] = (Vector3f(bbMax_[0], bbMin_[1], bbMin_[2]) - center).normalized(); 460 | view_dir_[12] = (Vector3f(bbMin_[0], bbMax_[1], bbMin_[2]) - center).normalized(); 461 | view_dir_[13] = (Vector3f(bbMin_[0], bbMin_[1], bbMin_[2]) - center).normalized(); 462 | 463 | // view centers 464 | for (int i = 0; i < total_view_num_; i++) { 465 | view_center_[i] = view_dir_[i] * len + center; 466 | } 467 | 468 | // dx & dy 469 | float d = (bbMax_ - bbMin_).maxCoeff() / (2 * resolution_ + 1); 470 | dx_[0] << d, 0, 0; 471 | dy_[0] << 0, d, 0; 472 | dx_[5] << d, 0, 0; 473 | dy_[5] << 0, d, 0; 474 | for (int i = 1; i < total_view_num_; ++i) { 475 | if (i == 5)continue; 476 | Vector3f Z(0.0, 0.0, 1.0); 477 | float dot01 = Z.dot(view_dir_[i]); 478 | if (dot01 < -1)dot01 = -1; 479 | if (dot01 > 1)dot01 = 1; 480 | float angle = acos(dot01); 481 | Vector3f axis = Z.cross(view_dir_[i]).normalized(); 482 | 483 | Matrix3f Rot; Rot = Eigen::AngleAxis(angle, axis); 484 | 485 | dx_[i] = Rot.col(0) * d; 486 | dy_[i] = Rot.col(1) * d; 487 | } 488 | } 489 | 490 | bool VirtualScanner::save_ply(const string& filename) { 491 | ofstream outfile(filename, std::ios::binary); 492 | if (!outfile) { 493 | cout << "Open " << filename << "error!" << endl; 494 | return false; 495 | } 496 | 497 | // write header 498 | int n = pts_.size() / 3; 499 | outfile << "ply" << endl 500 | << "format ascii 1.0" << endl 501 | << "element vertex " << n << endl 502 | << "property float x" << endl 503 | << "property float y" << endl 504 | << "property float z" << endl 505 | << "property float nx" << endl 506 | << "property float ny" << endl 507 | << "property float nz" << endl 508 | << "element face 0" << endl 509 | << "property list uchar int vertex_indices" << endl 510 | << "end_header" << endl; 511 | 512 | // wirte contents 513 | const int len = 128; 514 | char* buffer = new char[n * len]; 515 | char* pstr = buffer; 516 | //#pragma omp parallel for 517 | for (int i = 0; i < n; ++i) { 518 | sprintf(pstr + i * len, 519 | "%.6f %.6f %.6f %.6f %.6f %.6f\n", 520 | pts_[3 * i], pts_[3 * i + 1], pts_[3 * i + 2], 521 | normals_[3 * i], normals_[3 * i + 1], normals_[3 * i + 2]); 522 | } 523 | 524 | int k = 0; 525 | for (int i = 0; i < n; ++i) { 526 | for (int j = len * i; j < len * (i + 1); ++j) { 527 | if (buffer[j] == 0) break; 528 | buffer[k++] = buffer[j]; 529 | } 530 | } 531 | outfile.write(buffer, k); 532 | 533 | outfile.close(); 534 | delete[] buffer; 535 | return true; 536 | } 537 | 538 | bool VirtualScanner::save_binary(const string& filename) { 539 | bool succ = point_cloud_.set_points(pts_, normals_); 540 | if (!succ) { 541 | cout << "Warning: point_cloud_.set_points() failed!" << endl 542 | << "Save one point instead!" << endl; 543 | vector vec{ 1.0f, 0, 0 }; 544 | point_cloud_.set_points(vec, vec); 545 | } 546 | 547 | succ = point_cloud_.write_points(filename); 548 | if (!succ) cout << "Opening file error: " << filename << endl; 549 | return succ; 550 | } 551 | 552 | bool VirtualScanner::save_binary_legacy(const string& filename) { 553 | ofstream outfile(filename, std::ios::binary); 554 | if (!outfile) { 555 | cout << "Opening file error!" << endl; 556 | return false; 557 | } 558 | 559 | int n = pts_.size(); 560 | 561 | int num = n / 3; // point number 562 | outfile.write((char*)(&num), sizeof(int)); 563 | 564 | //int pt_n = 1 | 2; // has_point | has_normal 565 | //outfile.write((char*)(&pt_n), sizeof(int)); 566 | 567 | outfile.write((char*)pts_.data(), sizeof(float)*n); 568 | outfile.write((char*)normals_.data(), sizeof(float)*n); 569 | 570 | outfile.close(); 571 | 572 | if (!flags_.empty()) { 573 | string filename_flag = filename; 574 | filename_flag.replace(filename.rfind('.') + 1, string::npos, "flags"); 575 | outfile.open(filename_flag, std::ios::binary); 576 | outfile.write((char*)flags_.data(), sizeof(int)*flags_.size()); 577 | outfile.close(); 578 | } 579 | 580 | return true; 581 | } 582 | -------------------------------------------------------------------------------- /densecrf/src/permutohedral.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2013, Philipp Krähenbühl 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * Neither the name of the Stanford University nor the 13 | names of its contributors may be used to endorse or promote products 14 | derived from this software without specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY Philipp Krähenbühl ''AS IS'' AND ANY 17 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL Philipp Krähenbühl BE LIABLE FOR ANY 20 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #include "permutohedral.h" 29 | 30 | // #ifdef WIN32 31 | // inline int round(double X) { 32 | // return int(X+.5); 33 | // } 34 | // #endif 35 | 36 | #ifdef __SSE__ 37 | // SSE Permutoheral lattice 38 | # define SSE_PERMUTOHEDRAL 39 | #endif 40 | 41 | #if defined(SSE_PERMUTOHEDRAL) 42 | # include 43 | # include 44 | # ifdef __SSE4_1__ 45 | # include 46 | # endif 47 | #endif 48 | 49 | 50 | /************************************************/ 51 | /*** Hash Table ***/ 52 | /************************************************/ 53 | 54 | class HashTable{ 55 | protected: 56 | size_t key_size_, filled_, capacity_; 57 | std::vector< short > keys_; 58 | std::vector< int > table_; 59 | void grow(){ 60 | // Create the new memory and copy the values in 61 | int old_capacity = capacity_; 62 | capacity_ *= 2; 63 | std::vector old_keys( (old_capacity+10)*key_size_ ); 64 | std::copy( keys_.begin(), keys_.end(), old_keys.begin() ); 65 | std::vector old_table( capacity_, -1 ); 66 | 67 | // Swap the memory 68 | table_.swap( old_table ); 69 | keys_.swap( old_keys ); 70 | 71 | // Reinsert each element 72 | for( int i=0; i= 0){ 74 | int e = old_table[i]; 75 | size_t h = hash( getKey(e) ) % capacity_; 76 | for(; table_[h] >= 0; h = h= capacity_) grow(); 100 | // Get the hash value 101 | size_t h = hash( k ) % capacity_; 102 | // Find the element with he right key, using linear probing 103 | while(1){ 104 | int e = table_[h]; 105 | if (e==-1){ 106 | if (create){ 107 | // Insert a new key and return the new id 108 | for( size_t i=0; i0; j-- ){ 203 | __m128 cf = f[j-1]*scale_factor[j-1]; 204 | elevated[j] = sm - _mm_set1_ps(j)*cf; 205 | sm += cf; 206 | } 207 | elevated[0] = sm; 208 | 209 | // Find the closest 0-colored simplex through rounding 210 | __m128 sum = Zero; 211 | for( int i=0; i<=d_; i++ ){ 212 | __m128 v = invdplus1 * elevated[i]; 213 | #ifdef __SSE4_1__ 214 | v = _mm_round_ps( v, _MM_FROUND_TO_NEAREST_INT ); 215 | #else 216 | v = _mm_cvtepi32_ps( _mm_cvtps_epi32( v ) ); 217 | #endif 218 | rem0[i] = v*dplus1; 219 | sum += v; 220 | } 221 | 222 | // Find the simplex we are in and store it in rank (where rank describes what position coorinate i has in the sorted order of the features values) 223 | for( int i=0; i<=d_; i++ ) 224 | rank[i] = Zero; 225 | for( int i=0; i0; j-- ){ 366 | float cf = f[j-1]*scale_factor[j-1]; 367 | elevated[j] = sm - j*cf; 368 | sm += cf; 369 | } 370 | elevated[0] = sm; 371 | 372 | // Find the closest 0-colored simplex through rounding 373 | float down_factor = 1.0f / (d_+1); 374 | float up_factor = (d_+1); 375 | int sum = 0; 376 | for( int i=0; i<=d_; i++ ){ 377 | //int rd1 = round( down_factor * elevated[i]); 378 | int rd2; 379 | float v = down_factor * elevated[i]; 380 | float up = ceilf(v)*up_factor; 381 | float down = floorf(v)*up_factor; 382 | if (up - elevated[i] < elevated[i] - down) rd2 = (short)up; 383 | else rd2 = (short)down; 384 | 385 | //if(rd1!=rd2) 386 | // break; 387 | 388 | rem0[i] = rd2; 389 | sum += rd2*down_factor; 390 | } 391 | 392 | // Find the simplex we are in and store it in rank (where rank describes what position coorinate i has in the sorted order of the features values) 393 | for( int i=0; i<=d_; i++ ) 394 | rank[i] = 0; 395 | for( int i=0; i d_ ){ 412 | rank[i] -= d_+1; 413 | rem0[i] -= d_+1; 414 | } 415 | } 416 | 417 | // Compute the barycentric coordinates (p.10 in [Adams etal 2010]) 418 | for( int i=0; i<=d_+1; i++ ) 419 | barycentric[i] = 0; 420 | for( int i=0; i<=d_; i++ ){ 421 | float v = (elevated[i] - rem0[i])*down_factor; 422 | barycentric[d_-rank[i] ] += v; 423 | barycentric[d_-rank[i]+1] -= v; 424 | } 425 | // Wrap around 426 | barycentric[0] += 1.0 + barycentric[d_+1]; 427 | 428 | // Compute all vertices and their offset 429 | for( int remainder=0; remainder<=d_; remainder++ ){ 430 | for( int i=0; i 0 (used for blurring) 479 | float * values = new float[ (M_+2)*value_size ]; 480 | float * new_values = new float[ (M_+2)*value_size ]; 481 | 482 | for( int i=0; i<(M_+2)*value_size; i++ ) 483 | values[i] = new_values[i] = 0; 484 | 485 | // Splatting 486 | for( int i=0; i=0; reverse?j--:j++ ){ 496 | for( int i=0; i 0 (used for blurring) 533 | __m128 * sse_val = (__m128*) _mm_malloc( sse_value_size*sizeof(__m128), 16 ); 534 | __m128 * values = (__m128*) _mm_malloc( (M_+2)*sse_value_size*sizeof(__m128), 16 ); 535 | __m128 * new_values = (__m128*) _mm_malloc( (M_+2)*sse_value_size*sizeof(__m128), 16 ); 536 | 537 | __m128 Zero = _mm_set1_ps( 0 ); 538 | 539 | for( int i=0; i<(M_+2)*sse_value_size; i++ ) 540 | values[i] = new_values[i] = Zero; 541 | for( int i=0; i=0; reverse?j--:j++ ){ 557 | for( int i=0; i 0 (used for blurring) 615 | float * values = new float[ (M_+2)*value_size ]; 616 | float * new_values = new float[ (M_+2)*value_size ]; 617 | 618 | // Set the results to 0 619 | std::fill( df, df+N_*d_, 0.f ); 620 | 621 | // Initialize some constants 622 | std::vector scale_factor( d_ ); 623 | float inv_std_dev = sqrt(2.0 / 3.0)*(d_+1); 624 | for( int i=0; i=0; dir?j--:j++ ){ 646 | for( int i=0; i r_a( (d_+1)*value_size ), sm( value_size ); 662 | 663 | for( int i=0; id_?0:r0+1; 669 | int o0 = offset_[i*(d_+1)+r0]+1; 670 | int o1 = offset_[i*(d_+1)+r1]+1; 671 | for( int k=0; k