├── CMakeLists.txt ├── LICENSE ├── README.txt ├── clustering.cc ├── clustering.h ├── cmake ├── FindCUDA.cmake ├── FindCUDA │ ├── .svn │ │ ├── all-wcprops │ │ ├── entries │ │ ├── prop-base │ │ │ ├── make2cmake.cmake.svn-base │ │ │ ├── parse_cubin.cmake.svn-base │ │ │ └── run_nvcc.cmake.svn-base │ │ └── text-base │ │ │ ├── make2cmake.cmake.svn-base │ │ │ ├── parse_cubin.cmake.svn-base │ │ │ └── run_nvcc.cmake.svn-base │ ├── make2cmake.cmake │ ├── parse_cubin.cmake │ └── run_nvcc.cmake ├── FindCUDASDK.cmake ├── FindEigen.cmake └── FindQwt.cmake ├── commons.h ├── cudawrapper.cu ├── cudawrapper.h ├── dataArray.h ├── helper_math.h ├── line3D.cc ├── line3D.h ├── lsd ├── lsd.cpp ├── lsd.hpp ├── lsd_opencv.cpp ├── lsd_opencv.hpp ├── lsd_wrap.cpp └── lsd_wrap.hpp ├── main_bundler.cpp ├── main_vsfm.cpp ├── segments.h ├── serialization.h ├── sparsematrix.cc ├── sparsematrix.h ├── universe.h ├── view.cc └── view.h /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.6) 2 | 3 | set (CMAKE_BUILD_TYPE Release) 4 | SET (CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") 5 | 6 | ##----------------------------------------------------------------------------- 7 | ## OpenCV 8 | FIND_PACKAGE(OpenCV REQUIRED) 9 | set (EXTRA_INC_DIRS 10 | ${EXTRA_INC_DIRS} 11 | ${OpenCV_INCLUDE_DIRS} 12 | ) 13 | set (EXTRA_LIBRARIES 14 | ${EXTRA_LIBRARIES} 15 | ${OpenCV_LIBS} 16 | ) 17 | 18 | link_directories(${OPENCV_LIB_DIR}) 19 | 20 | ##----------------------------------------------------------------------------- 21 | ## Eigen 22 | FIND_PACKAGE(Eigen REQUIRED) 23 | 24 | set (EXTRA_INC_DIRS 25 | ${EXTRA_INC_DIRS} 26 | ${EIGEN3_INCLUDE_DIR} 27 | ${EIGEN3_INCLUDE_DIR}/unsupported 28 | ) 29 | include_directories(${EIGEN3_INCLUDE_DIR}) 30 | 31 | ##----------------------------------------------------------------------------- 32 | ## CUDA 33 | FIND_PACKAGE(CUDA REQUIRED) 34 | IF(CUDA_FOUND) 35 | set (EXTRA_INC_DIRS 36 | ${EXTRA_INC_DIRS} 37 | ${CUDA_INCLUDE_DIRS} 38 | ${CUDA_SDK_INCLUDE_DIR} 39 | ) 40 | cuda_include_directories(${EXTRA_INC_DIRS}) 41 | set (EXTRA_LIBRARIES 42 | ${EXTRA_LIBRARIES} 43 | ${CUDA_LIBS} 44 | ${CUDA_cublas_LIBRARY} 45 | ) 46 | ENDIF(CUDA_FOUND) 47 | 48 | ##----------------------------------------------------------------------------- 49 | ## Boost 50 | set(Boost_USE_STATIC_LIBS OFF) 51 | set(Boost_USE_STATIC_RUNTIME OFF) 52 | FIND_PACKAGE(Boost REQUIRED COMPONENTS serialization filesystem system) 53 | 54 | if(Boost_FOUND) 55 | set (EXTRA_INC_DIRS 56 | ${EXTRA_INC_DIRS} 57 | ${Boost_INCLUDE_DIRS} 58 | ) 59 | 60 | set (EXTRA_LIBRARIES 61 | ${EXTRA_LIBRARIES} 62 | ${Boost_LIBRARIES} 63 | ) 64 | endif(Boost_FOUND) 65 | 66 | ##----------------------------------------------------------------------------- 67 | ## LSD (external) 68 | ##------------------------------------------------------------------------------ 69 | SET(lsd_SOURCES lsd/lsd.cpp lsd/lsd_opencv.cpp lsd/lsd_wrap.cpp) 70 | SET(lsd_HEADERS lsd/lsd.hpp lsd/lsd_opencv.hpp lsd/lsd_wrap.hpp) 71 | add_library(line3D_lsd SHARED ${lsd_SOURCES} ${lsd_HEADERS}) 72 | target_link_libraries(line3D_lsd ${OpenCV_LIBS}) 73 | 74 | add_definitions(-frounding-math) 75 | 76 | #---- combine external libs ----- 77 | set(ALL_LIBRARIES line3D_lsd ${EXTRA_LIBRARIES}) 78 | 79 | #---- Add Line3D library---- 80 | SET(Line3D_SOURCES line3D.cc view.cc sparsematrix.cc clustering.cc cudawrapper.cu) 81 | SET(Line3D_HEADERS line3D.h view.h sparsematrix.h clustering.h universe.h segments.h serialization.h commons.h dataArray.h cudawrapper.h) 82 | 83 | CUDA_ADD_LIBRARY(line3D SHARED ${Line3D_SOURCES} ${Line3D_HEADERS}) 84 | target_link_libraries(line3D ${ALL_LIBRARIES}) 85 | 86 | #----- Add main for bundler -------- 87 | add_executable(runLine3D_bundler main_bundler.cpp) 88 | target_link_libraries(runLine3D_bundler line3D) 89 | target_link_libraries(runLine3D_bundler ${ALL_LIBRARIES}) 90 | 91 | #----- Add main for VisualSfM -------- 92 | add_executable(runLine3D_vsfm main_vsfm.cpp) 93 | target_link_libraries(runLine3D_vsfm line3D) 94 | target_link_libraries(runLine3D_vsfm ${ALL_LIBRARIES}) 95 | 96 | -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 2 | Important information: A new improved version of Line3D is now available: 3 | http://github.com/manhofer/Line3Dpp 4 | Therefore, this version will no longer be updated. 5 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 6 | 7 | -------------------------------------------------------------------------------- 8 | Line3D - Line-based 3D Reconstruction Algorithm 9 | -------------------------------------------------------------------------------- 10 | Written by: Manuel Hofer, hofer@icg.tugraz.at, 11 | Institute for Computer Graphics and Vision, 12 | Graz University of Technology, 13 | AUSTRIA, 14 | http://www.icg.tugraz.at/ 15 | -------------------------------------------------------------------------------- 16 | Corresponding Paper: 17 | "Line3D: Efficient 3D Scene Abstraction for the Built Environment", 18 | Manuel Hofer, Michael Maurer, Horst Bischof, 19 | In Proceedings of the 37th German Conference on Pattern Recognition (GCPR), 20 | 2015. 21 | -------------------------------------------------------------------------------- 22 | Acknowledgements: 23 | This work has been supported by the Austrian Research Promotion Agency (FFG) 24 | project FreeLine (Bridge1/843450). 25 | -------------------------------------------------------------------------------- 26 | 27 | 1, Requirements: 28 | There is a CMakeLists.txt file included, which should enable you to easily 29 | build the Line3D library using CMake. 30 | 31 | External dependencies: 32 | - CUDA (>= 5.0) 33 | - boost (>= 1.50.x) 34 | - Eigen3 35 | - OpenCV (>= 2.3.x) 36 | - tclap 37 | 38 | If all these libraries are properly installed, compiling should be no problem! 39 | The version numbers above are only rough guesses with respect to what I am 40 | using myself (it might as well work with much older/newer versions). 41 | 42 | There are also two external components, which are integrated into the sourcecode 43 | for your convenience: 44 | 45 | - LSD - LineSegmentDetector (see copyright notice in lsd/lsd_opencv.hpp): 46 | "A Fast Line Segment Detector with a False Detection Control", 47 | R. von Gioi, J. Jakubowicz, J.M. Morel, G. Randall, 48 | Transactions on Pattern Analysis and Machine Intelligence (PAMI), 2010. 49 | 50 | - Graph-based Segmentation (adopted from http://cs.brown.edu/~pff/segment/): 51 | "Efficient Graph-based Image Segmentation", 52 | P. Fezenszwalb, F. Huttenlocher, 53 | International Journal of Computer Vision, 2004. 54 | 55 | Note: I have only tried this application on Ubuntu (14.04)! Since all external 56 | libraries should run on Windows as well it should be no problem to compile Line3D 57 | there (adaptaions of the CMakeLists.txt might be necessary). 58 | 59 | -------------------------------------------------------------------------------- 60 | 61 | 2, Usage: 62 | Line3D is a library which can be linked to any kind of C/C++ application. 63 | However, for your convenience there are executables included which can process 64 | bundler (http://www.cs.cornell.edu/~snavely/bundler/) and VisualSfM 65 | (http://ccwu.me/vsfm/) results. 66 | 67 | To compute a line-based 3D model for a SfM reconstruction using bundler 68 | or VisualSfM run one of the following executables: 69 | 70 | for VisualSfM: 71 | ./runLine3D_vsfm -i -m 72 | 73 | for bundler: 74 | ./runLine3D_bundler -i 75 | 76 | That's it! The result will be placed in the folder: 77 | /Line3D/ 78 | 79 | If you want to use Line3D within your own 3D reconstruction pipeline 80 | you just need to either link it to your existing application, or create 81 | a new main.cpp file (have a look at main_vsfm.cpp and main_bundler.cpp) which can process 82 | your SfM output. 83 | 84 | The following steps need to be followed to create 3D line models: 85 | 86 | - create Line3D object: Line3D(...) [line3D.h] 87 | 88 | - add images: void addImage(...) [line3D.h] 89 | Call this function for each image in your SfM result. The method needs 90 | the camera information (intrinsics, position) and a list of worldpoint IDs. 91 | The 3D position of the worldpoints is irrelevant, this is only needed 92 | to find visual neighbors among the images. 93 | 94 | - compute 3D model: void compute3Dmodel(...) [line3D.h] 95 | The algorithm now runs the matching and reconstruction steps. You can 96 | specify if you want to perform a diffusion-based correspondence 97 | optimization or not (default is off; usually not needed). 98 | 99 | - get result: void getResult(...) [line3D.h] 100 | The result contains the 3D lines and the corresponding 2D segment IDs 101 | in the images (if needed, you can retrieve the coordinates using the 102 | float4 getSegment2D(...) function). 103 | 104 | If you have questions regarding this process, please have a look at 105 | the main_vsfm.cpp or contact me. 106 | 107 | -------------------------------------------------------------------------------- 108 | 109 | 3, Parameters: 110 | The executable (for VisualSfM/bundler) takes a number of command line parameters, 111 | most of which are optional: 112 | 113 | -i [string] - Input_Folder (required) 114 | Path to the folder where the bundler.rd.out is located 115 | 116 | -o [string] - Output_Folder 117 | Output folder. If not specified, same as Input_Folder but with /Line3D/ attached 118 | to it (will be created automatically). 119 | 120 | -w [int] - Image_Max_Width 121 | The maximum width (or height, if the image is in portrait format) to which the images 122 | will be downscaled before line segment detection. By default this is set to 1920 (FullHD), 123 | which should not be altered if you work with images >= 10Megapixels 124 | (the detection takes less time and the results do not suffer). 125 | 126 | -n [int] - Number_of_Visual_Neighbors 127 | The number of images with which each image is matched. By default this is set to 12. 128 | Since the matching is very fast I would not recommend to decrease this number. 129 | Increasing it should only be done if you have a GPU with a large amount of memory! 130 | If you set it to -1, all images which share worldpoints are used (not recommended!) 131 | 132 | -a [float] - Reprojection_Error_Lower_Bound 133 | -b [float] - Reprojection_Error_Upper_Bound 134 | The error bounds (in pixels) for the affinity computation and clustering. These 135 | values will be projected into 3D space for 3D similarity computation (please have 136 | a look at the paper). If the results are too sparse, try increasing -b. 137 | 138 | -g [float] - Sigma_Angle 139 | -p [float] - Sigma_Position 140 | Values for confidence estimation of 3D line hypotheses (again in pixels). Similar to 141 | the two values above, but usually don't need to be changed (again, please have 142 | a look at the paper). 143 | 144 | -d [bool] - Diffusion 145 | Activates the diffusion process before clustering. Should not be used for extremely 146 | large datasets (>1000 images) and can in general be left disabled. 147 | 148 | -v [bool] - Verbose 149 | Shows more debug output. 150 | 151 | -l [bool] - Load_And_Store_Segments 152 | If enabled, 2D line segments are stored on the harddrive and don't have to be 153 | computed again when the testcase is re-run. 154 | 155 | -e [bool] - Collinearity 156 | If enabled (default), collinear but spatially distant segments are grouped 157 | together and aligned. 158 | 159 | -x [float] - Min_Baseline 160 | To avoid that images with a very small baseline are matched, you can specify 161 | the minimal required basedline here. This is the only value which is not scale 162 | invariant! By default it is set to 0.25f, which should be sufficient for a 163 | large number of scenarios. 164 | 165 | -------------------------------------------------------------------------------- 166 | 167 | 4, Results: 168 | The default output format for the 3D line models is an .stl file. It is 169 | placed in the output folder and named with respect to the choosen parameters. 170 | 171 | Note: If you open this file in Meshlab (http://meshlab.sourceforge.net/) 172 | you should see a window which states "Post-Open Processing". You have to 173 | untick the option "Unify Duplicated Vertices" and klick OK. Then switch to 174 | "Wireframe", "Hidden Lines" or "Flat Lines" modes and you should see a 175 | result. 176 | 177 | In addition the result is also saved as a .txt file in the following format 178 | (one line in the file per resulting 3D line): 179 | 180 | n P1x P1y P1z Q1x Q1y Q1z ... Pnx Pny Pnz Qnx Qny Qnz m camID1 segID1 p1x p1y q1x q1y ... camIDm segIDm pmx pmy qmx qmy 181 | 182 | The first "n" stands for the number of 3D segments on the 3D line. 183 | It is followed by the coordinates of the start- (P) and endpoints (Q) of these 3D segments. 184 | The "m" stands for the number of 2D residuals. 185 | It is followed by the camera ID, segment ID and the 2D coordinates of the segments. 186 | 187 | -------------------------------------------------------------------------------- 188 | 189 | If you have any questions or have found any bugs please contact me: 190 | hofer@icg.tugraz.at 191 | 192 | Best, 193 | Manuel 194 | 195 | -------------------------------------------------------------------------------- /clustering.cc: -------------------------------------------------------------------------------- 1 | #include "clustering.h" 2 | 3 | namespace L3D 4 | { 5 | //------------------------------------------------------------------------------ 6 | CLUniverse* performClustering(std::list edges, int numNodes, float c) 7 | { 8 | if(edges.size() == 0) 9 | return NULL; 10 | 11 | // sort edges by weight (increasing) 12 | edges.sort(L3D::sortEdges); 13 | 14 | // init universe 15 | CLUniverse *u = new CLUniverse(numNodes); 16 | 17 | // init thresholds 18 | float* threshold = new float[numNodes]; 19 | for(int i=0; i < numNodes; ++i) 20 | threshold[i] = c; 21 | 22 | // perform clustering 23 | std::list::iterator it = edges.begin(); 24 | for(; it!=edges.end(); ++it) 25 | { 26 | CLEdge e = *it; 27 | 28 | // components conected by this edge 29 | int a = u->find(e.i_); 30 | int b = u->find(e.j_); 31 | if (a != b) 32 | { 33 | // not in the same segment yet 34 | if((e.w_ <= threshold[a]) && (e.w_ <= threshold[b])) 35 | { 36 | // join nodes 37 | u->join(a,b); 38 | a = u->find(a); 39 | threshold[a] = e.w_ + c/u->size(a); 40 | } 41 | } 42 | } 43 | 44 | // cleanup 45 | delete threshold; 46 | return u; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /clustering.h: -------------------------------------------------------------------------------- 1 | #ifndef I3D_LINE3D_CLUSTERING_H_ 2 | #define I3D_LINE3D_CLUSTERING_H_ 3 | 4 | /* 5 | * Disclaimer: 6 | * Re-implementation of the algorithm described in the paper 7 | * 8 | * Efficient Graph-based Image Segmentation, 9 | * P. Fezenszwalb, F. Huttenlocher, 10 | * International Journal of Computer Vision, 2004. 11 | * 12 | * and based on their official source code, which can be found at 13 | * from http://cs.brown.edu/~pff/segment/ 14 | * 15 | * Their code is put under the GNU GENERAL PUBLIC LICENSE, 16 | * and so is this version. 17 | */ 18 | 19 | /* 20 | Line3D - Line-based Multi View Stereo 21 | Copyright (C) 2015 Manuel Hofer 22 | 23 | This program is free software: you can redistribute it and/or modify 24 | it under the terms of the GNU General Public License as published by 25 | the Free Software Foundation, either version 3 of the License, or 26 | (at your option) any later version. 27 | 28 | This program is distributed in the hope that it will be useful, 29 | but WITHOUT ANY WARRANTY; without even the implied warranty of 30 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 31 | GNU General Public License for more details. 32 | 33 | You should have received a copy of the GNU General Public License 34 | along with this program. If not, see . 35 | */ 36 | 37 | #include 38 | #include 39 | 40 | #include "universe.h" 41 | 42 | /** 43 | * Clustering 44 | * ==================== 45 | * Clustering/Segmentation Algorithm. 46 | * [Felzenswalb & Huttenlocher, IJCV 2004] 47 | * 48 | * This code is an adaption of their original source code, 49 | * to fit into our datastructures. 50 | * ==================== 51 | * Author: M.Hofer, 2015 52 | */ 53 | 54 | namespace L3D 55 | { 56 | // edge in affinity matrix 57 | typedef struct { 58 | int i_; 59 | int j_; 60 | float w_; 61 | } CLEdge; 62 | 63 | // point on clustered 2D line 64 | typedef struct { 65 | unsigned int lineID_; 66 | float x_; 67 | float y_; 68 | float pos_; 69 | } CLPointOnLine; 70 | 71 | // sorting function for edges 72 | static bool sortEdges(const CLEdge& a, const CLEdge& b) 73 | { 74 | return a.w_ < b.w_; 75 | } 76 | 77 | static bool sortEdgesByRow(const CLEdge& a, const CLEdge& b) 78 | { 79 | if(a.i_ < b.i_) 80 | return true; 81 | else if(a.i_ == b.i_ && a.j_ < b.j_) 82 | return true; 83 | else 84 | return false; 85 | } 86 | 87 | static bool sortEdgesByCol(const CLEdge& a, const CLEdge& b) 88 | { 89 | if(a.j_ < b.j_) 90 | return true; 91 | else if(a.j_ == b.j_ && a.i_ < b.i_) 92 | return true; 93 | else 94 | return false; 95 | } 96 | 97 | // sort entries for sparse affinity matrix (CLEdges) 98 | static bool sortCLEdgesByCol(const CLEdge a1, const CLEdge a2) 99 | { 100 | if(a1.j_ < a2.j_) 101 | return true; 102 | else if(a1.j_ == a2.j_ && a1.i_ < a2.i_) 103 | return true; 104 | else 105 | return false; 106 | } 107 | 108 | static bool sortCLEdgesByRow(const CLEdge a1, const CLEdge a2) 109 | { 110 | if(a1.i_ < a2.i_) 111 | return true; 112 | else if(a1.i_ == a2.i_ && a1.j_ < a2.j_) 113 | return true; 114 | else 115 | return false; 116 | } 117 | 118 | // sorting function for projected points on a line 119 | static bool sortPointsOnLine(const CLPointOnLine& a, const CLPointOnLine& b) 120 | { 121 | return a.pos_ < b.pos_; 122 | } 123 | 124 | // perform graph clustering 125 | CLUniverse* performClustering(std::list edges, int numNodes, 126 | float c); 127 | 128 | } 129 | 130 | #endif //I3D_LINE3D_CLUSTERING_H_ 131 | -------------------------------------------------------------------------------- /cmake/FindCUDA/.svn/all-wcprops: -------------------------------------------------------------------------------- 1 | K 25 2 | svn:wc:ra_dav:version-url 3 | V 53 4 | /svn/findcuda/!svn/ver/1220/trunk/CMake/cuda/FindCUDA 5 | END 6 | parse_cubin.cmake 7 | K 25 8 | svn:wc:ra_dav:version-url 9 | V 71 10 | /svn/findcuda/!svn/ver/1210/trunk/CMake/cuda/FindCUDA/parse_cubin.cmake 11 | END 12 | run_nvcc.cmake 13 | K 25 14 | svn:wc:ra_dav:version-url 15 | V 68 16 | /svn/findcuda/!svn/ver/1220/trunk/CMake/cuda/FindCUDA/run_nvcc.cmake 17 | END 18 | make2cmake.cmake 19 | K 25 20 | svn:wc:ra_dav:version-url 21 | V 70 22 | /svn/findcuda/!svn/ver/1210/trunk/CMake/cuda/FindCUDA/make2cmake.cmake 23 | END 24 | -------------------------------------------------------------------------------- /cmake/FindCUDA/.svn/entries: -------------------------------------------------------------------------------- 1 | 10 2 | 3 | dir 4 | 1227 5 | https://gforge.sci.utah.edu/svn/findcuda/trunk/CMake/cuda/FindCUDA 6 | https://gforge.sci.utah.edu/svn/findcuda 7 | 8 | 9 | 10 | 2012-12-19T20:07:28.616378Z 11 | 1220 12 | bigler 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 81322f20-870f-0410-845c-a4cd4664c908 28 | 29 | parse_cubin.cmake 30 | file 31 | 32 | 33 | 34 | 35 | 2014-06-03T07:18:47.000000Z 36 | f233707b4334672f3556587babf3e336 37 | 2012-08-20T22:47:59.683791Z 38 | 1210 39 | bigler 40 | has-props 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 3666 62 | 63 | run_nvcc.cmake 64 | file 65 | 66 | 67 | 68 | 69 | 2014-06-03T07:18:47.000000Z 70 | 13d0777ff373d91976023d1a6d35e6f5 71 | 2012-12-19T20:07:28.616378Z 72 | 1220 73 | bigler 74 | has-props 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 12755 96 | 97 | make2cmake.cmake 98 | file 99 | 100 | 101 | 102 | 103 | 2014-06-03T07:18:47.000000Z 104 | 52601701409164fa716b8834f722aeef 105 | 2012-08-20T22:47:59.683791Z 106 | 1210 107 | bigler 108 | has-props 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 3532 130 | 131 | -------------------------------------------------------------------------------- /cmake/FindCUDA/.svn/prop-base/make2cmake.cmake.svn-base: -------------------------------------------------------------------------------- 1 | K 13 2 | svn:eol-style 3 | V 6 4 | native 5 | K 14 6 | svn:executable 7 | V 1 8 | * 9 | END 10 | -------------------------------------------------------------------------------- /cmake/FindCUDA/.svn/prop-base/parse_cubin.cmake.svn-base: -------------------------------------------------------------------------------- 1 | K 13 2 | svn:eol-style 3 | V 6 4 | native 5 | END 6 | -------------------------------------------------------------------------------- /cmake/FindCUDA/.svn/prop-base/run_nvcc.cmake.svn-base: -------------------------------------------------------------------------------- 1 | K 13 2 | svn:eol-style 3 | V 6 4 | native 5 | K 14 6 | svn:executable 7 | V 1 8 | * 9 | END 10 | -------------------------------------------------------------------------------- /cmake/FindCUDA/.svn/text-base/make2cmake.cmake.svn-base: -------------------------------------------------------------------------------- 1 | # James Bigler, NVIDIA Corp (nvidia.com - jbigler) 2 | # Abe Stephens, SCI Institute -- http://www.sci.utah.edu/~abe/FindCuda.html 3 | # 4 | # Copyright (c) 2008 - 2009 NVIDIA Corporation. All rights reserved. 5 | # 6 | # Copyright (c) 2007-2009 7 | # Scientific Computing and Imaging Institute, University of Utah 8 | # 9 | # This code is licensed under the MIT License. See the FindCUDA.cmake script 10 | # for the text of the license. 11 | 12 | # The MIT License 13 | # 14 | # License for the specific language governing rights and limitations under 15 | # Permission is hereby granted, free of charge, to any person obtaining a 16 | # copy of this software and associated documentation files (the "Software"), 17 | # to deal in the Software without restriction, including without limitation 18 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 19 | # and/or sell copies of the Software, and to permit persons to whom the 20 | # Software is furnished to do so, subject to the following conditions: 21 | # 22 | # The above copyright notice and this permission notice shall be included 23 | # in all copies or substantial portions of the Software. 24 | # 25 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 26 | # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 27 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 28 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 29 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 30 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 31 | # DEALINGS IN THE SOFTWARE. 32 | # 33 | 34 | ####################################################################### 35 | # This converts a file written in makefile syntax into one that can be included 36 | # by CMake. 37 | 38 | file(READ ${input_file} depend_text) 39 | 40 | if (${depend_text} MATCHES ".+") 41 | 42 | # message("FOUND DEPENDS") 43 | 44 | # Remember, four backslashes is escaped to one backslash in the string. 45 | string(REGEX REPLACE "\\\\ " " " depend_text ${depend_text}) 46 | 47 | # This works for the nvcc -M generated dependency files. 48 | string(REGEX REPLACE "^.* : " "" depend_text ${depend_text}) 49 | string(REGEX REPLACE "[ \\\\]*\n" ";" depend_text ${depend_text}) 50 | 51 | set(dependency_list "") 52 | 53 | foreach(file ${depend_text}) 54 | 55 | string(REGEX REPLACE "^ +" "" file ${file}) 56 | 57 | # OK, now if we had a UNC path, nvcc has a tendency to only output the first '/' 58 | # instead of '//'. Here we will test to see if the file exists, if it doesn't then 59 | # try to prepend another '/' to the path and test again. If it still fails remove the 60 | # path. 61 | 62 | if(NOT EXISTS "${file}") 63 | if (EXISTS "/${file}") 64 | set(file "/${file}") 65 | else() 66 | message(WARNING " Removing non-existant dependency file: ${file}") 67 | set(file "") 68 | endif() 69 | endif() 70 | 71 | if(NOT IS_DIRECTORY "${file}") 72 | # If softlinks start to matter, we should change this to REALPATH. For now we need 73 | # to flatten paths, because nvcc can generate stuff like /bin/../include instead of 74 | # just /include. 75 | get_filename_component(file_absolute "${file}" ABSOLUTE) 76 | list(APPEND dependency_list "${file_absolute}") 77 | endif() 78 | 79 | endforeach() 80 | 81 | else() 82 | # message("FOUND NO DEPENDS") 83 | endif() 84 | 85 | # Remove the duplicate entries and sort them. 86 | list(REMOVE_DUPLICATES dependency_list) 87 | list(SORT dependency_list) 88 | 89 | foreach(file ${dependency_list}) 90 | set(cuda_nvcc_depend "${cuda_nvcc_depend} \"${file}\"\n") 91 | endforeach() 92 | 93 | file(WRITE ${output_file} "# Generated by: make2cmake.cmake\nSET(CUDA_NVCC_DEPEND\n ${cuda_nvcc_depend})\n\n") 94 | -------------------------------------------------------------------------------- /cmake/FindCUDA/.svn/text-base/parse_cubin.cmake.svn-base: -------------------------------------------------------------------------------- 1 | # James Bigler, NVIDIA Corp (nvidia.com - jbigler) 2 | # Abe Stephens, SCI Institute -- http://www.sci.utah.edu/~abe/FindCuda.html 3 | # 4 | # Copyright (c) 2008 - 2009 NVIDIA Corporation. All rights reserved. 5 | # 6 | # Copyright (c) 2007-2009 7 | # Scientific Computing and Imaging Institute, University of Utah 8 | # 9 | # This code is licensed under the MIT License. See the FindCUDA.cmake script 10 | # for the text of the license. 11 | 12 | # The MIT License 13 | # 14 | # License for the specific language governing rights and limitations under 15 | # Permission is hereby granted, free of charge, to any person obtaining a 16 | # copy of this software and associated documentation files (the "Software"), 17 | # to deal in the Software without restriction, including without limitation 18 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 19 | # and/or sell copies of the Software, and to permit persons to whom the 20 | # Software is furnished to do so, subject to the following conditions: 21 | # 22 | # The above copyright notice and this permission notice shall be included 23 | # in all copies or substantial portions of the Software. 24 | # 25 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 26 | # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 27 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 28 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 29 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 30 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 31 | # DEALINGS IN THE SOFTWARE. 32 | # 33 | 34 | ####################################################################### 35 | # Parses a .cubin file produced by nvcc and reports statistics about the file. 36 | 37 | 38 | file(READ ${input_file} file_text) 39 | 40 | if (${file_text} MATCHES ".+") 41 | 42 | # Remember, four backslashes is escaped to one backslash in the string. 43 | string(REGEX REPLACE ";" "\\\\;" file_text ${file_text}) 44 | string(REGEX REPLACE "\ncode" ";code" file_text ${file_text}) 45 | 46 | list(LENGTH file_text len) 47 | 48 | foreach(line ${file_text}) 49 | 50 | # Only look at "code { }" blocks. 51 | if(line MATCHES "^code") 52 | 53 | # Break into individual lines. 54 | string(REGEX REPLACE "\n" ";" line ${line}) 55 | 56 | foreach(entry ${line}) 57 | 58 | # Extract kernel names. 59 | if (${entry} MATCHES "[^g]name = ([^ ]+)") 60 | string(REGEX REPLACE ".* = ([^ ]+)" "\\1" entry ${entry}) 61 | 62 | # Check to see if the kernel name starts with "_" 63 | set(skip FALSE) 64 | # if (${entry} MATCHES "^_") 65 | # Skip the rest of this block. 66 | # message("Skipping ${entry}") 67 | # set(skip TRUE) 68 | # else () 69 | message("Kernel: ${entry}") 70 | # endif () 71 | 72 | endif() 73 | 74 | # Skip the rest of the block if necessary 75 | if(NOT skip) 76 | 77 | # Registers 78 | if (${entry} MATCHES "reg([ ]+)=([ ]+)([^ ]+)") 79 | string(REGEX REPLACE ".*([ ]+)=([ ]+)([^ ]+)" "\\3" entry ${entry}) 80 | message("Registers: ${entry}") 81 | endif() 82 | 83 | # Local memory 84 | if (${entry} MATCHES "lmem([ ]+)=([ ]+)([^ ]+)") 85 | string(REGEX REPLACE ".*([ ]+)=([ ]+)([^ ]+)" "\\3" entry ${entry}) 86 | message("Local: ${entry}") 87 | endif() 88 | 89 | # Shared memory 90 | if (${entry} MATCHES "smem([ ]+)=([ ]+)([^ ]+)") 91 | string(REGEX REPLACE ".*([ ]+)=([ ]+)([^ ]+)" "\\3" entry ${entry}) 92 | message("Shared: ${entry}") 93 | endif() 94 | 95 | if (${entry} MATCHES "^}") 96 | message("") 97 | endif() 98 | 99 | endif() 100 | 101 | 102 | endforeach() 103 | 104 | endif() 105 | 106 | endforeach() 107 | 108 | else() 109 | # message("FOUND NO DEPENDS") 110 | endif() 111 | 112 | 113 | -------------------------------------------------------------------------------- /cmake/FindCUDA/.svn/text-base/run_nvcc.cmake.svn-base: -------------------------------------------------------------------------------- 1 | # James Bigler, NVIDIA Corp (nvidia.com - jbigler) 2 | # 3 | # Copyright (c) 2008 - 2009 NVIDIA Corporation. All rights reserved. 4 | # 5 | # This code is licensed under the MIT License. See the FindCUDA.cmake script 6 | # for the text of the license. 7 | 8 | # The MIT License 9 | # 10 | # License for the specific language governing rights and limitations under 11 | # Permission is hereby granted, free of charge, to any person obtaining a 12 | # copy of this software and associated documentation files (the "Software"), 13 | # to deal in the Software without restriction, including without limitation 14 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 15 | # and/or sell copies of the Software, and to permit persons to whom the 16 | # Software is furnished to do so, subject to the following conditions: 17 | # 18 | # The above copyright notice and this permission notice shall be included 19 | # in all copies or substantial portions of the Software. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 22 | # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 24 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 26 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 27 | # DEALINGS IN THE SOFTWARE. 28 | 29 | 30 | ########################################################################## 31 | # This file runs the nvcc commands to produce the desired output file along with 32 | # the dependency file needed by CMake to compute dependencies. In addition the 33 | # file checks the output of each command and if the command fails it deletes the 34 | # output files. 35 | 36 | # Input variables 37 | # 38 | # verbose:BOOL=<> OFF: Be as quiet as possible (default) 39 | # ON : Describe each step 40 | # 41 | # build_configuration:STRING=<> Typically one of Debug, MinSizeRel, Release, or 42 | # RelWithDebInfo, but it should match one of the 43 | # entries in CUDA_HOST_FLAGS. This is the build 44 | # configuration used when compiling the code. If 45 | # blank or unspecified Debug is assumed as this is 46 | # what CMake does. 47 | # 48 | # generated_file:STRING=<> File to generate. This argument must be passed in. 49 | # 50 | # generated_cubin_file:STRING=<> File to generate. This argument must be passed 51 | # in if build_cubin is true. 52 | # generate_dependency_only:BOOL=<> Only generate the dependency file. 53 | # 54 | # check_dependencies:BOOL=<> Check the dependencies. If everything is up to 55 | # date, simply touch the output file instead of 56 | # generating it. 57 | 58 | if(NOT generated_file) 59 | message(FATAL_ERROR "You must specify generated_file on the command line") 60 | endif() 61 | 62 | # Set these up as variables to make reading the generated file easier 63 | set(CMAKE_COMMAND "@CMAKE_COMMAND@") # path 64 | set(source_file "@source_file@") # path 65 | set(NVCC_generated_dependency_file "@NVCC_generated_dependency_file@") # path 66 | set(cmake_dependency_file "@cmake_dependency_file@") # path 67 | set(CUDA_make2cmake "@CUDA_make2cmake@") # path 68 | set(CUDA_parse_cubin "@CUDA_parse_cubin@") # path 69 | set(build_cubin @build_cubin@) # bool 70 | set(CUDA_HOST_COMPILER "@CUDA_HOST_COMPILER@") # bool 71 | # We won't actually use these variables for now, but we need to set this, in 72 | # order to force this file to be run again if it changes. 73 | set(generated_file_path "@generated_file_path@") # path 74 | set(generated_file_internal "@generated_file@") # path 75 | set(generated_cubin_file_internal "@generated_cubin_file@") # path 76 | 77 | set(CUDA_NVCC_EXECUTABLE "@CUDA_NVCC_EXECUTABLE@") # path 78 | set(CUDA_NVCC_FLAGS @CUDA_NVCC_FLAGS@ ;; @CUDA_WRAP_OPTION_NVCC_FLAGS@) # list 79 | @CUDA_NVCC_FLAGS_CONFIG@ 80 | set(nvcc_flags @nvcc_flags@) # list 81 | set(CUDA_NVCC_INCLUDE_ARGS "@CUDA_NVCC_INCLUDE_ARGS@") # list (needs to be in quotes to handle spaces properly). 82 | set(format_flag "@format_flag@") # string 83 | 84 | if(build_cubin AND NOT generated_cubin_file) 85 | message(FATAL_ERROR "You must specify generated_cubin_file on the command line") 86 | endif() 87 | 88 | # This is the list of host compilation flags. It C or CXX should already have 89 | # been chosen by FindCUDA.cmake. 90 | @CUDA_HOST_FLAGS@ 91 | 92 | # Take the compiler flags and package them up to be sent to the compiler via -Xcompiler 93 | set(nvcc_host_compiler_flags "") 94 | # If we weren't given a build_configuration, use Debug. 95 | if(NOT build_configuration) 96 | set(build_configuration Debug) 97 | endif() 98 | string(TOUPPER "${build_configuration}" build_configuration) 99 | #message("CUDA_NVCC_HOST_COMPILER_FLAGS = ${CUDA_NVCC_HOST_COMPILER_FLAGS}") 100 | foreach(flag ${CMAKE_HOST_FLAGS} ${CMAKE_HOST_FLAGS_${build_configuration}}) 101 | # Extra quotes are added around each flag to help nvcc parse out flags with spaces. 102 | set(nvcc_host_compiler_flags "${nvcc_host_compiler_flags},\"${flag}\"") 103 | endforeach() 104 | if (nvcc_host_compiler_flags) 105 | set(nvcc_host_compiler_flags "-Xcompiler" ${nvcc_host_compiler_flags}) 106 | endif() 107 | #message("nvcc_host_compiler_flags = \"${nvcc_host_compiler_flags}\"") 108 | # Add the build specific configuration flags 109 | list(APPEND CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS_${build_configuration}}) 110 | 111 | # Any -ccbin existing in CUDA_NVCC_FLAGS gets highest priority 112 | list( FIND CUDA_NVCC_FLAGS "-ccbin" ccbin_found0 ) 113 | list( FIND CUDA_NVCC_FLAGS "--compiler-bindir" ccbin_found1 ) 114 | if( ccbin_found0 LESS 0 AND ccbin_found1 LESS 0 ) 115 | if (CUDA_HOST_COMPILER STREQUAL "$(VCInstallDir)bin" AND DEFINED CCBIN) 116 | set(CCBIN -ccbin "${CCBIN}") 117 | else() 118 | set(CCBIN -ccbin "${CUDA_HOST_COMPILER}") 119 | endif() 120 | endif() 121 | 122 | # cuda_execute_process - Executes a command with optional command echo and status message. 123 | # 124 | # status - Status message to print if verbose is true 125 | # command - COMMAND argument from the usual execute_process argument structure 126 | # ARGN - Remaining arguments are the command with arguments 127 | # 128 | # CUDA_result - return value from running the command 129 | # 130 | # Make this a macro instead of a function, so that things like RESULT_VARIABLE 131 | # and other return variables are present after executing the process. 132 | macro(cuda_execute_process status command) 133 | set(_command ${command}) 134 | if(NOT _command STREQUAL "COMMAND") 135 | message(FATAL_ERROR "Malformed call to cuda_execute_process. Missing COMMAND as second argument. (command = ${command})") 136 | endif() 137 | if(verbose) 138 | execute_process(COMMAND "${CMAKE_COMMAND}" -E echo -- ${status}) 139 | # Now we need to build up our command string. We are accounting for quotes 140 | # and spaces, anything else is left up to the user to fix if they want to 141 | # copy and paste a runnable command line. 142 | set(cuda_execute_process_string) 143 | foreach(arg ${ARGN}) 144 | # If there are quotes, excape them, so they come through. 145 | string(REPLACE "\"" "\\\"" arg ${arg}) 146 | # Args with spaces need quotes around them to get them to be parsed as a single argument. 147 | if(arg MATCHES " ") 148 | list(APPEND cuda_execute_process_string "\"${arg}\"") 149 | else() 150 | list(APPEND cuda_execute_process_string ${arg}) 151 | endif() 152 | endforeach() 153 | # Echo the command 154 | execute_process(COMMAND ${CMAKE_COMMAND} -E echo ${cuda_execute_process_string}) 155 | endif() 156 | # Run the command 157 | execute_process(COMMAND ${ARGN} RESULT_VARIABLE CUDA_result ) 158 | endmacro() 159 | 160 | # For CUDA 2.3 and below, -G -M doesn't work, so remove the -G flag 161 | # for dependency generation and hope for the best. 162 | set(depends_CUDA_NVCC_FLAGS "${CUDA_NVCC_FLAGS}") 163 | set(CUDA_VERSION @CUDA_VERSION@) 164 | if(CUDA_VERSION VERSION_LESS "3.0") 165 | cmake_policy(PUSH) 166 | # CMake policy 0007 NEW states that empty list elements are not 167 | # ignored. I'm just setting it to avoid the warning that's printed. 168 | cmake_policy(SET CMP0007 NEW) 169 | # Note that this will remove all occurances of -G. 170 | list(REMOVE_ITEM depends_CUDA_NVCC_FLAGS "-G") 171 | cmake_policy(POP) 172 | endif() 173 | 174 | # nvcc doesn't define __CUDACC__ for some reason when generating dependency files. This 175 | # can cause incorrect dependencies when #including files based on this macro which is 176 | # defined in the generating passes of nvcc invokation. We will go ahead and manually 177 | # define this for now until a future version fixes this bug. 178 | set(CUDACC_DEFINE -D__CUDACC__) 179 | 180 | # Generate the dependency file 181 | cuda_execute_process( 182 | "Generating dependency file: ${NVCC_generated_dependency_file}" 183 | COMMAND "${CUDA_NVCC_EXECUTABLE}" 184 | -M 185 | ${CUDACC_DEFINE} 186 | "${source_file}" 187 | -o "${NVCC_generated_dependency_file}" 188 | ${CCBIN} 189 | ${nvcc_flags} 190 | ${nvcc_host_compiler_flags} 191 | ${depends_CUDA_NVCC_FLAGS} 192 | -DNVCC 193 | ${CUDA_NVCC_INCLUDE_ARGS} 194 | ) 195 | 196 | if(CUDA_result) 197 | message(FATAL_ERROR "Error generating ${generated_file}") 198 | endif() 199 | 200 | # Generate the cmake readable dependency file to a temp file. Don't put the 201 | # quotes just around the filenames for the input_file and output_file variables. 202 | # CMake will pass the quotes through and not be able to find the file. 203 | cuda_execute_process( 204 | "Generating temporary cmake readable file: ${cmake_dependency_file}.tmp" 205 | COMMAND "${CMAKE_COMMAND}" 206 | -D "input_file:FILEPATH=${NVCC_generated_dependency_file}" 207 | -D "output_file:FILEPATH=${cmake_dependency_file}.tmp" 208 | -P "${CUDA_make2cmake}" 209 | ) 210 | 211 | if(CUDA_result) 212 | message(FATAL_ERROR "Error generating ${generated_file}") 213 | endif() 214 | 215 | # Copy the file if it is different 216 | cuda_execute_process( 217 | "Copy if different ${cmake_dependency_file}.tmp to ${cmake_dependency_file}" 218 | COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${cmake_dependency_file}.tmp" "${cmake_dependency_file}" 219 | ) 220 | 221 | if(CUDA_result) 222 | message(FATAL_ERROR "Error generating ${generated_file}") 223 | endif() 224 | 225 | # Delete the temporary file 226 | cuda_execute_process( 227 | "Removing ${cmake_dependency_file}.tmp" 228 | COMMAND "${CMAKE_COMMAND}" -E remove "${cmake_dependency_file}.tmp" 229 | ) 230 | 231 | if(CUDA_result) 232 | message(FATAL_ERROR "Error generating ${generated_file}") 233 | endif() 234 | 235 | if (generate_dependency_only) 236 | return() 237 | endif() 238 | 239 | if (check_dependencies) 240 | set(rebuild FALSE) 241 | include(${cmake_dependency_file}) 242 | if(NOT CUDA_NVCC_DEPEND) 243 | # CUDA_NVCC_DEPEND should have something useful in it by now. If not we 244 | # should force the rebuild. 245 | if (verbose) 246 | message(WARNING "CUDA_NVCC_DEPEND not found for ${generated_file}") 247 | endif() 248 | set(rebuild TRUE) 249 | endif() 250 | # Rebuilding is also dependent on this file changing. 251 | list(APPEND CUDA_NVCC_DEPEND "${CMAKE_CURRENT_LIST_FILE}") 252 | foreach(f ${CUDA_NVCC_DEPEND}) 253 | # True if file1 is newer than file2 or if one of the two files doesn't 254 | # exist. Behavior is well-defined only for full paths. If the file time 255 | # stamps are exactly the same, an IS_NEWER_THAN comparison returns true, so 256 | # that any dependent build operations will occur in the event of a tie. This 257 | # includes the case of passing the same file name for both file1 and file2. 258 | if("${f}" IS_NEWER_THAN "${generated_file}") 259 | #message("file ${f} is newer than ${generated_file}") 260 | set(rebuild TRUE) 261 | endif() 262 | endforeach() 263 | if (NOT rebuild) 264 | #message("Not rebuilding ${generated_file}") 265 | cuda_execute_process( 266 | "Dependencies up to date. Not rebuilding ${generated_file}" 267 | COMMAND "${CMAKE_COMMAND}" -E touch "${generated_file}" 268 | ) 269 | return() 270 | endif() 271 | endif() 272 | 273 | # Delete the target file 274 | cuda_execute_process( 275 | "Removing ${generated_file}" 276 | COMMAND "${CMAKE_COMMAND}" -E remove "${generated_file}" 277 | ) 278 | 279 | # Generate the code 280 | cuda_execute_process( 281 | "Generating ${generated_file}" 282 | COMMAND "${CUDA_NVCC_EXECUTABLE}" 283 | "${source_file}" 284 | ${format_flag} -o "${generated_file}" 285 | ${CCBIN} 286 | ${nvcc_flags} 287 | ${nvcc_host_compiler_flags} 288 | ${CUDA_NVCC_FLAGS} 289 | -DNVCC 290 | ${CUDA_NVCC_INCLUDE_ARGS} 291 | ) 292 | 293 | if(CUDA_result) 294 | # Since nvcc can sometimes leave half done files make sure that we delete the output file. 295 | cuda_execute_process( 296 | "Removing ${generated_file}" 297 | COMMAND "${CMAKE_COMMAND}" -E remove "${generated_file}" 298 | ) 299 | message(FATAL_ERROR "Error generating file ${generated_file}") 300 | else() 301 | if(verbose) 302 | message("Generated ${generated_file} successfully.") 303 | endif() 304 | endif() 305 | 306 | # Cubin resource report commands. 307 | if( build_cubin ) 308 | # Run with -cubin to produce resource usage report. 309 | cuda_execute_process( 310 | "Generating ${generated_cubin_file}" 311 | COMMAND "${CUDA_NVCC_EXECUTABLE}" 312 | "${source_file}" 313 | ${CUDA_NVCC_FLAGS} 314 | ${nvcc_flags} 315 | ${CCBIN} 316 | ${nvcc_host_compiler_flags} 317 | -DNVCC 318 | -cubin 319 | -o "${generated_cubin_file}" 320 | ${CUDA_NVCC_INCLUDE_ARGS} 321 | ) 322 | 323 | # Execute the parser script. 324 | cuda_execute_process( 325 | "Executing the parser script" 326 | COMMAND "${CMAKE_COMMAND}" 327 | -D "input_file:STRING=${generated_cubin_file}" 328 | -P "${CUDA_parse_cubin}" 329 | ) 330 | 331 | endif() 332 | -------------------------------------------------------------------------------- /cmake/FindCUDA/make2cmake.cmake: -------------------------------------------------------------------------------- 1 | # James Bigler, NVIDIA Corp (nvidia.com - jbigler) 2 | # Abe Stephens, SCI Institute -- http://www.sci.utah.edu/~abe/FindCuda.html 3 | # 4 | # Copyright (c) 2008 - 2009 NVIDIA Corporation. All rights reserved. 5 | # 6 | # Copyright (c) 2007-2009 7 | # Scientific Computing and Imaging Institute, University of Utah 8 | # 9 | # This code is licensed under the MIT License. See the FindCUDA.cmake script 10 | # for the text of the license. 11 | 12 | # The MIT License 13 | # 14 | # License for the specific language governing rights and limitations under 15 | # Permission is hereby granted, free of charge, to any person obtaining a 16 | # copy of this software and associated documentation files (the "Software"), 17 | # to deal in the Software without restriction, including without limitation 18 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 19 | # and/or sell copies of the Software, and to permit persons to whom the 20 | # Software is furnished to do so, subject to the following conditions: 21 | # 22 | # The above copyright notice and this permission notice shall be included 23 | # in all copies or substantial portions of the Software. 24 | # 25 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 26 | # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 27 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 28 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 29 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 30 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 31 | # DEALINGS IN THE SOFTWARE. 32 | # 33 | 34 | ####################################################################### 35 | # This converts a file written in makefile syntax into one that can be included 36 | # by CMake. 37 | 38 | file(READ ${input_file} depend_text) 39 | 40 | if (${depend_text} MATCHES ".+") 41 | 42 | # message("FOUND DEPENDS") 43 | 44 | # Remember, four backslashes is escaped to one backslash in the string. 45 | string(REGEX REPLACE "\\\\ " " " depend_text ${depend_text}) 46 | 47 | # This works for the nvcc -M generated dependency files. 48 | string(REGEX REPLACE "^.* : " "" depend_text ${depend_text}) 49 | string(REGEX REPLACE "[ \\\\]*\n" ";" depend_text ${depend_text}) 50 | 51 | set(dependency_list "") 52 | 53 | foreach(file ${depend_text}) 54 | 55 | string(REGEX REPLACE "^ +" "" file ${file}) 56 | 57 | # OK, now if we had a UNC path, nvcc has a tendency to only output the first '/' 58 | # instead of '//'. Here we will test to see if the file exists, if it doesn't then 59 | # try to prepend another '/' to the path and test again. If it still fails remove the 60 | # path. 61 | 62 | if(NOT EXISTS "${file}") 63 | if (EXISTS "/${file}") 64 | set(file "/${file}") 65 | else() 66 | message(WARNING " Removing non-existant dependency file: ${file}") 67 | set(file "") 68 | endif() 69 | endif() 70 | 71 | if(NOT IS_DIRECTORY "${file}") 72 | # If softlinks start to matter, we should change this to REALPATH. For now we need 73 | # to flatten paths, because nvcc can generate stuff like /bin/../include instead of 74 | # just /include. 75 | get_filename_component(file_absolute "${file}" ABSOLUTE) 76 | list(APPEND dependency_list "${file_absolute}") 77 | endif() 78 | 79 | endforeach() 80 | 81 | else() 82 | # message("FOUND NO DEPENDS") 83 | endif() 84 | 85 | # Remove the duplicate entries and sort them. 86 | list(REMOVE_DUPLICATES dependency_list) 87 | list(SORT dependency_list) 88 | 89 | foreach(file ${dependency_list}) 90 | set(cuda_nvcc_depend "${cuda_nvcc_depend} \"${file}\"\n") 91 | endforeach() 92 | 93 | file(WRITE ${output_file} "# Generated by: make2cmake.cmake\nSET(CUDA_NVCC_DEPEND\n ${cuda_nvcc_depend})\n\n") 94 | -------------------------------------------------------------------------------- /cmake/FindCUDA/parse_cubin.cmake: -------------------------------------------------------------------------------- 1 | # James Bigler, NVIDIA Corp (nvidia.com - jbigler) 2 | # Abe Stephens, SCI Institute -- http://www.sci.utah.edu/~abe/FindCuda.html 3 | # 4 | # Copyright (c) 2008 - 2009 NVIDIA Corporation. All rights reserved. 5 | # 6 | # Copyright (c) 2007-2009 7 | # Scientific Computing and Imaging Institute, University of Utah 8 | # 9 | # This code is licensed under the MIT License. See the FindCUDA.cmake script 10 | # for the text of the license. 11 | 12 | # The MIT License 13 | # 14 | # License for the specific language governing rights and limitations under 15 | # Permission is hereby granted, free of charge, to any person obtaining a 16 | # copy of this software and associated documentation files (the "Software"), 17 | # to deal in the Software without restriction, including without limitation 18 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 19 | # and/or sell copies of the Software, and to permit persons to whom the 20 | # Software is furnished to do so, subject to the following conditions: 21 | # 22 | # The above copyright notice and this permission notice shall be included 23 | # in all copies or substantial portions of the Software. 24 | # 25 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 26 | # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 27 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 28 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 29 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 30 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 31 | # DEALINGS IN THE SOFTWARE. 32 | # 33 | 34 | ####################################################################### 35 | # Parses a .cubin file produced by nvcc and reports statistics about the file. 36 | 37 | 38 | file(READ ${input_file} file_text) 39 | 40 | if (${file_text} MATCHES ".+") 41 | 42 | # Remember, four backslashes is escaped to one backslash in the string. 43 | string(REGEX REPLACE ";" "\\\\;" file_text ${file_text}) 44 | string(REGEX REPLACE "\ncode" ";code" file_text ${file_text}) 45 | 46 | list(LENGTH file_text len) 47 | 48 | foreach(line ${file_text}) 49 | 50 | # Only look at "code { }" blocks. 51 | if(line MATCHES "^code") 52 | 53 | # Break into individual lines. 54 | string(REGEX REPLACE "\n" ";" line ${line}) 55 | 56 | foreach(entry ${line}) 57 | 58 | # Extract kernel names. 59 | if (${entry} MATCHES "[^g]name = ([^ ]+)") 60 | string(REGEX REPLACE ".* = ([^ ]+)" "\\1" entry ${entry}) 61 | 62 | # Check to see if the kernel name starts with "_" 63 | set(skip FALSE) 64 | # if (${entry} MATCHES "^_") 65 | # Skip the rest of this block. 66 | # message("Skipping ${entry}") 67 | # set(skip TRUE) 68 | # else () 69 | message("Kernel: ${entry}") 70 | # endif () 71 | 72 | endif() 73 | 74 | # Skip the rest of the block if necessary 75 | if(NOT skip) 76 | 77 | # Registers 78 | if (${entry} MATCHES "reg([ ]+)=([ ]+)([^ ]+)") 79 | string(REGEX REPLACE ".*([ ]+)=([ ]+)([^ ]+)" "\\3" entry ${entry}) 80 | message("Registers: ${entry}") 81 | endif() 82 | 83 | # Local memory 84 | if (${entry} MATCHES "lmem([ ]+)=([ ]+)([^ ]+)") 85 | string(REGEX REPLACE ".*([ ]+)=([ ]+)([^ ]+)" "\\3" entry ${entry}) 86 | message("Local: ${entry}") 87 | endif() 88 | 89 | # Shared memory 90 | if (${entry} MATCHES "smem([ ]+)=([ ]+)([^ ]+)") 91 | string(REGEX REPLACE ".*([ ]+)=([ ]+)([^ ]+)" "\\3" entry ${entry}) 92 | message("Shared: ${entry}") 93 | endif() 94 | 95 | if (${entry} MATCHES "^}") 96 | message("") 97 | endif() 98 | 99 | endif() 100 | 101 | 102 | endforeach() 103 | 104 | endif() 105 | 106 | endforeach() 107 | 108 | else() 109 | # message("FOUND NO DEPENDS") 110 | endif() 111 | 112 | 113 | -------------------------------------------------------------------------------- /cmake/FindCUDA/run_nvcc.cmake: -------------------------------------------------------------------------------- 1 | # James Bigler, NVIDIA Corp (nvidia.com - jbigler) 2 | # 3 | # Copyright (c) 2008 - 2009 NVIDIA Corporation. All rights reserved. 4 | # 5 | # This code is licensed under the MIT License. See the FindCUDA.cmake script 6 | # for the text of the license. 7 | 8 | # The MIT License 9 | # 10 | # License for the specific language governing rights and limitations under 11 | # Permission is hereby granted, free of charge, to any person obtaining a 12 | # copy of this software and associated documentation files (the "Software"), 13 | # to deal in the Software without restriction, including without limitation 14 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 15 | # and/or sell copies of the Software, and to permit persons to whom the 16 | # Software is furnished to do so, subject to the following conditions: 17 | # 18 | # The above copyright notice and this permission notice shall be included 19 | # in all copies or substantial portions of the Software. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 22 | # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 24 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 26 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 27 | # DEALINGS IN THE SOFTWARE. 28 | 29 | 30 | ########################################################################## 31 | # This file runs the nvcc commands to produce the desired output file along with 32 | # the dependency file needed by CMake to compute dependencies. In addition the 33 | # file checks the output of each command and if the command fails it deletes the 34 | # output files. 35 | 36 | # Input variables 37 | # 38 | # verbose:BOOL=<> OFF: Be as quiet as possible (default) 39 | # ON : Describe each step 40 | # 41 | # build_configuration:STRING=<> Typically one of Debug, MinSizeRel, Release, or 42 | # RelWithDebInfo, but it should match one of the 43 | # entries in CUDA_HOST_FLAGS. This is the build 44 | # configuration used when compiling the code. If 45 | # blank or unspecified Debug is assumed as this is 46 | # what CMake does. 47 | # 48 | # generated_file:STRING=<> File to generate. This argument must be passed in. 49 | # 50 | # generated_cubin_file:STRING=<> File to generate. This argument must be passed 51 | # in if build_cubin is true. 52 | # generate_dependency_only:BOOL=<> Only generate the dependency file. 53 | # 54 | # check_dependencies:BOOL=<> Check the dependencies. If everything is up to 55 | # date, simply touch the output file instead of 56 | # generating it. 57 | 58 | if(NOT generated_file) 59 | message(FATAL_ERROR "You must specify generated_file on the command line") 60 | endif() 61 | 62 | # Set these up as variables to make reading the generated file easier 63 | set(CMAKE_COMMAND "@CMAKE_COMMAND@") # path 64 | set(source_file "@source_file@") # path 65 | set(NVCC_generated_dependency_file "@NVCC_generated_dependency_file@") # path 66 | set(cmake_dependency_file "@cmake_dependency_file@") # path 67 | set(CUDA_make2cmake "@CUDA_make2cmake@") # path 68 | set(CUDA_parse_cubin "@CUDA_parse_cubin@") # path 69 | set(build_cubin @build_cubin@) # bool 70 | set(CUDA_HOST_COMPILER "@CUDA_HOST_COMPILER@") # bool 71 | # We won't actually use these variables for now, but we need to set this, in 72 | # order to force this file to be run again if it changes. 73 | set(generated_file_path "@generated_file_path@") # path 74 | set(generated_file_internal "@generated_file@") # path 75 | set(generated_cubin_file_internal "@generated_cubin_file@") # path 76 | 77 | set(CUDA_NVCC_EXECUTABLE "@CUDA_NVCC_EXECUTABLE@") # path 78 | set(CUDA_NVCC_FLAGS @CUDA_NVCC_FLAGS@ ;; @CUDA_WRAP_OPTION_NVCC_FLAGS@) # list 79 | @CUDA_NVCC_FLAGS_CONFIG@ 80 | set(nvcc_flags @nvcc_flags@) # list 81 | set(CUDA_NVCC_INCLUDE_ARGS "@CUDA_NVCC_INCLUDE_ARGS@") # list (needs to be in quotes to handle spaces properly). 82 | set(format_flag "@format_flag@") # string 83 | 84 | if(build_cubin AND NOT generated_cubin_file) 85 | message(FATAL_ERROR "You must specify generated_cubin_file on the command line") 86 | endif() 87 | 88 | # This is the list of host compilation flags. It C or CXX should already have 89 | # been chosen by FindCUDA.cmake. 90 | @CUDA_HOST_FLAGS@ 91 | 92 | # Take the compiler flags and package them up to be sent to the compiler via -Xcompiler 93 | set(nvcc_host_compiler_flags "") 94 | # If we weren't given a build_configuration, use Debug. 95 | if(NOT build_configuration) 96 | set(build_configuration Debug) 97 | endif() 98 | string(TOUPPER "${build_configuration}" build_configuration) 99 | #message("CUDA_NVCC_HOST_COMPILER_FLAGS = ${CUDA_NVCC_HOST_COMPILER_FLAGS}") 100 | foreach(flag ${CMAKE_HOST_FLAGS} ${CMAKE_HOST_FLAGS_${build_configuration}}) 101 | # Extra quotes are added around each flag to help nvcc parse out flags with spaces. 102 | set(nvcc_host_compiler_flags "${nvcc_host_compiler_flags},\"${flag}\"") 103 | endforeach() 104 | if (nvcc_host_compiler_flags) 105 | set(nvcc_host_compiler_flags "-Xcompiler" ${nvcc_host_compiler_flags}) 106 | endif() 107 | #message("nvcc_host_compiler_flags = \"${nvcc_host_compiler_flags}\"") 108 | # Add the build specific configuration flags 109 | list(APPEND CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS_${build_configuration}}) 110 | 111 | # Any -ccbin existing in CUDA_NVCC_FLAGS gets highest priority 112 | list( FIND CUDA_NVCC_FLAGS "-ccbin" ccbin_found0 ) 113 | list( FIND CUDA_NVCC_FLAGS "--compiler-bindir" ccbin_found1 ) 114 | if( ccbin_found0 LESS 0 AND ccbin_found1 LESS 0 ) 115 | if (CUDA_HOST_COMPILER STREQUAL "$(VCInstallDir)bin" AND DEFINED CCBIN) 116 | set(CCBIN -ccbin "${CCBIN}") 117 | else() 118 | set(CCBIN -ccbin "${CUDA_HOST_COMPILER}") 119 | endif() 120 | endif() 121 | 122 | # cuda_execute_process - Executes a command with optional command echo and status message. 123 | # 124 | # status - Status message to print if verbose is true 125 | # command - COMMAND argument from the usual execute_process argument structure 126 | # ARGN - Remaining arguments are the command with arguments 127 | # 128 | # CUDA_result - return value from running the command 129 | # 130 | # Make this a macro instead of a function, so that things like RESULT_VARIABLE 131 | # and other return variables are present after executing the process. 132 | macro(cuda_execute_process status command) 133 | set(_command ${command}) 134 | if(NOT _command STREQUAL "COMMAND") 135 | message(FATAL_ERROR "Malformed call to cuda_execute_process. Missing COMMAND as second argument. (command = ${command})") 136 | endif() 137 | if(verbose) 138 | execute_process(COMMAND "${CMAKE_COMMAND}" -E echo -- ${status}) 139 | # Now we need to build up our command string. We are accounting for quotes 140 | # and spaces, anything else is left up to the user to fix if they want to 141 | # copy and paste a runnable command line. 142 | set(cuda_execute_process_string) 143 | foreach(arg ${ARGN}) 144 | # If there are quotes, excape them, so they come through. 145 | string(REPLACE "\"" "\\\"" arg ${arg}) 146 | # Args with spaces need quotes around them to get them to be parsed as a single argument. 147 | if(arg MATCHES " ") 148 | list(APPEND cuda_execute_process_string "\"${arg}\"") 149 | else() 150 | list(APPEND cuda_execute_process_string ${arg}) 151 | endif() 152 | endforeach() 153 | # Echo the command 154 | execute_process(COMMAND ${CMAKE_COMMAND} -E echo ${cuda_execute_process_string}) 155 | endif() 156 | # Run the command 157 | execute_process(COMMAND ${ARGN} RESULT_VARIABLE CUDA_result ) 158 | endmacro() 159 | 160 | # For CUDA 2.3 and below, -G -M doesn't work, so remove the -G flag 161 | # for dependency generation and hope for the best. 162 | set(depends_CUDA_NVCC_FLAGS "${CUDA_NVCC_FLAGS}") 163 | set(CUDA_VERSION @CUDA_VERSION@) 164 | if(CUDA_VERSION VERSION_LESS "3.0") 165 | cmake_policy(PUSH) 166 | # CMake policy 0007 NEW states that empty list elements are not 167 | # ignored. I'm just setting it to avoid the warning that's printed. 168 | cmake_policy(SET CMP0007 NEW) 169 | # Note that this will remove all occurances of -G. 170 | list(REMOVE_ITEM depends_CUDA_NVCC_FLAGS "-G") 171 | cmake_policy(POP) 172 | endif() 173 | 174 | # nvcc doesn't define __CUDACC__ for some reason when generating dependency files. This 175 | # can cause incorrect dependencies when #including files based on this macro which is 176 | # defined in the generating passes of nvcc invokation. We will go ahead and manually 177 | # define this for now until a future version fixes this bug. 178 | set(CUDACC_DEFINE -D__CUDACC__) 179 | 180 | # Generate the dependency file 181 | cuda_execute_process( 182 | "Generating dependency file: ${NVCC_generated_dependency_file}" 183 | COMMAND "${CUDA_NVCC_EXECUTABLE}" 184 | -M 185 | ${CUDACC_DEFINE} 186 | "${source_file}" 187 | -o "${NVCC_generated_dependency_file}" 188 | ${CCBIN} 189 | ${nvcc_flags} 190 | ${nvcc_host_compiler_flags} 191 | ${depends_CUDA_NVCC_FLAGS} 192 | -DNVCC 193 | ${CUDA_NVCC_INCLUDE_ARGS} 194 | ) 195 | 196 | if(CUDA_result) 197 | message(FATAL_ERROR "Error generating ${generated_file}") 198 | endif() 199 | 200 | # Generate the cmake readable dependency file to a temp file. Don't put the 201 | # quotes just around the filenames for the input_file and output_file variables. 202 | # CMake will pass the quotes through and not be able to find the file. 203 | cuda_execute_process( 204 | "Generating temporary cmake readable file: ${cmake_dependency_file}.tmp" 205 | COMMAND "${CMAKE_COMMAND}" 206 | -D "input_file:FILEPATH=${NVCC_generated_dependency_file}" 207 | -D "output_file:FILEPATH=${cmake_dependency_file}.tmp" 208 | -P "${CUDA_make2cmake}" 209 | ) 210 | 211 | if(CUDA_result) 212 | message(FATAL_ERROR "Error generating ${generated_file}") 213 | endif() 214 | 215 | # Copy the file if it is different 216 | cuda_execute_process( 217 | "Copy if different ${cmake_dependency_file}.tmp to ${cmake_dependency_file}" 218 | COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${cmake_dependency_file}.tmp" "${cmake_dependency_file}" 219 | ) 220 | 221 | if(CUDA_result) 222 | message(FATAL_ERROR "Error generating ${generated_file}") 223 | endif() 224 | 225 | # Delete the temporary file 226 | cuda_execute_process( 227 | "Removing ${cmake_dependency_file}.tmp" 228 | COMMAND "${CMAKE_COMMAND}" -E remove "${cmake_dependency_file}.tmp" 229 | ) 230 | 231 | if(CUDA_result) 232 | message(FATAL_ERROR "Error generating ${generated_file}") 233 | endif() 234 | 235 | if (generate_dependency_only) 236 | return() 237 | endif() 238 | 239 | if (check_dependencies) 240 | set(rebuild FALSE) 241 | include(${cmake_dependency_file}) 242 | if(NOT CUDA_NVCC_DEPEND) 243 | # CUDA_NVCC_DEPEND should have something useful in it by now. If not we 244 | # should force the rebuild. 245 | if (verbose) 246 | message(WARNING "CUDA_NVCC_DEPEND not found for ${generated_file}") 247 | endif() 248 | set(rebuild TRUE) 249 | endif() 250 | # Rebuilding is also dependent on this file changing. 251 | list(APPEND CUDA_NVCC_DEPEND "${CMAKE_CURRENT_LIST_FILE}") 252 | foreach(f ${CUDA_NVCC_DEPEND}) 253 | # True if file1 is newer than file2 or if one of the two files doesn't 254 | # exist. Behavior is well-defined only for full paths. If the file time 255 | # stamps are exactly the same, an IS_NEWER_THAN comparison returns true, so 256 | # that any dependent build operations will occur in the event of a tie. This 257 | # includes the case of passing the same file name for both file1 and file2. 258 | if("${f}" IS_NEWER_THAN "${generated_file}") 259 | #message("file ${f} is newer than ${generated_file}") 260 | set(rebuild TRUE) 261 | endif() 262 | endforeach() 263 | if (NOT rebuild) 264 | #message("Not rebuilding ${generated_file}") 265 | cuda_execute_process( 266 | "Dependencies up to date. Not rebuilding ${generated_file}" 267 | COMMAND "${CMAKE_COMMAND}" -E touch "${generated_file}" 268 | ) 269 | return() 270 | endif() 271 | endif() 272 | 273 | # Delete the target file 274 | cuda_execute_process( 275 | "Removing ${generated_file}" 276 | COMMAND "${CMAKE_COMMAND}" -E remove "${generated_file}" 277 | ) 278 | 279 | # Generate the code 280 | cuda_execute_process( 281 | "Generating ${generated_file}" 282 | COMMAND "${CUDA_NVCC_EXECUTABLE}" 283 | "${source_file}" 284 | ${format_flag} -o "${generated_file}" 285 | ${CCBIN} 286 | ${nvcc_flags} 287 | ${nvcc_host_compiler_flags} 288 | ${CUDA_NVCC_FLAGS} 289 | -DNVCC 290 | ${CUDA_NVCC_INCLUDE_ARGS} 291 | ) 292 | 293 | if(CUDA_result) 294 | # Since nvcc can sometimes leave half done files make sure that we delete the output file. 295 | cuda_execute_process( 296 | "Removing ${generated_file}" 297 | COMMAND "${CMAKE_COMMAND}" -E remove "${generated_file}" 298 | ) 299 | message(FATAL_ERROR "Error generating file ${generated_file}") 300 | else() 301 | if(verbose) 302 | message("Generated ${generated_file} successfully.") 303 | endif() 304 | endif() 305 | 306 | # Cubin resource report commands. 307 | if( build_cubin ) 308 | # Run with -cubin to produce resource usage report. 309 | cuda_execute_process( 310 | "Generating ${generated_cubin_file}" 311 | COMMAND "${CUDA_NVCC_EXECUTABLE}" 312 | "${source_file}" 313 | ${CUDA_NVCC_FLAGS} 314 | ${nvcc_flags} 315 | ${CCBIN} 316 | ${nvcc_host_compiler_flags} 317 | -DNVCC 318 | -cubin 319 | -o "${generated_cubin_file}" 320 | ${CUDA_NVCC_INCLUDE_ARGS} 321 | ) 322 | 323 | # Execute the parser script. 324 | cuda_execute_process( 325 | "Executing the parser script" 326 | COMMAND "${CMAKE_COMMAND}" 327 | -D "input_file:STRING=${generated_cubin_file}" 328 | -P "${CUDA_parse_cubin}" 329 | ) 330 | 331 | endif() 332 | -------------------------------------------------------------------------------- /cmake/FindCUDASDK.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # The script defines the following variables: 3 | # 4 | ############################################################################## 5 | # Note: Removed everything related to CUDA_SDK_ROOT_DIR and only left this as 6 | # a possible environment variable to set the SDK directory. 7 | # Include file will be: CUDA_CUT_INCLUDE_DIR 8 | # Cutil library: CUDA_CUT_LIBRARY 9 | ############################################################################## 10 | # 11 | # 12 | # CUDA_SDK_ROOT_DIR -- Path to the CUDA SDK. Use this to find files in the 13 | # SDK. This script will not directly support finding 14 | # specific libraries or headers, as that isn't 15 | # supported by NVIDIA. If you want to change 16 | # libraries when the path changes see the 17 | # FindCUDA.cmake script for an example of how to clear 18 | # these variables. There are also examples of how to 19 | # use the CUDA_SDK_ROOT_DIR to locate headers or 20 | # libraries, if you so choose (at your own risk). 21 | # 22 | # This code is licensed under the MIT License. See the FindCUDASDK.cmake script 23 | # for the text of the license. 24 | 25 | # The MIT License 26 | # 27 | # License for the specific language governing rights and limitations under 28 | # Permission is hereby granted, free of charge, to any person obtaining a 29 | # copy of this software and associated documentation files (the "Software"), 30 | # to deal in the Software without restriction, including without limitation 31 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 32 | # and/or sell copies of the Software, and to permit persons to whom the 33 | # Software is furnished to do so, subject to the following conditions: 34 | # 35 | # The above copyright notice and this permission notice shall be included 36 | # in all copies or substantial portions of the Software. 37 | # 38 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 39 | # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 40 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 41 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 42 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 43 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 44 | # DEALINGS IN THE SOFTWARE. 45 | # 46 | ############################################################################### 47 | 48 | # FindCUDASDK.cmake 49 | 50 | # # Check to see if the CUDA_SDK_ROOT_DIR has changed, 51 | # # if it has then clear the cache variable, so that it will be detected again. 52 | # if(NOT "${CUDA_SDK_ROOT_DIR}" STREQUAL "${CUDA_SDK_ROOT_DIR_INTERNAL}") 53 | # # No specific variables to catch. Use this kind of code before calling 54 | # # find_package(CUDA) to clean up any variables that may depend on this path. 55 | # 56 | # # unset(MY_SPECIAL_CUDA_SDK_INCLUDE_DIR CACHE) 57 | # # unset(MY_SPECIAL_CUDA_SDK_LIBRARY CACHE) 58 | # endif() 59 | # 60 | # ######################## 61 | # # Look for the SDK stuff 62 | # find_path(CUDA_SDK_ROOT_DIR cutil.h 63 | # PATH_SUFFIXES "common/inc" "C/common/inc" 64 | # "$ENV{NVSDKCUDA_ROOT}" 65 | # "[HKEY_LOCAL_MACHINE\\SOFTWARE\\NVIDIA Corporation\\Installed Products\\NVIDIA SDK 10\\Compute;InstallDir]" 66 | # "/Developer/GPU\ Computing/C" 67 | # ) 68 | # 69 | # # fallback method for determining CUDA_SDK_ROOT_DIR in case the previous one failed! 70 | # if (NOT CUDA_SDK_ROOT_DIR) 71 | # find_path(CUDA_SDK_ROOT_DIR C/common/inc/cutil.h 72 | # "$ENV{NVSDKCUDA_ROOT}" 73 | # "[HKEY_LOCAL_MACHINE\\SOFTWARE\\NVIDIA Corporation\\Installed Products\\NVIDIA SDK 10\\Compute;InstallDir]" 74 | # "/Developer/GPU\ Computing/C" 75 | # ) 76 | # endif() 77 | 78 | # Keep the CUDA_SDK_ROOT_DIR first in order to be able to override the 79 | # environment variables. 80 | set(CUDA_SDK_SEARCH_PATH 81 | "${CUDA_SDK_ROOT_DIR}" 82 | "${CUDA_TOOLKIT_ROOT_DIR}/local/NVSDK0.2" 83 | "${CUDA_TOOLKIT_ROOT_DIR}/NVSDK0.2" 84 | "${CUDA_TOOLKIT_ROOT_DIR}/NV_SDK" 85 | "${CUDA_TOOLKIT_ROOT_DIR}/NV_CUDA_SDK" 86 | "$ENV{HOME}/NVIDIA_CUDA_SDK" 87 | "$ENV{HOME}/NVIDIA_CUDA_SDK_MACOSX" 88 | "$ENV{HOME}/NVIDIA_GPU_Computing_SDK" 89 | "$ENV{NVSDKCUDA_ROOT}" 90 | "/Developer/CUDA" 91 | ) 92 | 93 | # Find include file from the CUDA_SDK_SEARCH_PATH 94 | 95 | find_path(CUDA_CUT_INCLUDE_DIR 96 | cutil.h 97 | PATHS ${CUDA_SDK_SEARCH_PATH} 98 | PATH_SUFFIXES "common/inc" "C/common/inc" 99 | DOC "Location of cutil.h" 100 | NO_DEFAULT_PATH 101 | ) 102 | # Now search system paths 103 | find_path(CUDA_CUT_INCLUDE_DIR cutil.h DOC "Location of cutil.h") 104 | 105 | # mark_as_advanced(CUDA_CUT_INCLUDE_DIR) 106 | 107 | 108 | # Example of how to find a library in the CUDA_SDK_ROOT_DIR 109 | 110 | # cutil library is called cutil64 for 64 bit builds on windows. We don't want 111 | # to get these confused, so we are setting the name based on the word size of 112 | # the build. 113 | 114 | # New library might be called cutil_x86_64 ! 115 | 116 | if(CMAKE_SIZEOF_VOID_P EQUAL 8) 117 | set(cuda_cutil_name cutil64) 118 | else(CMAKE_SIZEOF_VOID_P EQUAL 8) 119 | set(cuda_cutil_name cutil32) 120 | endif(CMAKE_SIZEOF_VOID_P EQUAL 8) 121 | 122 | find_library(CUDA_CUT_LIBRARY 123 | NAMES ${cuda_cutil_name} cutil cutil_x86_64 cutil_i386 124 | PATHS ${CUDA_SDK_SEARCH_PATH} 125 | # The new version of the sdk shows up in common/lib, but the old one is in lib 126 | # The very newest installation Path of the SDK is in subdirectory 'C'. Please add this Path to the possible suffixes. 127 | PATH_SUFFIXES "C/lib" "common/lib" "lib" "C/common/lib" "common/lib" 128 | DOC "Location of cutil library" 129 | NO_DEFAULT_PATH 130 | ) 131 | # # Now search system paths 132 | # find_library(CUDA_CUT_LIBRARY NAMES cutil ${cuda_cutil_name} DOC "Location of cutil library") 133 | mark_as_advanced(CUDA_CUT_LIBRARY) 134 | set(CUDA_CUT_LIBRARIES ${CUDA_CUT_LIBRARY}) 135 | 136 | ############################# 137 | # Check for required components 138 | if(CUDA_CUT_INCLUDE_DIR) 139 | set(CUDASDK_FOUND TRUE) 140 | endif(CUDA_CUT_INCLUDE_DIR) 141 | 142 | # set(CUDA_SDK_ROOT_DIR_INTERNAL "${CUDA_SDK_ROOT_DIR}" CACHE INTERNAL 143 | # "This is the value of the last time CUDA_SDK_ROOT_DIR was set successfully." FORCE) 144 | -------------------------------------------------------------------------------- /cmake/FindEigen.cmake: -------------------------------------------------------------------------------- 1 | # - Try to find Eigen3 lib 2 | # 3 | # This module supports requiring a minimum version, e.g. you can do 4 | # find_package(Eigen3 3.1.2) 5 | # to require version 3.1.2 or newer of Eigen3. 6 | # 7 | # Once done this will define 8 | # 9 | # EIGEN3_FOUND - system has eigen lib with correct version 10 | # EIGEN3_INCLUDE_DIR - the eigen include directory 11 | # EIGEN3_VERSION - eigen version 12 | 13 | # Copyright (c) 2006, 2007 Montel Laurent, 14 | # Copyright (c) 2008, 2009 Gael Guennebaud, 15 | # Copyright (c) 2009 Benoit Jacob 16 | # Redistribution and use is allowed according to the terms of the 2-clause BSD license. 17 | 18 | if(NOT Eigen3_FIND_VERSION) 19 | if(NOT Eigen3_FIND_VERSION_MAJOR) 20 | set(Eigen3_FIND_VERSION_MAJOR 2) 21 | endif(NOT Eigen3_FIND_VERSION_MAJOR) 22 | if(NOT Eigen3_FIND_VERSION_MINOR) 23 | set(Eigen3_FIND_VERSION_MINOR 91) 24 | endif(NOT Eigen3_FIND_VERSION_MINOR) 25 | if(NOT Eigen3_FIND_VERSION_PATCH) 26 | set(Eigen3_FIND_VERSION_PATCH 0) 27 | endif(NOT Eigen3_FIND_VERSION_PATCH) 28 | 29 | set(Eigen3_FIND_VERSION "${Eigen3_FIND_VERSION_MAJOR}.${Eigen3_FIND_VERSION_MINOR}.${Eigen3_FIND_VERSION_PATCH}") 30 | endif(NOT Eigen3_FIND_VERSION) 31 | 32 | macro(_eigen3_check_version) 33 | file(READ "${EIGEN3_INCLUDE_DIR}/Eigen/src/Core/util/Macros.h" _eigen3_version_header) 34 | 35 | string(REGEX MATCH "define[ \t]+EIGEN_WORLD_VERSION[ \t]+([0-9]+)" _eigen3_world_version_match "${_eigen3_version_header}") 36 | set(EIGEN3_WORLD_VERSION "${CMAKE_MATCH_1}") 37 | string(REGEX MATCH "define[ \t]+EIGEN_MAJOR_VERSION[ \t]+([0-9]+)" _eigen3_major_version_match "${_eigen3_version_header}") 38 | set(EIGEN3_MAJOR_VERSION "${CMAKE_MATCH_1}") 39 | string(REGEX MATCH "define[ \t]+EIGEN_MINOR_VERSION[ \t]+([0-9]+)" _eigen3_minor_version_match "${_eigen3_version_header}") 40 | set(EIGEN3_MINOR_VERSION "${CMAKE_MATCH_1}") 41 | 42 | set(EIGEN3_VERSION ${EIGEN3_WORLD_VERSION}.${EIGEN3_MAJOR_VERSION}.${EIGEN3_MINOR_VERSION}) 43 | if(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION}) 44 | set(EIGEN3_VERSION_OK FALSE) 45 | else(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION}) 46 | set(EIGEN3_VERSION_OK TRUE) 47 | endif(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION}) 48 | 49 | if(NOT EIGEN3_VERSION_OK) 50 | 51 | message(STATUS "Eigen3 version ${EIGEN3_VERSION} found in ${EIGEN3_INCLUDE_DIR}, " 52 | "but at least version ${Eigen3_FIND_VERSION} is required") 53 | endif(NOT EIGEN3_VERSION_OK) 54 | endmacro(_eigen3_check_version) 55 | 56 | if (EIGEN3_INCLUDE_DIR) 57 | 58 | # in cache already 59 | _eigen3_check_version() 60 | set(EIGEN3_FOUND ${EIGEN3_VERSION_OK}) 61 | 62 | else (EIGEN3_INCLUDE_DIR) 63 | 64 | find_path(EIGEN3_INCLUDE_DIR NAMES signature_of_eigen3_matrix_library 65 | PATHS 66 | ${CMAKE_INSTALL_PREFIX}/include 67 | ${KDE4_INCLUDE_DIR} 68 | PATH_SUFFIXES eigen3 eigen 69 | ) 70 | 71 | if(EIGEN3_INCLUDE_DIR) 72 | _eigen3_check_version() 73 | endif(EIGEN3_INCLUDE_DIR) 74 | 75 | include(FindPackageHandleStandardArgs) 76 | find_package_handle_standard_args(Eigen3 DEFAULT_MSG EIGEN3_INCLUDE_DIR EIGEN3_VERSION_OK) 77 | 78 | mark_as_advanced(EIGEN3_INCLUDE_DIR) 79 | 80 | endif(EIGEN3_INCLUDE_DIR) 81 | 82 | -------------------------------------------------------------------------------- /cmake/FindQwt.cmake: -------------------------------------------------------------------------------- 1 | # - Try to find the Qwt includes and library 2 | # which defines 3 | # 4 | # QWT_FOUND - system has Qwt 5 | # QWT_INCLUDE_DIR - where to find qwt.h 6 | # QWT_LIBRARIES - the libraries to link against to use Qwt 7 | # QWT_LIBRARY - where to find the Qwt library (not for general use) 8 | 9 | # copyright (c) 2006 Thomas Moenicke thomas.moenicke@kdemail.net 10 | # 11 | # Redistribution and use is allowed according to the terms of the BSD license. 12 | 13 | IF(NOT QT4_FOUND) 14 | INCLUDE(FindQt4) 15 | ENDIF(NOT QT4_FOUND) 16 | 17 | SET(QWT_FOUND "NO") 18 | 19 | IF(QT4_FOUND) 20 | FIND_PATH(QWT_INCLUDE_DIR qwt.h 21 | /usr/local/qwt/include 22 | /usr/local/include 23 | /usr/include/qwt 24 | /usr/include/qwt-qt4 25 | /usr/include/qwt5 26 | /usr/include 27 | $ENV{QWT_DIR}/include 28 | $ENV{QWT_DIR}/src 29 | $ENV{QWTDIR}/include 30 | $ENV{QWTDIR}/src 31 | $ENV{QWT_ROOT}/include 32 | $ENV{QWT_ROOT}/src 33 | $ENV{QWTROOT}/include 34 | $ENV{QWTROOT}/src 35 | ) 36 | 37 | SET(POTENTIAL_LIBRARY_PATHS /usr/local/qwt/lib /usr/local/lib /usr/lib 38 | $ENV{QWT_DIR}/lib $ENV{QWTDIR}/lib $ENV{QWT_ROOT}/lib $ENV{QWTROOT}/lib) 39 | 40 | SET(QWT_NAMES ${QWT_NAMES} qwt qwt-qt4 qwt5 ) 41 | FIND_LIBRARY(QWT_LIBRARY 42 | NAMES ${QWT_NAMES} 43 | PATHS ${POTENTIAL_LIBRARY_PATHS} 44 | ) 45 | MARK_AS_ADVANCED(QWT_LIBRARY) 46 | 47 | IF (QWT_LIBRARY) 48 | 49 | IF(WIN32 AND NOT CYGWIN) 50 | 51 | SET(QWT_NAMES_DEBUG qwtd qwtd-qt4 qwtd5 ) 52 | FIND_LIBRARY(QWT_LIBRARY_DEBUG 53 | NAMES ${QWT_NAMES_DEBUG} 54 | PATHS ${POTENTIAL_LIBRARY_PATHS} 55 | ) 56 | MARK_AS_ADVANCED(QWT_LIBRARY_DEBUG) 57 | 58 | IF(QWT_LIBRARY_DEBUG) 59 | SET(QWT_LIBRARIES optimized ${QWT_LIBRARY} debug ${QWT_LIBRARY_DEBUG} CACHE DOC "QWT library files") 60 | ELSE(QWT_LIBRARY_DEBUG) 61 | SET(QWT_LIBRARIES ${QWT_LIBRARY} CACHE DOC "QWT library files") 62 | ENDIF(QWT_LIBRARY_DEBUG) 63 | 64 | ELSE(WIN32 AND NOT CYGWIN) 65 | 66 | SET(QWT_LIBRARIES ${QWT_LIBRARY} CACHE DOC "QWT library files") 67 | 68 | ENDIF(WIN32 AND NOT CYGWIN) 69 | 70 | SET(QWT_FOUND "YES") 71 | 72 | IF (CYGWIN) 73 | IF(BUILD_SHARED_LIBS) 74 | # No need to define QWT_USE_DLL here, because it's default for Cygwin. 75 | ELSE(BUILD_SHARED_LIBS) 76 | SET (QWT_DEFINITIONS -DQWT_STATIC) 77 | ENDIF(BUILD_SHARED_LIBS) 78 | ENDIF (CYGWIN) 79 | 80 | ENDIF (QWT_LIBRARY) 81 | ENDIF(QT4_FOUND) 82 | 83 | IF (QWT_FOUND) 84 | IF (NOT QWT_FIND_QUIETLY) 85 | MESSAGE(STATUS "Found Qwt: ${QWT_LIBRARIES}") 86 | ENDIF (NOT QWT_FIND_QUIETLY) 87 | ELSE (QWT_FOUND) 88 | IF (QWT_FIND_REQUIRED) 89 | MESSAGE(FATAL_ERROR "Could not find Qwt library") 90 | ENDIF (QWT_FIND_REQUIRED) 91 | ENDIF (QWT_FOUND) 92 | 93 | MARK_AS_ADVANCED(QWT_INCLUDE_DIR QWT_LIBRARY) 94 | 95 | -------------------------------------------------------------------------------- /commons.h: -------------------------------------------------------------------------------- 1 | #ifndef I3D_LINE3D_COMMONS_H_ 2 | #define I3D_LINE3D_COMMONS_H_ 3 | 4 | /* 5 | Line3D - Line-based Multi View Stereo 6 | Copyright (C) 2015 Manuel Hofer 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | // external 23 | #include "eigen3/Eigen/Eigen" 24 | #include "cuda.h" 25 | #include "helper_math.h" 26 | 27 | // internal 28 | #include "serialization.h" 29 | #include "clustering.h" 30 | 31 | /** 32 | * Line3D - Constants 33 | * ==================== 34 | * Default parameters, etc. 35 | * ==================== 36 | * Author: M.Hofer, 2015 37 | */ 38 | 39 | namespace L3D 40 | { 41 | // feature detection 42 | #define L3D_DEF_MAX_IMG_WIDTH 1920 43 | #define L3D_DEF_MIN_LINE_LENGTH_F 0.005f 44 | #define L3D_DEF_MAX_NUM_SEGMENTS 3000 45 | #define L3D_DEF_LOAD_AND_STORE_SEGMENTS true 46 | 47 | // collinearity 48 | #define L3D_DEF_COLLINEARITY_S 2.0f 49 | #define L3D_DEF_COLLINEARITY_FOR_CLUSTERING true 50 | 51 | // matching 52 | #define L3D_DEF_MATCHING_NEIGHBORS 10 53 | #define L3D_DEF_UNCERTAINTY_UPPER_T 5.0f 54 | #define L3D_DEF_UNCERTAINTY_LOWER_T 1.0f 55 | #define L3D_DEF_MIN_BASELINE_T 0.25f 56 | // same as for GPU! 57 | #define L3D_DEF_SIGMA_P 3.5f 58 | #define L3D_DEF_SIGMA_A 10.0f 59 | 60 | // replicator dynamics diffusion 61 | #define L3D_DEF_PERFORM_RDD false 62 | 63 | // clustering 64 | #define L3D_MIN_AFFINITY 0.25f 65 | 66 | #define L3D_EPS 1e-12 67 | 68 | // 3D segment 69 | struct L3DSegment3D 70 | { 71 | Eigen::Vector3d P1_; 72 | Eigen::Vector3d P2_; 73 | Eigen::Vector3d dir_; 74 | float depth_p1_; 75 | float depth_p2_; 76 | unsigned int camID_; 77 | unsigned int segID_; 78 | }; 79 | 80 | // 2D segment (sortable) 81 | class L3DSegment2D 82 | { 83 | public: 84 | L3DSegment2D() : camID_(0), segID_(0){} 85 | L3DSegment2D(unsigned int camID, 86 | unsigned int segID) : 87 | camID_(camID), segID_(segID){} 88 | inline unsigned int camID() const {return camID_;} 89 | inline unsigned int segID() const {return segID_;} 90 | 91 | inline bool operator== (const L3DSegment2D& rhs) const {return ((camID_ == rhs.camID_) && (segID_ == rhs.segID_));} 92 | inline bool operator< (const L3DSegment2D& rhs) const { 93 | return ((camID_ < rhs.camID_) || (camID_ == rhs.camID_ && segID_ < rhs.segID_)); 94 | } 95 | inline bool operator!= (const L3DSegment2D& rhs) const {return !((*this) == rhs);} 96 | private: 97 | unsigned int camID_; 98 | unsigned int segID_; 99 | }; 100 | 101 | // selected match 102 | class L3DCorrespondenceRRW 103 | { 104 | public: 105 | L3DCorrespondenceRRW(){ 106 | valid_ = false; 107 | confidence_ = 0.0f; 108 | confidence_old_ = 0.0f; 109 | score_ = 0.0f; 110 | } 111 | L3DCorrespondenceRRW(unsigned int id, float confidence, 112 | L3D::L3DSegment3D src_seg3D, 113 | L3D::L3DSegment2D src, 114 | L3D::L3DSegment2D tgt, 115 | bool valid=true) : 116 | id_(id),confidence_(confidence), 117 | confidence_old_(0.0f),score_(0.0f), 118 | src_seg3D_(src_seg3D), 119 | src_(src),tgt_(tgt), 120 | valid_(valid){} 121 | ~L3DCorrespondenceRRW(){} 122 | 123 | // data 124 | unsigned int id(){return id_;} 125 | float confidence(){return confidence_;} 126 | float confidence_old(){return confidence_old_;} 127 | float score(){return score_;} 128 | L3D::L3DSegment3D src_seg3D(){return src_seg3D_;} 129 | L3D::L3DSegment2D src(){return src_;} 130 | L3D::L3DSegment2D tgt(){return tgt_;} 131 | bool valid(){return valid_;} 132 | 133 | // update confidence 134 | void updateConfidence(float c){ 135 | confidence_old_ = confidence_; 136 | confidence_ = c; 137 | } 138 | 139 | void normalizeConfidence(float c){ 140 | confidence_old_ = confidence_; 141 | confidence_ /= c; 142 | } 143 | 144 | void setScore(float s){ 145 | score_ = s; 146 | } 147 | 148 | void invalidate(){valid_ = false;} 149 | void validate(){valid_ = true;} 150 | 151 | private: 152 | unsigned int id_; 153 | float confidence_; 154 | float confidence_old_; 155 | float score_; 156 | L3D::L3DSegment3D src_seg3D_; 157 | L3D::L3DSegment2D src_; 158 | L3D::L3DSegment2D tgt_; 159 | bool valid_; 160 | }; 161 | 162 | static bool sortSelectedMatchesByConf(L3DCorrespondenceRRW* sm1, 163 | L3DCorrespondenceRRW* sm2) 164 | { 165 | return (sm1->confidence() > sm2->confidence()); 166 | } 167 | 168 | // visual neighbor 169 | struct L3DVisualNeighbor 170 | { 171 | unsigned int camID_; 172 | float similarity_; 173 | }; 174 | 175 | static bool sortVisualNeighbors(const L3DVisualNeighbor vn1, 176 | const L3DVisualNeighbor vn2) 177 | { 178 | return (vn1.similarity_ > vn2.similarity_); 179 | } 180 | 181 | struct L3DscorePlusID 182 | { 183 | float score_; 184 | unsigned int id_; 185 | }; 186 | 187 | static bool sortScorePlusID(const L3DscorePlusID si1, 188 | const L3DscorePlusID si2) 189 | { 190 | return (si1.score_ > si2.score_); 191 | } 192 | 193 | // sort detected segments by length 194 | static bool sortSegmentsByLength(const float2 s1, const float2 s2) 195 | { 196 | return (s1.y > s2.y); 197 | } 198 | 199 | // sortable 3D point along line 200 | struct SortablePointOnLine3D 201 | { 202 | Eigen::Vector3d P_; 203 | unsigned int segID_3D_; 204 | unsigned int camID_; 205 | float dist_; 206 | }; 207 | 208 | static bool sortPointsOnLine3D(const SortablePointOnLine3D p1, 209 | const SortablePointOnLine3D p2) 210 | { 211 | return (p1.dist_ < p2.dist_); 212 | } 213 | 214 | // class for clustered 3D line 215 | class L3DFinalLine3D 216 | { 217 | public: 218 | L3DFinalLine3D(std::list segments2D, 219 | std::list > segments3D) 220 | { 221 | segments3D_ = segments3D; 222 | segments2D_ = segments2D; 223 | } 224 | 225 | std::list >* segments3D(){ 226 | return &segments3D_; 227 | } 228 | 229 | std::list* segments2D(){ 230 | return &segments2D_; 231 | } 232 | 233 | private: 234 | // 3D segments (along line) 235 | std::list > segments3D_; 236 | // 2D references 237 | std::list segments2D_; 238 | }; 239 | } 240 | 241 | #endif //I3D_LINE3D_COMMONS_H_ 242 | -------------------------------------------------------------------------------- /cudawrapper.h: -------------------------------------------------------------------------------- 1 | #ifndef I3D_LINE3D_CUDAWRAPPER_H_ 2 | #define I3D_LINE3D_CUDAWRAPPER_H_ 3 | 4 | /* 5 | Line3D - Line-based Multi View Stereo 6 | Copyright (C) 2015 Manuel Hofer 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | // external 23 | #include "math_constants.h" 24 | #include "cuda.h" 25 | #include "helper_math.h" 26 | 27 | // internal 28 | #include "sparsematrix.h" 29 | #include "dataArray.h" 30 | 31 | // std 32 | #include 33 | 34 | // params 35 | #define L3D_RDD_MAX_ITER 10 36 | 37 | namespace L3D 38 | { 39 | // constants CPU 40 | const unsigned int L3D_CU_BLOCK_SIZE_C = 16; 41 | 42 | // constants GPU 43 | __device__ const float L3D_EPS_G = 1e-12; 44 | __device__ const float L3D_COLLIN_AFF_T_G = 0.50f; 45 | __device__ const float L3D_MIN_OVERLAP_LOWER_T_G = 0.10f; 46 | __device__ const float L3D_MIN_OVERLAP_UPPER_T_G = 0.30f; 47 | 48 | // compute pairwise 2D line segment collinearity score 49 | extern void compute_collinearity(L3D::DataArray* segments, 50 | L3D::DataArray* relation, 51 | const float collin_s); 52 | 53 | // perform segment matching 54 | extern void compute_pairwise_matches(L3D::DataArray* segments_src, 55 | L3D::DataArray* RtKinv_src, 56 | L3D::DataArray* segments_tgt, 57 | L3D::DataArray* RtKinv_tgt, 58 | L3D::DataArray* camCenters_tgt, 59 | const float3 camCenter_src, 60 | L3D::DataArray* fundamentals, 61 | L3D::DataArray* projections, 62 | L3D::DataArray* offsets, 63 | std::list& toBeMatched, 64 | std::list& matches, 65 | std::map& local2global, 66 | const unsigned int maxSegments, const unsigned int vID, 67 | const float uncertainty_k_upper, 68 | const float uncertainty_k_lower, 69 | const float sigma_p, const float sigma_a, 70 | const float spatial_k, float& median_depth, 71 | const bool verbose, const std::string prefix); 72 | 73 | // replicator dynamics diffusion [M.Donoser, BMVC'13] 74 | extern void replicator_dynamics_diffusion(L3D::SparseMatrix* &W, const bool verbose, 75 | const std::string prefix); 76 | } 77 | 78 | #endif //I3D_LINE3D_CUDAWRAPPER_H_ 79 | -------------------------------------------------------------------------------- /dataArray.h: -------------------------------------------------------------------------------- 1 | #ifndef I3D_LINE3D_DATAARRAY_H_ 2 | #define I3D_LINE3D_DATAARRAY_H_ 3 | 4 | /* 5 | Line3D - Line-based Multi View Stereo 6 | Copyright (C) 2015 Manuel Hofer 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | // external 23 | #include "cuda.h" 24 | #include "cuda_runtime.h" 25 | #include 26 | #include 27 | #include 28 | 29 | // std 30 | #include 31 | #include 32 | 33 | /** 34 | * Line3D - DataArray CPU/GPU 35 | * ==================== 36 | * DataArray that can be moved from CPU to GPU 37 | * and vice versa. Adapted from the ImageUtilities lib 38 | * by Manuel Werlberger. 39 | * ==================== 40 | * Author: M.Hofer, 2015 41 | */ 42 | 43 | namespace L3D 44 | { 45 | // floatN array (2D) 46 | template 47 | class DataArray 48 | { 49 | public: 50 | DataArray() 51 | { 52 | width_ = 0; 53 | height_ = 0; 54 | real_width_ = 0; 55 | 56 | // CPU 57 | pitchCPU_ = 0; 58 | strideCPU_ = 0; 59 | 60 | // GPU 61 | dataGPU_ = NULL; 62 | pitchGPU_ = 0; 63 | strideGPU_ = 0; 64 | } 65 | 66 | DataArray(unsigned int width, 67 | unsigned int height, 68 | const bool allocate_GPU_memory=false, 69 | const std::vector& data=std::vector()) 70 | { 71 | // init 72 | width_ = width; 73 | height_ = height; 74 | 75 | // pitch (CPU) 76 | pitchCPU_ = width_*sizeof(PixelType); 77 | 78 | unsigned int elements2pitch; 79 | if(pitchCPU_ % 32 == 0) 80 | elements2pitch = 0; 81 | else 82 | elements2pitch = (32-(pitchCPU_ % 32))/sizeof(PixelType); 83 | 84 | width += elements2pitch; 85 | pitchCPU_ = width*sizeof(PixelType); 86 | strideCPU_ = pitchCPU_/sizeof(PixelType); 87 | real_width_ = width; 88 | 89 | // CPU --> stored line by line 90 | dataCPU_ = std::vector(width*height_); 91 | if(data.size() == width_*height_) 92 | { 93 | for(unsigned int h=0; h 0 && x < width_ && y < height_) 119 | return &dataCPU_[y*strideCPU_+x]; 120 | else 121 | return NULL; 122 | } 123 | 124 | PixelType* dataGPU(unsigned int x=0, 125 | unsigned int y=0) 126 | { 127 | if(dataGPU_ == NULL) 128 | { 129 | std::cerr << "DataArray::dataGPU(): data is _not_ on GPU!" << std::endl; 130 | return NULL; 131 | } 132 | 133 | if(dataGPU_ != NULL && x < width_ && y < height_) 134 | return &dataGPU_[y*strideGPU_+x]; 135 | else 136 | return NULL; 137 | } 138 | 139 | // data transfer CPU/GPU 140 | void upload() 141 | { 142 | if(dataGPU_ == NULL) 143 | allocateGPU(); 144 | 145 | // host -> device 146 | if(dataGPU_ != NULL) 147 | { 148 | cudaError_t status = cudaMemcpy2D(dataGPU_,pitchGPU_, 149 | &dataCPU_[0],pitchCPU_, 150 | width_*sizeof(PixelType),height_, 151 | cudaMemcpyHostToDevice); 152 | 153 | if(status != cudaSuccess) 154 | { 155 | std::cerr << "DataArray::upload(): copying from CPU to GPU failed...[" << cudaGetErrorString(status) << "]" << std::endl; 156 | } 157 | } 158 | else 159 | { 160 | std::cerr << "DataArray::upload(): GPU memory not allocated..." << std::endl; 161 | } 162 | 163 | cudaDeviceSynchronize(); 164 | } 165 | 166 | void download() 167 | { 168 | // device -> host 169 | if(dataGPU_ != NULL) 170 | { 171 | cudaError_t status = cudaMemcpy2D(&dataCPU_[0],pitchCPU_, 172 | dataGPU_,pitchGPU_, 173 | width_*sizeof(PixelType),height_, 174 | cudaMemcpyDeviceToHost); 175 | 176 | if(status != cudaSuccess) 177 | { 178 | std::cerr << "DataArray::download(): copying from GPU to CPU failed... [" << cudaGetErrorString(status) << "]" << std::endl; 179 | } 180 | } 181 | } 182 | 183 | void removeFromGPU() 184 | { 185 | if(dataGPU_ != NULL) 186 | { 187 | cudaError_t status = cudaFree((void *)dataGPU_); 188 | 189 | if(status != cudaSuccess) 190 | { 191 | std::cerr << "DataArray::removeFromGPU(): could not remove data from GPU...[" << cudaGetErrorString(status) << "]" << std::endl; 192 | } 193 | 194 | dataGPU_ = NULL; 195 | pitchGPU_ = 0; 196 | strideGPU_ = 0; 197 | } 198 | } 199 | 200 | // set constant value (CPU only!) 201 | void setValue(const PixelType p, const bool uploadToGPU=false) 202 | { 203 | for(unsigned int i=0; i cpu 214 | for(unsigned int h=0; hdataCPU(w,h)[0] = dataCPU(w,h)[0]; 217 | 218 | if(uploadToGPU) 219 | dst->upload(); 220 | } 221 | 222 | // basics 223 | unsigned int width(){return width_;} 224 | unsigned int height(){return height_;} 225 | size_t pitchCPU(){return pitchCPU_;} 226 | size_t strideCPU(){return strideCPU_;} 227 | size_t pitchGPU() 228 | { 229 | if(dataGPU_ == NULL) 230 | { 231 | std::cerr << "DataArray::pitchGPU(): data is _not_ on GPU!" << std::endl; 232 | } 233 | 234 | return pitchGPU_; 235 | } 236 | size_t strideGPU() 237 | { 238 | if(dataGPU_ == NULL) 239 | { 240 | std::cerr << "DataArray::strideGPU(): data is _not_ on GPU!" << std::endl; 241 | } 242 | 243 | return strideGPU_; 244 | } 245 | bool onGPU(){return (dataGPU_ != NULL);} 246 | size_t bytes(){return height_*pitchCPU_;} 247 | 248 | private: 249 | 250 | // allocate GPU memory 251 | void allocateGPU() 252 | { 253 | if(dataGPU_ != NULL) 254 | return; 255 | 256 | if(width_ > 0 && height_ > 0) 257 | { 258 | dataGPU_ = 0; 259 | cudaError_t status = cudaMallocPitch((void **)&dataGPU_, &pitchGPU_, 260 | width_*sizeof(PixelType), height_); 261 | 262 | if(status != cudaSuccess) 263 | { 264 | std::cerr << "DataArray::allocateGPU(): GPU memory could not be allocated...[" << cudaGetErrorString(status) << "]" << std::endl; 265 | dataGPU_ = NULL; 266 | pitchGPU_ = 0; 267 | strideGPU_ = 0; 268 | return; 269 | } 270 | 271 | strideGPU_ = pitchGPU_/sizeof(PixelType); 272 | } 273 | else 274 | { 275 | std::cerr << "DataArray::allocateGPU(): width or height are zero! w=" << width_ << " h=" << height_ << std::endl; 276 | } 277 | 278 | cudaDeviceSynchronize(); 279 | } 280 | 281 | // basic 282 | unsigned int width_; 283 | unsigned int height_; 284 | unsigned int real_width_; 285 | 286 | // CPU 287 | std::vector dataCPU_; 288 | size_t pitchCPU_; 289 | size_t strideCPU_; 290 | 291 | // GPU 292 | PixelType* dataGPU_; 293 | size_t pitchGPU_; 294 | size_t strideGPU_; 295 | 296 | // serialization 297 | friend class boost::serialization::access; 298 | template 299 | void serialize(Archive & ar, const unsigned int version) 300 | { 301 | ar & boost::serialization::make_nvp("width_", width_); 302 | ar & boost::serialization::make_nvp("height_", height_); 303 | ar & boost::serialization::make_nvp("real_width_", real_width_); 304 | ar & boost::serialization::make_nvp("pitchCPU_", pitchCPU_); 305 | ar & boost::serialization::make_nvp("strideCPU_", strideCPU_); 306 | ar & boost::serialization::make_nvp("pitchGPU_", pitchGPU_); 307 | ar & boost::serialization::make_nvp("strideGPU_", strideGPU_); 308 | 309 | if(Archive::is_loading::value) 310 | { 311 | dataGPU_ = NULL; 312 | pitchGPU_ = 0; 313 | strideGPU_ = 0; 314 | dataCPU_ = std::vector(real_width_*height_); 315 | } 316 | 317 | ar & boost::serialization::make_array(&dataCPU_[0],dataCPU_.size()); 318 | } 319 | }; 320 | } 321 | 322 | #endif //I3D_LINE3D_DATAARRAY_H_ 323 | -------------------------------------------------------------------------------- /line3D.h: -------------------------------------------------------------------------------- 1 | #ifndef I3D_LINE3D_LINE3D_H_ 2 | #define I3D_LINE3D_LINE3D_H_ 3 | 4 | /* 5 | Line3D - Line-based Multi View Stereo 6 | Copyright (C) 2015 Manuel Hofer 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | // std 23 | #include 24 | 25 | // external 26 | #include "opencv/cv.h" 27 | //#include "opencv/highgui.h" // debug 28 | #include "eigen3/Eigen/Eigen" 29 | #include "boost/filesystem.hpp" 30 | 31 | // LSD 32 | #include "lsd/lsd_opencv.hpp" 33 | 34 | // internal 35 | #include "commons.h" 36 | #include "view.h" 37 | #include "serialization.h" 38 | #include "segments.h" 39 | #include "cudawrapper.h" 40 | #include "clustering.h" 41 | #include "sparsematrix.h" 42 | #include "dataArray.h" 43 | 44 | /** 45 | * Line3D - Base Class 46 | * ==================== 47 | * Line-based Multi-view Stereo 48 | * Reference: 49 | * "Line3D: Efficient 3D Scene Abstraction for the Built Environment" 50 | * Manuel Hofer, Michael Maurer, Horst Bischof, 51 | * German Conference on Pattern Recognition (GCPR), 2015. 52 | * ==================== 53 | * Author: M.Hofer, 2015 54 | */ 55 | 56 | namespace L3D 57 | { 58 | class Line3D 59 | { 60 | public: 61 | Line3D(const std::string data_directory, const int matchingNeighbors=L3D_DEF_MATCHING_NEIGHBORS, 62 | const float uncertainty_t_upper_2D=L3D_DEF_UNCERTAINTY_UPPER_T, 63 | const float uncertainty_t_lower_2D=L3D_DEF_UNCERTAINTY_LOWER_T, 64 | const float sigma_p=L3D_DEF_SIGMA_P, const float sigma_a=L3D_DEF_SIGMA_A, 65 | const float min_baseline=L3D_DEF_MIN_BASELINE_T, 66 | bool useCollinearity=L3D_DEF_COLLINEARITY_FOR_CLUSTERING, bool verbose=false); 67 | ~Line3D(); 68 | 69 | // add a new image to the system 70 | void addImage(const unsigned int imageID, const cv::Mat image, 71 | const Eigen::Matrix3d K, const Eigen::Matrix3d R, 72 | const Eigen::Vector3d t, std::list& worldpointIDs, 73 | const int maxImgWidth=L3D_DEF_MAX_IMG_WIDTH, 74 | const bool loadAndStoreSegments=L3D_DEF_LOAD_AND_STORE_SEGMENTS); 75 | 76 | void addImage_fixed_sim(const unsigned int imageID, const cv::Mat image, 77 | const Eigen::Matrix3d K, const Eigen::Matrix3d R, 78 | const Eigen::Vector3d t, std::map& viewSimilarity, 79 | const int maxImgWidth=L3D_DEF_MAX_IMG_WIDTH, 80 | const bool loadAndStoreSegments=L3D_DEF_LOAD_AND_STORE_SEGMENTS); 81 | 82 | // reconstructs 3D model 83 | void compute3Dmodel(bool perform_diffusion=L3D_DEF_PERFORM_RDD); 84 | 85 | // get resulting 3D model 86 | void getResult(std::list& result); 87 | 88 | // get coordinates of a 2D segment (float4: p1x, p1y, p2x, p2y) 89 | float4 getSegment2D(L3D::L3DSegment2D& seg2D); 90 | 91 | // save model as STL file 92 | void save3DLinesAsSTL(std::list& result, std::string filename); 93 | 94 | // save model as txt file 95 | void save3DLinesAsTXT(std::list& result, std::string filename); 96 | 97 | // number of cameras 98 | unsigned int numCameras(){return views_.size();} 99 | 100 | // delete views etc. 101 | void reset(); 102 | 103 | private: 104 | // system params 105 | bool verbose_; 106 | std::string prefix_; 107 | std::string separator_; 108 | std::string data_directory_; 109 | bool computation_; 110 | 111 | // view neighborhood information 112 | std::map num_wps_; 113 | std::map > common_wps_; 114 | std::map > view_similarities_; 115 | std::map > worldpoints2views_; 116 | std::map > visual_neighbors_; 117 | std::map > fundamentals_; 118 | 119 | // matching 120 | std::map > matched_; 121 | std::map global2local_; 122 | std::map local2global_; 123 | int matching_neighbors_; 124 | float min_baseline_; 125 | 126 | // scoring 127 | float uncertainty_upper_2D_; 128 | float uncertainty_lower_2D_; 129 | float sigma_p_; 130 | float sigma_a_; 131 | 132 | // final hypotheses 133 | std::map best_match_; 134 | std::map > potential_correspondences_; 135 | 136 | // clustering 137 | bool use_collinearity_; 138 | std::list clustered_result_; 139 | 140 | // geometry transformation 141 | Eigen::Matrix4d Qinv_; 142 | double transf_scale_; 143 | Eigen::Matrix3d transf_R_; 144 | Eigen::Vector3d transf_t_; 145 | // inverse transform 146 | double transf_scale_inv_; 147 | Eigen::Matrix3d transf_Rinv_; 148 | Eigen::Vector3d transf_tneg_; 149 | 150 | // LSD 151 | cv::Ptr ls_; 152 | 153 | // views 154 | std::map views_; 155 | 156 | // detect line segments using the LSD algorithm 157 | bool detectLineSegments(const cv::Mat& image, std::list &lineSegments, 158 | const unsigned int new_width, const unsigned int new_height, 159 | const float min_length); 160 | 161 | // computes the length of a 2D line segment 162 | float segmentLength2D(const float4 coords); 163 | 164 | // adds worldpoint information to system 165 | void processWorldpointList(const unsigned int viewID, std::list& wps); 166 | 167 | // for pmvs_data: set view similarity (according to overlap.txt) 168 | void setViewSimilarity(const unsigned int viewID, std::map& sim); 169 | 170 | // find visually nearest neighbors among views 171 | void findVisualNeighbors(); 172 | 173 | // transform geometry to avoid numerical imprecision 174 | void transformGeometry(); 175 | Eigen::Vector3d inverseTransform(Eigen::Vector3d P); 176 | 177 | // computes a similarity transform between two pointsets 178 | void findSimilarityTransform(std::vector& input, Eigen::Vector3d& cog_in, 179 | std::vector& output, Eigen::Vector3d& cog_out); 180 | 181 | // computes an Euclidean transformation between two pointsets 182 | void euclideanTransformation(std::vector& input, Eigen::Vector3d& cog_in, 183 | std::vector& output, Eigen::Vector3d& cog_out); 184 | 185 | // applies found transformation to all cameras 186 | void applyTransformation(); 187 | 188 | // match views with visual neighbors 189 | void matchViews(); 190 | void performMatching(const unsigned int vID, std::list& matches); 191 | 192 | // optimize correspondences 193 | void optimizeLocalMatches(); 194 | void greedySelection(); 195 | 196 | // cluster 2D segments to obtain final 3D model 197 | void clusterSegments2D(bool perform_diffusion); 198 | void performDiffusion(std::list& A, const unsigned int num_rows_cols); 199 | void processClusteredSegments(L3D::CLUniverse* U, std::map &local2global); 200 | void untransformClusteredSegments(std::list& seg2D, 201 | std::map >& transformed3D); 202 | void alignClusteredSegments(std::map >& transformed3D, 203 | std::list >& seg3D, 204 | std::list& seg2D); 205 | void getLineEquation3D(std::map >& seg3D, 206 | L3D::L3DSegment3D& line3D); 207 | void projectToLine(std::map >& unaligned, 208 | std::list >& aligned, 209 | const L3D::L3DSegment3D line3D); 210 | 211 | 212 | // 2D similarity based on collinearity 213 | float similarity_coll3D(const L3D::L3DSegment3D seg1_3D, const L3D::L3DSegment3D seg2_3D); 214 | float distance_point2line_3D(const L3D::L3DSegment3D seg3D, const Eigen::Vector3d X); 215 | 216 | // compute fundamental matrices among visual neighbors 217 | void computeFundamentals(const unsigned int vID); 218 | Eigen::Matrix3d fundamental(const unsigned int view1, 219 | const unsigned int view2); 220 | }; 221 | } 222 | 223 | #endif //I3D_LINE3D_LINE3D_H_ 224 | -------------------------------------------------------------------------------- /lsd/lsd.hpp: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------------------- 2 | 3 | LSD - Line Segment Detector on digital images 4 | 5 | This code is part of the following publication and was subject 6 | to peer review: 7 | 8 | "LSD: a Line Segment Detector" by Rafael Grompone von Gioi, 9 | Jeremie Jakubowicz, Jean-Michel Morel, and Gregory Randall, 10 | Image Processing On Line, 2012. DOI:10.5201/ipol.2012.gjmr-lsd 11 | http://dx.doi.org/10.5201/ipol.2012.gjmr-lsd 12 | 13 | Copyright (c) 2007-2011 rafael grompone von gioi 14 | 15 | This program is free software: you can redistribute it and/or modify 16 | it under the terms of the GNU Affero General Public License as 17 | published by the Free Software Foundation, either version 3 of the 18 | License, or (at your option) any later version. 19 | 20 | This program is distributed in the hope that it will be useful, 21 | but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | GNU Affero General Public License for more details. 24 | 25 | You should have received a copy of the GNU Affero General Public License 26 | along with this program. If not, see . 27 | 28 | ----------------------------------------------------------------------------*/ 29 | 30 | /*----------------------------------------------------------------------------*/ 31 | /** @file lsd.h 32 | LSD module header 33 | @author rafael grompone von gioi 34 | */ 35 | /*----------------------------------------------------------------------------*/ 36 | #ifndef LSD_HEADER 37 | #define LSD_HEADER 38 | 39 | /*----------------------------------------------------------------------------*/ 40 | /** LSD Full Interface 41 | 42 | @param n_out Pointer to an int where LSD will store the number of 43 | line segments detected. 44 | 45 | @param img Pointer to input image data. It must be an array of 46 | doubles of size X x Y, and the pixel at coordinates 47 | (x,y) is obtained by img[x+y*X]. 48 | 49 | @param X X size of the image: the number of columns. 50 | 51 | @param Y Y size of the image: the number of rows. 52 | 53 | @param scale When different from 1.0, LSD will scale the input image 54 | by 'scale' factor by Gaussian filtering, before detecting 55 | line segments. 56 | Example: if scale=0.8, the input image will be subsampled 57 | to 80% of its size, before the line segment detector 58 | is applied. 59 | Suggested value: 0.8 60 | 61 | @param sigma_scale When scale!=1.0, the sigma of the Gaussian filter is: 62 | sigma = sigma_scale / scale, if scale < 1.0 63 | sigma = sigma_scale, if scale >= 1.0 64 | Suggested value: 0.6 65 | 66 | @param quant Bound to the quantization error on the gradient norm. 67 | Example: if gray levels are quantized to integer steps, 68 | the gradient (computed by finite differences) error 69 | due to quantization will be bounded by 2.0, as the 70 | worst case is when the error are 1 and -1, that 71 | gives an error of 2.0. 72 | Suggested value: 2.0 73 | 74 | @param ang_th Gradient angle tolerance in the region growing 75 | algorithm, in degrees. 76 | Suggested value: 22.5 77 | 78 | @param log_eps Detection threshold, accept if -log10(NFA) > log_eps. 79 | The larger the value, the more strict the detector is, 80 | and will result in less detections. 81 | (Note that the 'minus sign' makes that this 82 | behavior is opposite to the one of NFA.) 83 | The value -log10(NFA) is equivalent but more 84 | intuitive than NFA: 85 | - -1.0 gives an average of 10 false detections on noise 86 | - 0.0 gives an average of 1 false detections on noise 87 | - 1.0 gives an average of 0.1 false detections on nose 88 | - 2.0 gives an average of 0.01 false detections on noise 89 | . 90 | Suggested value: 0.0 91 | 92 | @param density_th Minimal proportion of 'supporting' points in a rectangle. 93 | Suggested value: 0.7 94 | 95 | @param n_bins Number of bins used in the pseudo-ordering of gradient 96 | modulus. 97 | Suggested value: 1024 98 | 99 | @param reg_img Optional output: if desired, LSD will return an 100 | int image where each pixel indicates the line segment 101 | to which it belongs. Unused pixels have the value '0', 102 | while the used ones have the number of the line segment, 103 | numbered 1,2,3,..., in the same order as in the 104 | output list. If desired, a non NULL int** pointer must 105 | be assigned, and LSD will make that the pointer point 106 | to an int array of size reg_x x reg_y, where the pixel 107 | value at (x,y) is obtained with (*reg_img)[x+y*reg_x]. 108 | Note that the resulting image has the size of the image 109 | used for the processing, that is, the size of the input 110 | image scaled by the given factor 'scale'. If scale!=1 111 | this size differs from XxY and that is the reason why 112 | its value is given by reg_x and reg_y. 113 | Suggested value: NULL 114 | 115 | @param reg_x Pointer to an int where LSD will put the X size 116 | 'reg_img' image, when asked for. 117 | Suggested value: NULL 118 | 119 | @param reg_y Pointer to an int where LSD will put the Y size 120 | 'reg_img' image, when asked for. 121 | Suggested value: NULL 122 | 123 | @return A double array of size 7 x n_out, containing the list 124 | of line segments detected. The array contains first 125 | 7 values of line segment number 1, then the 7 values 126 | of line segment number 2, and so on, and it finish 127 | by the 7 values of line segment number n_out. 128 | The seven values are: 129 | - x1,y1,x2,y2,width,p,-log10(NFA) 130 | . 131 | for a line segment from coordinates (x1,y1) to (x2,y2), 132 | a width 'width', an angle precision of p in (0,1) given 133 | by angle_tolerance/180 degree, and NFA value 'NFA'. 134 | If 'out' is the returned pointer, the 7 values of 135 | line segment number 'n+1' are obtained with 136 | 'out[7*n+0]' to 'out[7*n+6]'. 137 | */ 138 | double * LineSegmentDetection( int * n_out, 139 | double * img, int X, int Y, 140 | double scale, double sigma_scale, double quant, 141 | double ang_th, double log_eps, double density_th, 142 | int n_bins, 143 | int ** reg_img, int * reg_x, int * reg_y ); 144 | 145 | /*----------------------------------------------------------------------------*/ 146 | /** LSD Simple Interface with Scale and Region output. 147 | 148 | @param n_out Pointer to an int where LSD will store the number of 149 | line segments detected. 150 | 151 | @param img Pointer to input image data. It must be an array of 152 | doubles of size X x Y, and the pixel at coordinates 153 | (x,y) is obtained by img[x+y*X]. 154 | 155 | @param X X size of the image: the number of columns. 156 | 157 | @param Y Y size of the image: the number of rows. 158 | 159 | @param scale When different from 1.0, LSD will scale the input image 160 | by 'scale' factor by Gaussian filtering, before detecting 161 | line segments. 162 | Example: if scale=0.8, the input image will be subsampled 163 | to 80% of its size, before the line segment detector 164 | is applied. 165 | Suggested value: 0.8 166 | 167 | @param reg_img Optional output: if desired, LSD will return an 168 | int image where each pixel indicates the line segment 169 | to which it belongs. Unused pixels have the value '0', 170 | while the used ones have the number of the line segment, 171 | numbered 1,2,3,..., in the same order as in the 172 | output list. If desired, a non NULL int** pointer must 173 | be assigned, and LSD will make that the pointer point 174 | to an int array of size reg_x x reg_y, where the pixel 175 | value at (x,y) is obtained with (*reg_img)[x+y*reg_x]. 176 | Note that the resulting image has the size of the image 177 | used for the processing, that is, the size of the input 178 | image scaled by the given factor 'scale'. If scale!=1 179 | this size differs from XxY and that is the reason why 180 | its value is given by reg_x and reg_y. 181 | Suggested value: NULL 182 | 183 | @param reg_x Pointer to an int where LSD will put the X size 184 | 'reg_img' image, when asked for. 185 | Suggested value: NULL 186 | 187 | @param reg_y Pointer to an int where LSD will put the Y size 188 | 'reg_img' image, when asked for. 189 | Suggested value: NULL 190 | 191 | @return A double array of size 7 x n_out, containing the list 192 | of line segments detected. The array contains first 193 | 7 values of line segment number 1, then the 7 values 194 | of line segment number 2, and so on, and it finish 195 | by the 7 values of line segment number n_out. 196 | The seven values are: 197 | - x1,y1,x2,y2,width,p,-log10(NFA) 198 | . 199 | for a line segment from coordinates (x1,y1) to (x2,y2), 200 | a width 'width', an angle precision of p in (0,1) given 201 | by angle_tolerance/180 degree, and NFA value 'NFA'. 202 | If 'out' is the returned pointer, the 7 values of 203 | line segment number 'n+1' are obtained with 204 | 'out[7*n+0]' to 'out[7*n+6]'. 205 | */ 206 | double * lsd_scale_region( int * n_out, 207 | double * img, int X, int Y, double scale, 208 | int ** reg_img, int * reg_x, int * reg_y ); 209 | 210 | /*----------------------------------------------------------------------------*/ 211 | /** LSD Simple Interface with Scale 212 | 213 | @param n_out Pointer to an int where LSD will store the number of 214 | line segments detected. 215 | 216 | @param img Pointer to input image data. It must be an array of 217 | doubles of size X x Y, and the pixel at coordinates 218 | (x,y) is obtained by img[x+y*X]. 219 | 220 | @param X X size of the image: the number of columns. 221 | 222 | @param Y Y size of the image: the number of rows. 223 | 224 | @param scale When different from 1.0, LSD will scale the input image 225 | by 'scale' factor by Gaussian filtering, before detecting 226 | line segments. 227 | Example: if scale=0.8, the input image will be subsampled 228 | to 80% of its size, before the line segment detector 229 | is applied. 230 | Suggested value: 0.8 231 | 232 | @return A double array of size 7 x n_out, containing the list 233 | of line segments detected. The array contains first 234 | 7 values of line segment number 1, then the 7 values 235 | of line segment number 2, and so on, and it finish 236 | by the 7 values of line segment number n_out. 237 | The seven values are: 238 | - x1,y1,x2,y2,width,p,-log10(NFA) 239 | . 240 | for a line segment from coordinates (x1,y1) to (x2,y2), 241 | a width 'width', an angle precision of p in (0,1) given 242 | by angle_tolerance/180 degree, and NFA value 'NFA'. 243 | If 'out' is the returned pointer, the 7 values of 244 | line segment number 'n+1' are obtained with 245 | 'out[7*n+0]' to 'out[7*n+6]'. 246 | */ 247 | double * lsd_scale(int * n_out, double * img, int X, int Y, double scale); 248 | 249 | /*----------------------------------------------------------------------------*/ 250 | /** LSD Simple Interface 251 | 252 | @param n_out Pointer to an int where LSD will store the number of 253 | line segments detected. 254 | 255 | @param img Pointer to input image data. It must be an array of 256 | doubles of size X x Y, and the pixel at coordinates 257 | (x,y) is obtained by img[x+y*X]. 258 | 259 | @param X X size of the image: the number of columns. 260 | 261 | @param Y Y size of the image: the number of rows. 262 | 263 | @return A double array of size 7 x n_out, containing the list 264 | of line segments detected. The array contains first 265 | 7 values of line segment number 1, then the 7 values 266 | of line segment number 2, and so on, and it finish 267 | by the 7 values of line segment number n_out. 268 | The seven values are: 269 | - x1,y1,x2,y2,width,p,-log10(NFA) 270 | . 271 | for a line segment from coordinates (x1,y1) to (x2,y2), 272 | a width 'width', an angle precision of p in (0,1) given 273 | by angle_tolerance/180 degree, and NFA value 'NFA'. 274 | If 'out' is the returned pointer, the 7 values of 275 | line segment number 'n+1' are obtained with 276 | 'out[7*n+0]' to 'out[7*n+6]'. 277 | */ 278 | double * lsd(int * n_out, double * img, int X, int Y); 279 | 280 | #endif /* !LSD_HEADER */ 281 | /*----------------------------------------------------------------------------*/ 282 | -------------------------------------------------------------------------------- /lsd/lsd_opencv.hpp: -------------------------------------------------------------------------------- 1 | /*M/////////////////////////////////////////////////////////////////////////////////////// 2 | // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. 3 | // 4 | // By downloading, copying, installing or using the software you agree to this license. 5 | // If you do not agree to this license, do not download, install, 6 | // copy or use the software. 7 | // 8 | // 9 | // License Agreement 10 | // For Open Source Computer Vision Library 11 | // 12 | // Copyright (C) 2000-2008, Intel Corporation, all rights reserved. 13 | // Copyright (C) 2008-2011, Willow Garage Inc., all rights reserved. 14 | // Third party copyrights are property of their respective owners. 15 | // 16 | // Redistribution and use in source and binary forms, with or without modification, 17 | // are permitted provided that the following conditions are met: 18 | // 19 | // * Redistributions of source code must retain the above copyright notice, 20 | // this list of conditions and the following disclaimer. 21 | // 22 | // * Redistributions in binary form must reproduce the above copyright notice, 23 | // this list of conditions and the following disclaimer in the documentation 24 | // and/or other materials provided with the distribution. 25 | // 26 | // * The name of the copyright holders may not be used to endorse or promote products 27 | // derived from this software without specific prior written permission. 28 | // 29 | // This software is provided by the copyright holders and contributors "as is" and 30 | // any express or implied warranties, including, but not limited to, the implied 31 | // warranties of merchantability and fitness for a particular purpose are disclaimed. 32 | // In no event shall the Intel Corporation or contributors be liable for any direct, 33 | // indirect, incidental, special, exemplary, or consequential damages 34 | // (including, but not limited to, procurement of substitute goods or services; 35 | // loss of use, data, or profits; or business interruption) however caused 36 | // and on any theory of liability, whether in contract, strict liability, 37 | // or tort (including negligence or otherwise) arising in any way out of 38 | // the use of this software, even if advised of the possibility of such damage. 39 | // 40 | //M*/ 41 | 42 | #ifndef _OPENCV_LSD_HPP_ 43 | #define _OPENCV_LSD_HPP_ 44 | #ifdef __cplusplus 45 | 46 | #include 47 | 48 | namespace cv { 49 | 50 | enum {LSD_NO_SIZE_LIMIT = -1, 51 | LSD_REFINE_NONE = 0, 52 | LSD_REFINE_STD = 1, 53 | LSD_REFINE_ADV = 2, 54 | 55 | 56 | }; 57 | 58 | class LineSegmentDetector : public Algorithm 59 | { 60 | public: 61 | /** 62 | * Detect lines in the input image with the specified ROI. 63 | * 64 | * @param _image A grayscale(CV_8UC1) input image. 65 | * If only a roi needs to be selected, use 66 | * lsd_ptr->detect(image(roi), ..., lines); 67 | * lines += Scalar(roi.x, roi.y, roi.x, roi.y); 68 | * @param _lines Return: A vector of Vec4i elements specifying the beginning and ending point of a line. 69 | * Where Vec4i is (x1, y1, x2, y2), point 1 is the start, point 2 - end. 70 | * Returned lines are strictly oriented depending on the gradient. 71 | * @param _roi Return: ROI of the image, where lines are to be found. If specified, the returning 72 | * lines coordinates are image wise. 73 | * @param width Return: Vector of widths of the regions, where the lines are found. E.g. Width of line. 74 | * @param prec Return: Vector of precisions with which the lines are found. 75 | * @param nfa Return: Vector containing number of false alarms in the line region, with precision of 10%. 76 | * The bigger the value, logarithmically better the detection. 77 | * * -1 corresponds to 10 mean false alarms 78 | * * 0 corresponds to 1 mean false alarm 79 | * * 1 corresponds to 0.1 mean false alarms 80 | * This vector will be calculated _only_ when the objects type is REFINE_ADV 81 | */ 82 | virtual void detect(InputArray _image, OutputArray _lines, 83 | OutputArray width = noArray(), OutputArray prec = noArray(), 84 | OutputArray nfa = noArray()) = 0; 85 | 86 | /** 87 | * Draw lines on the given canvas. 88 | * 89 | * @param image The image, where lines will be drawn. 90 | * Should have the size of the image, where the lines were found 91 | * @param lines The lines that need to be drawn 92 | */ 93 | virtual void drawSegments(InputOutputArray _image, InputArray lines) = 0; 94 | 95 | /** 96 | * Draw both vectors on the image canvas. Uses blue for lines 1 and red for lines 2. 97 | * 98 | * @param image The image, where lines will be drawn. 99 | * Should have the size of the image, where the lines were found. 100 | * @param lines1 The first lines that need to be drawn. Color - Blue. 101 | * @param lines2 The second lines that need to be drawn. Color - Red. 102 | * @return The number of mismatching pixels between lines1 and lines2. 103 | */ 104 | virtual int compareSegments(const Size& size, InputArray lines1, InputArray lines2, InputOutputArray _image = noArray()) = 0; 105 | 106 | /** 107 | * Find all line elements that are *not* fullfilling the angle and range requirenmnets. 108 | * Take all lines, whose angle(line_segment) is outside [min_angle, max_angle] range. 109 | * 110 | * @param lines Input lines. 111 | * @param filtered The output vector of lines not containing those fulfilling the requirement. 112 | * @param min_angle The min angle to be considered in degrees. Should be in range [0..180]. 113 | * @param max_angle The max angle to be considered in degrees. Should be >= min_angle and widthin range [0..180]. 114 | * @return Returns the number of line segments not included in the output vector. 115 | */ 116 | CV_WRAP virtual int filterOutAngle(InputArray lines, OutputArray filtered, float min_angle, float max_angle) = 0; 117 | 118 | /** 119 | * Find all line elements that are fullfilling the angle and range requirenmnets. 120 | * Take all lines, whose angle(line_segment) is inside [min_angle, max_angle] range. 121 | * The opposite of the filterOutAngle method. 122 | * 123 | * @param lines Input lines. 124 | * @param filtered The output vector of lines not containing those fulfilling the requirement. 125 | * @param min_angle The min angle to be considered in degrees. Should be in range [0..180]. 126 | * @param max_angle The max angle to be considered in degrees. Should be >= min_angle and widthin range [0..180]. 127 | * @return Returns the number of line segments not included in the output vector. 128 | */ 129 | CV_WRAP virtual int retainAngle(InputArray lines, OutputArray filtered, float min_angle, float max_angle) = 0; 130 | 131 | /** 132 | * Find all line elements that *are* fullfilling the size requirenmnets. 133 | * Lines which are shorter than max_length and longer than min_length. 134 | * 135 | * @param lines Input lines. 136 | * @param filtered The output vector of lines containing those fulfilling the requirement. 137 | * @param max_length Maximum length of the line segment. 138 | * @param min_length Minimum length of the line segment. 139 | * @return Returns the number of line segments not included in the output vector. 140 | */ 141 | CV_WRAP virtual int filterSize(InputArray lines, OutputArray filtered, float min_length, float max_length = LSD_NO_SIZE_LIMIT) = 0; 142 | 143 | /* 144 | * Find itnersection point of 2 lines. 145 | * 146 | * @param line1 First line in format Vec4i(x1, y1, x2, y2). 147 | * @param line2 Second line in the same format as line1. 148 | * @param P The point where line1 and line2 intersect. 149 | * @return The value in variable P is only valid when the return value is true. 150 | * Otherwise, the lines are parallel and the value can be ignored. 151 | */ 152 | CV_WRAP virtual bool intersection(InputArray line1, InputArray line2, Point& P) = 0; 153 | 154 | virtual ~LineSegmentDetector() {}; 155 | }; 156 | 157 | //! Returns a pointer to a LineSegmentDetector class. 158 | CV_EXPORTS Ptr createLineSegmentDetectorPtr( 159 | int _refine = LSD_REFINE_STD, double _scale = 0.8, 160 | double _sigma_scale = 0.6, double _quant = 2.0, double _ang_th = 22.5, 161 | double _log_eps = 0, double _density_th = 0.7, int _n_bins = 1024); 162 | 163 | } 164 | #endif 165 | #endif 166 | -------------------------------------------------------------------------------- /lsd/lsd_wrap.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * lsd_wrap.cpp 3 | * 4 | * Created on: May 20, 2013 5 | * Author: gary 6 | */ 7 | #include "lsd_wrap.hpp" 8 | #include "lsd.hpp" 9 | 10 | using namespace cv; 11 | using namespace std; 12 | using namespace lsdwrap; 13 | /** 14 | * Find line segments 15 | * 16 | * @param I Input image. CV_8UC1 or C3 (gray or color) allowed, will be converted to gray, CV_64C1 17 | * @param segments Return: Vector of found line segments "seg" 18 | * @param Roi Optional region of interest to compute segments in. Smaller the image, finer the segments found 19 | * @return Return number of segments found (-1 => error) 20 | */ 21 | int LsdWrap::lsdw(Mat &I, std::vector &segments, cv::Rect *Roi) 22 | { 23 | //CHECKS AND CONVERSTIONS 24 | if(I.empty()) 25 | return -1; 26 | if(I.channels() == 3) 27 | { 28 | cv::cvtColor(I, Igray, CV_BGR2GRAY); 29 | } 30 | else if (I.channels() == 1) 31 | { 32 | Igray = I; //Just point to it 33 | } 34 | else 35 | return -2; 36 | if(Roi) 37 | { 38 | Mat Itmp = Igray(*Roi).clone(); 39 | Igray = Itmp; 40 | } 41 | Igray.convertTo(I64F,CV_64FC1); 42 | 43 | //DO LSD 44 | double *dp = I64F.ptr(0); 45 | int X = I64F.cols; 46 | int Y = I64F.rows; 47 | int n; 48 | double *out = lsd(&n,dp,X,Y); 49 | double *op = out; 50 | 51 | //RECORD THE RESULTS: 52 | if(0 == n) { segments.clear(); return 0;} 53 | segments.resize(n); 54 | vector::iterator it = segments.begin(), eit = segments.end(); 55 | if(Roi) //Taking a subset of the image 56 | { 57 | float ox = (float)(Roi->x);//offsets to the original boundaries 58 | float oy = (float)(Roi->y); 59 | for(; it != eit; ++it) 60 | { 61 | (*it).x1 = (float)(*op++) + ox; 62 | (*it).y1 = (float)(*op++) + oy; 63 | (*it).x2 = (float)(*op++) + ox; 64 | (*it).y2 = (float)(*op++) + oy; 65 | (*it).width = (float)(*op++); 66 | (*it).p = (float)(*op++); 67 | (*it).NFA = (float)(*op++); 68 | } 69 | } 70 | else //Do the whole image 71 | { 72 | for(; it != eit; ++it) 73 | { 74 | (*it).x1 = (float)(*op++); 75 | (*it).y1 = (float)(*op++); 76 | (*it).x2 = (float)(*op++); 77 | (*it).y2 = (float)(*op++); 78 | (*it).width = (float)(*op++); 79 | (*it).p = (float)(*op++); 80 | (*it).NFA = (float)(*op++); 81 | } 82 | } 83 | free( (void *) out ); //Clean up internal allocations 84 | return n; 85 | } 86 | 87 | /** 88 | * Subdivide image and call by parts 89 | * Basically, this just creates Rois to break up the image into div_factor x div_factor pieces, then calls lsd(I,segmetns,ROI) above 90 | * 91 | * @param I Input image, will be converted to gray, CV_64C1 92 | * @param segments Return: Vector of found line segments "seg" 93 | * @param div_factor How many parts should image be divided into in each dimension? 2 => 4 parts, 3=>9 etc. [1,I.rows()/2] 94 | * @return Return number of segments found 95 | */ 96 | int LsdWrap::lsd_subdivided(Mat &I, std::vector &segments, int div_factor) 97 | { 98 | int width = I.cols; 99 | int height = I.rows; 100 | segments.clear(); 101 | if((div_factor < 1)||(div_factor > height/2)) 102 | div_factor = 1; 103 | int dw = width/div_factor; 104 | int dh = height/div_factor; 105 | int dwo = dw/20; //overlap 106 | int dho = dh/20; //overlap 107 | int N = 0; 108 | vector segs; 109 | for(int x = 0; x < width; x += dw) 110 | { 111 | int w = dw + dwo; 112 | if(x+w >= width) 113 | { 114 | int dx = x+w-width; 115 | x -= dx/2; 116 | w = width - 1 - x; 117 | } 118 | for(int y = 0; y < height; y += dh) 119 | { 120 | int h = dh + dho; 121 | if(h+y >= height) 122 | { 123 | int dy = h+y-height; 124 | y -= dy/2; 125 | h = height - 1 - y; 126 | } 127 | Rect R(x,y,w,h); 128 | N += lsdw(I,segs,&R); 129 | segments.insert(segments.end(),segs.begin(),segs.end()); 130 | } 131 | } 132 | return N; 133 | } 134 | 135 | /** 136 | * Visualize segments 137 | * 138 | * @param name Name of window to display in when you declared it outside with void namedWindow(const string& winname) 139 | * @param gray Image, CV_8UC1. Will convert it to color image so that it can paint segments in red 140 | * @param segments Segments found from a call to lsd(...) 141 | */ 142 | void LsdWrap::imshow_segs(const std::string &name, Mat &gray, std::vector &segments) 143 | { 144 | Mat Ig; 145 | if(gray.empty()) 146 | return; 147 | if(gray.channels() == 3) 148 | { 149 | cv::cvtColor(gray, Ig, CV_BGR2GRAY); 150 | } 151 | else if (gray.channels() == 1) 152 | { 153 | Ig = gray; //Just point to it 154 | } 155 | else 156 | return; 157 | //Create 3 channel image so we can draw colored line segments on the gray scale image 158 | vector planes; 159 | planes.push_back(Ig); 160 | planes.push_back(Ig); 161 | planes.push_back(Ig); 162 | //Merge them into a color image 163 | Mat combine; 164 | merge(planes,combine); 165 | //draw segments ... 166 | vector::iterator it = segments.begin(), eit = segments.end(); 167 | for(; it != eit; ++it) 168 | { 169 | Point p1((int)((*it).x1 + 0.5), (int)((*it).y1 + 0.5)); 170 | Point p2((int)((*it).x2 + 0.5), (int)((*it).y2 + 0.5)); 171 | line(combine,p1,p2,Scalar(0,0,255),2); 172 | } 173 | //and display ... 174 | imshow(name.c_str(),combine); 175 | } 176 | 177 | 178 | /** 179 | * To help in unit tests, compare 2 different segment finds 180 | * @param seg1 Vector1 of segments (in Blue) 181 | * @param seg2 Vector2 of segments (in Red) 182 | * @param size Size of images that were used to find the segment 183 | * @param name Optional name of window to display results in 184 | * @param I Optional pointer. If not null, then draw image in namedWindow(name). 185 | * @return How many points do not overlap between segments in seg1 and seg2 186 | */ 187 | int LsdWrap::CompareSegs(std::vector &seg1,std::vector &seg2, 188 | cv::Size size, const std::string &name, cv::Mat *I) 189 | { 190 | //SET UP AND SIZE 191 | Mat I1, I2; 192 | if(I && size != I->size()) size = I->size(); 193 | I1 = Mat(size,CV_8UC1,Scalar::all(0)); 194 | I2 = Mat(size,CV_8UC1,Scalar::all(0)); 195 | 196 | //DRAW SEGMENTS 197 | vector::iterator it = seg1.begin(), eit = seg1.end(); 198 | for(; it != eit; ++it) 199 | { 200 | Point p1((int)((*it).x1 + 0.5), (int)((*it).y1 + 0.5)); 201 | Point p2((int)((*it).x2 + 0.5), (int)((*it).y2 + 0.5)); 202 | line(I1,p1,p2,Scalar::all(255),1); 203 | } 204 | it = seg2.begin(); 205 | eit = seg2.end(); 206 | for(; it != eit; ++it) 207 | { 208 | Point p1((int)((*it).x1 + 0.5), (int)((*it).y1 + 0.5)); 209 | Point p2((int)((*it).x2 + 0.5), (int)((*it).y2 + 0.5)); 210 | line(I2,p1,p2,Scalar::all(255),1); 211 | } 212 | 213 | //MARKPLACES WHERE THEY DO NOT AGREE 214 | Mat Ixor; 215 | bitwise_xor(I1, I2, Ixor); 216 | int N = countNonZero(Ixor); //This is the missmatch number 217 | 218 | //DRAW IT IF ASKED 219 | if(I) 220 | { 221 | Mat Ig; 222 | if(size != I->size()) 223 | { 224 | *I = Mat(size,CV_8UC1,Scalar::all(0)); 225 | } 226 | if(I->channels() == 3) 227 | { 228 | cv::cvtColor(*I, Ig, CV_BGR2GRAY); 229 | } 230 | else if (I->channels() == 1) 231 | { 232 | Ig = *I; //Just point to it 233 | } 234 | else 235 | return -2; 236 | //Create 3 channel image so we can draw colored line segments on the gray scale image 237 | vector planes; 238 | planes.push_back(I1); 239 | planes.push_back(Ig); 240 | planes.push_back(I2); 241 | //Merge them into a color image 242 | Mat combine; 243 | merge(planes,combine); 244 | imshow(name.c_str(),combine); //Show it 245 | } 246 | 247 | //DONE 248 | return(N); 249 | } 250 | 251 | /** 252 | * To help in unit tests, compare 2 different segments, one from a gray image, 1 from a 253 | * list & give number of differing pixels 254 | * @param Ig CV_8UC1 image of drawn segments (Blue) 255 | * @param seg2 Vector2 of segments (Red) 256 | * @param size Size of images that were used to find the segment 257 | * @param name Optional name of window to display results in 258 | * @param I Optional pointer. If not null, then draw image in namedWindow(name). 259 | * @return How many points do not overlap between segments in seg1 and seg2 260 | */ 261 | int LsdWrap::CompareSegs(cv::Mat &Ig, std::vector &seg2, const std::string &name, cv::Mat *I) 262 | { 263 | //SET UP AND SIZE 264 | Mat I1,I2; 265 | 266 | //GET SEGMETNS 1 267 | if(Ig.empty()) 268 | return -1; 269 | if(Ig.channels() == 3) 270 | { 271 | cv::cvtColor(Ig, I1, CV_BGR2GRAY); 272 | } 273 | else if (Ig.channels() == 1) 274 | { 275 | I1 = Ig; //Just point to it 276 | } 277 | else 278 | return -2; 279 | I2 = Mat(Ig.size(),CV_8UC1,Scalar::all(0)); 280 | 281 | //DRAW SEGMENTS 2 282 | vector::iterator it = seg2.begin(), eit = seg2.end(); 283 | for(; it != eit; ++it) 284 | { 285 | Point p1((int)((*it).x1 + 0.5), (int)((*it).y1 + 0.5)); 286 | Point p2((int)((*it).x2 + 0.5), (int)((*it).y2 + 0.5)); 287 | line(I2,p1,p2,Scalar::all(255),1); 288 | } 289 | 290 | //MARKPLACES WHERE THEY DO NOT AGREE 291 | Mat Ixor; 292 | bitwise_xor(I1, I2, Ixor); 293 | int N = countNonZero(Ixor); //This is the missmatch number 294 | 295 | //DRAW IT IF ASKED 296 | if(I) 297 | { 298 | if(Ig.size() != I->size()) 299 | { 300 | *I = Ig.clone(); 301 | I->setTo(Scalar::all(0)); 302 | } 303 | Mat Igreen; 304 | if(I->channels() == 3) 305 | { 306 | cv::cvtColor(*I, Igreen, CV_BGR2GRAY); 307 | } 308 | else if (I->channels() == 1) 309 | { 310 | Igreen = *I; //Just point to it 311 | } 312 | else 313 | return -2; 314 | //Create 3 channel image so we can draw colored line segments on the gray scale image 315 | vector planes; 316 | planes.push_back(I1); 317 | planes.push_back(Igreen); 318 | planes.push_back(I2); 319 | //Merge them into a color image 320 | Mat combine; 321 | merge(planes,combine); 322 | imshow(name.c_str(),combine); //Show it 323 | } 324 | 325 | //DONE 326 | return(N); 327 | } 328 | 329 | 330 | /** 331 | * Pass in segments and image size, return segments drawn on 8UC1 image 332 | * @param seg1 Vector of segments to be drawn 333 | * @param size width & height of image 334 | * @return Drawn image segments on CV_8UC1 image 335 | */ 336 | cv::Mat LsdWrap::segments_to_image8UC1(std::vector &seg1, cv::Size size) 337 | { 338 | Mat I1(size,CV_8UC1,Scalar::all(0)); //allocate an image, set it to zero 339 | 340 | //DRAW SEGMENTS 341 | vector::iterator it = seg1.begin(), eit = seg1.end(); 342 | for(; it != eit; ++it) 343 | { 344 | Point p1((int)((*it).x1 + 0.5), (int)((*it).y1 + 0.5)); 345 | Point p2((int)((*it).x2 + 0.5), (int)((*it).y2 + 0.5)); 346 | line(I1,p1,p2,Scalar::all(255),1); 347 | } 348 | return I1; 349 | } 350 | 351 | -------------------------------------------------------------------------------- /lsd/lsd_wrap.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * lsd_wrap.hpp 3 | * 4 | * Created on: May 17, 2013 5 | * Author: gary 6 | * 7 | * Just a simple wrap of LSD for now. If LSD is used extensively, it needs a deep re-write. 8 | * published 9 | * 2012-03-24 10 | * reference 11 | * Rafael Grompone von Gioi, Jérémie Jakubowicz, Jean-Michel Morel, and Gregory Randall, 12 | * LSD: a Line Segment Detector, Image Processing On Line, 2012. http://dx.doi.org/10.5201/ipol.2012.gjmr-lsd 13 | * 14 | * Notes 15 | * 5/18/2013 Author of LSD, rafael grompone von gioi , has allowed the code to be BSD for OpenCV. I will 16 | * allocate Google Summer of Code students on this. 17 | * 18 | * Calling example snippet: 19 | * ======================= 20 | namedWindow("ImageL"); 21 | namedWindow("ImageS"); 22 | namedWindow("Segs"); 23 | String sseg("Segs"); 24 | int num_images = file.size(); 25 | Mat I,Isegs; 26 | int64 t_; 27 | double sum_dt_ = 0, tick_freq_ = (double)getTickFrequency(); 28 | vector segmentsSub,segmentsWhole; 29 | // Mat foo; 30 | for(int i = 0; i 0) ls.CompareSegs(foo,segmentsSub,string("Segs"),&Isegs); //Blue L, Red S 44 | // foo = ls.segments_to_image8UC1(segmentsWhole,I.size()); 45 | // ls.CompareSegs(segmentsWhole,segmentsSub,I.size(),string("Segs"),&Isegs); //Blue L, Red S 46 | 47 | //HANDLE KEY INPUT AND PAUSE 48 | int k = 0xFF&waitKey(0); 49 | * 50 | * ================================ 51 | * 52 | */ 53 | 54 | #ifndef LSD_WRAP_HPP_ 55 | #define LSD_WRAP_HPP_ 56 | #include 57 | #include 58 | #include 59 | #include 60 | 61 | //#pragma hdrstop 62 | 63 | 64 | namespace lsdwrap { 65 | 66 | /** 67 | * seg Line segment structure 68 | * A double array of size 7 x n_out, containing the list 69 | * of line segments detected. The array contains first 70 | * 7 values of line segment number 1, then the 7 values 71 | * of line segment number 2, and so on, and it finish 72 | * by the 7 values of line segment number n_out. 73 | * The seven values are: 74 | * - x1,y1,x2,y2,width,p,-log10(NFA) 75 | * . 76 | * for a line segment from coordinates (x1,y1) to (x2,y2), 77 | * NOTE: This is an oriented dark to light edge from pt1 -> pt2. +90degrees from the angle pt1->pt2 is the dark side 78 | * a width 'width', 79 | * an angle precision of p in (0,1) given by angle_tolerance/180 degree, and 80 | * Number of False Alarms (NFA) 0 <= NFA <= 2. Smaller is better 81 | */ 82 | typedef struct seg_s 83 | { 84 | float x1; //Start point of a segment 85 | float y1; 86 | float x2; //End point of a segment. +90degree from the line from pt1 -> pt2 points into dark 87 | float y2; 88 | float width; //The width of the rectangle that bounds the segment. Smaller is better 89 | float p; //Angle tollerance, default is 22.5 deg/180 deg 90 | float NFA; //Number of False Alarms (NFA) 0 <= NFA <= 2. Smaller is better 91 | } seg; 92 | 93 | 94 | /** 95 | * For rotation invariance, this class calls BarPose 3 times: 0 deg, 45 deg and 90 deg 96 | */ 97 | 98 | /////////////////////////////////////////////////////////////////////////////////// 99 | // BARCODE DETECTION CLASS //////////////////////////////////////////////////////// 100 | /////////////////////////////////////////////////////////////////////////////////// 101 | 102 | class LsdWrap 103 | { 104 | public: 105 | cv::Mat I64F; //Will convert lsd(I,...) to a gray 64 bit image here. If not allocated or the wrong size, will reallocate 106 | cv::Mat Igray; //Convert or point to gray. On multiple use, if same size, it saves on allocation 107 | 108 | /** 109 | * Find line segments 110 | * 111 | * @param I Input image, will be converted to gray, CV_64C1 112 | * @param segments Return: Vector of found line segments "seg" 113 | * @param Roi Optional region of interest to compute segments in. Smaller the image, finer the segments found 114 | * @return Return number of segments found 115 | */ 116 | int lsdw(cv::Mat &I, std::vector &segments, cv::Rect *Roi = 0); 117 | 118 | /** 119 | * Subdivide image and call by parts 120 | * Basically, this just creates Rois to break up the image into div_factor x div_factor pieces, then calls lsd(I,segmetns,ROI) above 121 | * 122 | * @param I Input image, will be converted to gray, CV_64C1 123 | * @param segments Return: Vector of found line segments "seg" 124 | * @param div_factor How many parts should image be divided into in each dimension? 2 => 4 parts, 3=>9 etc. [1,I.rows()/2] 125 | * @return Return number of segments found 126 | */ 127 | int lsd_subdivided(cv::Mat &I, std::vector &segments, int div_factor = 1); 128 | 129 | /** 130 | * Visualize segments 131 | * 132 | * @param name Name of window to display in when you declared it outside with void namedWindow(const string& winname) 133 | * @param gray Image, CV_8UC1. Will convert it to color image so that it can paint segments in red 134 | * @param segments Segments found from a call to lsd(...) 135 | */ 136 | void imshow_segs(const std::string &name, cv::Mat &gray, std::vector &segments); 137 | 138 | /** 139 | * Pass in segments and image size, return segments drawn on 8UC1 image 140 | * @param seg1 Vector of segments to be drawn 141 | * @param size width & height of image 142 | * @return Drawn image segments on CV_8UC1 image 143 | */ 144 | cv::Mat segments_to_image8UC1(std::vector &seg1, cv::Size size); 145 | 146 | /** 147 | * To help in unit tests, compare 2 different segments, one from a gray image, 1 from a list & give number of differing pixels 148 | * @param Ig CV_8UC1 image of drawn segments (drawn in blue) 149 | * @param seg2 Vector2 of segments (drawn in red) 150 | * @param size Size of images that were used to find the segment 151 | * @param name Optional name of window to display results in 152 | * @param I Optional pointer. If not null, then draw image in namedWindow(name). 153 | * @return How many points do not overlap between segments in seg1 and seg2 154 | */ 155 | int CompareSegs(cv::Mat &Ig, std::vector &seg2, const std::string &name, cv::Mat *I = 0); 156 | 157 | 158 | /** 159 | * To help in unit tests, compare 2 different segment finds 160 | * @param seg1 Vector1 of segments (drawn in blue) 161 | * @param seg2 Vector2 of segments (drawn in red) 162 | * @param size Size of images that were used to find the segment 163 | * @param name Optional name of window to display results in 164 | * @param I Optional pointer. If not null, then draw image in namedWindow(name). 165 | * @return How many points do not overlap between segments in seg1 and seg2 166 | */ 167 | int CompareSegs(std::vector &seg1,std::vector &seg2, 168 | cv::Size size, const std::string &name, cv::Mat *I = 0); 169 | 170 | }; //end class 171 | 172 | } //Namespace lsdwrap 173 | 174 | #endif /* LSD_WRAP_HPP_ */ 175 | 176 | 177 | -------------------------------------------------------------------------------- /main_bundler.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Line3D - Line-based Multi View Stereo 3 | Copyright (C) 2015 Manuel Hofer 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | // EXTERNAL 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include "eigen3/Eigen/Eigen" 26 | 27 | // std 28 | #include 29 | #include 30 | 31 | // lib 32 | #include "line3D.h" 33 | 34 | int main(int argc, char *argv[]) 35 | { 36 | TCLAP::CmdLine cmd("LINE3D"); 37 | 38 | TCLAP::ValueArg imgArg("i", "input_folder", "folder that contains the bundle.rd.out file", true, ".", "string"); 39 | cmd.add(imgArg); 40 | 41 | TCLAP::ValueArg outputArg("o", "output_folder", "folder where result and temporary files are stored (if not specified --> image folder)", false, "", "string"); 42 | cmd.add(outputArg); 43 | 44 | TCLAP::ValueArg scaleArg("w", "max_image_width", "scale image down to fixed max width for line segment detection", false, L3D_DEF_MAX_IMG_WIDTH, "int"); 45 | cmd.add(scaleArg); 46 | 47 | TCLAP::ValueArg neighborArg("n", "num_matching_neighbors", "number of neighbors for matching (-1 --> use all)", false, L3D_DEF_MATCHING_NEIGHBORS, "int"); 48 | cmd.add(neighborArg); 49 | 50 | TCLAP::ValueArg affLowerArg("a", "reprojection_error_lower_bound", "min uncertainty in image space for affinity estimation (t_l)", false, L3D_DEF_UNCERTAINTY_LOWER_T, "float"); 51 | cmd.add(affLowerArg); 52 | 53 | TCLAP::ValueArg affUpperArg("b", "reprojection_error_upper_bound", "max uncertainty in image space for affinity estimation (t_u)", false, L3D_DEF_UNCERTAINTY_UPPER_T, "float"); 54 | cmd.add(affUpperArg); 55 | 56 | TCLAP::ValueArg sigma_A_Arg("g", "sigma_a", "angle regularizer", false, L3D_DEF_SIGMA_A, "float"); 57 | cmd.add(sigma_A_Arg); 58 | 59 | TCLAP::ValueArg sigma_P_Arg("p", "sigma_p", "position regularizer", false, L3D_DEF_SIGMA_P, "float"); 60 | cmd.add(sigma_P_Arg); 61 | 62 | TCLAP::ValueArg diffusionArg("d", "diffusion", "perform Replicator Dynamics Diffusion before clustering", false, L3D_DEF_PERFORM_RDD, "bool"); 63 | cmd.add(diffusionArg); 64 | 65 | TCLAP::ValueArg verboseArg("v", "verbose", "more debug output is shown", false, false, "bool"); 66 | cmd.add(verboseArg); 67 | 68 | TCLAP::ValueArg loadArg("l", "load_and_store_flag", "load/store segments (recommended for big images)", false, L3D_DEF_LOAD_AND_STORE_SEGMENTS, "bool"); 69 | cmd.add(loadArg); 70 | 71 | TCLAP::ValueArg collinArg("e", "collinearity_flag", "try to cluster collinear segments", false, L3D_DEF_COLLINEARITY_FOR_CLUSTERING, "bool"); 72 | cmd.add(collinArg); 73 | 74 | TCLAP::ValueArg minBaselineArg("x", "min_image_baseline", "minimum baseline between matching images (world space)", false, L3D_DEF_MIN_BASELINE_T, "float"); 75 | cmd.add(minBaselineArg); 76 | 77 | // read arguments 78 | cmd.parse(argc,argv); 79 | std::string inputFolder = imgArg.getValue().c_str(); 80 | std::string outputFolder = outputArg.getValue().c_str(); 81 | if(outputFolder.length() == 0) 82 | outputFolder = inputFolder+"/Line3D/"; 83 | 84 | int max_width = scaleArg.getValue(); 85 | int neighbors = neighborArg.getValue(); 86 | float max_uncertainty = fabs(affUpperArg.getValue()); 87 | float min_uncertainty = fabs(affLowerArg.getValue()); 88 | bool diffusion = diffusionArg.getValue(); 89 | bool verbose = verboseArg.getValue(); 90 | bool loadAndStore = loadArg.getValue(); 91 | bool collinearity = collinArg.getValue(); 92 | float sigma_a = fabs(sigma_A_Arg.getValue()); 93 | float sigma_p = fabs(sigma_P_Arg.getValue()); 94 | float min_baseline = fabs(minBaselineArg.getValue()); 95 | 96 | std::string prefix = "[SYS] "; 97 | 98 | // create output directory 99 | boost::filesystem::path dir(outputFolder); 100 | boost::filesystem::create_directory(dir); 101 | std::string data_directory = outputFolder+"/L3D_data/"; 102 | 103 | // create Line3D object 104 | L3D::Line3D* line3D = new L3D::Line3D(data_directory,neighbors, 105 | max_uncertainty,min_uncertainty, 106 | sigma_p,sigma_a,min_baseline, 107 | collinearity,verbose); 108 | 109 | // read bundle.rd.out 110 | std::ifstream bundle_file; 111 | bundle_file.open((inputFolder+"/bundle.rd.out").c_str()); 112 | 113 | std::string bundle_line; 114 | std::getline(bundle_file,bundle_line); // ignore first line... 115 | std::getline(bundle_file,bundle_line); 116 | 117 | // read number of images and 3D points 118 | std::stringstream bundle_stream(bundle_line); 119 | unsigned int num_cams,num_points; 120 | bundle_stream >> num_cams >> num_points; 121 | 122 | std::cout << prefix << "num_cameras: " << num_cams << " // num_points: " << num_points << std::endl; 123 | 124 | if(num_cams == 0 || num_points == 0) 125 | { 126 | std::cerr << prefix << "No cameras and/or points in bundle file!" << std::endl; 127 | return -1; 128 | } 129 | 130 | // read camera data (sequentially) 131 | std::map cams_focals; 132 | std::map cams_rotation; 133 | std::map cams_translation; 134 | std::map > cams_distortion; 135 | for(unsigned int i=0; i> focal_length >> dist1 >> dist2; 144 | 145 | cams_focals[i] = focal_length; 146 | cams_distortion[i] = std::pair(dist1,dist2); 147 | 148 | // rotation 149 | Eigen::Matrix3d R; 150 | for(unsigned int j=0; j<3; ++j) 151 | { 152 | std::getline(bundle_file,bundle_line); 153 | bundle_stream.str(""); 154 | bundle_stream.clear(); 155 | bundle_stream.str(bundle_line); 156 | bundle_stream >> R(j,0) >> R(j,1) >> R(j,2); 157 | } 158 | 159 | // flip 2nd and 3rd line 160 | R(1,0) *= -1.0; R(1,1) *= -1.0; R(1,2) *= -1.0; 161 | R(2,0) *= -1.0; R(2,1) *= -1.0; R(2,2) *= -1.0; 162 | 163 | cams_rotation[i] = R; 164 | 165 | // translation 166 | std::getline(bundle_file,bundle_line); 167 | bundle_stream.str(""); 168 | bundle_stream.clear(); 169 | bundle_stream.str(bundle_line); 170 | Eigen::Vector3d t; 171 | bundle_stream >> t(0) >> t(1) >> t(2); 172 | 173 | // flip y and z! 174 | t(1) *= -1.0; 175 | t(2) *= -1.0; 176 | 177 | cams_translation[i] = t; 178 | } 179 | 180 | // read features (for image similarity calculation) 181 | std::map > cams_worldpointIDs; 182 | for(unsigned int i=0; i> num_views; 194 | 195 | unsigned int camID,siftID; 196 | float posX,posY; 197 | for(unsigned int j=0; j> camID >> siftID; 200 | iss >> posX >> posY; 201 | cams_worldpointIDs[camID].push_back(i); 202 | } 203 | } 204 | bundle_file.close(); 205 | 206 | // load images sequentially 207 | for(unsigned int i=0; i possible_imgs; 220 | possible_imgs.push_back(boost::filesystem::wpath(inputFolder+"/visualize/"+fixedID+".jpg")); 221 | possible_imgs.push_back(boost::filesystem::wpath(inputFolder+"/visualize/"+fixedID+".JPG")); 222 | possible_imgs.push_back(boost::filesystem::wpath(inputFolder+"/visualize/"+fixedID+".png")); 223 | possible_imgs.push_back(boost::filesystem::wpath(inputFolder+"/visualize/"+fixedID+".PNG")); 224 | possible_imgs.push_back(boost::filesystem::wpath(inputFolder+"/visualize/"+fixedID+".jpeg")); 225 | possible_imgs.push_back(boost::filesystem::wpath(inputFolder+"/visualize/"+fixedID+".JPEG")); 226 | 227 | bool image_found = false; 228 | unsigned int pos = 0; 229 | while(!image_found && pos < possible_imgs.size()) 230 | { 231 | if(boost::filesystem::exists(possible_imgs[pos])) 232 | { 233 | image_found = true; 234 | img_filename = possible_imgs[pos].string(); 235 | } 236 | ++pos; 237 | } 238 | 239 | if(image_found) 240 | { 241 | // load image 242 | image = cv::imread(img_filename); 243 | 244 | // setup intrinsics 245 | float px = float(image.cols)/2.0f; 246 | float py = float(image.rows)/2.0f; 247 | float f = cams_focals[i]; 248 | 249 | Eigen::Matrix3d K = Eigen::Matrix3d::Zero(); 250 | K(0,0) = f; 251 | K(1,1) = f; 252 | K(0,2) = px; 253 | K(1,2) = py; 254 | K(2,2) = 1.0; 255 | 256 | // undistort (if necessary) 257 | float d1 = cams_distortion[i].first; 258 | float d2 = cams_distortion[i].second; 259 | 260 | if(fabs(d1) > L3D_EPS || fabs(d2) > L3D_EPS) 261 | { 262 | std::cout << prefix << "undistorting... " << std::endl; 263 | 264 | cv::Mat I = cv::Mat_::eye(3,3); 265 | cv::Mat cvK = cv::Mat_::zeros(3,3); 266 | cvK.at(0,0) = K(0,0); 267 | cvK.at(1,1) = K(1,1); 268 | cvK.at(0,2) = K(0,2); 269 | cvK.at(1,2) = K(1,2); 270 | cvK.at(2,2) = 1.0; 271 | 272 | cv::Mat cvDistCoeffs(4,1,CV_64FC1,cv::Scalar(0)); 273 | cvDistCoeffs.at(0) = d1; 274 | cvDistCoeffs.at(1) = d2; 275 | cvDistCoeffs.at(2) = 0.0; 276 | cvDistCoeffs.at(3) = 0.0; 277 | 278 | cv::Mat undistort_map_x; 279 | cv::Mat undistort_map_y; 280 | 281 | cv::initUndistortRectifyMap(cvK,cvDistCoeffs,I,cvK,cv::Size(image.cols, image.rows), 282 | undistort_map_x.type(), undistort_map_x, undistort_map_y ); 283 | cv::remap(image,image,undistort_map_x,undistort_map_y,cv::INTER_LINEAR,cv::BORDER_CONSTANT); 284 | } 285 | 286 | // add to system 287 | line3D->addImage(i,image,K,cams_rotation[i],cams_translation[i],cams_worldpointIDs[i],max_width,loadAndStore); 288 | } 289 | else 290 | { 291 | std::cerr << prefix << "warning: no image found! (only jpg and png supported)" << std::endl; 292 | } 293 | } 294 | 295 | // compute result 296 | line3D->compute3Dmodel(diffusion); 297 | 298 | // save end result 299 | std::list result; 300 | line3D->getResult(result); 301 | 302 | // set filename according to parameters 303 | std::stringstream str; 304 | str << "/line3D_result__"; 305 | str << "W_" << max_width << "__"; 306 | 307 | if(neighbors < 0) 308 | str << "N_ALL__"; 309 | else 310 | str << "N_" << neighbors << "__"; 311 | 312 | str << "tL_" << min_uncertainty << "__"; 313 | str << "tU_" << max_uncertainty << "__"; 314 | 315 | str << "sigmaP_" << sigma_p << "__"; 316 | str << "sigmaA_" << sigma_a << "__"; 317 | 318 | if(collinearity) 319 | str << "COLLIN__"; 320 | else 321 | str << "NO_COLLIN__"; 322 | 323 | if(diffusion) 324 | str << "DIFFUSION"; 325 | else 326 | str << "NO_DIFFUSION"; 327 | 328 | // save as STL 329 | line3D->save3DLinesAsSTL(result,outputFolder+str.str()+".stl"); 330 | 331 | // save as txt 332 | line3D->save3DLinesAsTXT(result,outputFolder+str.str()+".txt"); 333 | 334 | unsigned int num_indiv_segments = 0; 335 | std::list::iterator rit = result.begin(); 336 | for(; rit!=result.end(); ++rit) 337 | { 338 | L3D::L3DFinalLine3D fl = *rit; 339 | num_indiv_segments += fl.segments3D()->size(); 340 | } 341 | 342 | std::cout << prefix << "3D lines: " << result.size() << std::endl; 343 | std::cout << prefix << "3D segments: " << num_indiv_segments << std::endl; 344 | std::cout << prefix << "#images: " << line3D->numCameras() << std::endl; 345 | 346 | // cleanup 347 | delete line3D; 348 | } 349 | -------------------------------------------------------------------------------- /main_vsfm.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Line3D - Line-based Multi View Stereo 3 | Copyright (C) 2015 Manuel Hofer 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | // EXTERNAL 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include "eigen3/Eigen/Eigen" 26 | 27 | // std 28 | #include 29 | #include 30 | 31 | // lib 32 | #include "line3D.h" 33 | 34 | int main(int argc, char *argv[]) 35 | { 36 | TCLAP::CmdLine cmd("LINE3D"); 37 | 38 | TCLAP::ValueArg imgArg("i", "input_folder", "folder that contains the images", true, ".", "string"); 39 | cmd.add(imgArg); 40 | 41 | TCLAP::ValueArg nvmArg("m", "nvm_file", "full path to the VisualSfM result file (.nvm)", true, ".", "string"); 42 | cmd.add(nvmArg); 43 | 44 | TCLAP::ValueArg outputArg("o", "output_folder", "folder where result and temporary files are stored (if not specified --> image folder)", false, "", "string"); 45 | cmd.add(outputArg); 46 | 47 | TCLAP::ValueArg scaleArg("w", "max_image_width", "scale image down to fixed max width for line segment detection", false, L3D_DEF_MAX_IMG_WIDTH, "int"); 48 | cmd.add(scaleArg); 49 | 50 | TCLAP::ValueArg neighborArg("n", "num_matching_neighbors", "number of neighbors for matching (-1 --> use all)", false, L3D_DEF_MATCHING_NEIGHBORS, "int"); 51 | cmd.add(neighborArg); 52 | 53 | TCLAP::ValueArg affLowerArg("a", "reprojection_error_lower_bound", "min uncertainty in image space for affinity estimation (t_l)", false, L3D_DEF_UNCERTAINTY_LOWER_T, "float"); 54 | cmd.add(affLowerArg); 55 | 56 | TCLAP::ValueArg affUpperArg("b", "reprojection_error_upper_bound", "max uncertainty in image space for affinity estimation (t_u)", false, L3D_DEF_UNCERTAINTY_UPPER_T, "float"); 57 | cmd.add(affUpperArg); 58 | 59 | TCLAP::ValueArg sigma_A_Arg("g", "sigma_a", "angle regularizer", false, L3D_DEF_SIGMA_A, "float"); 60 | cmd.add(sigma_A_Arg); 61 | 62 | TCLAP::ValueArg sigma_P_Arg("p", "sigma_p", "position regularizer", false, L3D_DEF_SIGMA_P, "float"); 63 | cmd.add(sigma_P_Arg); 64 | 65 | TCLAP::ValueArg diffusionArg("d", "diffusion", "perform Replicator Dynamics Diffusion before clustering", false, L3D_DEF_PERFORM_RDD, "bool"); 66 | cmd.add(diffusionArg); 67 | 68 | TCLAP::ValueArg verboseArg("v", "verbose", "more debug output is shown", false, false, "bool"); 69 | cmd.add(verboseArg); 70 | 71 | TCLAP::ValueArg loadArg("l", "load_and_store_flag", "load/store segments (recommended for big images)", false, L3D_DEF_LOAD_AND_STORE_SEGMENTS, "bool"); 72 | cmd.add(loadArg); 73 | 74 | TCLAP::ValueArg collinArg("e", "collinearity_flag", "try to cluster collinear segments", false, L3D_DEF_COLLINEARITY_FOR_CLUSTERING, "bool"); 75 | cmd.add(collinArg); 76 | 77 | TCLAP::ValueArg minBaselineArg("x", "min_image_baseline", "minimum baseline between matching images (world space)", false, L3D_DEF_MIN_BASELINE_T, "float"); 78 | cmd.add(minBaselineArg); 79 | 80 | // read arguments 81 | cmd.parse(argc,argv); 82 | std::string inputFolder = imgArg.getValue().c_str(); 83 | std::string nvmFile = nvmArg.getValue().c_str(); 84 | std::string outputFolder = outputArg.getValue().c_str(); 85 | if(outputFolder.length() == 0) 86 | outputFolder = inputFolder+"/Line3D/"; 87 | 88 | int max_width = scaleArg.getValue(); 89 | int neighbors = neighborArg.getValue(); 90 | float max_uncertainty = fabs(affUpperArg.getValue()); 91 | float min_uncertainty = fabs(affLowerArg.getValue()); 92 | bool diffusion = diffusionArg.getValue(); 93 | bool verbose = verboseArg.getValue(); 94 | bool loadAndStore = loadArg.getValue(); 95 | bool collinearity = collinArg.getValue(); 96 | float sigma_a = fabs(sigma_A_Arg.getValue()); 97 | float sigma_p = fabs(sigma_P_Arg.getValue()); 98 | float min_baseline = fabs(minBaselineArg.getValue()); 99 | 100 | std::string prefix = "[SYS] "; 101 | 102 | // check if NVM file exists 103 | boost::filesystem::path nvm(nvmFile); 104 | if(!boost::filesystem::exists(nvm)) 105 | { 106 | std::cerr << "NVM file " << nvmFile << " does not exist!" << std::endl; 107 | return -1; 108 | } 109 | 110 | // create output directory 111 | boost::filesystem::path dir(outputFolder); 112 | boost::filesystem::create_directory(dir); 113 | std::string data_directory = outputFolder+"/L3D_data/"; 114 | 115 | // create Line3D object 116 | L3D::Line3D* line3D = new L3D::Line3D(data_directory,neighbors, 117 | max_uncertainty,min_uncertainty, 118 | sigma_p,sigma_a,min_baseline, 119 | collinearity,verbose); 120 | 121 | // read NVM file 122 | std::ifstream nvm_file; 123 | nvm_file.open(nvmFile.c_str()); 124 | 125 | std::string nvm_line; 126 | std::getline(nvm_file,nvm_line); // ignore first line... 127 | std::getline(nvm_file,nvm_line); // ignore second line... 128 | 129 | // read number of images 130 | std::getline(nvm_file,nvm_line); 131 | std::stringstream nvm_stream(nvm_line); 132 | unsigned int num_cams; 133 | nvm_stream >> num_cams; 134 | 135 | if(num_cams == 0) 136 | { 137 | std::cerr << prefix << "No aligned cameras in NVM file!" << std::endl; 138 | return -1; 139 | } 140 | 141 | // read camera data (sequentially) 142 | std::vector cams_imgFilenames(num_cams); 143 | std::vector cams_focals(num_cams); 144 | std::vector cams_rotation(num_cams); 145 | std::vector cams_translation(num_cams); 146 | std::vector cams_distortion(num_cams); 147 | for(unsigned int i=0; i> filename >> focal_length >> quat3 >> quat0 >> quat1 >> quat2; 162 | nvm_stream >> Cx >> Cy >> Cz >> dist; 163 | 164 | cams_imgFilenames[i] = filename; 165 | cams_focals[i] = focal_length; 166 | cams_distortion[i] = dist; 167 | 168 | // rotation 169 | Eigen::Matrix3d R; 170 | R(0,0) = 1.0-2.0*quat1*quat1-2.0*quat2*quat2; 171 | R(0,1) = 2.0*quat0*quat1-2.0*quat2*quat3; 172 | R(0,2) = 2.0*quat0*quat2+2.0*quat1*quat3; 173 | 174 | R(1,0) = 2.0*quat0*quat1+2.0*quat2*quat3; 175 | R(1,1) = 1.0-2.0*quat0*quat0-2.0*quat2*quat2; 176 | R(1,2) = 2.0*quat1*quat2-2.0*quat0*quat3; 177 | 178 | R(2,0) = 2.0*quat0*quat2-2.0*quat1*quat3; 179 | R(2,1) = 2.0*quat1*quat2+2.0*quat0*quat3; 180 | R(2,2) = 1.0-2.0*quat0*quat0-2.0*quat1*quat1; 181 | 182 | // translation 183 | Eigen::Vector3d C(Cx,Cy,Cz); 184 | Eigen::Vector3d t = -R*C; 185 | 186 | cams_translation[i] = t; 187 | cams_rotation[i] = R; 188 | } 189 | 190 | // read number of images 191 | std::getline(nvm_file,nvm_line); // ignore line... 192 | std::getline(nvm_file,nvm_line); 193 | nvm_stream.str(""); 194 | nvm_stream.clear(); 195 | nvm_stream.str(nvm_line); 196 | unsigned int num_points; 197 | nvm_stream >> num_points; 198 | 199 | // read features (for image similarity calculation) 200 | std::vector > cams_worldpointIDs(num_cams); 201 | for(unsigned int i=0; i> px >> py >> pz; 208 | iss_point3D >> colR >> colG >> colB; 209 | 210 | // measurements 211 | unsigned int num_views; 212 | iss_point3D >> num_views; 213 | 214 | unsigned int camID,siftID; 215 | float posX,posY; 216 | for(unsigned int j=0; j> camID >> siftID; 219 | iss_point3D >> posX >> posY; 220 | cams_worldpointIDs[camID].push_back(i); 221 | } 222 | } 223 | nvm_file.close(); 224 | 225 | // load images sequentially 226 | for(unsigned int i=0; i L3D_EPS) 247 | { 248 | std::cout << prefix << "undistorting... " << std::endl; 249 | 250 | cv::Mat I = cv::Mat_::eye(3,3); 251 | cv::Mat cvK = cv::Mat_::zeros(3,3); 252 | cvK.at(0,0) = K(0,0); 253 | cvK.at(1,1) = K(1,1); 254 | cvK.at(0,2) = K(0,2); 255 | cvK.at(1,2) = K(1,2); 256 | cvK.at(2,2) = 1.0; 257 | 258 | cv::Mat cvDistCoeffs(4,1,CV_64FC1,cv::Scalar(0)); 259 | cvDistCoeffs.at(0) = -d; 260 | cvDistCoeffs.at(1) = 0.0; 261 | cvDistCoeffs.at(2) = 0.0; 262 | cvDistCoeffs.at(3) = 0.0; 263 | 264 | cv::Mat undistort_map_x; 265 | cv::Mat undistort_map_y; 266 | 267 | cv::initUndistortRectifyMap(cvK,cvDistCoeffs,I,cvK,cv::Size(image.cols, image.rows), 268 | undistort_map_x.type(), undistort_map_x, undistort_map_y ); 269 | cv::remap(image,image,undistort_map_x,undistort_map_y,cv::INTER_LINEAR,cv::BORDER_CONSTANT); 270 | } 271 | 272 | // add to system 273 | line3D->addImage(i,image,K,cams_rotation[i],cams_translation[i],cams_worldpointIDs[i],max_width,loadAndStore); 274 | } 275 | 276 | // compute result 277 | line3D->compute3Dmodel(diffusion); 278 | 279 | // save end result 280 | std::list result; 281 | line3D->getResult(result); 282 | 283 | // set filename according to parameters 284 | std::stringstream str; 285 | str << "/line3D_result__"; 286 | str << "W_" << max_width << "__"; 287 | 288 | if(neighbors < 0) 289 | str << "N_ALL__"; 290 | else 291 | str << "N_" << neighbors << "__"; 292 | 293 | str << "tL_" << min_uncertainty << "__"; 294 | str << "tU_" << max_uncertainty << "__"; 295 | 296 | str << "sigmaP_" << sigma_p << "__"; 297 | str << "sigmaA_" << sigma_a << "__"; 298 | 299 | if(collinearity) 300 | str << "COLLIN__"; 301 | else 302 | str << "NO_COLLIN__"; 303 | 304 | if(diffusion) 305 | str << "DIFFUSION"; 306 | else 307 | str << "NO_DIFFUSION"; 308 | 309 | // save as STL 310 | line3D->save3DLinesAsSTL(result,outputFolder+str.str()+".stl"); 311 | 312 | // save as txt 313 | line3D->save3DLinesAsTXT(result,outputFolder+str.str()+".txt"); 314 | 315 | unsigned int num_indiv_segments = 0; 316 | std::list::iterator rit = result.begin(); 317 | for(; rit!=result.end(); ++rit) 318 | { 319 | L3D::L3DFinalLine3D fl = *rit; 320 | num_indiv_segments += fl.segments3D()->size(); 321 | } 322 | 323 | std::cout << prefix << "3D lines: " << result.size() << std::endl; 324 | std::cout << prefix << "3D segments: " << num_indiv_segments << std::endl; 325 | std::cout << prefix << "#images: " << line3D->numCameras() << std::endl; 326 | 327 | // cleanup 328 | delete line3D; 329 | } 330 | -------------------------------------------------------------------------------- /segments.h: -------------------------------------------------------------------------------- 1 | #ifndef I3D_LINE3D_SEGMENTS_H_ 2 | #define I3D_LINE3D_SEGMENTS_H_ 3 | 4 | /* 5 | Line3D - Line-based Multi View Stereo 6 | Copyright (C) 2015 Manuel Hofer 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | // std 23 | #include 24 | #include 25 | 26 | // external 27 | #include "boost/serialization/serialization.hpp" 28 | 29 | // internal 30 | #include "commons.h" 31 | #include "cudawrapper.h" 32 | #include "serialization.h" 33 | #include "dataArray.h" 34 | 35 | /** 36 | * Line3D - Segments 37 | * ==================== 38 | * Class that holds all segments and 39 | * collinearity/intersection information 40 | * for one specific view. 41 | * ==================== 42 | * Author: M.Hofer, 2015 43 | */ 44 | 45 | namespace L3D 46 | { 47 | // segment container 48 | class L3DSegments 49 | { 50 | public: 51 | // basic constructors 52 | L3DSegments(){ 53 | segments_ = NULL; 54 | } 55 | ~L3DSegments(){ 56 | delete segments_; 57 | } 58 | 59 | // data constructor 60 | L3DSegments(std::list& segments, const bool collin) 61 | { 62 | // store segments 63 | segments_ = new L3D::DataArray(4,segments.size()); 64 | std::list::iterator it = segments.begin(); 65 | for(unsigned int i=0; it!=segments.end(); ++i,++it) 66 | { 67 | segments_->dataCPU(0,i)[0] = (*it).x; 68 | segments_->dataCPU(1,i)[0] = (*it).y; 69 | segments_->dataCPU(2,i)[0] = (*it).z; 70 | segments_->dataCPU(3,i)[0] = (*it).w; 71 | } 72 | 73 | if(collin) 74 | { 75 | // compute collinearity 76 | L3D::DataArray* relation = new L3D::DataArray(segments_->height(),segments_->height(),true); 77 | segments_->upload(); 78 | L3D::compute_collinearity(segments_,relation,L3D_DEF_COLLINEARITY_S); 79 | segments_->removeFromGPU(); 80 | 81 | // download 82 | relation->download(); 83 | relation->removeFromGPU(); 84 | 85 | for(unsigned int i=0; iwidth()-1; ++i) 86 | { 87 | for(unsigned int j=i+1; jheight(); ++j) 88 | { 89 | float data = relation->dataCPU(i,j)[0]; 90 | 91 | // collinearity 92 | if(data > 0.0f) 93 | { 94 | segment2collinearities_[i][j] = data; 95 | segment2collinearities_[j][i] = data; 96 | } 97 | } 98 | } 99 | 100 | delete relation; 101 | } 102 | } 103 | 104 | // data access 105 | unsigned int num_segments(){ 106 | if(segments_ != NULL) 107 | return segments_->height(); 108 | else 109 | return 0; 110 | } 111 | L3D::DataArray* segments(){ 112 | return segments_; 113 | } 114 | 115 | std::map >* collinearities(){ 116 | return &segment2collinearities_; 117 | } 118 | 119 | private: 120 | // segment data 121 | L3D::DataArray* segments_; 122 | std::map > segment2collinearities_; 123 | 124 | // serialization 125 | friend class boost::serialization::access; 126 | template 127 | void serialize(Archive & ar, const unsigned int version) 128 | { 129 | ar & boost::serialization::make_nvp("segment2collinearities_", segment2collinearities_); 130 | ar & boost::serialization::make_nvp("segments_", segments_); 131 | } 132 | }; 133 | } 134 | 135 | #endif //I3D_LINE3D_SEGMENTS_H_ 136 | -------------------------------------------------------------------------------- /serialization.h: -------------------------------------------------------------------------------- 1 | #ifndef I3D_LINE3D_SERIALIZATION_H_ 2 | #define I3D_LINE3D_SERIALIZATION_H_ 3 | 4 | /* 5 | Line3D - Line-based Multi View Stereo 6 | Copyright (C) 2015 Manuel Hofer 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include 33 | 34 | /** 35 | * Line3D - Serialization 36 | * ==================== 37 | * Handles serialization of view- and 38 | * matching-data to the hard drive 39 | * using boost. 40 | * ==================== 41 | * Author: M.Hofer, 2015 42 | */ 43 | 44 | namespace L3D 45 | { 46 | // serialization 47 | template 48 | inline void 49 | serializeToFile(std::string file, T const& data, bool binary = true) 50 | { 51 | std::ofstream os(file.c_str(), binary? std::ios::binary : std::ios::out); 52 | boost::archive::binary_oarchive ar(os); 53 | ar & boost::serialization::make_nvp("data", data); 54 | } 55 | 56 | template 57 | inline void 58 | serializeFromFile(std::string file, T& data, bool binary = true) 59 | { 60 | std::ifstream is(file.c_str(), binary? std::ios::binary : std::ios::in); 61 | if(is.bad()) { 62 | std::cout << "[L3D] serializeFromFileArchive(): File '" << file << "'' could not be opened " << std::endl; 63 | exit(1); 64 | } 65 | boost::archive::binary_iarchive ar(is); 66 | ar & boost::serialization::make_nvp("data", data); 67 | } 68 | } 69 | 70 | #endif //I3D_LINE3D_SERIALIZATION_H_ 71 | -------------------------------------------------------------------------------- /sparsematrix.cc: -------------------------------------------------------------------------------- 1 | #include "sparsematrix.h" 2 | 3 | namespace L3D 4 | { 5 | //------------------------------------------------------------------------------ 6 | SparseMatrix::SparseMatrix(std::list& entries, const unsigned int num_rows_cols, 7 | const float normalization_factor, 8 | const bool sort_by_row, const bool already_sorted) 9 | { 10 | // init 11 | entries_ = NULL; 12 | start_indices_ = NULL; 13 | row_sorted_ = sort_by_row; 14 | num_rows_cols_ = num_rows_cols; 15 | num_entries_ = entries.size(); 16 | 17 | if(entries.size() == 0 || num_rows_cols == 0) 18 | return; 19 | 20 | // sort data 21 | if(!already_sorted) 22 | { 23 | if(sort_by_row) 24 | entries.sort(L3D::sortAffEntriesByRow); 25 | else 26 | entries.sort(L3D::sortAffEntriesByCol); 27 | } 28 | 29 | // copy data 30 | entries_ = new L3D::DataArray(entries.size(),1); 31 | start_indices_ = new L3D::DataArray(num_rows_cols_,1); 32 | start_indices_->setValue(-1); 33 | std::list::iterator it = entries.begin(); 34 | unsigned int pos = 0; 35 | int current_rc = -1; 36 | for(; it!=entries.end(); ++it,++pos) 37 | { 38 | // store data 39 | float4 data = *it; 40 | data.z /= normalization_factor; 41 | entries_->dataCPU(pos,0)[0] = data; 42 | 43 | // check for new row/column 44 | int rc; 45 | if(sort_by_row) 46 | rc = int((*it).x); 47 | else 48 | rc = int((*it).y); 49 | 50 | if(current_rc != rc) 51 | { 52 | start_indices_->dataCPU(rc,0)[0] = pos; 53 | current_rc = rc; 54 | } 55 | } 56 | 57 | // copy to GPU 58 | entries_->upload(); 59 | start_indices_->upload(); 60 | } 61 | 62 | //------------------------------------------------------------------------------ 63 | SparseMatrix::SparseMatrix(std::list& entries, const unsigned int num_rows_cols, 64 | const float normalization_factor, 65 | const bool sort_by_row, const bool already_sorted) 66 | { 67 | // init 68 | entries_ = NULL; 69 | start_indices_ = NULL; 70 | row_sorted_ = sort_by_row; 71 | num_rows_cols_ = num_rows_cols; 72 | num_entries_ = entries.size(); 73 | 74 | if(entries.size() == 0 || num_rows_cols == 0) 75 | return; 76 | 77 | // sort data 78 | if(!already_sorted) 79 | { 80 | if(sort_by_row) 81 | entries.sort(L3D::sortCLEdgesByRow); 82 | else 83 | entries.sort(L3D::sortCLEdgesByCol); 84 | } 85 | 86 | // copy data 87 | entries_ = new L3D::DataArray(entries.size(),1); 88 | start_indices_ = new L3D::DataArray(num_rows_cols_,1); 89 | start_indices_->setValue(-1); 90 | std::list::iterator it = entries.begin(); 91 | unsigned int pos = 0; 92 | int current_rc = -1; 93 | for(; it!=entries.end(); ++it,++pos) 94 | { 95 | // store data 96 | CLEdge data = *it; 97 | data.w_ /= normalization_factor; 98 | entries_->dataCPU(pos,0)[0] = make_float4(data.i_,data.j_,data.w_,0.0f); 99 | 100 | // check for new row/column 101 | int rc; 102 | if(sort_by_row) 103 | rc = (*it).i_; 104 | else 105 | rc = (*it).j_; 106 | 107 | if(current_rc != rc) 108 | { 109 | start_indices_->dataCPU(rc,0)[0] = pos; 110 | current_rc = rc; 111 | } 112 | } 113 | 114 | // copy to GPU 115 | entries_->upload(); 116 | start_indices_->upload(); 117 | } 118 | 119 | //------------------------------------------------------------------------------ 120 | SparseMatrix::SparseMatrix(SparseMatrix* M, const bool change_sorting) 121 | { 122 | // init 123 | entries_ = NULL; 124 | start_indices_ = NULL; 125 | num_rows_cols_ = M->num_rows_cols(); 126 | num_entries_ = M->num_entries(); 127 | 128 | if(M->num_entries() == 0 || M->num_rows_cols() == 0) 129 | return; 130 | 131 | if(!change_sorting) 132 | row_sorted_ = M->isRowSorted(); 133 | else 134 | row_sorted_ = !M->isRowSorted(); 135 | 136 | // copy entries 137 | entries_ = new L3D::DataArray(num_entries_,1); 138 | start_indices_ = new L3D::DataArray(num_rows_cols_,1); 139 | if(!change_sorting) 140 | { 141 | // direct copy 142 | M->entries()->copyTo(entries_); 143 | M->start_indices()->copyTo(start_indices_); 144 | } 145 | else 146 | { 147 | // change sorting 148 | std::list entries; 149 | for(unsigned int i=0; ientries()->width(); ++i) 150 | { 151 | CLEdge e; 152 | e.i_ = M->entries()->dataCPU(i,0)[0].x; 153 | e.j_ = M->entries()->dataCPU(i,0)[0].y; 154 | e.w_ = M->entries()->dataCPU(i,0)[0].z; 155 | entries.push_back(e); 156 | } 157 | 158 | if(row_sorted_) 159 | entries.sort(L3D::sortCLEdgesByRow); 160 | else 161 | entries.sort(L3D::sortCLEdgesByCol); 162 | 163 | start_indices_->setValue(-1); 164 | std::list::iterator it = entries.begin(); 165 | unsigned int pos = 0; 166 | int current_rc = -1; 167 | for(; it!=entries.end(); ++it,++pos) 168 | { 169 | // store data 170 | CLEdge data = *it; 171 | entries_->dataCPU(pos,0)[0] = make_float4(data.i_,data.j_,data.w_,0.0f); 172 | 173 | // check for new row/column 174 | int rc; 175 | if(row_sorted_) 176 | rc = (*it).i_; 177 | else 178 | rc = (*it).j_; 179 | 180 | if(current_rc != rc) 181 | { 182 | start_indices_->dataCPU(rc,0)[0] = pos; 183 | current_rc = rc; 184 | } 185 | } 186 | } 187 | 188 | // copy to GPU 189 | entries_->upload(); 190 | start_indices_->upload(); 191 | } 192 | 193 | //------------------------------------------------------------------------------ 194 | SparseMatrix::~SparseMatrix() 195 | { 196 | // cleanup CPU 197 | if(entries_ != NULL) 198 | delete entries_; 199 | 200 | if(start_indices_ != NULL) 201 | delete start_indices_; 202 | } 203 | } 204 | -------------------------------------------------------------------------------- /sparsematrix.h: -------------------------------------------------------------------------------- 1 | #ifndef I3D_LINE3D_SPARSEMATRIX_H_ 2 | #define I3D_LINE3D_SPARSEMATRIX_H_ 3 | 4 | /* 5 | Line3D - Line-based Multi View Stereo 6 | Copyright (C) 2015 Manuel Hofer 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | // internal 23 | #include "clustering.h" 24 | #include "dataArray.h" 25 | 26 | /** 27 | * Line3D - Sparsematrix 28 | * ==================== 29 | * Sparse GPU matrix. 30 | * ==================== 31 | * Author: M.Hofer, 2015 32 | */ 33 | 34 | namespace L3D 35 | { 36 | // matching pair 37 | struct L3DMatchingPair 38 | { 39 | // src_image 40 | unsigned int segID1_; 41 | // tgt_image 42 | unsigned int camID2_; 43 | unsigned int segID2_; 44 | // depths 45 | float4 depths_; 46 | // confidence 47 | float confidence_; 48 | // defines if mp is still active 49 | bool active_; 50 | 51 | // serialization 52 | friend class boost::serialization::access; 53 | template 54 | void serialize(Archive & ar, const unsigned int version) 55 | { 56 | ar & boost::serialization::make_nvp("segID1_", segID1_); 57 | ar & boost::serialization::make_nvp("camID2_", camID2_); 58 | ar & boost::serialization::make_nvp("segID2_", segID2_); 59 | ar & boost::serialization::make_nvp("depths_x", depths_.x); 60 | ar & boost::serialization::make_nvp("depths_y", depths_.y); 61 | ar & boost::serialization::make_nvp("depths_z", depths_.z); 62 | ar & boost::serialization::make_nvp("depths_w", depths_.w); 63 | ar & boost::serialization::make_nvp("confidence_", confidence_); 64 | ar & boost::serialization::make_nvp("active_", active_); 65 | } 66 | }; 67 | 68 | static bool sortMatchingPairs(const L3DMatchingPair mp1, 69 | const L3DMatchingPair mp2) 70 | { 71 | if(mp1.segID1_ < mp2.segID1_) 72 | return true; 73 | else if(mp1.segID1_ == mp2.segID1_ && mp1.camID2_ < mp2.camID2_) 74 | return true; 75 | else if(mp1.segID1_ == mp2.segID1_ && mp1.camID2_ == mp2.camID2_ && mp1.segID2_ < mp2.segID2_) 76 | return true; 77 | else 78 | return false; 79 | } 80 | 81 | static bool sortMatchingPairsByConf(const L3DMatchingPair mp1, 82 | const L3DMatchingPair mp2) 83 | { 84 | return (mp1.confidence_ > mp2.confidence_); 85 | } 86 | 87 | // sort entries for sparse affinity matrix 88 | static bool sortAffEntriesByCol(const float4 a1, const float4 a2) 89 | { 90 | // affinity in z-Coordinate 91 | if(int(a1.y) < int(a2.y)) 92 | return true; 93 | else if(int(a1.y) == int(a2.y) && int(a1.x) < int(a2.x)) 94 | return true; 95 | else 96 | return false; 97 | } 98 | 99 | static bool sortAffEntriesByRow(const float4 a1, const float4 a2) 100 | { 101 | // affinity in z-Coordinate 102 | if(int(a1.x) < int(a2.x)) 103 | return true; 104 | else if(int(a1.x) == int(a2.x) && int(a1.y) < int(a2.y)) 105 | return true; 106 | else 107 | return false; 108 | } 109 | 110 | // segment with confidence (to best match) 111 | struct L3DSegmentInScope 112 | { 113 | unsigned int camID_; 114 | unsigned int segID_; 115 | float weight_; 116 | }; 117 | 118 | // best match plus scope 119 | struct L3DBestMatch 120 | { 121 | L3D::L3DMatchingPair ref_; 122 | std::list scope_; 123 | }; 124 | 125 | class SparseMatrix 126 | { 127 | public: 128 | SparseMatrix(std::list& entries, const unsigned int num_rows_cols, 129 | const float normalization_factor=1.0f, 130 | const bool sort_by_row=false, const bool already_sorted=false); 131 | SparseMatrix(std::list& entries, const unsigned int num_rows_cols, 132 | const float normalization_factor=1.0f, 133 | const bool sort_by_row=false, const bool already_sorted=false); 134 | SparseMatrix(SparseMatrix* M, const bool change_sorting=false); 135 | ~SparseMatrix(); 136 | 137 | // check element sorting 138 | bool isRowSorted(){ 139 | return row_sorted_; 140 | } 141 | bool isColSorted(){ 142 | return !row_sorted_; 143 | } 144 | 145 | // data access 146 | unsigned int num_rows_cols(){ 147 | return num_rows_cols_; 148 | } 149 | unsigned int num_entries(){ 150 | return num_entries_; 151 | } 152 | 153 | // CPU/GPU data 154 | L3D::DataArray* entries(){ 155 | return entries_; 156 | } 157 | L3D::DataArray* start_indices(){ 158 | return start_indices_; 159 | } 160 | 161 | // download entries to CPU 162 | void download(){ 163 | entries_->download(); 164 | } 165 | 166 | private: 167 | // CPU/GPU data 168 | L3D::DataArray* entries_; 169 | L3D::DataArray* start_indices_; 170 | 171 | bool row_sorted_; 172 | unsigned int num_rows_cols_; 173 | unsigned int num_entries_; 174 | }; 175 | } 176 | 177 | #endif //I3D_LINE3D_SPARSEMATRIX_H_ 178 | -------------------------------------------------------------------------------- /universe.h: -------------------------------------------------------------------------------- 1 | #ifndef I3D_LINE3D_UNIVERSE_H_ 2 | #define I3D_LINE3D_UNIVERSE_H_ 3 | 4 | /* 5 | * Disclaimer: 6 | * Re-implementation of the algorithm described in the paper 7 | * 8 | * Efficient Graph-based Image Segmentation, 9 | * P. Fezenszwalb, F. Huttenlocher, 10 | * International Journal of Computer Vision, 2004. 11 | * 12 | * and based on their official source code, which can be found at 13 | * from http://cs.brown.edu/~pff/segment/ 14 | * 15 | * Their code is put under the GNU GENERAL PUBLIC LICENSE, 16 | * and so is this version. 17 | */ 18 | 19 | /* 20 | Line3D - Line-based Multi View Stereo 21 | Copyright (C) 2015 Manuel Hofer 22 | 23 | This program is free software: you can redistribute it and/or modify 24 | it under the terms of the GNU General Public License as published by 25 | the Free Software Foundation, either version 3 of the License, or 26 | (at your option) any later version. 27 | 28 | This program is distributed in the hope that it will be useful, 29 | but WITHOUT ANY WARRANTY; without even the implied warranty of 30 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 31 | GNU General Public License for more details. 32 | 33 | You should have received a copy of the GNU General Public License 34 | along with this program. If not, see . 35 | */ 36 | 37 | /** 38 | * Universe (for clustering.h) 39 | * ==================== 40 | * Clustering/Segmentation Algorithm. 41 | * [Felzenswalb & Huttenlocher, IJCV 2004] 42 | * 43 | * This code is an adaption of their original source code, 44 | * to fit into our datastructures. 45 | * ==================== 46 | * Author: M.Hofer, 2015 47 | */ 48 | 49 | // element of cluster universe 50 | typedef struct { 51 | int rank_; 52 | int clusterID_; 53 | int size_; 54 | } CLUnivElement; 55 | 56 | namespace L3D 57 | { 58 | // class that holds a clustering result 59 | class CLUniverse 60 | { 61 | public: 62 | CLUniverse(int numNodes) 63 | { 64 | // init 65 | elements_ = new CLUnivElement[numNodes]; 66 | num_ = numNodes; 67 | for(int i = 0; i < numNodes; ++i) 68 | { 69 | elements_[i].rank_ = 0; 70 | elements_[i].size_ = 1; 71 | elements_[i].clusterID_ = i; 72 | } 73 | } 74 | 75 | ~CLUniverse() 76 | { 77 | delete [] elements_; 78 | } 79 | 80 | // find clusterID for given node 81 | int find(int nodeID) 82 | { 83 | int y = nodeID; 84 | while(y != elements_[y].clusterID_) 85 | y = elements_[y].clusterID_; 86 | 87 | elements_[nodeID].clusterID_ = y; 88 | return y; 89 | } 90 | 91 | // joins two nodes into one class/segment 92 | void join(int x, int y) 93 | { 94 | if(elements_[x].rank_ > elements_[y].rank_) 95 | { 96 | elements_[y].clusterID_ = x; 97 | elements_[x].size_ += elements_[y].size_; 98 | } 99 | else 100 | { 101 | elements_[x].clusterID_ = y; 102 | elements_[y].size_ += elements_[x].size_; 103 | if(elements_[x].rank_ == elements_[y].rank_) 104 | elements_[y].rank_++; 105 | } 106 | --num_; 107 | } 108 | 109 | float size(int x) const { return elements_[x].size_; } 110 | int numSets() const { return num_; } 111 | 112 | private: 113 | CLUnivElement* elements_; 114 | int num_; 115 | }; 116 | } 117 | 118 | #endif //I3D_LINE3D_UNIVERSE_H_ 119 | -------------------------------------------------------------------------------- /view.cc: -------------------------------------------------------------------------------- 1 | #include "view.h" 2 | 3 | namespace L3D 4 | { 5 | //------------------------------------------------------------------------------ 6 | L3DView::L3DView(const unsigned int id, L3D::L3DSegments* segments, 7 | const Eigen::Matrix3d K, const Eigen::Matrix3d R, 8 | const Eigen::Vector3d t, 9 | const unsigned int width, const unsigned int height, 10 | const float uncertainty_upper_px, 11 | const float uncertainty_lower_px, 12 | const std::string matchFilename, 13 | const std::string prefix) 14 | { 15 | // init 16 | K_ = K; 17 | R_ = R; 18 | t_ = t; 19 | 20 | principal_point_(0) = float(width)/2.0f; 21 | principal_point_(1) = float(height)/2.0f; 22 | principal_point_(2) = 1.0; 23 | 24 | Kinv_ = K_.inverse(); 25 | Rt_ = R_.transpose(); 26 | RtKinv_ = Rt_*Kinv_; 27 | C_ = Rt_ * (-1.0 * t_); 28 | center_ = make_float3(C_(0),C_(1),C_(2)); 29 | 30 | // projection matrix 31 | Eigen::MatrixXd R_plus_t(3,4); 32 | R_plus_t.block<3,3>(0,0) = R_; 33 | R_plus_t.block<3,1>(0,3) = t_; 34 | P_ = K_ * R_plus_t; 35 | 36 | id_ = id; 37 | width_ = width; 38 | height_ = height; 39 | 40 | segments_ = segments; 41 | 42 | uncertainty_upper_px_ = uncertainty_upper_px; 43 | uncertainty_lower_px_ = uncertainty_lower_px; 44 | median_depth_ = 1.0f; 45 | 46 | raw_matches_file_ = matchFilename+"_raw.bin"; 47 | final_matches_file_ = matchFilename+"_final.bin"; 48 | prefix_ = prefix; 49 | 50 | // remove raw matches (if they exist) 51 | boost::filesystem::wpath file(raw_matches_file_); 52 | if(boost::filesystem::exists(file)) 53 | { 54 | boost::filesystem::remove(file); 55 | } 56 | 57 | // remove final matches (if they exist) 58 | file = boost::filesystem::wpath(final_matches_file_); 59 | if(boost::filesystem::exists(file)) 60 | { 61 | boost::filesystem::remove(file); 62 | } 63 | 64 | // compute linear spatial uncertainty parameters 65 | defineSpatialUncertainty(); 66 | } 67 | 68 | //------------------------------------------------------------------------------ 69 | L3DView::~L3DView() 70 | { 71 | if(segments_ != NULL) 72 | delete segments_; 73 | 74 | // remove raw matches 75 | boost::filesystem::wpath file(raw_matches_file_); 76 | if(boost::filesystem::exists(file)) 77 | { 78 | boost::filesystem::remove(file); 79 | } 80 | 81 | // remove final matches 82 | file = boost::filesystem::wpath(final_matches_file_); 83 | if(boost::filesystem::exists(file)) 84 | { 85 | boost::filesystem::remove(file); 86 | } 87 | } 88 | 89 | //------------------------------------------------------------------------------ 90 | void L3DView::defineSpatialUncertainty() 91 | { 92 | // compute plane parallel to image plane 93 | Eigen::Vector3d n = RtKinv_*principal_point_; 94 | n.normalize(); 95 | Eigen::Vector3d P = C_ + n; // depth = 1 96 | 97 | // shift principal point (x direction) 98 | Eigen::Vector3d pp_shifted1(principal_point_.x()+uncertainty_upper_px_, 99 | principal_point_.y(),1.0); 100 | Eigen::Vector3d pp_shifted2(principal_point_.x()+uncertainty_lower_px_, 101 | principal_point_.y(),1.0); 102 | 103 | // compute ray through shifted point 104 | Eigen::Vector3d d1 = RtKinv_*pp_shifted1; 105 | d1.normalize(); 106 | Eigen::Vector3d d2 = RtKinv_*pp_shifted2; 107 | d2.normalize(); 108 | 109 | // intersect with plane 110 | double t1 = (P.dot(n) - n.dot(C_)) / (n.dot(d1)); 111 | Eigen::Vector3d Q1 = C_ + t1 * d1; 112 | double t2 = (P.dot(n) - n.dot(C_)) / (n.dot(d2)); 113 | Eigen::Vector3d Q2 = C_ + t2 * d2; 114 | 115 | // compute distance 116 | double dist1 = (P-Q1).norm(); 117 | double dist2 = (P-Q2).norm(); 118 | 119 | k_upper_ = dist1; 120 | k_lower_ = dist2; 121 | } 122 | 123 | //------------------------------------------------------------------------------ 124 | float L3DView::specificSpatialUncertaintyK(const float dist_px) 125 | { 126 | // compute plane parallel to image plane 127 | Eigen::Vector3d n = RtKinv_*principal_point_; 128 | n.normalize(); 129 | Eigen::Vector3d P = C_ + n; // depth = 1 130 | 131 | // shift principal point (x direction) 132 | Eigen::Vector3d pp_shifted(principal_point_.x()+dist_px, 133 | principal_point_.y(),1.0); 134 | 135 | // compute ray through shifted point 136 | Eigen::Vector3d d = RtKinv_*pp_shifted; 137 | d.normalize(); 138 | 139 | // intersect with plane 140 | double t = (P.dot(n) - n.dot(C_)) / (n.dot(d)); 141 | Eigen::Vector3d Q = C_ + t * d; 142 | 143 | // compute distance 144 | double dist = (P-Q).norm(); 145 | 146 | return dist; 147 | } 148 | 149 | //------------------------------------------------------------------------------ 150 | void L3DView::loadExistingMatches(std::list& matches) 151 | { 152 | boost::filesystem::wpath file(raw_matches_file_); 153 | if(boost::filesystem::exists(file)) 154 | { 155 | std::list M; 156 | L3D::serializeFromFile(raw_matches_file_,M); 157 | matches.splice(matches.end(), M); 158 | } 159 | } 160 | 161 | //------------------------------------------------------------------------------ 162 | void L3DView::addMatches(std::list& matches, bool remove_old, 163 | bool only_best) 164 | { 165 | if(only_best) 166 | { 167 | // only save the best match for each segment 168 | // (only makes sense when finalizing!) 169 | std::map > best; 170 | std::list::iterator it = matches.begin(); 171 | for(; it!=matches.end(); ++it) 172 | { 173 | best[(*it).segID1_].push_back(*it); 174 | } 175 | 176 | matches.clear(); 177 | std::map >::iterator it2 = best.begin(); 178 | for(; it2!=best.end(); ++it2) 179 | { 180 | it2->second.sort(L3D::sortMatchingPairsByConf); 181 | matches.push_back(it2->second.front()); 182 | } 183 | } 184 | 185 | boost::filesystem::wpath file(raw_matches_file_); 186 | if(boost::filesystem::exists(file) && !remove_old) 187 | { 188 | std::list M; 189 | L3D::serializeFromFile(raw_matches_file_,M); 190 | M.insert(M.end(),matches.begin(),matches.end()); 191 | L3D::serializeToFile(raw_matches_file_,M); 192 | } 193 | else 194 | { 195 | L3D::serializeToFile(raw_matches_file_,matches); 196 | } 197 | } 198 | 199 | //------------------------------------------------------------------------------ 200 | void L3DView::loadAndLocalizeExistingMatches(std::list& matches, 201 | std::map& global2local) 202 | { 203 | boost::filesystem::wpath file(raw_matches_file_); 204 | if(boost::filesystem::exists(file)) 205 | { 206 | std::list M; 207 | L3D::serializeFromFile(raw_matches_file_,M); 208 | 209 | std::list::iterator it = M.begin(); 210 | for(; it!=M.end(); ++it) 211 | { 212 | L3D::L3DMatchingPair mp = *it; 213 | if(global2local.find(mp.camID2_) != global2local.end()) 214 | { 215 | mp.camID2_ = global2local[mp.camID2_]; 216 | matches.push_back(mp); 217 | } 218 | else 219 | { 220 | std::cerr << prefix_ << "matches outside the local neighborhood in set!" << std::endl; 221 | } 222 | } 223 | } 224 | } 225 | 226 | //------------------------------------------------------------------------------ 227 | void L3DView::transform(Eigen::Matrix4d& Qinv, double scale) 228 | { 229 | // update translation 230 | t_ *= scale; 231 | 232 | // update orientation 233 | Eigen::MatrixXd Rt(3,4); 234 | Rt.block<3,3>(0,0) = R_; 235 | Rt.block<3,1>(0,3) = t_; 236 | 237 | Rt *= Qinv; 238 | 239 | R_ = Rt.block<3,3>(0,0); 240 | t_ = Rt.block<3,1>(0,3); 241 | 242 | // update derived values 243 | Rt_ = R_.transpose(); 244 | P_ = K_ * Rt; 245 | 246 | RtKinv_ = Rt_*Kinv_; 247 | /* 248 | for(int r=0; r<3; ++r) 249 | { 250 | for(int c=0; c<3; ++c) 251 | { 252 | RtKinv_CPU_->data(c,r)[0] = RtKinv_(r,c); 253 | } 254 | } 255 | */ 256 | C_ = Rt_ * (-1.0 * t_); 257 | center_ = make_float3(C_(0),C_(1),C_(2)); 258 | 259 | // update spatial uncertainty 260 | defineSpatialUncertainty(); 261 | } 262 | 263 | //------------------------------------------------------------------------------ 264 | L3D::DataArray* L3DView::seg_coords() 265 | { 266 | if(segments_ != NULL) 267 | { 268 | // segments available 269 | return segments_->segments(); 270 | } 271 | return NULL; 272 | } 273 | 274 | //------------------------------------------------------------------------------ 275 | float4 L3DView::getSegmentCoords(const unsigned int id) 276 | { 277 | if(segments_ != NULL && id < segments_->segments()->height()) 278 | { 279 | return make_float4(segments_->segments()->dataCPU(0,id)[0], 280 | segments_->segments()->dataCPU(1,id)[0], 281 | segments_->segments()->dataCPU(2,id)[0], 282 | segments_->segments()->dataCPU(3,id)[0]); 283 | } 284 | else 285 | { 286 | return make_float4(0,0,0,0); 287 | } 288 | } 289 | 290 | //------------------------------------------------------------------------------ 291 | std::map >* L3DView::seg_collinearities() 292 | { 293 | if(segments_ != NULL) 294 | { 295 | // segments available 296 | return segments_->collinearities(); 297 | } 298 | return NULL; 299 | } 300 | 301 | //------------------------------------------------------------------------------ 302 | L3D::L3DSegment3D L3DView::unprojectSegment(const unsigned int id, const float depth_p1, 303 | const float depth_p2) 304 | { 305 | L3D::L3DSegment3D seg3D; 306 | if(id > segments_->segments()->height()) 307 | { 308 | std::cerr << prefix_ << "lineID out of range!" << std::endl; 309 | return seg3D; 310 | } 311 | 312 | // get 2D segment data 313 | Eigen::Vector3d p1(segments_->segments()->dataCPU(0,id)[0], 314 | segments_->segments()->dataCPU(1,id)[0], 315 | 1.0); 316 | Eigen::Vector3d p2(segments_->segments()->dataCPU(2,id)[0], 317 | segments_->segments()->dataCPU(3,id)[0], 318 | 1.0); 319 | 320 | // get rays 321 | Eigen::Vector3d ray1 = RtKinv_*p1; 322 | ray1.normalize(); 323 | Eigen::Vector3d ray2 = RtKinv_*p2; 324 | ray2.normalize(); 325 | 326 | seg3D.P1_ = C_ + ray1*depth_p1; 327 | seg3D.P2_ = C_ + ray2*depth_p2; 328 | 329 | // direction (normalized) 330 | seg3D.dir_ = seg3D.P2_-seg3D.P1_; 331 | seg3D.dir_.normalize(); 332 | 333 | // cam ID 334 | seg3D.camID_ = id_; 335 | seg3D.segID_ = id; 336 | 337 | // depth 338 | seg3D.depth_p1_ = depth_p1; 339 | seg3D.depth_p2_ = depth_p2; 340 | 341 | return seg3D; 342 | } 343 | 344 | //------------------------------------------------------------------------------ 345 | Eigen::Vector3d L3DView::getNormalizedRay(const Eigen::Vector3d p) 346 | { 347 | Eigen::Vector3d ray = RtKinv_*p; 348 | ray.normalize(); 349 | return ray; 350 | } 351 | 352 | //------------------------------------------------------------------------------ 353 | float L3DView::get_lower_uncertainty(const float depth) 354 | { 355 | if(depth < median_depth_) 356 | return k_lower_*depth; 357 | else 358 | return k_lower_*median_depth_; 359 | } 360 | 361 | //------------------------------------------------------------------------------ 362 | float L3DView::get_upper_uncertainty(const float depth) 363 | { 364 | if(depth < median_depth_) 365 | return k_upper_*depth; 366 | else 367 | return k_upper_*median_depth_; 368 | } 369 | 370 | //------------------------------------------------------------------------------ 371 | float L3DView::get_uncertainty_sigma_squared(const float depth) 372 | { 373 | float d1 = get_lower_uncertainty(depth); 374 | float d2 = get_upper_uncertainty(depth); 375 | 376 | return -(d2-d1)*(d2-d1)/(2.0f*logf(0.01f)); 377 | } 378 | 379 | //------------------------------------------------------------------------------ 380 | float L3DView::projective_similarity(const L3D::L3DSegment3D seg3D, const unsigned int seg2D_id, 381 | const float sigma) 382 | { 383 | if(seg2D_id >= segments_->segments()->height()) 384 | return 0.0f; 385 | 386 | // project to image 387 | Eigen::Vector3d q1 = P_*Eigen::Vector4d(seg3D.P1_.x(),seg3D.P1_.y(),seg3D.P1_.z(),1.0); 388 | Eigen::Vector3d q2 = P_*Eigen::Vector4d(seg3D.P2_.x(),seg3D.P2_.y(),seg3D.P2_.z(),1.0); 389 | 390 | if(fabs(q1.z()) < L3D_EPS || fabs(q2.z()) < L3D_EPS) 391 | return 0.0f; 392 | 393 | q1 /= q1.z(); 394 | q2 /= q2.z(); 395 | 396 | // lines 397 | Eigen::Vector3d p1(segments_->segments()->dataCPU(0,seg2D_id)[0], 398 | segments_->segments()->dataCPU(1,seg2D_id)[0],1.0); 399 | Eigen::Vector3d p2(segments_->segments()->dataCPU(2,seg2D_id)[0], 400 | segments_->segments()->dataCPU(3,seg2D_id)[0],1.0); 401 | Eigen::Vector3d l1 = p1.cross(p2); 402 | l1.normalize(); 403 | Eigen::Vector3d l2 = q1.cross(q2); 404 | l2.normalize(); 405 | 406 | // compute distances 407 | float d1 = fabs((l1.x()*q1.x()+l1.y()*q1.y()+l1.z())/sqrtf(l1.x()*l1.x()+l1.y()*l1.y())); 408 | float d2 = fabs((l1.x()*q2.x()+l1.y()*q2.y()+l1.z())/sqrtf(l1.x()*l1.x()+l1.y()*l1.y())); 409 | float d3 = fabs((l2.x()*p1.x()+l2.y()*p1.y()+l2.z())/sqrtf(l2.x()*l2.x()+l2.y()*l2.y())); 410 | float d4 = fabs((l2.x()*p2.x()+l2.y()*p2.y()+l2.z())/sqrtf(l2.x()*l2.x()+l2.y()*l2.y())); 411 | 412 | float d = fmax(fmax(d1,d2),fmax(d3,d4)); 413 | 414 | return expf(-d*d/(2.0f*sigma*sigma)); 415 | } 416 | 417 | //------------------------------------------------------------------------------ 418 | void L3DView::drawLines(cv::Mat& I, std::list highlight) 419 | { 420 | I = cv::Mat::zeros(height_,width_,CV_8UC3); 421 | 422 | L3D::DataArray* segs = segments_->segments(); 423 | for(unsigned int i=0; iheight(); ++i) 424 | { 425 | cv::Point p1(segs->dataCPU(0,i)[0],segs->dataCPU(1,i)[0]); 426 | cv::Point p2(segs->dataCPU(2,i)[0],segs->dataCPU(3,i)[0]); 427 | 428 | cv::line(I,p1,p2,cv::Scalar(255,255,255),4); 429 | } 430 | 431 | std::list::iterator it = highlight.begin(); 432 | for(; it!=highlight.end(); ++it) 433 | { 434 | unsigned int id = *it; 435 | if(id < segs->height()) 436 | { 437 | cv::Point p1(segs->dataCPU(0,id)[0],segs->dataCPU(1,id)[0]); 438 | cv::Point p2(segs->dataCPU(2,id)[0],segs->dataCPU(3,id)[0]); 439 | 440 | cv::line(I,p1,p2,cv::Scalar(0,0,255),4); 441 | } 442 | } 443 | } 444 | 445 | //------------------------------------------------------------------------------ 446 | float L3DView::baseline(L3D::L3DView* v) 447 | { 448 | return (C_ - v->C()).norm(); 449 | } 450 | } 451 | -------------------------------------------------------------------------------- /view.h: -------------------------------------------------------------------------------- 1 | #ifndef I3D_LINE3D_VIEW_H_ 2 | #define I3D_LINE3D_VIEW_H_ 3 | 4 | /* 5 | Line3D - Line-based Multi View Stereo 6 | Copyright (C) 2015 Manuel Hofer 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | // external 23 | #include "eigen3/Eigen/Eigen" 24 | #include "boost/filesystem.hpp" 25 | #include "opencv/cv.h" 26 | 27 | // internal 28 | #include "segments.h" 29 | 30 | /** 31 | * Line3D - View 32 | * ==================== 33 | * Class that holds one reference image. 34 | * ==================== 35 | * Author: M.Hofer, 2015 36 | */ 37 | 38 | namespace L3D 39 | { 40 | class L3DView 41 | { 42 | public: 43 | L3DView(const unsigned int id, L3D::L3DSegments* segments, 44 | const Eigen::Matrix3d K, const Eigen::Matrix3d R, 45 | const Eigen::Vector3d t, 46 | const unsigned int width, const unsigned int height, 47 | const float uncertainty_upper_px, 48 | const float uncertainty_lower_px, 49 | const std::string matchFilename, 50 | const std::string prefix); 51 | ~L3DView(); 52 | 53 | // transform camera 54 | void transform(Eigen::Matrix4d& Qinv, double scale); 55 | 56 | // load existing pairwise matches 57 | void loadExistingMatches(std::list& matches); 58 | void loadAndLocalizeExistingMatches(std::list& matches, 59 | std::map& global2local); 60 | void addMatches(std::list& matches, bool remove_old=false, 61 | bool only_best=false); 62 | 63 | // segment data access 64 | L3D::DataArray* seg_coords(); 65 | std::map >* seg_collinearities(); 66 | float4 getSegmentCoords(const unsigned int id); 67 | 68 | // camera data access 69 | Eigen::Matrix3d K(){return K_;} 70 | Eigen::Matrix3d Kinv(){return Kinv_;} 71 | Eigen::Matrix3d R(){return R_;} 72 | Eigen::Matrix3d Rt(){return Rt_;} 73 | Eigen::Matrix3d RtKinv(){return RtKinv_;} 74 | Eigen::Vector3d t(){return t_;} 75 | Eigen::Vector3d C(){return C_;} 76 | Eigen::MatrixXd P(){return P_;} 77 | Eigen::Vector3d principalPoint(){return principal_point_;} 78 | 79 | unsigned int width(){return width_;} 80 | unsigned int height(){return height_;} 81 | unsigned int id(){return id_;} 82 | 83 | // uncertainty estimator 84 | float uncertainty_k_upper(){return k_upper_;} 85 | float uncertainty_k_lower(){return k_lower_;} 86 | float median_depth(){return median_depth_;} 87 | 88 | void setMedianDepth(float value){ 89 | median_depth_ = value; 90 | } 91 | 92 | // get uncertainty based on depth 93 | float get_lower_uncertainty(const float depth); 94 | float get_upper_uncertainty(const float depth); 95 | float get_uncertainty_sigma_squared(const float depth); 96 | 97 | // projective similarity 98 | float projective_similarity(const L3D::L3DSegment3D seg3D, const unsigned int seg2D_id, 99 | const float sigma); 100 | 101 | // unproject point with given depth 102 | L3D::L3DSegment3D unprojectSegment(const unsigned int id, const float depth_p1, 103 | const float depth_p2); 104 | 105 | // get the normalized ray through a 2D point and the camera center 106 | Eigen::Vector3d getNormalizedRay(const Eigen::Vector3d p); 107 | 108 | // draw lines into image 109 | void drawLines(cv::Mat& I, std::list highlight); 110 | 111 | // baseline between views 112 | float baseline(L3D::L3DView* v); 113 | 114 | // specific spatial uncertainty slope (for scoring) 115 | float specificSpatialUncertaintyK(const float dist_px); 116 | 117 | private: 118 | // define spatial uncertainty 119 | void defineSpatialUncertainty(); 120 | 121 | // camera data 122 | Eigen::Matrix3d K_; 123 | Eigen::Matrix3d Kinv_; 124 | Eigen::Matrix3d R_; 125 | Eigen::Matrix3d Rt_; 126 | Eigen::Matrix3d RtKinv_; 127 | Eigen::Vector3d t_; 128 | Eigen::Vector3d C_; 129 | Eigen::MatrixXd P_; 130 | Eigen::Vector3d principal_point_; 131 | 132 | float3 center_; 133 | 134 | // image data 135 | unsigned int id_; 136 | unsigned int width_; 137 | unsigned int height_; 138 | 139 | // matching data 140 | float uncertainty_upper_px_; 141 | float uncertainty_lower_px_; 142 | float k_upper_; 143 | float k_lower_; 144 | float median_depth_; 145 | 146 | // segment data 147 | L3D::L3DSegments* segments_; 148 | 149 | // system 150 | std::string raw_matches_file_; 151 | std::string final_matches_file_; 152 | std::string prefix_; 153 | }; 154 | } 155 | 156 | #endif //I3D_LINE3D_VIEW_H_ 157 | --------------------------------------------------------------------------------