├── 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