├── .gitignore ├── ParforProgMon ├── ParforProgMon.m ├── java │ ├── ParforProgressMonitor$1.class │ ├── ParforProgressMonitor$ProgServer$1.class │ ├── ParforProgressMonitor$ProgServer.class │ ├── ParforProgressMonitor$ProgThing.class │ ├── ParforProgressMonitor$ProgWorker.class │ ├── ParforProgressMonitor.class │ └── ParforProgressMonitor.java └── license.txt ├── README.md ├── SLICO-Superpixels ├── CMakeLists.txt ├── USAGE_SLIC.txt ├── precompiled_bin │ ├── SLICO.exe │ ├── opencv_core249.dll │ └── opencv_highgui249.dll └── src │ ├── SLIC.cpp │ ├── SLIC.h │ └── main.cpp └── matlab ├── code ├── axis_angle_to_matrix.m ├── compute_RTS_3_points_3d.m ├── compute_RTS_3_points_3d_same_scale.m ├── compute_RTS_N_points_3d.m ├── compute_RTS_N_points_3d_same_scale.m ├── compute_baseline_angle_between_cameras.m ├── compute_baseline_angle_between_cameras2.m ├── compute_baseline_angles_between_camera_pairs.m ├── compute_baseline_angles_between_camera_pairs2.m ├── compute_camera_observation_segments2.m ├── compute_camera_pair_segments2.m ├── compute_camera_spanning_tree.m ├── compute_conflicting_indices2.m ├── compute_conflicting_indices2_merging.m ├── compute_connected_camera_matrix.m ├── compute_connected_camera_matrix2.m ├── compute_distance_threshold_3d.m ├── compute_edge_conflict2.m ├── compute_edge_conflict2_merging.m ├── compute_group_sizes.m ├── compute_image_segmentations.m ├── compute_similarity_inliers.m ├── compute_spanning_tree_conflict2.m ├── compute_split_group_assignments.m ├── create_camera_observations.m ├── create_point_observations.m ├── create_thumbnails.m ├── create_visibility_matrix.m ├── edge_label_baseline_angle_class.m ├── edge_label_conflict_class.m ├── enforce_n_view_points.m ├── enforce_n_view_points_no_inliers.m ├── find_disconnected_inlier_point_indices.m ├── find_disconnected_inliers.m ├── find_edge_index.m ├── find_nearby_indices.cpp ├── find_split_cameras.m ├── generate_split_camera_tasks.m ├── generate_split_camera_tasks_helper.m ├── generate_split_camera_tasks_single_edge.m ├── get_num_edges_in_tree.m ├── identify_common_points_between_groups.m ├── init_matlabpool.m ├── normalize_group_assignments.m ├── plot_3_merged_models.m ├── plot_merged_model_inliers.m ├── quaternion_to_matrix.m ├── ransac.m ├── ransac_3d_similarity.m ├── read_all_inlier_matches.m ├── read_inlier_matches.m ├── read_nvm_and_image_dimensions.m ├── split_camera_tree.m ├── transform_camera_group.m ├── trim_filename.m ├── visualize_camera_tree.m └── write_merged_nvm.m ├── main.m ├── main_load_data.m ├── main_process_merging_result.m ├── main_run.m ├── main_run_merging2.m ├── main_run_splitting2.m ├── main_settings.m └── precompiled_mex └── find_nearby_indices.mexw64 /.gitignore: -------------------------------------------------------------------------------- 1 | # MATLAB temporary files. 2 | *.asv 3 | 4 | # Generated figures. 5 | matlab/figures/ 6 | -------------------------------------------------------------------------------- /ParforProgMon/ParforProgMon.m: -------------------------------------------------------------------------------- 1 | % Copyright 2009 The MathWorks, Inc. 2 | 3 | classdef ParforProgMon < handle 4 | 5 | properties ( GetAccess = private, SetAccess = private ) 6 | Port 7 | HostName 8 | end 9 | 10 | properties (Transient, GetAccess = private, SetAccess = private) 11 | JavaBit 12 | end 13 | 14 | methods ( Static ) 15 | function o = loadobj( X ) 16 | % Once we've been loaded, we need to reconstruct ourselves correctly as a 17 | % worker-side object. 18 | o = ParforProgMon( {X.HostName, X.Port} ); 19 | end 20 | end 21 | 22 | methods 23 | function o = ParforProgMon( s, N, progressStepSize, width, height ) 24 | % ParforProgMon Build a Parfor Progress Monitor 25 | % Use the syntax: ParforProgMon( 'Window Title', N, progressStepSize, width, height ) 26 | % where N is the number of iterations in the PARFOR loop 27 | % progressStepSize indicates after how many iterations progress is shown 28 | % width indicates the width of the progress window 29 | % height indicates the width of the progress window 30 | 31 | if nargin == 1 && iscell( s ) 32 | % "Private" constructor used on the workers 33 | o.JavaBit = ParforProgressMonitor.createWorker( s{1}, s{2} ); 34 | o.Port = []; 35 | elseif nargin == 5 36 | % Normal construction 37 | o.JavaBit = ParforProgressMonitor.createServer( s, N, progressStepSize, width, height ); 38 | o.Port = double( o.JavaBit.getPort() ); 39 | % Get the client host name from pctconfig 40 | cfg = pctconfig; 41 | o.HostName = cfg.hostname; 42 | else 43 | error( 'Public constructor is: ParforProgressMonitor( ''Text'', N, progressStepSize, width, height )' ); 44 | end 45 | end 46 | 47 | function X = saveobj( o ) 48 | % Only keep the Port and HostName 49 | X.Port = o.Port; 50 | X.HostName = o.HostName; 51 | end 52 | 53 | function increment( o ) 54 | % Update the UI 55 | o.JavaBit.increment(); 56 | end 57 | 58 | function delete( o ) 59 | % Close the UI 60 | o.JavaBit.done(); 61 | end 62 | end 63 | end 64 | -------------------------------------------------------------------------------- /ParforProgMon/java/ParforProgressMonitor$1.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jheinly/sfm_duplicate_structure_correction/1e4376729b2c2e690181ff6ba6acb4dc644b3640/ParforProgMon/java/ParforProgressMonitor$1.class -------------------------------------------------------------------------------- /ParforProgMon/java/ParforProgressMonitor$ProgServer$1.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jheinly/sfm_duplicate_structure_correction/1e4376729b2c2e690181ff6ba6acb4dc644b3640/ParforProgMon/java/ParforProgressMonitor$ProgServer$1.class -------------------------------------------------------------------------------- /ParforProgMon/java/ParforProgressMonitor$ProgServer.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jheinly/sfm_duplicate_structure_correction/1e4376729b2c2e690181ff6ba6acb4dc644b3640/ParforProgMon/java/ParforProgressMonitor$ProgServer.class -------------------------------------------------------------------------------- /ParforProgMon/java/ParforProgressMonitor$ProgThing.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jheinly/sfm_duplicate_structure_correction/1e4376729b2c2e690181ff6ba6acb4dc644b3640/ParforProgMon/java/ParforProgressMonitor$ProgThing.class -------------------------------------------------------------------------------- /ParforProgMon/java/ParforProgressMonitor$ProgWorker.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jheinly/sfm_duplicate_structure_correction/1e4376729b2c2e690181ff6ba6acb4dc644b3640/ParforProgMon/java/ParforProgressMonitor$ProgWorker.class -------------------------------------------------------------------------------- /ParforProgMon/java/ParforProgressMonitor.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jheinly/sfm_duplicate_structure_correction/1e4376729b2c2e690181ff6ba6acb4dc644b3640/ParforProgMon/java/ParforProgressMonitor.class -------------------------------------------------------------------------------- /ParforProgMon/java/ParforProgressMonitor.java: -------------------------------------------------------------------------------- 1 | import javax.swing.*; 2 | import java.io.*; 3 | import java.net.*; 4 | import java.util.concurrent.atomic.AtomicBoolean; 5 | 6 | // Copyright 2009 The MathWorks, Inc. 7 | 8 | public class ParforProgressMonitor { 9 | 10 | /** 11 | * Create a "server" progress monitor - this runs on the desktop client and 12 | * pops up the progress monitor UI. 13 | */ 14 | public static ProgServer createServer( String s, int N, int progressStepSize, int width, int height ) 15 | throws IOException { 16 | ProgServer ret = new ProgServer( s, N, progressStepSize, width, height ); 17 | ret.start(); 18 | return ret; 19 | } 20 | 21 | /** 22 | * Create a "worker" progress monitor - runs on the remote lab and sends updates 23 | */ 24 | public static ProgWorker createWorker( String host, int port ) 25 | throws IOException { 26 | return new ProgWorker( host, port ); 27 | } 28 | 29 | /** 30 | * Common interface exposed by both objects 31 | */ 32 | public interface ProgThing { 33 | public void increment(); 34 | public void done(); 35 | } 36 | 37 | /** 38 | * The worker-side object. Simply connects to the server to indicate that a 39 | * quantum of progress has been made. This is a very basic implementation - 40 | * a more sophisticated implementation would use a persistent connection, 41 | * and a SocketChannel on the client with a thread doing a select loop and 42 | * accepting connections etc. 43 | */ 44 | private static class ProgWorker implements ProgThing { 45 | private int fPort; 46 | private String fHost; 47 | private ProgWorker( String host, int port ) { 48 | fHost = host; 49 | fPort = port; 50 | } 51 | 52 | /** 53 | * Connect and disconnect immediately to indicate progress 54 | */ 55 | public void increment() { 56 | try { 57 | Socket s = new Socket( fHost, fPort ); 58 | s.close(); 59 | } catch( Exception e ) { 60 | e.printStackTrace(); 61 | } 62 | } 63 | 64 | /** 65 | * Nothing for us to do here 66 | */ 67 | public void done() { 68 | } 69 | } 70 | 71 | /** 72 | * The client-side object which pops up a window with a 73 | * JProgressBar. Accepts connections from the workers, and then disconnects 74 | * them immediately. Beware, the connection backlog of the ServerSocket 75 | * might be insufficient. 76 | */ 77 | private static class ProgServer implements Runnable, ProgThing { 78 | private JFrame fFrame; 79 | private JProgressBar fBar; 80 | private ServerSocket fSocket; 81 | private int fValue, fN, fStep; 82 | private String title; 83 | private Thread fThread; 84 | private AtomicBoolean fKeepGoing; 85 | 86 | private ProgServer( String s, int N, int progressStepSize, int width, int height ) throws IOException { 87 | // The UI 88 | fFrame = new JFrame( s ); 89 | fBar = new JProgressBar( 0, N ); 90 | fFrame.getContentPane().add( fBar ); 91 | fFrame.pack(); 92 | fFrame.setSize(width,height); 93 | fFrame.setLocationRelativeTo( null ); 94 | fFrame.setVisible( true ); 95 | 96 | // How far we are through - requires synchronized access 97 | fValue = 0; 98 | fN = N; 99 | fStep = progressStepSize; 100 | title = s; 101 | 102 | // Get an anonymous port 103 | fSocket = new ServerSocket( 0 ); 104 | // Set SO_TIMEOUT so that we don't block forever 105 | fSocket.setSoTimeout( 100 ); 106 | 107 | // Our background thread 108 | fThread = new Thread( this ); 109 | fThread.setDaemon( true ); 110 | 111 | // Used to indicate to fThread when it's time to go 112 | fKeepGoing = new AtomicBoolean( true ); 113 | } 114 | 115 | /** 116 | * Don't start the Thread in the constructor 117 | */ 118 | public void start() { fThread.start(); } 119 | 120 | /** 121 | * Loop over accepting connections and updating 122 | */ 123 | public void run() { 124 | while( fKeepGoing.get() ) { 125 | try { 126 | acceptAndIncrement(); 127 | } catch( Exception e ) { 128 | if( fKeepGoing.get() ) { 129 | e.printStackTrace(); 130 | } 131 | } 132 | } 133 | } 134 | 135 | /** 136 | * If there's a connection - accept and then disconnect; increment our count. 137 | */ 138 | private void acceptAndIncrement() throws IOException { 139 | Socket worker; 140 | try { 141 | worker = fSocket.accept(); 142 | } catch( SocketTimeoutException timeout ) { 143 | // don't care about timeouts 144 | return; 145 | } 146 | worker.close(); 147 | increment(); 148 | } 149 | 150 | 151 | /** 152 | * On the EDT, update the progress bar 153 | */ 154 | private void updateBar( final int newVal ) { 155 | SwingUtilities.invokeLater( new Runnable() { 156 | public void run() { 157 | fBar.setValue( fStep*newVal ); 158 | double percentage = 100.0*fStep*newVal/fN; 159 | fFrame.setTitle(title + (int)percentage + "% completed."); 160 | if ( newVal == fBar.getMaximum() ) { 161 | done(); 162 | } 163 | } 164 | } ); 165 | } 166 | 167 | /** 168 | * M-code needs to know which port we got 169 | */ 170 | public int getPort() { 171 | return ((InetSocketAddress)fSocket.getLocalSocketAddress()).getPort(); 172 | } 173 | 174 | /** 175 | * Provide public access to this for pool-close PARFORs 176 | */ 177 | public synchronized void increment() { 178 | fValue++; 179 | updateBar( fValue ); 180 | } 181 | 182 | /** 183 | * Shut it all down 184 | */ 185 | public void done() { 186 | fKeepGoing.set( false ); 187 | try { 188 | fSocket.close(); 189 | } catch( Exception e ) { 190 | e.printStackTrace(); 191 | } 192 | fFrame.dispose(); 193 | } 194 | } 195 | 196 | /** This class isn't useful - use the static methods */ 197 | private ParforProgressMonitor() {} 198 | } -------------------------------------------------------------------------------- /ParforProgMon/license.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011, Willem-Jan de Goeij 2 | Copyright (c) 2009, The MathWorks, Inc. 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are 7 | met: 8 | 9 | * Redistributions of source code must retain the above copyright 10 | notice, this list of conditions and the following disclaimer. 11 | * Redistributions in binary form must reproduce the above copyright 12 | notice, this list of conditions and the following disclaimer in 13 | the documentation and/or other materials provided with the distribution 14 | * Neither the name of the The MathWorks, Inc. nor the names 15 | of its contributors may be used to endorse or promote products derived 16 | from this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | sfm_duplicate_structure_correction 2 | ================================== 3 | 4 | This is the code that corresponds to the paper: 5 | J. Heinly, E. Dunn, and J.M. Frahm, "Correcting for Duplicate Scene Structure in Sparse 3D Reconstruction", ECCV 2014. 6 | 7 | Website: 8 | http://jaredheinly.com/duplicate_structure.html 9 | 10 | Setup 11 | ----- 12 | Before using this code, several things will need to be done: 13 | 14 | 1. Compile the SLICO Superpixels executable. In order to do this, run CMake 3.0 (http://www.cmake.org/download/) on the included SLICO-Superpixels/ folder. Then, run the resulting build scripts to generate an executable. For ease of use, a precompiled version of the Windows executable is available in SLICO-Superpixels/precompiled_bin/. 15 | 16 | 2. Make sure that your MATLAB instance is properly set up to generate MEX files. If you are unsure, execute the "mex -setup" command within MATLAB, and follow the instructions to choose your default C/C++ compiler. The main MATLAB script (main.m) will automatically attempt to compile the necessary MEX file, but if this fails for some reason, a precompiled version of the file is available in matlab/precompiled_mex/. 17 | 18 | 3. If you want to visualize the camera spanning tree, download the Graphviz package (http://www.graphviz.org/Download..php). 19 | 20 | Datasets 21 | -------- 22 | Links to datasets available for download are provided at: 23 | http://jaredheinly.com/duplicate_structure.html 24 | 25 | Execution 26 | --------- 27 | In order to execute the code, point MATLAB to the included matlab/ folder, and follow the steps below: 28 | 29 | 1. Open main_settings.m and modify its values. 30 | - Change the paths of the SLICO executable, Graphviz executable, and dataset folder to reflect the paths on your system. 31 | - Change the name of the dataset you want to execute by modifying the model_name variable. Valid options for dataset names can be found in main_load_data.m. 32 | - Enable/disable spanning tree visualization by setting the spanning tree flags to true/false. 33 | - This file also contains method parameters which can be tuned, but these can be left at their default values as they have proved to be robust. 34 | 35 | 2. Execute main.m. 36 | 37 | 3. If spanning tree visualization was enabled, the images will be saved in the matlab/figures/ folder. 38 | 39 | 4. Near the end of the method, as it starts attempting to merge sub-models, a new MATLAB figure will be opened for each merge attempt. This allows the user to view both successful and failed merge operations. 40 | 41 | Execution on New Dataset 42 | ------------------------ 43 | Currently, this code only supports VisualSFM file formats (http://ccwu.me/vsfm/). When you have finished executing VisualSFM on your images, save the following files: 44 | 45 | 1. SfM -> Save NView Match, this will save a *.nvm file which contains the camera poses, 3D point locations, and 2D point observations. 46 | 47 | 2. SfM -> Pairwise Matching -> Export F-Matrix Matches, this will save a *.txt file which contains the inlier match data for each pair of images that was matched. 48 | 49 | After saving these files, modify the main_settings.m file to reflect the location of these files and your data. 50 | 51 | Troubleshooting 52 | --------------- 53 | If your MATLAB instance does not support 12 matlabpool threads, find all calls to init_matlabpool(12) and replace the argument with a smaller number. 54 | 55 | On the largest datasets (e.g. Berliner Dom) your machine may run out of memory when executing parfor loops. If this is the case, modify the init_matlabpool(12) call directly before the offending parfor loop and change it to a smaller value. 56 | 57 | SLICO Superpixels 58 | ----------------- 59 | Code obtained from: 60 | http://ivrg.epfl.ch/research/superpixels#SLICO 61 | 62 | ParforProgMon 63 | ------------- 64 | Code obtained from: 65 | http://www.mathworks.com/matlabcentral/fileexchange/31673-parfor-progress-monitor-v2 66 | -------------------------------------------------------------------------------- /SLICO-Superpixels/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | project(SLICO) 4 | 5 | find_package(OpenCV COMPONENTS core highgui) 6 | 7 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${SLICO_SOURCE_DIR}/bin/Debug) 8 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${SLICO_SOURCE_DIR}/bin/Release) 9 | 10 | set(SLIC_SOURCE_FILES 11 | src/SLIC.h 12 | src/SLIC.cpp 13 | ) 14 | 15 | set(MAIN_SOURCE_FILES 16 | src/main.cpp 17 | ) 18 | 19 | add_executable(SLICO 20 | ${SLIC_SOURCE_FILES} 21 | ${MAIN_SOURCE_FILES} 22 | ) 23 | 24 | source_group(SLIC FILES ${SLIC_SOURCE_FILES}) 25 | source_group(main FILES ${MAIN_SOURCE_FILES}) 26 | 27 | target_include_directories(SLICO PUBLIC 28 | ${CMAKE_CURRENT_LIST_DIR}/src 29 | ${OpenCV_INCLUDE_DIRS} 30 | ) 31 | 32 | target_link_libraries(SLICO PUBLIC ${OpenCV_LIBS}) 33 | -------------------------------------------------------------------------------- /SLICO-Superpixels/USAGE_SLIC.txt: -------------------------------------------------------------------------------- 1 | 2 | SLIC class declaration and implementation files are provided along with a MS VC+6 workspace. The files provide the code to perform superpixel segmentation as explained in the paper: 3 | 4 | "SLIC Superpixels Compated to State-of-the-art Superpixel Methods", 5 | Radhakrishna Achanta, Appu Shaji, Kevin Smith, Aurelien Lucchi, Pascal Fua, and Sabine Susstrunk. 6 | IEEE TPAMI, November2012. 7 | 8 | The usage is quite straight forward if one wants to incorporate SLICO in his/her projects. One has to instantiate an object of the SLIC class and call the various methods on it. Here is an example main() file: 9 | 10 | ==================================================================================================== 11 | NOTE: For commercial use please contact the author Radhakrishna Achanta (firstname.lastname@epfl.ch) 12 | ==================================================================================================== 13 | 14 | #include 15 | #include "SLIC.h" 16 | 17 | int main() 18 | { 19 | int width(0), height(0); 20 | // unsigned int (32 bits) to hold a pixel in ARGB format as follows: 21 | // from left to right, 22 | // the first 8 bits are for the alpha channel (and are ignored) 23 | // the next 8 bits are for the red channel 24 | // the next 8 bits are for the green channel 25 | // the last 8 bits are for the blue channel 26 | unsigned int* pbuff = new UINT[sz]; 27 | ReadImage(pbuff, width, height);//YOUR own function to read an image into the ARGB format 28 | 29 | //---------------------------------- 30 | // Initialize parameters 31 | //---------------------------------- 32 | int k = 200;//Desired number of superpixels. 33 | double m = 20;//Compactness factor. use a value ranging from 10 to 40 depending on your needs. Default is 10 34 | int* klabels = NULL; 35 | int numlabels(0); 36 | string filename = "yourfilename.jpg"; 37 | string savepath = "yourpathname"; 38 | //---------------------------------- 39 | // Perform SLIC on the image buffer 40 | //---------------------------------- 41 | SLIC segment; 42 | segment.PerformSLICO_ForGivenK(pbuff, width, height, klabels, numlabels, k, m); 43 | // Alternately one can also use the function PerformSLICO_ForGivenStepSize() for a desired superpixel size 44 | //---------------------------------- 45 | // Save the labels to a text file 46 | //---------------------------------- 47 | segment.SaveSuperpixelLabels(klabels, width, height, filename, savepath); 48 | //---------------------------------- 49 | // Draw boundaries around segments 50 | //---------------------------------- 51 | segment.DrawContoursAroundSegments(pbuff, klabels, width, height, 0xff0000); 52 | //---------------------------------- 53 | // Save the image with segment boundaries. 54 | //---------------------------------- 55 | SaveSegmentedImageFile(pbuff, width, height);//YOUR own function to save an ARGB buffer as an image 56 | //---------------------------------- 57 | // Clean up 58 | //---------------------------------- 59 | if(pbuff) delete [] pbuff; 60 | if(klabels) delete [] klabels; 61 | 62 | return 0; 63 | } 64 | 65 | As a disclaimer, the author of the code or EPFL are not responsible for any damages that may result from using this code or the compiled executable. There are no warraties associated with the code or executables. 66 | 67 | 68 | -------------------------------------------------------------------------------- /SLICO-Superpixels/precompiled_bin/SLICO.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jheinly/sfm_duplicate_structure_correction/1e4376729b2c2e690181ff6ba6acb4dc644b3640/SLICO-Superpixels/precompiled_bin/SLICO.exe -------------------------------------------------------------------------------- /SLICO-Superpixels/precompiled_bin/opencv_core249.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jheinly/sfm_duplicate_structure_correction/1e4376729b2c2e690181ff6ba6acb4dc644b3640/SLICO-Superpixels/precompiled_bin/opencv_core249.dll -------------------------------------------------------------------------------- /SLICO-Superpixels/precompiled_bin/opencv_highgui249.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jheinly/sfm_duplicate_structure_correction/1e4376729b2c2e690181ff6ba6acb4dc644b3640/SLICO-Superpixels/precompiled_bin/opencv_highgui249.dll -------------------------------------------------------------------------------- /SLICO-Superpixels/src/SLIC.h: -------------------------------------------------------------------------------- 1 | // SLIC.h: interface for the SLIC class. 2 | //=========================================================================== 3 | // This code implements the zero parameter superpixel segmentation technique 4 | // described in: 5 | // 6 | // 7 | // 8 | // "SLIC Superpixels Compared to State-of-the-art Superpixel Methods" 9 | // 10 | // Radhakrishna Achanta, Appu Shaji, Kevin Smith, Aurelien Lucchi, Pascal Fua, 11 | // and Sabine Susstrunk, 12 | // 13 | // IEEE TPAMI, Volume 34, Issue 11, Pages 2274-2282, November 2012. 14 | // 15 | // 16 | //=========================================================================== 17 | // Copyright (c) 2013 Radhakrishna Achanta. 18 | // 19 | // For commercial use please contact the author: 20 | // 21 | // Email: firstname.lastname@epfl.ch 22 | //=========================================================================== 23 | 24 | #if !defined(_SLIC_H_INCLUDED_) 25 | #define _SLIC_H_INCLUDED_ 26 | 27 | 28 | #include 29 | #include 30 | #include 31 | using namespace std; 32 | 33 | 34 | class SLIC 35 | { 36 | public: 37 | SLIC(); 38 | virtual ~SLIC(); 39 | //============================================================================ 40 | // Superpixel segmentation for a given step size (superpixel size ~= step*step) 41 | //============================================================================ 42 | void PerformSLICO_ForGivenStepSize( 43 | const unsigned int* ubuff,//Each 32 bit unsigned int contains ARGB pixel values. 44 | const int width, 45 | const int height, 46 | int* klabels, 47 | int& numlabels, 48 | const int& STEP, 49 | const double& m); 50 | //============================================================================ 51 | // Superpixel segmentation for a given number of superpixels 52 | //============================================================================ 53 | void PerformSLICO_ForGivenK( 54 | const unsigned int* ubuff,//Each 32 bit unsigned int contains ARGB pixel values. 55 | const int width, 56 | const int height, 57 | int* klabels, 58 | int& numlabels, 59 | const int& K, 60 | const double& m); 61 | 62 | //============================================================================ 63 | // Save superpixel labels in a text file in raster scan order 64 | //============================================================================ 65 | void SaveSuperpixelLabels( 66 | const int* labels, 67 | const int& width, 68 | const int& height, 69 | const string& filename, 70 | const string& path); 71 | //============================================================================ 72 | // Function to draw boundaries around superpixels of a given 'color'. 73 | // Can also be used to draw boundaries around supervoxels, i.e layer by layer. 74 | //============================================================================ 75 | void DrawContoursAroundSegments( 76 | unsigned int* segmentedImage, 77 | const int* labels, 78 | const int& width, 79 | const int& height, 80 | const unsigned int& color ); 81 | 82 | void DrawContoursAroundSegmentsTwoColors( 83 | unsigned int* ubuff, 84 | const int* labels, 85 | const int& width, 86 | const int& height); 87 | 88 | private: 89 | 90 | //============================================================================ 91 | // Magic SLIC. No need to set M (compactness factor) and S (step size). 92 | // SLICO (SLIC Zero) varies only M dynamicaly, not S. 93 | //============================================================================ 94 | void PerformSuperpixelSegmentation_VariableSandM( 95 | vector& kseedsl, 96 | vector& kseedsa, 97 | vector& kseedsb, 98 | vector& kseedsx, 99 | vector& kseedsy, 100 | int* klabels, 101 | const int& STEP, 102 | const int& NUMITR); 103 | //============================================================================ 104 | // Pick seeds for superpixels when step size of superpixels is given. 105 | //============================================================================ 106 | void GetLABXYSeeds_ForGivenStepSize( 107 | vector& kseedsl, 108 | vector& kseedsa, 109 | vector& kseedsb, 110 | vector& kseedsx, 111 | vector& kseedsy, 112 | const int& STEP, 113 | const bool& perturbseeds, 114 | const vector& edgemag); 115 | //============================================================================ 116 | // Pick seeds for superpixels when number of superpixels is input. 117 | //============================================================================ 118 | void GetLABXYSeeds_ForGivenK( 119 | vector& kseedsl, 120 | vector& kseedsa, 121 | vector& kseedsb, 122 | vector& kseedsx, 123 | vector& kseedsy, 124 | const int& STEP, 125 | const bool& perturbseeds, 126 | const vector& edges); 127 | 128 | //============================================================================ 129 | // Move the seeds to low gradient positions to avoid putting seeds at region boundaries. 130 | //============================================================================ 131 | void PerturbSeeds( 132 | vector& kseedsl, 133 | vector& kseedsa, 134 | vector& kseedsb, 135 | vector& kseedsx, 136 | vector& kseedsy, 137 | const vector& edges); 138 | //============================================================================ 139 | // Detect color edges, to help PerturbSeeds() 140 | //============================================================================ 141 | void DetectLabEdges( 142 | const double* lvec, 143 | const double* avec, 144 | const double* bvec, 145 | const int& width, 146 | const int& height, 147 | vector& edges); 148 | //============================================================================ 149 | // xRGB to XYZ conversion; helper for RGB2LAB() 150 | //============================================================================ 151 | void RGB2XYZ( 152 | const int& sR, 153 | const int& sG, 154 | const int& sB, 155 | double& X, 156 | double& Y, 157 | double& Z); 158 | //============================================================================ 159 | // sRGB to CIELAB conversion 160 | //============================================================================ 161 | void RGB2LAB( 162 | const int& sR, 163 | const int& sG, 164 | const int& sB, 165 | double& lval, 166 | double& aval, 167 | double& bval); 168 | //============================================================================ 169 | // sRGB to CIELAB conversion for 2-D images 170 | //============================================================================ 171 | void DoRGBtoLABConversion( 172 | const unsigned int*& ubuff, 173 | double*& lvec, 174 | double*& avec, 175 | double*& bvec); 176 | //============================================================================ 177 | // sRGB to CIELAB conversion for 3-D volumes 178 | //============================================================================ 179 | void DoRGBtoLABConversion( 180 | const unsigned int**& ubuff, 181 | double**& lvec, 182 | double**& avec, 183 | double**& bvec); 184 | 185 | //============================================================================ 186 | // Post-processing of SLIC segmentation, to avoid stray labels. 187 | //============================================================================ 188 | void EnforceLabelConnectivity( 189 | const int* labels, 190 | const int& width, 191 | const int& height, 192 | int* nlabels,//input labels that need to be corrected to remove stray labels 193 | int& numlabels,//the number of labels changes in the end if segments are removed 194 | const int& K); //the number of superpixels desired by the user 195 | 196 | 197 | private: 198 | int m_width; 199 | int m_height; 200 | int m_depth; 201 | 202 | double* m_lvec; 203 | double* m_avec; 204 | double* m_bvec; 205 | 206 | double** m_lvecvec; 207 | double** m_avecvec; 208 | double** m_bvecvec; 209 | }; 210 | 211 | #endif // !defined(_SLIC_H_INCLUDED_) 212 | -------------------------------------------------------------------------------- /SLICO-Superpixels/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | std::string parent_name(const std::string & path) 8 | { 9 | size_t index = path.find_last_of("/\\"); 10 | 11 | if (index == path.length() - 1) 12 | { 13 | index = path.find_last_of("/\\", path.length() - 2); 14 | if (index == path.npos) 15 | { 16 | return ""; 17 | } 18 | else 19 | { 20 | return path.substr(0, index + 1); 21 | } 22 | } 23 | else 24 | { 25 | if (index == path.npos) 26 | { 27 | return ""; 28 | } 29 | else 30 | { 31 | return path.substr(0, index + 1); 32 | } 33 | } 34 | } 35 | 36 | int main(int argc, char ** argv) 37 | { 38 | if (argc != 3) 39 | { 40 | std::cerr << "ERROR: expected 2 argumens: " << std::endl; 41 | return EXIT_FAILURE; 42 | } 43 | 44 | std::string input_image_path = argv[1]; 45 | int num_superpixels = atoi(argv[2]); 46 | 47 | cv::Mat image_rgb = cv::imread(input_image_path); 48 | cv::Mat image_uint(image_rgb.rows, image_rgb.cols, CV_32SC1); 49 | 50 | for (int row = 0; row < image_rgb.rows; ++row) 51 | { 52 | for (int col = 0; col < image_rgb.cols; ++col) 53 | { 54 | cv::Vec3b pixel = image_rgb.at(row, col); 55 | int b = pixel[0]; 56 | int g = pixel[1]; 57 | int r = pixel[2]; 58 | 59 | int pixel_int = b + (g << 8) + (r << 16); 60 | image_uint.at(row, col) = pixel_int; 61 | } 62 | } 63 | 64 | SLIC slic; 65 | int * labels = new int[image_uint.cols * image_uint.rows]; 66 | int num_labels = 0; 67 | 68 | slic.PerformSLICO_ForGivenK( 69 | image_uint.ptr(0), 70 | image_uint.cols, 71 | image_uint.rows, 72 | labels, 73 | num_labels, 74 | num_superpixels, 75 | 10.0); 76 | slic.SaveSuperpixelLabels(labels, 77 | image_uint.cols, 78 | image_uint.rows, 79 | input_image_path, 80 | parent_name(input_image_path)); 81 | 82 | return EXIT_SUCCESS; 83 | } 84 | -------------------------------------------------------------------------------- /matlab/code/axis_angle_to_matrix.m: -------------------------------------------------------------------------------- 1 | % http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle 2 | 3 | function [R] = axis_angle_to_matrix(axis, angle) 4 | 5 | x = axis(1); 6 | y = axis(2); 7 | z = axis(3); 8 | s = sin(angle); 9 | c = cos(angle); 10 | 11 | c1 = 1 - c; 12 | xc1 = x * c1; 13 | yc1 = y * c1; 14 | zc1 = z * c1; 15 | xyc1 = x * yc1; 16 | xzc1 = x * zc1; 17 | yzc1 = y * zc1; 18 | xs = x * s; 19 | ys = y * s; 20 | zs = z * s; 21 | 22 | R = [c + x*xc1, xyc1 - zs, xzc1 + ys;... 23 | xyc1 + zs, c + y*yc1, yzc1 - xs;... 24 | xzc1 - ys, yzc1 + xs, c + z*zc1]; 25 | 26 | end 27 | -------------------------------------------------------------------------------- /matlab/code/compute_RTS_3_points_3d.m: -------------------------------------------------------------------------------- 1 | function [M] = compute_RTS_3_points_3d(left_points, right_points) 2 | 3 | % left_points should be 3x3, where each column is a point 4 | % right_points should be 3x3, where each column is a point 5 | 6 | left_mean = mean(left_points, 2); 7 | right_mean = mean(right_points, 2); 8 | 9 | left_normed = left_points - repmat(left_mean, 1, 3); 10 | right_normed = right_points - repmat(right_mean, 1, 3); 11 | 12 | S = sqrt(sum(sum(right_normed .^ 2, 1)) / sum(sum(left_normed .^ 2, 1))); 13 | 14 | left_normed = S .* left_normed; 15 | left_mean = S .* left_mean; 16 | 17 | left_plane_norm = cross(left_normed(:,2) - left_normed(:,1),... 18 | left_normed(:,3) - left_normed(:,1)); 19 | left_plane_norm = left_plane_norm ./ norm(left_plane_norm); 20 | 21 | right_plane_norm = cross(right_normed(:,2) - right_normed(:,1),... 22 | right_normed(:,3) - right_normed(:,1)); 23 | right_plane_norm = right_plane_norm ./ norm(right_plane_norm); 24 | 25 | plane_axis = cross(left_plane_norm, right_plane_norm); 26 | plane_axis = plane_axis ./ norm(plane_axis); 27 | 28 | plane_angle = acos(dot(left_plane_norm, right_plane_norm)); 29 | 30 | if plane_angle < 0.00000001 31 | plane_axis = [0 0 1]'; 32 | end 33 | 34 | plane_R = axis_angle_to_matrix(plane_axis, plane_angle); 35 | 36 | left_normed = plane_R * left_normed; 37 | 38 | cos_dots = dot(left_normed, right_normed, 1); 39 | cos_sum = sum(cos_dots); 40 | 41 | sin_crosses = cross(left_normed, right_normed, 1); 42 | sum_sin_crosses = sum(sin_crosses, 2); 43 | sin_sum = dot(sum_sin_crosses, right_plane_norm); 44 | 45 | theta = asin(sin_sum / sqrt(sin_sum ^ 2 + cos_sum ^ 2)); 46 | 47 | inplane_R = axis_angle_to_matrix(right_plane_norm, theta); 48 | 49 | R = inplane_R * plane_R; 50 | 51 | left_mean = R * left_mean; 52 | 53 | T = right_mean - left_mean; 54 | 55 | M = [R * S, T]; 56 | 57 | end 58 | -------------------------------------------------------------------------------- /matlab/code/compute_RTS_3_points_3d_same_scale.m: -------------------------------------------------------------------------------- 1 | function [M] = compute_RTS_3_points_3d_same_scale(left_points, right_points) 2 | 3 | % left_points should be 3x3, where each column is a point 4 | % right_points should be 3x3, where each column is a point 5 | 6 | left_mean = mean(left_points, 2); 7 | right_mean = mean(right_points, 2); 8 | 9 | left_normed = left_points - repmat(left_mean, 1, 3); 10 | right_normed = right_points - repmat(right_mean, 1, 3); 11 | 12 | %S = sqrt(sum(sum(right_normed .^ 2, 1)) / sum(sum(left_normed .^ 2, 1))); 13 | 14 | %left_normed = S .* left_normed; 15 | %left_mean = S .* left_mean; 16 | 17 | left_plane_norm = cross(left_normed(:,2) - left_normed(:,1),... 18 | left_normed(:,3) - left_normed(:,1)); 19 | left_plane_norm = left_plane_norm ./ norm(left_plane_norm); 20 | 21 | right_plane_norm = cross(right_normed(:,2) - right_normed(:,1),... 22 | right_normed(:,3) - right_normed(:,1)); 23 | right_plane_norm = right_plane_norm ./ norm(right_plane_norm); 24 | 25 | plane_axis = cross(left_plane_norm, right_plane_norm); 26 | plane_axis = plane_axis ./ norm(plane_axis); 27 | 28 | plane_angle = acos(dot(left_plane_norm, right_plane_norm)); 29 | 30 | if plane_angle < 0.00000001 31 | plane_axis = [0 0 1]'; 32 | end 33 | 34 | plane_R = axis_angle_to_matrix(plane_axis, plane_angle); 35 | 36 | left_normed = plane_R * left_normed; 37 | 38 | cos_dots = dot(left_normed, right_normed, 1); 39 | cos_sum = sum(cos_dots); 40 | 41 | sin_crosses = cross(left_normed, right_normed, 1); 42 | sum_sin_crosses = sum(sin_crosses, 2); 43 | sin_sum = dot(sum_sin_crosses, right_plane_norm); 44 | 45 | theta = asin(sin_sum / sqrt(sin_sum ^ 2 + cos_sum ^ 2)); 46 | 47 | inplane_R = axis_angle_to_matrix(right_plane_norm, theta); 48 | 49 | R = inplane_R * plane_R; 50 | 51 | left_mean = R * left_mean; 52 | 53 | T = right_mean - left_mean; 54 | 55 | %M = [R * S, T]; 56 | M = [R, T]; 57 | 58 | end 59 | -------------------------------------------------------------------------------- /matlab/code/compute_RTS_N_points_3d.m: -------------------------------------------------------------------------------- 1 | function [M] = compute_RTS_N_points_3d(left_points, right_points) 2 | 3 | % left_points should be 3xN, where each column is a point and N > 3 4 | % right_points should be 3xN, where each column is a point and N > 3 5 | 6 | N = size(left_points, 2); 7 | 8 | left_mean = mean(left_points, 2); 9 | right_mean = mean(right_points, 2); 10 | 11 | left_normed = left_points - repmat(left_mean, 1, N); 12 | right_normed = right_points - repmat(right_mean, 1, N); 13 | 14 | S = sqrt(sum(sum(right_normed .^ 2, 1)) / sum(sum(left_normed .^ 2, 1))); 15 | 16 | left_normed = S .* left_normed; 17 | left_mean = S .* left_mean; 18 | 19 | Smat = left_normed * right_normed'; 20 | Sxx = Smat(1,1); 21 | Sxy = Smat(1,2); 22 | Sxz = Smat(1,3); 23 | Syx = Smat(2,1); 24 | Syy = Smat(2,2); 25 | Syz = Smat(2,3); 26 | Szx = Smat(3,1); 27 | Szy = Smat(3,2); 28 | Szz = Smat(3,3); 29 | 30 | Qmat = [Sxx + Syy + Szz, Syz - Szy, Szx - Sxz, Sxy - Syx; 31 | Syz - Szy, Sxx - Syy - Szz, Sxy + Syx, Szx + Sxz; 32 | Szx - Sxz, Sxy + Syx, -Sxx + Syy - Szz, Syz + Szy; 33 | Sxy - Syx, Szx + Sxz, Syz + Szy, -Sxx - Syy + Szz]; 34 | 35 | if any(any(isnan(Qmat))) || any(any(isinf(Qmat))) 36 | M = []; 37 | return 38 | end 39 | 40 | % columns are eigenvectors 41 | [vectors, values] = eig(Qmat); 42 | [val, idx] = max(diag(values)); 43 | 44 | Q = vectors(:,idx); 45 | Q = Q / norm(Q); 46 | 47 | R = quaternion_to_matrix(Q); 48 | 49 | left_mean = R * left_mean; 50 | 51 | T = right_mean - left_mean; 52 | 53 | M = [R * S, T]; 54 | 55 | end 56 | -------------------------------------------------------------------------------- /matlab/code/compute_RTS_N_points_3d_same_scale.m: -------------------------------------------------------------------------------- 1 | function [M] = compute_RTS_N_points_3d_same_scale(left_points, right_points) 2 | 3 | % left_points should be 3xN, where each column is a point and N > 3 4 | % right_points should be 3xN, where each column is a point and N > 3 5 | 6 | N = size(left_points, 2); 7 | 8 | left_mean = mean(left_points, 2); 9 | right_mean = mean(right_points, 2); 10 | 11 | left_normed = left_points - repmat(left_mean, 1, N); 12 | right_normed = right_points - repmat(right_mean, 1, N); 13 | 14 | %S = sqrt(sum(sum(right_normed .^ 2, 1)) / sum(sum(left_normed .^ 2, 1))); 15 | 16 | %left_normed = S .* left_normed; 17 | %left_mean = S .* left_mean; 18 | 19 | Smat = left_normed * right_normed'; 20 | Sxx = Smat(1,1); 21 | Sxy = Smat(1,2); 22 | Sxz = Smat(1,3); 23 | Syx = Smat(2,1); 24 | Syy = Smat(2,2); 25 | Syz = Smat(2,3); 26 | Szx = Smat(3,1); 27 | Szy = Smat(3,2); 28 | Szz = Smat(3,3); 29 | 30 | Qmat = [Sxx + Syy + Szz, Syz - Szy, Szx - Sxz, Sxy - Syx; 31 | Syz - Szy, Sxx - Syy - Szz, Sxy + Syx, Szx + Sxz; 32 | Szx - Sxz, Sxy + Syx, -Sxx + Syy - Szz, Syz + Szy; 33 | Sxy - Syx, Szx + Sxz, Syz + Szy, -Sxx - Syy + Szz]; 34 | 35 | if any(any(isnan(Qmat))) || any(any(isinf(Qmat))) 36 | M = []; 37 | return 38 | end 39 | 40 | % columns are eigenvectors 41 | [vectors, values] = eig(Qmat); 42 | [val, idx] = max(diag(values)); 43 | 44 | Q = vectors(:,idx); 45 | Q = Q / norm(Q); 46 | 47 | R = quaternion_to_matrix(Q); 48 | 49 | left_mean = R * left_mean; 50 | 51 | T = right_mean - left_mean; 52 | 53 | %M = [R * S, T]; 54 | M = [R, T]; 55 | 56 | end 57 | -------------------------------------------------------------------------------- /matlab/code/compute_baseline_angle_between_cameras.m: -------------------------------------------------------------------------------- 1 | function [angle] = compute_baseline_angle_between_cameras(... 2 | cam_idx1, cam_idx2, camera_data, point_data, visibility_matrix) 3 | 4 | common_point_flags = visibility_matrix(cam_idx1,:) &... 5 | visibility_matrix(cam_idx2,:); 6 | 7 | if ~any(common_point_flags) 8 | disp(['ERROR: compute_baseline_angle_between_cameras, cameras have no points in common: '... 9 | num2str(cam_idx1) ', ' num2str(cam_idx2)]) 10 | angle = -1; 11 | return 12 | end 13 | 14 | common_points = point_data.xyzs(:,common_point_flags); 15 | mean_point = mean(common_points, 2); 16 | 17 | vector1 = camera_data.centers(:,cam_idx1) - mean_point; 18 | vector2 = camera_data.centers(:,cam_idx2) - mean_point; 19 | 20 | vector1 = vector1 ./ norm(vector1); 21 | vector2 = vector2 ./ norm(vector2); 22 | 23 | angle = rad2deg(acos(dot(vector1, vector2))); 24 | 25 | end 26 | -------------------------------------------------------------------------------- /matlab/code/compute_baseline_angle_between_cameras2.m: -------------------------------------------------------------------------------- 1 | function [angle] = compute_baseline_angle_between_cameras2(... 2 | cam_idx1, cam_idx2, camera_data, point_data, camera_observations) 3 | 4 | points1 = camera_observations{cam_idx1}.point_indices; 5 | points2 = camera_observations{cam_idx2}.point_indices; 6 | 7 | % We assume that camera_observations.point_indices is sorted so we can use ismembc 8 | common_point_indices = points1(ismembc(points1, points2)); 9 | %common_point_indices = intersect(points1, points2); 10 | 11 | if isempty(common_point_indices) 12 | disp(['ERROR: compute_baseline_angle_between_cameras2, cameras have no points in common: '... 13 | num2str(cam_idx1) ', ' num2str(cam_idx2)]) 14 | angle = -1; 15 | return 16 | end 17 | 18 | common_points = point_data.xyzs(:,common_point_indices); 19 | mean_point = mean(common_points, 2); 20 | 21 | vector1 = camera_data.centers(:,cam_idx1) - mean_point; 22 | vector2 = camera_data.centers(:,cam_idx2) - mean_point; 23 | 24 | vector1 = vector1 ./ norm(vector1); 25 | vector2 = vector2 ./ norm(vector2); 26 | 27 | angle = rad2deg(acos(dot(vector1, vector2))); 28 | 29 | end 30 | -------------------------------------------------------------------------------- /matlab/code/compute_baseline_angles_between_camera_pairs.m: -------------------------------------------------------------------------------- 1 | function [angles] = compute_baseline_angles_between_camera_pairs(... 2 | camera_pairs, camera_data, point_data, visibility_matrix) 3 | 4 | num_pairs = size(camera_pairs, 1); 5 | angles = zeros(num_pairs, 1); 6 | 7 | init_matlabpool(12); 8 | 9 | parfor i = 1:num_pairs 10 | cam_idx1 = camera_pairs(i,1); 11 | cam_idx2 = camera_pairs(i,2); 12 | 13 | angles(i) = compute_baseline_angle_between_cameras(cam_idx1, cam_idx2,... 14 | camera_data, point_data, visibility_matrix); 15 | end 16 | 17 | end % function 18 | -------------------------------------------------------------------------------- /matlab/code/compute_baseline_angles_between_camera_pairs2.m: -------------------------------------------------------------------------------- 1 | function [angles] = compute_baseline_angles_between_camera_pairs2(... 2 | camera_pairs, camera_data, point_data, camera_observations) 3 | 4 | num_pairs = size(camera_pairs, 1); 5 | angles = zeros(num_pairs, 1); 6 | 7 | init_matlabpool(12); 8 | 9 | parfor i = 1:num_pairs 10 | cam_idx1 = camera_pairs(i,1); 11 | cam_idx2 = camera_pairs(i,2); 12 | 13 | angles(i) = compute_baseline_angle_between_cameras2(cam_idx1, cam_idx2,... 14 | camera_data, point_data, camera_observations); 15 | end 16 | 17 | % for i = 1:num_pairs 18 | % cam_idx1 = camera_pairs(i,1); 19 | % cam_idx2 = camera_pairs(i,2); 20 | % 21 | % angles(i) = compute_baseline_angle_between_cameras2(cam_idx1, cam_idx2,... 22 | % camera_data, point_data, camera_observations); 23 | % end 24 | 25 | end % function 26 | -------------------------------------------------------------------------------- /matlab/code/compute_camera_observation_segments2.m: -------------------------------------------------------------------------------- 1 | function [camera_observation_segments] = compute_camera_observation_segments2(... 2 | camera_observations, camera_data, segmentation_folder) 3 | 4 | num_cameras = camera_data.num_cameras; 5 | camera_observation_segments = cell(1, num_cameras); 6 | 7 | num_superpixels = 100; 8 | num_segmentations = 8; 9 | 10 | init_matlabpool(12); 11 | 12 | progress = ParforProgMon('Camera Segments: ', num_cameras, 1, 300, 80); 13 | 14 | parfor cam_idx = 1:num_cameras 15 | %width = size(image_segmentations{cam_idx}{1}.segmentation, 2); 16 | %height = size(image_segmentations{cam_idx}{1}.segmentation, 1); 17 | width = camera_data.dimensions(1,cam_idx); 18 | height = camera_data.dimensions(2,cam_idx); 19 | 20 | locations_2d = round(camera_observations{cam_idx}.locations_2d + 1); 21 | valid_flags =... 22 | locations_2d(1,:) >= 1 & locations_2d(1,:) <= width &... 23 | locations_2d(2,:) >= 1 & locations_2d(2,:) <= height; 24 | num_points = length(valid_flags); 25 | locations_2d_valid = locations_2d(:,valid_flags); 26 | indices = sub2ind(... 27 | [height, width],... 28 | locations_2d_valid(2,:), locations_2d_valid(1,:)); 29 | 30 | camera_observation_segments{cam_idx} = cell(1, num_segmentations); 31 | 32 | for seg_idx = 1:num_segmentations 33 | segment_indices = -ones(1, num_points); 34 | 35 | % Load segmentation 36 | segmentation_png_name = [segmentation_folder '/' camera_data.names{cam_idx}... 37 | '_seg_' num2str(num_superpixels) '_' num2str(seg_idx) '.png']; 38 | segmentation = imread(segmentation_png_name); 39 | 40 | %segments = image_segmentations{cam_idx}{seg_idx}.segmentation(indices); 41 | segments = segmentation(indices); 42 | 43 | segment_indices(valid_flags) = segments; 44 | 45 | % for i = 1:num_points 46 | % if valid_flags(i) 47 | % x = locations_2d(1,i); 48 | % y = locations_2d(2,i); 49 | % segment_indices(i) =... 50 | % image_segmentations{cam_idx}{seg_idx}.segmentation(y, x); 51 | % end 52 | % end 53 | 54 | camera_observation_segments{cam_idx}{seg_idx} = struct(... 55 | 'segment_indices', int8(segment_indices),... 56 | 'valid_flags', valid_flags,... 57 | 'max_num_segments', double(max(max(segmentation))) + 1); 58 | end 59 | 60 | progress.increment(); 61 | end 62 | 63 | progress.delete(); 64 | 65 | end % function 66 | -------------------------------------------------------------------------------- /matlab/code/compute_camera_pair_segments2.m: -------------------------------------------------------------------------------- 1 | function [camera_pair_segments] = compute_camera_pair_segments2(... 2 | split_camera_tasks, camera_data, point_data, camera_observations,... 3 | segmentation_folder) 4 | 5 | num_split_camera_tasks = length(split_camera_tasks); 6 | split_camera_pairs = []; 7 | for i = 1:num_split_camera_tasks 8 | split_camera_pairs = [split_camera_pairs; split_camera_tasks{i}.camera_pairs]; 9 | end 10 | split_camera_pairs = unique(split_camera_pairs, 'rows'); 11 | num_split_camera_pairs = size(split_camera_pairs, 1); 12 | 13 | disp(['Reduced # split camera pairs: ' num2str(num_split_camera_pairs)]) 14 | 15 | if num_split_camera_pairs == 0 16 | camera_pair_segments = struct(... 17 | 'num_camera_pairs', 0,... 18 | 'camera_pairs', [],... 19 | 'pair_data', [],... 20 | 'valid_flags1_to2', [],... 21 | 'valid_flags2_to1', [],... 22 | 'projected_points', []); 23 | return 24 | end 25 | 26 | init_matlabpool(12); 27 | 28 | num_superpixels = 100; 29 | num_segmentations = 8; 30 | 31 | num_cameras = camera_data.num_cameras; 32 | camera_pair_segments_storage = cell(1, num_cameras); 33 | 34 | progress = ParforProgMon('Camera Segments: ', num_cameras, 1, 300, 80); 35 | 36 | parfor cam_idx = 1:num_cameras 37 | % Find split camera pairs that use cam_idx 38 | 39 | cam_in_pair_flags1 = split_camera_pairs(:,1) == cam_idx; 40 | cam_in_pair_flags2 = split_camera_pairs(:,2) == cam_idx; 41 | 42 | split_pair_indices1 = find(cam_in_pair_flags1); 43 | split_pair_indices2 = find(cam_in_pair_flags2); 44 | 45 | split_camera_indices1 = split_camera_pairs(cam_in_pair_flags1, 2); 46 | split_camera_indices2 = split_camera_pairs(cam_in_pair_flags2, 1); 47 | 48 | num_cam_in_pair1 = length(split_camera_indices1); 49 | num_cam_in_pair2 = length(split_camera_indices2); 50 | 51 | camera_pair_segments_storage{cam_idx} = struct(... 52 | 'first_pair_indices', split_pair_indices1,... 53 | 'second_pair_indices', split_pair_indices2,... 54 | 'first_data', {cell(1,num_cam_in_pair1)},... 55 | 'second_data', {cell(1,num_cam_in_pair2)}); 56 | 57 | if num_cam_in_pair1 + num_cam_in_pair2 == 0 58 | progress.increment(); 59 | continue 60 | end 61 | 62 | % Load segmentations 63 | 64 | segmentations = cell(1, num_segmentations); 65 | max_segments = zeros(1, num_segmentations); 66 | for seg_idx = 1:num_segmentations 67 | segmentation_png_name = [segmentation_folder '/' camera_data.names{cam_idx}... 68 | '_seg_' num2str(num_superpixels) '_' num2str(seg_idx) '.png']; 69 | segmentations{seg_idx} = imread(segmentation_png_name); 70 | max_segments(seg_idx) = double(max(max(segmentations{seg_idx}))) + 1; 71 | end 72 | 73 | % Iterate over split camera pairs that use cam_idx 74 | 75 | center_current = camera_data.centers(:,cam_idx); 76 | R_current = camera_data.orientations{cam_idx}; 77 | R_current = R_current'; 78 | width_current = camera_data.dimensions(1,cam_idx); 79 | height_current = camera_data.dimensions(2,cam_idx); 80 | focal_current = camera_data.focals(cam_idx); 81 | K_current = [focal_current, 0, width_current / 2; 82 | 0, focal_current, height_current / 2; 83 | 0, 0, 1]; 84 | 85 | % This loop is almost the same as the following one 86 | for idx = 1:num_cam_in_pair1 87 | cam_idx2 = split_camera_indices1(idx); 88 | 89 | point_indices = camera_observations{cam_idx2}.point_indices; 90 | points = point_data.xyzs(:,point_indices); 91 | 92 | points_projected = points; 93 | points_projected(1,:) = points_projected(1,:) - center_current(1); 94 | points_projected(2,:) = points_projected(2,:) - center_current(2); 95 | points_projected(3,:) = points_projected(3,:) - center_current(3); 96 | points_projected = R_current * points_projected; 97 | points_projected_in_front = points_projected(3,:) > 0; 98 | points_projected(1,:) = points_projected(1,:) ./ points_projected(3,:); 99 | points_projected(2,:) = points_projected(2,:) ./ points_projected(3,:); 100 | points_projected(3,:) = 1; 101 | points_projected = K_current * points_projected; 102 | 103 | points_projected = int32(round(points_projected(1:2,:) + 1)); 104 | points_projected_in_bounds =... 105 | points_projected(1,:) >= 1 & points_projected(1,:) <= width_current &... 106 | points_projected(2,:) >= 1 & points_projected(2,:) <= height_current; 107 | 108 | valid_flags = points_projected_in_front & points_projected_in_bounds; 109 | num_points = size(points, 2); 110 | 111 | points_projected_valid = points_projected(:,valid_flags); 112 | indices = sub2ind([height_current, width_current],... 113 | points_projected_valid(2,:), points_projected_valid(1,:)); 114 | 115 | camera_pair_segments_storage{cam_idx}.first_data{idx} = struct(... 116 | 'valid_flags', valid_flags,... 117 | 'projected_points', int16(points_projected),... 118 | 'segment_indices', {cell(1,num_segmentations)},... 119 | 'max_num_segments', max_segments); 120 | 121 | for seg_idx = 1:num_segmentations 122 | segments = segmentations{seg_idx}(indices); 123 | segments_final = -ones(1, num_points, 'int32'); 124 | segments_final(valid_flags) = segments; 125 | segments_final = int8(segments_final); 126 | 127 | camera_pair_segments_storage{cam_idx}.first_data{idx}.segment_indices{seg_idx} = segments_final; 128 | end 129 | end 130 | 131 | % This loop is almost the same as the previous one 132 | for idx = 1:num_cam_in_pair2 133 | cam_idx1 = split_camera_indices2(idx); 134 | 135 | point_indices = camera_observations{cam_idx1}.point_indices; 136 | points = point_data.xyzs(:,point_indices); 137 | 138 | points_projected = points; 139 | points_projected(1,:) = points_projected(1,:) - center_current(1); 140 | points_projected(2,:) = points_projected(2,:) - center_current(2); 141 | points_projected(3,:) = points_projected(3,:) - center_current(3); 142 | points_projected = R_current * points_projected; 143 | points_projected_in_front = points_projected(3,:) > 0; 144 | points_projected(1,:) = points_projected(1,:) ./ points_projected(3,:); 145 | points_projected(2,:) = points_projected(2,:) ./ points_projected(3,:); 146 | points_projected(3,:) = 1; 147 | points_projected = K_current * points_projected; 148 | 149 | points_projected = int32(round(points_projected(1:2,:) + 1)); 150 | points_projected_in_bounds =... 151 | points_projected(1,:) >= 1 & points_projected(1,:) <= width_current &... 152 | points_projected(2,:) >= 1 & points_projected(2,:) <= height_current; 153 | 154 | valid_flags = points_projected_in_front & points_projected_in_bounds; 155 | num_points = size(points, 2); 156 | 157 | points_projected_valid = points_projected(:,valid_flags); 158 | indices = sub2ind([height_current, width_current],... 159 | points_projected_valid(2,:), points_projected_valid(1,:)); 160 | 161 | camera_pair_segments_storage{cam_idx}.second_data{idx} = struct(... 162 | 'valid_flags', valid_flags,... 163 | 'projected_points', int16(points_projected),... 164 | 'segment_indices', {cell(1,num_segmentations)},... 165 | 'max_num_segments', max_segments); 166 | 167 | for seg_idx = 1:num_segmentations 168 | segments = segmentations{seg_idx}(indices); 169 | segments_final = -ones(1, num_points, 'int32'); 170 | segments_final(valid_flags) = segments; 171 | segments_final = int8(segments_final); 172 | 173 | camera_pair_segments_storage{cam_idx}.second_data{idx}.segment_indices{seg_idx} = segments_final; 174 | end 175 | end 176 | 177 | progress.increment(); 178 | end 179 | 180 | progress.delete(); 181 | 182 | % Construct the camera_pair_segments object 183 | disp('Constructing camera_pair_segments object...') 184 | tic 185 | 186 | camera_pair_segments = struct(... 187 | 'num_camera_pairs', num_split_camera_pairs,... 188 | 'camera_pairs', split_camera_pairs,... 189 | 'pair_data', {cell(1,num_split_camera_pairs)},... 190 | 'valid_flags1_to2', {cell(1,num_split_camera_pairs)},... 191 | 'valid_flags2_to1', {cell(1,num_split_camera_pairs)},... 192 | 'projected_points', {cell(1,num_split_camera_pairs)}); 193 | 194 | for pair_idx = 1:num_split_camera_pairs 195 | camera_pair_segments.pair_data{pair_idx} = cell(1, num_segmentations); 196 | 197 | for seg_idx = 1:num_segmentations 198 | camera_pair_segments.pair_data{pair_idx}{seg_idx} = struct(... 199 | 'segment_indices1_to2', [],... 200 | 'max_num_segments1_to2', 0,... 201 | 'segment_indices2_to1', [],... 202 | 'max_num_segments2_to1', 0); 203 | end 204 | 205 | camera_pair_segments.projected_points{pair_idx} = struct(... 206 | 'points1_projected_to2', [],... 207 | 'points2_projected_to1', []); 208 | end 209 | 210 | for cam_idx = 1:num_cameras 211 | first_pair_indices = camera_pair_segments_storage{cam_idx}.first_pair_indices; 212 | second_pair_indices = camera_pair_segments_storage{cam_idx}.second_pair_indices; 213 | 214 | num_first_pair_indices = length(first_pair_indices); 215 | num_second_pair_indices = length(second_pair_indices); 216 | 217 | for idx = 1:num_first_pair_indices 218 | pair_idx = first_pair_indices(idx); 219 | 220 | for seg_idx = 1:num_segmentations 221 | camera_pair_segments.pair_data{pair_idx}{seg_idx}.segment_indices2_to1 =... 222 | camera_pair_segments_storage{cam_idx}.first_data{idx}.segment_indices{seg_idx}; 223 | camera_pair_segments.pair_data{pair_idx}{seg_idx}.max_num_segments2_to1 =... 224 | camera_pair_segments_storage{cam_idx}.first_data{idx}.max_num_segments(seg_idx); 225 | end 226 | 227 | camera_pair_segments.projected_points{pair_idx}.points2_projected_to1 =... 228 | camera_pair_segments_storage{cam_idx}.first_data{idx}.projected_points; 229 | 230 | camera_pair_segments.valid_flags2_to1{pair_idx} =... 231 | camera_pair_segments_storage{cam_idx}.first_data{idx}.valid_flags; 232 | end 233 | 234 | for idx = 1:num_second_pair_indices 235 | pair_idx = second_pair_indices(idx); 236 | 237 | for seg_idx = 1:num_segmentations 238 | camera_pair_segments.pair_data{pair_idx}{seg_idx}.segment_indices1_to2 =... 239 | camera_pair_segments_storage{cam_idx}.second_data{idx}.segment_indices{seg_idx}; 240 | camera_pair_segments.pair_data{pair_idx}{seg_idx}.max_num_segments1_to2 =... 241 | camera_pair_segments_storage{cam_idx}.second_data{idx}.max_num_segments(seg_idx); 242 | end 243 | 244 | camera_pair_segments.projected_points{pair_idx}.points1_projected_to2 =... 245 | camera_pair_segments_storage{cam_idx}.second_data{idx}.projected_points; 246 | 247 | camera_pair_segments.valid_flags1_to2{pair_idx} =... 248 | camera_pair_segments_storage{cam_idx}.second_data{idx}.valid_flags; 249 | end 250 | end 251 | 252 | toc 253 | disp('Constructing camera_pair_segments object done') 254 | 255 | end % function 256 | -------------------------------------------------------------------------------- /matlab/code/compute_camera_spanning_tree.m: -------------------------------------------------------------------------------- 1 | function [camera_tree] = compute_camera_spanning_tree(... 2 | camera_observations) 3 | 4 | num_cameras = length(camera_observations); 5 | weights = zeros(num_cameras, num_cameras); 6 | 7 | init_matlabpool(12); 8 | %init_matlabpool(6); 9 | 10 | num_tasks = (num_cameras * (num_cameras - 1)) / 2; 11 | linear_weights = zeros(num_tasks, 1); 12 | camera_indices = zeros(num_tasks, 2); 13 | 14 | idx = 1; 15 | for cam_idx1 = 1:num_cameras-1 16 | for cam_idx2 = cam_idx1+1:num_cameras 17 | camera_indices(idx,:) = [cam_idx1, cam_idx2]; 18 | idx = idx + 1; 19 | end 20 | end 21 | 22 | parfor task_idx = 1:num_tasks 23 | cam1 = camera_indices(task_idx, 1); 24 | cam2 = camera_indices(task_idx, 2); 25 | 26 | points1 = camera_observations{cam1}.point_indices; 27 | points2 = camera_observations{cam2}.point_indices; 28 | 29 | size1 = length(points1); 30 | size2 = length(points2); 31 | % We assume that points_indices1 and point_indices2 are sorted. 32 | intersect_size = sum(ismembc(points1, points2)); 33 | union_size = size1 + size2 - intersect_size; 34 | linear_weights(task_idx) = 1 - intersect_size / union_size; 35 | end 36 | 37 | idx = 1; 38 | for cam_idx1 = 1:num_cameras-1 39 | for cam_idx2 = cam_idx1+1:num_cameras 40 | weight = linear_weights(idx); 41 | weights(cam_idx1, cam_idx2) = weight; 42 | weights(cam_idx2, cam_idx1) = weight; 43 | idx = idx + 1; 44 | end 45 | end 46 | 47 | % for cam_idx1 = 1:num_cameras-1 48 | % for cam_idx2 = cam_idx1+1:num_cameras 49 | % point_indices1 = camera_observations{cam_idx1}.point_indices; 50 | % point_indices2 = camera_observations{cam_idx2}.point_indices; 51 | % 52 | % size1 = length(point_indices1); 53 | % size2 = length(point_indices2); 54 | % % We assume that points_indices1 and point_indices2 are sorted. 55 | % intersect_size = sum(ismembc(point_indices1, point_indices2)); 56 | % union_size = size1 + size2 - intersect_size; 57 | % weight = -intersect_size / union_size; 58 | % %weight = length(intersect(point_indices1, point_indices2)) /... 59 | % % length(union(point_indices1, point_indices2)); 60 | % %weight = -weight; 61 | % 62 | % weights(cam_idx1, cam_idx2) = weight; 63 | % weights(cam_idx2, cam_idx1) = weight; 64 | % end 65 | % end 66 | 67 | [camera_tree, ~] = graphminspantree(sparse(weights), 'Method', 'Kruskal'); 68 | 69 | end % function 70 | -------------------------------------------------------------------------------- /matlab/code/compute_conflicting_indices2.m: -------------------------------------------------------------------------------- 1 | function [conflicting_indices1, conflicting_indices2] = compute_conflicting_indices2(... 2 | camera_observations, camera_observation_segments,... 3 | camera_pair_segments, valid_flags1_to2, valid_flags2_to1, projected_points,... 4 | visibility_matrix, group_assignments, cam_idx1, cam_idx2, image_folder, camera_data) 5 | 6 | group_idx1 = group_assignments(cam_idx1); 7 | group_idx2 = group_assignments(cam_idx2); 8 | 9 | group1_camera_flags = group_assignments == group_idx1; 10 | group2_camera_flags = group_assignments == group_idx2; 11 | 12 | group1_point_flags = any(visibility_matrix(group1_camera_flags,:), 1); 13 | group2_point_flags = any(visibility_matrix(group2_camera_flags,:), 1); 14 | 15 | group1_point_indices = find(group1_point_flags); 16 | group2_point_indices = find(group2_point_flags); 17 | 18 | camera1_point_indices = camera_observations{cam_idx1}.point_indices; 19 | camera2_point_indices = camera_observations{cam_idx2}.point_indices; 20 | 21 | % We assume that group1_point_indices and group2_point_indices are sorted 22 | camera1_unique_point_flags = ~ismembc(double(camera1_point_indices), group2_point_indices); 23 | camera2_unique_point_flags = ~ismembc(double(camera2_point_indices), group1_point_indices); 24 | %camera1_unique_point_flags = ~ismember(camera1_point_indices, group2_point_indices); 25 | %camera2_unique_point_flags = ~ismember(camera2_point_indices, group1_point_indices); 26 | 27 | camera1_common_point_flags = ~camera1_unique_point_flags; 28 | camera2_common_point_flags = ~camera2_unique_point_flags; 29 | 30 | num_segmentations = length(camera_pair_segments); 31 | num_segments1 = length(camera_observation_segments{cam_idx1}{1}.segment_indices); 32 | num_segments2 = length(camera_observation_segments{cam_idx2}{1}.segment_indices); 33 | 34 | segment_matches1_to2 = false(num_segments1, num_segments2); 35 | segment_matches2_to1 = false(num_segments1, num_segments2); 36 | 37 | segments_near_common1 = false(1, num_segments1); 38 | segments_near_common2 = false(1, num_segments2); 39 | segments_near_common1_to2 = false(1, num_segments1); 40 | segments_near_common2_to1 = false(1, num_segments2); 41 | 42 | for seg_idx = 1:num_segmentations 43 | segment_indices1 = camera_observation_segments{cam_idx1}{seg_idx}.segment_indices; 44 | segment_indices2 = camera_observation_segments{cam_idx2}{seg_idx}.segment_indices; 45 | segment_indices1_to2 = camera_pair_segments{seg_idx}.segment_indices1_to2; 46 | segment_indices2_to1 = camera_pair_segments{seg_idx}.segment_indices2_to1; 47 | 48 | % matches1_to2 = false(num_segments1, num_segments2); 49 | % matches2_to1 = false(num_segments1, num_segments2); 50 | % for i = 1:num_segments2 51 | % matches1_to2(:,i) = segment_indices1_to2 == segment_indices2(i); 52 | % matches2_to1(:,i) = segment_indices1 == segment_indices2_to1(i); 53 | % end 54 | % segment_matches1_to2 = segment_matches1_to2 | matches1_to2; 55 | % segment_matches2_to1 = segment_matches2_to1 | matches2_to1; 56 | 57 | common_segment_indices2 = segment_indices2(camera2_common_point_flags); 58 | common_segment_indices1 = segment_indices1(camera1_common_point_flags); 59 | 60 | [nearby_indices1_to2, near_common1_to2, near_common2] = find_nearby_indices(... 61 | segment_indices1_to2, segment_indices2,... 62 | camera_observation_segments{cam_idx2}{seg_idx}.max_num_segments,... 63 | num_segments1, common_segment_indices2); 64 | [nearby_indices2_to1, near_common1, near_common2_to1] = find_nearby_indices(... 65 | segment_indices1, segment_indices2_to1,... 66 | camera_observation_segments{cam_idx1}{seg_idx}.max_num_segments,... 67 | num_segments1, common_segment_indices1); 68 | 69 | %nearby_ind1_to2 = sub2ind(size(segment_matches1_to2),... 70 | % nearby_indices1_to2(:,1), nearby_indices1_to2(:,2)); 71 | %nearby_ind2_to1 = sub2ind(size(segment_matches2_to1),... 72 | % nearby_indices2_to1(:,1), nearby_indices2_to1(:,2)); 73 | 74 | segment_matches1_to2(nearby_indices1_to2) = true; 75 | segment_matches2_to1(nearby_indices2_to1) = true; 76 | 77 | %near_common1_to2 = ismember(segment_indices1_to2, common_segment_indices2); 78 | %near_common2 = ismember(segment_indices2, common_segment_indices2); 79 | %near_common1 = ismember(segment_indices1, common_segment_indices1); 80 | %near_common2_to1 = ismember(segment_indices2_to1, common_segment_indices1); 81 | 82 | segments_near_common1 = segments_near_common1 | near_common1; 83 | segments_near_common2 = segments_near_common2 | near_common2; 84 | segments_near_common1_to2 = segments_near_common1_to2 | near_common1_to2; 85 | segments_near_common2_to1 = segments_near_common2_to1 | near_common2_to1; 86 | end 87 | 88 | segment_matches1_to2(segments_near_common1_to2, :) = false; 89 | segment_matches1_to2(:, segments_near_common2) = false; 90 | segment_matches2_to1(segments_near_common1, :) = false; 91 | segment_matches2_to1(:, segments_near_common2_to1) = false; 92 | 93 | segment_matches1_to2(~camera1_unique_point_flags, :) = false; 94 | segment_matches2_to1(~camera1_unique_point_flags, :) = false; 95 | segment_matches1_to2(:, ~camera2_unique_point_flags) = false; 96 | segment_matches2_to1(:, ~camera2_unique_point_flags) = false; 97 | 98 | % The valid flags will be the same for all segmentations 99 | segment_indices1_valid = camera_observation_segments{cam_idx1}{1}.valid_flags; 100 | segment_indices2_valid = camera_observation_segments{cam_idx2}{1}.valid_flags; 101 | segment_indices1_to2_valid = valid_flags1_to2; 102 | segment_indices2_to1_valid = valid_flags2_to1; 103 | 104 | segment_matches1_to2(~segment_indices1_to2_valid, :) = false; 105 | segment_matches1_to2(:, ~segment_indices2_valid) = false; 106 | segment_matches2_to1(~segment_indices1_valid, :) = false; 107 | segment_matches1_to2(:, ~segment_indices2_to1_valid) = false; 108 | 109 | camera1_point_indices1 = camera1_point_indices(any(segment_matches1_to2, 2)); 110 | camera1_point_indices2 = camera1_point_indices(any(segment_matches2_to1, 2)); 111 | camera2_point_indices1 = camera2_point_indices(any(segment_matches1_to2, 1)); 112 | camera2_point_indices2 = camera2_point_indices(any(segment_matches2_to1, 1)); 113 | 114 | % We can assume that camera1_point_indices2 and camera2_point_indices2 are sorted 115 | conflicting_indices1 =... 116 | camera1_point_indices1(ismembc(camera1_point_indices1, camera1_point_indices2)); 117 | conflicting_indices2 =... 118 | camera2_point_indices1(ismembc(camera2_point_indices1, camera2_point_indices2)); 119 | %conflicting_indices1 = intersect(camera1_point_indices1, camera1_point_indices2); 120 | %conflicting_indices2 = intersect(camera2_point_indices1, camera2_point_indices2); 121 | 122 | if ~isempty(image_folder) && ~isempty(conflicting_indices1) && ~isempty(conflicting_indices2) 123 | img1 = rgb2gray(imread([image_folder '/' camera_data.names{cam_idx1} '.jpg'])); 124 | img2 = rgb2gray(imread([image_folder '/' camera_data.names{cam_idx2} '.jpg'])); 125 | 126 | [h1, w1] = size(img1); 127 | [h2, w2] = size(img2); 128 | 129 | new_h = min(h1, h2); 130 | 131 | scale1 = new_h / h1; 132 | scale2 = new_h / h2; 133 | 134 | new_w1 = round(scale1 * w1); 135 | new_w2 = round(scale2 * w2); 136 | 137 | if h1 ~= new_h 138 | img1 = imresize(img1, [new_h, new_w1]); 139 | end 140 | if h2 ~= new_h 141 | img2 = imresize(img2, [new_h, new_w2]); 142 | end 143 | 144 | new_img = [img1 img2]; 145 | 146 | imshow(new_img); 147 | hold on 148 | 149 | title_text = sprintf('cams: %d - %d, num conflicting points: %d - %d',... 150 | cam_idx1, cam_idx2, length(conflicting_indices1), length(conflicting_indices2)); 151 | title(title_text) 152 | 153 | % Plot common points 154 | common_flags1 = camera1_common_point_flags & segment_indices1_valid; 155 | common_flags2 = camera2_common_point_flags & segment_indices2_valid; 156 | common_locations1 = camera_observations{cam_idx1}.locations_2d(:,common_flags1); 157 | common_locations2 = camera_observations{cam_idx2}.locations_2d(:,common_flags2); 158 | plot(scale1 * common_locations1(1,:), scale1 * common_locations1(2,:), '.g'); 159 | plot(new_w1 + scale2 * common_locations2(1,:), scale2 * common_locations2(2,:), '.g'); 160 | 161 | % Plot camera 1's unique points 162 | unique_flags1 = camera1_unique_point_flags & ~segments_near_common1 & ~segments_near_common1_to2; 163 | unique_locations1 = camera_observations{cam_idx1}.locations_2d(:,unique_flags1); 164 | unique_locations1_2 = projected_points.points1_projected_to2(:,unique_flags1 & segment_indices1_to2_valid); 165 | plot(scale1 * unique_locations1(1,:), scale1 * unique_locations1(2,:), '.r'); 166 | plot(new_w1 + scale2 * unique_locations1_2(1,:), scale2 * unique_locations1_2(2,:), '.r'); 167 | val1 = sum(scale1 * unique_locations1(1,:) < -10); 168 | val2 = sum(scale2 * unique_locations1_2(1,:) < 10); 169 | if val1 > 0 170 | disp(['val1: ' num2str(val1)]) 171 | end 172 | if val2 > 0 173 | disp(['val2: ' num2str(val2)]) 174 | end 175 | 176 | % Plot camera 2's unique points 177 | unique_flags2 = camera2_unique_point_flags & ~segments_near_common2 & ~segments_near_common2_to1; 178 | unique_locations2 = camera_observations{cam_idx2}.locations_2d(:,unique_flags2); 179 | unique_locations2_1 = projected_points.points2_projected_to1(:,unique_flags2 & segment_indices2_to1_valid); 180 | plot(new_w1 + scale2 * unique_locations2(1,:), scale2 * unique_locations2(2,:), '.b'); 181 | plot(scale1 * unique_locations2_1(1,:), scale1 * unique_locations2_1(2,:), '.b'); 182 | val3 = sum(scale1 * unique_locations2(1,:) < -10); 183 | val4 = sum(scale2 * unique_locations2_1(1,:) < 10); 184 | if val3 > 0 185 | disp(['val3: ' num2str(val1)]) 186 | end 187 | if val4 > 0 188 | disp(['val4: ' num2str(val2)]) 189 | end 190 | 191 | hold off 192 | waitforbuttonpress 193 | end 194 | 195 | end % function 196 | -------------------------------------------------------------------------------- /matlab/code/compute_conflicting_indices2_merging.m: -------------------------------------------------------------------------------- 1 | function [conflicting_indices1, conflicting_indices2] = compute_conflicting_indices2_merging(... 2 | camera_observations, camera_observation_segments,... 3 | camera_pair_segments, valid_flags1_to2, valid_flags2_to1, projected_points,... 4 | visibility_matrix, group_assignments, cam_idx1, cam_idx2,... 5 | all_inlier_matches, all_inlier_matches_camera_indices,... 6 | segmentation_folder, camera_data, image_folder) 7 | 8 | group_idx1 = group_assignments(cam_idx1); 9 | group_idx2 = group_assignments(cam_idx2); 10 | 11 | group1_camera_flags = group_assignments == group_idx1; 12 | group2_camera_flags = group_assignments == group_idx2; 13 | 14 | group1_point_flags = any(visibility_matrix(group1_camera_flags,:), 1); 15 | group2_point_flags = any(visibility_matrix(group2_camera_flags,:), 1); 16 | 17 | group1_point_indices = find(group1_point_flags); 18 | group2_point_indices = find(group2_point_flags); 19 | 20 | camera1_point_indices = camera_observations{cam_idx1}.point_indices; 21 | camera2_point_indices = camera_observations{cam_idx2}.point_indices; 22 | 23 | % We assume that group1_point_indices and group2_point_indices are sorted 24 | camera1_unique_point_flags = ~ismembc(camera1_point_indices, group2_point_indices); 25 | camera2_unique_point_flags = ~ismembc(camera2_point_indices, group1_point_indices); 26 | %camera1_unique_point_flags = ~ismember(camera1_point_indices, group2_point_indices); 27 | %camera2_unique_point_flags = ~ismember(camera2_point_indices, group1_point_indices); 28 | 29 | camera1_common_point_flags = ~camera1_unique_point_flags; 30 | camera2_common_point_flags = ~camera2_unique_point_flags; 31 | 32 | num_segmentations = length(camera_pair_segments); 33 | num_segments1 = length(camera_observation_segments{cam_idx1}{1}.segment_indices); 34 | num_segments2 = length(camera_observation_segments{cam_idx2}{1}.segment_indices); 35 | 36 | segment_matches1_to2 = false(num_segments1, num_segments2); 37 | segment_matches2_to1 = false(num_segments1, num_segments2); 38 | 39 | segments_near_common1 = false(1, num_segments1); 40 | segments_near_common2 = false(1, num_segments2); 41 | segments_near_common1_to2 = false(1, num_segments1); 42 | segments_near_common2_to1 = false(1, num_segments2); 43 | 44 | 45 | 46 | inlier_common_segment_indices1 = cell(1, num_segmentations); 47 | inlier_common_segment_indices2 = cell(1, num_segmentations); 48 | for i = 1:num_segmentations 49 | inlier_common_segment_indices1{i} = []; 50 | inlier_common_segment_indices2{i} = []; 51 | end 52 | inlier_match_flags =... 53 | all_inlier_matches_camera_indices == cam_idx1 |... 54 | all_inlier_matches_camera_indices == cam_idx2; 55 | inlier_match_flags = all(inlier_match_flags, 2); 56 | inlier_match_index = find(inlier_match_flags, 1); 57 | if ~isempty(inlier_match_index) 58 | num_superpixels = 100; 59 | %num_segmentations = 8; 60 | segmentations1 = cell(1, num_segmentations); 61 | segmentations2 = cell(1, num_segmentations); 62 | for seg_idx = 1:num_segmentations 63 | segmentation1_png_name = [segmentation_folder '/' camera_data.names{cam_idx1}... 64 | '_seg_' num2str(num_superpixels) '_' num2str(seg_idx) '.png']; 65 | segmentation2_png_name = [segmentation_folder '/' camera_data.names{cam_idx2}... 66 | '_seg_' num2str(num_superpixels) '_' num2str(seg_idx) '.png']; 67 | segmentations1{seg_idx} = imread(segmentation1_png_name); 68 | segmentations2{seg_idx} = imread(segmentation2_png_name); 69 | end 70 | if all_inlier_matches{inlier_match_index}.camera_indices(1) == cam_idx1 71 | locations2d_1 = all_inlier_matches{inlier_match_index}.locations_2d([1 2], :); 72 | locations2d_2 = all_inlier_matches{inlier_match_index}.locations_2d([3 4], :); 73 | else 74 | locations2d_1 = all_inlier_matches{inlier_match_index}.locations_2d([3 4], :); 75 | locations2d_2 = all_inlier_matches{inlier_match_index}.locations_2d([1 2], :); 76 | end 77 | locations2d_1 = int32(round(locations2d_1)); 78 | locations2d_2 = int32(round(locations2d_2)); 79 | size1 = size(segmentations1{1}); 80 | size2 = size(segmentations2{1}); 81 | valid1 = locations2d_1(1,:) >= 1 & locations2d_1(1,:) <= size1(2) &... 82 | locations2d_1(2,:) >= 1 & locations2d_1(2,:) <= size1(1); 83 | valid2 = locations2d_2(1,:) >= 1 & locations2d_2(1,:) <= size2(2) &... 84 | locations2d_2(2,:) >= 1 & locations2d_2(2,:) <= size2(1); 85 | locations2d_1 = locations2d_1(:,valid1); 86 | locations2d_2 = locations2d_2(:,valid2); 87 | indices1 = sub2ind(size1, locations2d_1(2,:), locations2d_1(1,:)); 88 | indices2 = sub2ind(size2, locations2d_2(2,:), locations2d_2(1,:)); 89 | for seg_idx = 1:num_segmentations 90 | segments1 = int8(segmentations1{seg_idx}(indices1)); 91 | segments2 = int8(segmentations2{seg_idx}(indices2)); 92 | inlier_common_segment_indices1{seg_idx} = segments1; 93 | inlier_common_segment_indices2{seg_idx} = segments2; 94 | end 95 | else 96 | % No inlier matches were found for this camera pair 97 | locations2d_1 = []; 98 | locations2d_2 = []; 99 | end 100 | 101 | 102 | 103 | 104 | for seg_idx = 1:num_segmentations 105 | segment_indices1 = camera_observation_segments{cam_idx1}{seg_idx}.segment_indices; 106 | segment_indices2 = camera_observation_segments{cam_idx2}{seg_idx}.segment_indices; 107 | segment_indices1_to2 = camera_pair_segments{seg_idx}.segment_indices1_to2; 108 | segment_indices2_to1 = camera_pair_segments{seg_idx}.segment_indices2_to1; 109 | 110 | % matches1_to2 = false(num_segments1, num_segments2); 111 | % matches2_to1 = false(num_segments1, num_segments2); 112 | % for i = 1:num_segments2 113 | % matches1_to2(:,i) = segment_indices1_to2 == segment_indices2(i); 114 | % matches2_to1(:,i) = segment_indices1 == segment_indices2_to1(i); 115 | % end 116 | % segment_matches1_to2 = segment_matches1_to2 | matches1_to2; 117 | % segment_matches2_to1 = segment_matches2_to1 | matches2_to1; 118 | 119 | common_segment_indices2 = segment_indices2(camera2_common_point_flags); 120 | common_segment_indices1 = segment_indices1(camera1_common_point_flags); 121 | 122 | 123 | 124 | common_segment_indices2 = [common_segment_indices2 inlier_common_segment_indices2{seg_idx}]; 125 | common_segment_indices1 = [common_segment_indices1 inlier_common_segment_indices1{seg_idx}]; 126 | 127 | 128 | 129 | [nearby_indices1_to2, near_common1_to2, near_common2] = find_nearby_indices(... 130 | segment_indices1_to2, segment_indices2,... 131 | camera_observation_segments{cam_idx2}{seg_idx}.max_num_segments,... 132 | num_segments1, common_segment_indices2); 133 | [nearby_indices2_to1, near_common1, near_common2_to1] = find_nearby_indices(... 134 | segment_indices1, segment_indices2_to1,... 135 | camera_observation_segments{cam_idx1}{seg_idx}.max_num_segments,... 136 | num_segments1, common_segment_indices1); 137 | 138 | %nearby_ind1_to2 = sub2ind(size(segment_matches1_to2),... 139 | % nearby_indices1_to2(:,1), nearby_indices1_to2(:,2)); 140 | %nearby_ind2_to1 = sub2ind(size(segment_matches2_to1),... 141 | % nearby_indices2_to1(:,1), nearby_indices2_to1(:,2)); 142 | 143 | segment_matches1_to2(nearby_indices1_to2) = true; 144 | segment_matches2_to1(nearby_indices2_to1) = true; 145 | 146 | %near_common1_to2 = ismember(segment_indices1_to2, common_segment_indices2); 147 | %near_common2 = ismember(segment_indices2, common_segment_indices2); 148 | %near_common1 = ismember(segment_indices1, common_segment_indices1); 149 | %near_common2_to1 = ismember(segment_indices2_to1, common_segment_indices1); 150 | 151 | segments_near_common1 = segments_near_common1 | near_common1; 152 | segments_near_common2 = segments_near_common2 | near_common2; 153 | segments_near_common1_to2 = segments_near_common1_to2 | near_common1_to2; 154 | segments_near_common2_to1 = segments_near_common2_to1 | near_common2_to1; 155 | end 156 | 157 | segment_matches1_to2(segments_near_common1_to2, :) = false; 158 | segment_matches1_to2(:, segments_near_common2) = false; 159 | segment_matches2_to1(segments_near_common1, :) = false; 160 | segment_matches2_to1(:, segments_near_common2_to1) = false; 161 | 162 | segment_matches1_to2(~camera1_unique_point_flags, :) = false; 163 | segment_matches2_to1(~camera1_unique_point_flags, :) = false; 164 | segment_matches1_to2(:, ~camera2_unique_point_flags) = false; 165 | segment_matches2_to1(:, ~camera2_unique_point_flags) = false; 166 | 167 | % The valid flags will be the same for all segmentations 168 | segment_indices1_valid = camera_observation_segments{cam_idx1}{1}.valid_flags; 169 | segment_indices2_valid = camera_observation_segments{cam_idx2}{1}.valid_flags; 170 | segment_indices1_to2_valid = valid_flags1_to2; 171 | segment_indices2_to1_valid = valid_flags2_to1; 172 | 173 | segment_matches1_to2(~segment_indices1_to2_valid, :) = false; 174 | segment_matches1_to2(:, ~segment_indices2_valid) = false; 175 | segment_matches2_to1(~segment_indices1_valid, :) = false; 176 | segment_matches1_to2(:, ~segment_indices2_to1_valid) = false; 177 | 178 | camera1_point_indices1 = camera1_point_indices(any(segment_matches1_to2, 2)); 179 | camera1_point_indices2 = camera1_point_indices(any(segment_matches2_to1, 2)); 180 | camera2_point_indices1 = camera2_point_indices(any(segment_matches1_to2, 1)); 181 | camera2_point_indices2 = camera2_point_indices(any(segment_matches2_to1, 1)); 182 | 183 | % We can assume that camera1_point_indices2 and camera2_point_indices2 are sorted 184 | conflicting_indices1 =... 185 | camera1_point_indices1(ismembc(camera1_point_indices1, camera1_point_indices2)); 186 | conflicting_indices2 =... 187 | camera2_point_indices1(ismembc(camera2_point_indices1, camera2_point_indices2)); 188 | %conflicting_indices1 = intersect(camera1_point_indices1, camera1_point_indices2); 189 | %conflicting_indices2 = intersect(camera2_point_indices1, camera2_point_indices2); 190 | 191 | if ~isempty(image_folder) && ~isempty(conflicting_indices1) && ~isempty(conflicting_indices2) 192 | img1 = rgb2gray(imread([image_folder '/' camera_data.names{cam_idx1} '.jpg'])); 193 | img2 = rgb2gray(imread([image_folder '/' camera_data.names{cam_idx2} '.jpg'])); 194 | 195 | [h1, w1] = size(img1); 196 | [h2, w2] = size(img2); 197 | 198 | new_h = min(h1, h2); 199 | 200 | scale1 = new_h / h1; 201 | scale2 = new_h / h2; 202 | 203 | new_w1 = round(scale1 * w1); 204 | new_w2 = round(scale2 * w2); 205 | 206 | if h1 ~= new_h 207 | img1 = imresize(img1, [new_h, new_w1]); 208 | end 209 | if h2 ~= new_h 210 | img2 = imresize(img2, [new_h, new_w2]); 211 | end 212 | 213 | new_img = [img1 img2]; 214 | 215 | imshow(new_img); 216 | hold on 217 | 218 | title_text = sprintf('cams: %d - %d, num conflicting points: %d - %d',... 219 | cam_idx1, cam_idx2, length(conflicting_indices1), length(conflicting_indices2)); 220 | title(title_text) 221 | 222 | % Plot common points 223 | common_flags1 = camera1_common_point_flags & segment_indices1_valid; 224 | common_flags2 = camera2_common_point_flags & segment_indices2_valid; 225 | common_locations1 = camera_observations{cam_idx1}.locations_2d(:,common_flags1); 226 | common_locations2 = camera_observations{cam_idx2}.locations_2d(:,common_flags2); 227 | plot(scale1 * common_locations1(1,:), scale1 * common_locations1(2,:), '.g'); 228 | plot(new_w1 + scale2 * common_locations2(1,:), scale2 * common_locations2(2,:), '.g'); 229 | 230 | % Plot camera 1's unique points 231 | unique_flags1 = camera1_unique_point_flags & ~segments_near_common1 & ~segments_near_common1_to2; 232 | unique_locations1 = camera_observations{cam_idx1}.locations_2d(:,unique_flags1); 233 | unique_locations1_2 = projected_points.points1_projected_to2(:,unique_flags1 & segment_indices1_to2_valid); 234 | plot(scale1 * unique_locations1(1,:), scale1 * unique_locations1(2,:), '.r'); 235 | plot(new_w1 + scale2 * unique_locations1_2(1,:), scale2 * unique_locations1_2(2,:), '.r'); 236 | val1 = sum(scale1 * unique_locations1(1,:) < -10); 237 | val2 = sum(scale2 * unique_locations1_2(1,:) < 10); 238 | if val1 > 0 239 | disp(['val1: ' num2str(val1)]) 240 | end 241 | if val2 > 0 242 | disp(['val2: ' num2str(val2)]) 243 | end 244 | 245 | % Plot camera 2's unique points 246 | unique_flags2 = camera2_unique_point_flags & ~segments_near_common2 & ~segments_near_common2_to1; 247 | unique_locations2 = camera_observations{cam_idx2}.locations_2d(:,unique_flags2); 248 | unique_locations2_1 = projected_points.points2_projected_to1(:,unique_flags2 & segment_indices2_to1_valid); 249 | plot(new_w1 + scale2 * unique_locations2(1,:), scale2 * unique_locations2(2,:), '.b'); 250 | plot(scale1 * unique_locations2_1(1,:), scale1 * unique_locations2_1(2,:), '.b'); 251 | val3 = sum(scale1 * unique_locations2(1,:) < -10); 252 | val4 = sum(scale2 * unique_locations2_1(1,:) < 10); 253 | if val3 > 0 254 | disp(['val3: ' num2str(val1)]) 255 | end 256 | if val4 > 0 257 | disp(['val4: ' num2str(val2)]) 258 | end 259 | 260 | 261 | 262 | if ~isempty(locations2d_1) 263 | plot(scale1 * locations2d_1(1,:), scale1 * locations2d_1(2,:), '+y', 'MarkerSize', 2); 264 | plot(new_w1 + scale2 * locations2d_2(1,:), scale2 * locations2d_2(2,:), '+y', 'MarkerSize', 2); 265 | end 266 | 267 | 268 | 269 | hold off 270 | waitforbuttonpress 271 | end 272 | 273 | end % function 274 | -------------------------------------------------------------------------------- /matlab/code/compute_connected_camera_matrix.m: -------------------------------------------------------------------------------- 1 | function [connected_camera_matrix] = compute_connected_camera_matrix(... 2 | visibility_matrix, min_common_points_for_connection) 3 | 4 | num_cameras = size(visibility_matrix, 1); 5 | 6 | connected_camera_matrix = false(num_cameras, num_cameras); 7 | 8 | for cam_idx1 = 1:num_cameras-1 9 | for cam_idx2 = cam_idx1+1:num_cameras 10 | visible_points1 = visibility_matrix(cam_idx1, :); 11 | visible_points2 = visibility_matrix(cam_idx2, :); 12 | 13 | if sum(visible_points1 & visible_points2) >= min_common_points_for_connection 14 | connected_camera_matrix(cam_idx1, cam_idx2) = true; 15 | connected_camera_matrix(cam_idx2, cam_idx1) = true; 16 | end 17 | end 18 | %disp(cam_idx1) 19 | end 20 | 21 | end 22 | -------------------------------------------------------------------------------- /matlab/code/compute_connected_camera_matrix2.m: -------------------------------------------------------------------------------- 1 | function [connected_camera_matrix] = compute_connected_camera_matrix2(... 2 | camera_observations, min_common_points_for_connection) 3 | 4 | num_cameras = length(camera_observations); 5 | connected_camera_matrix = false(num_cameras, num_cameras); 6 | 7 | init_matlabpool(12); 8 | 9 | num_tasks = (num_cameras * (num_cameras - 1)) / 2; 10 | linear_valid_connections = false(num_tasks, 1); 11 | camera_indices = zeros(num_tasks, 2); 12 | 13 | idx = 1; 14 | for cam_idx1 = 1:num_cameras-1 15 | for cam_idx2 = cam_idx1+1:num_cameras 16 | camera_indices(idx,:) = [cam_idx1, cam_idx2]; 17 | idx = idx + 1; 18 | end 19 | end 20 | 21 | parfor task_idx = 1:num_tasks 22 | cam1 = camera_indices(task_idx, 1); 23 | cam2 = camera_indices(task_idx, 2); 24 | 25 | points1 = camera_observations{cam1}.point_indices; 26 | points2 = camera_observations{cam2}.point_indices; 27 | 28 | % We assume that points_indices1 and point_indices2 are sorted. 29 | intersect_size = sum(ismembc(points1, points2)); 30 | 31 | linear_valid_connections(task_idx) = intersect_size >= min_common_points_for_connection; 32 | end 33 | 34 | idx = 1; 35 | for cam_idx1 = 1:num_cameras-1 36 | for cam_idx2 = cam_idx1+1:num_cameras 37 | if linear_valid_connections(idx) 38 | connected_camera_matrix(cam_idx1, cam_idx2) = true; 39 | connected_camera_matrix(cam_idx2, cam_idx1) = true; 40 | end 41 | idx = idx + 1; 42 | end 43 | end 44 | 45 | % for cam_idx1 = 1:num_cameras-1 46 | % for cam_idx2 = cam_idx1+1:num_cameras 47 | % points1 = camera_observations{cam_idx1}.point_indices; 48 | % points2 = camera_observations{cam_idx2}.point_indices; 49 | % 50 | % %intersect_size = length(intersect(points1, points2)); 51 | % 52 | % % We assume that points1 and points2 are sorted 53 | % intersect_size = sum(ismembc(points1, points2)); 54 | % 55 | % if intersect_size >= min_common_points_for_connection 56 | % connected_camera_matrix(cam_idx1, cam_idx2) = true; 57 | % connected_camera_matrix(cam_idx2, cam_idx1) = true; 58 | % end 59 | % end 60 | % end 61 | 62 | end 63 | -------------------------------------------------------------------------------- /matlab/code/compute_distance_threshold_3d.m: -------------------------------------------------------------------------------- 1 | function [distance_threshold_3d] = compute_distance_threshold_3d(... 2 | camera_data, point_data, percentage) 3 | 4 | points = [camera_data.centers point_data.xyzs]; 5 | mean_point = mean(points, 2); 6 | 7 | num_points = size(points, 2); 8 | 9 | diff = points - repmat(mean_point, 1, num_points); 10 | diff = diff .^ 2; 11 | diff = sum(diff, 1); 12 | diff = sqrt(diff); 13 | 14 | val = prctile(diff, 90); 15 | 16 | distance_threshold_3d = val * percentage; 17 | 18 | end 19 | -------------------------------------------------------------------------------- /matlab/code/compute_edge_conflict2.m: -------------------------------------------------------------------------------- 1 | function [edge_conflict, num_split_cameras] = compute_edge_conflict2(... 2 | split_camera_task, camera_observations, camera_observation_segments, camera_pair_segments,... 3 | visibility_matrix, image_folder, camera_data) 4 | 5 | if ~exist('image_folder', 'var') 6 | image_folder = ''; 7 | camera_data = []; 8 | end 9 | 10 | split_camera_pairs = split_camera_task.camera_pairs; 11 | group_assignments = split_camera_task.group_assignments; 12 | 13 | num_split_camera_pairs = size(split_camera_pairs, 1); 14 | 15 | num_split_cameras = num_split_camera_pairs; 16 | if num_split_camera_pairs == 0 17 | edge_conflict = 0; 18 | return 19 | end 20 | 21 | split_cameras_conflict = zeros(num_split_camera_pairs, 1); 22 | 23 | for pair_idx = 1:num_split_camera_pairs 24 | cam_idx1 = split_camera_pairs(pair_idx, 1); 25 | cam_idx2 = split_camera_pairs(pair_idx, 2); 26 | 27 | index = find(... 28 | camera_pair_segments.camera_pairs(:,1) == cam_idx1 &... 29 | camera_pair_segments.camera_pairs(:,2) == cam_idx2); 30 | 31 | [conflicting_indices1, conflicting_indices2] = compute_conflicting_indices2(... 32 | camera_observations, camera_observation_segments,... 33 | camera_pair_segments.pair_data{index},... 34 | camera_pair_segments.valid_flags1_to2{index},... 35 | camera_pair_segments.valid_flags2_to1{index},... 36 | camera_pair_segments.projected_points{index}, visibility_matrix,... 37 | group_assignments, cam_idx1, cam_idx2, image_folder, camera_data); 38 | 39 | %split_cameras_conflict(i) =... 40 | % length(conflicting_indices1) + length(conflicting_indices2); 41 | split_cameras_conflict(pair_idx) =... 42 | min(length(conflicting_indices1), length(conflicting_indices2)); 43 | end 44 | 45 | edge_conflict = mean(split_cameras_conflict); 46 | 47 | end % function 48 | -------------------------------------------------------------------------------- /matlab/code/compute_edge_conflict2_merging.m: -------------------------------------------------------------------------------- 1 | function [edge_conflict, num_split_cameras] = compute_edge_conflict2_merging(... 2 | split_camera_task, camera_observations, camera_observation_segments, camera_pair_segments,... 3 | visibility_matrix, all_inlier_matches, all_inlier_matches_camera_indices,... 4 | segmentation_folder, camera_data, image_folder) 5 | 6 | if ~exist('image_folder', 'var') 7 | image_folder = ''; 8 | end 9 | 10 | split_camera_pairs = split_camera_task.camera_pairs; 11 | group_assignments = split_camera_task.group_assignments; 12 | 13 | num_split_camera_pairs = size(split_camera_pairs, 1); 14 | 15 | num_split_cameras = num_split_camera_pairs; 16 | if num_split_camera_pairs == 0 17 | edge_conflict = 0; 18 | return 19 | end 20 | 21 | split_cameras_conflict = zeros(num_split_camera_pairs, 1); 22 | 23 | init_matlabpool(12); 24 | 25 | progress = ParforProgMon('Camera Segments: ', num_split_camera_pairs, 1, 300, 80); 26 | 27 | parfor pair_idx = 1:num_split_camera_pairs 28 | cam_idx1 = split_camera_pairs(pair_idx, 1); 29 | cam_idx2 = split_camera_pairs(pair_idx, 2); 30 | 31 | index = find(... 32 | camera_pair_segments.camera_pairs(:,1) == cam_idx1 &... 33 | camera_pair_segments.camera_pairs(:,2) == cam_idx2); 34 | 35 | [conflicting_indices1, conflicting_indices2] = compute_conflicting_indices2_merging(... 36 | camera_observations, camera_observation_segments,... 37 | camera_pair_segments.pair_data{index},... 38 | camera_pair_segments.valid_flags1_to2{index},... 39 | camera_pair_segments.valid_flags2_to1{index},... 40 | camera_pair_segments.projected_points{index}, visibility_matrix,... 41 | group_assignments, cam_idx1, cam_idx2,... 42 | all_inlier_matches, all_inlier_matches_camera_indices,... 43 | segmentation_folder, camera_data, image_folder); 44 | 45 | %split_cameras_conflict(i) =... 46 | % length(conflicting_indices1) + length(conflicting_indices2); 47 | split_cameras_conflict(pair_idx) =... 48 | min(length(conflicting_indices1), length(conflicting_indices2)); 49 | 50 | progress.increment(); 51 | end 52 | 53 | progress.delete(); 54 | 55 | edge_conflict = mean(split_cameras_conflict); 56 | 57 | end % function 58 | -------------------------------------------------------------------------------- /matlab/code/compute_group_sizes.m: -------------------------------------------------------------------------------- 1 | function [group_sizes] = compute_group_sizes(group_assignments) 2 | 3 | num_groups = max(group_assignments); 4 | group_sizes = zeros(num_groups, 1); 5 | for i = 1:num_groups 6 | group_sizes(i) = sum(group_assignments == i); 7 | end 8 | 9 | end 10 | -------------------------------------------------------------------------------- /matlab/code/compute_image_segmentations.m: -------------------------------------------------------------------------------- 1 | function [] = compute_image_segmentations(... 2 | camera_data, image_folder, segmentation_folder, segmentation_exe) 3 | 4 | if ~exist(segmentation_folder, 'dir') 5 | mkdir(segmentation_folder) 6 | end 7 | 8 | init_matlabpool(12); 9 | 10 | progress = ParforProgMon('Segmentation: ', camera_data.num_cameras, 1, 300, 80); 11 | 12 | num_superpixels = 100; 13 | num_transforms = 8; 14 | 15 | parfor cam_idx = 1:camera_data.num_cameras 16 | width = camera_data.dimensions(1, cam_idx); 17 | height = camera_data.dimensions(2, cam_idx); 18 | img = imread([image_folder '/' camera_data.names{cam_idx} '.jpg']); 19 | if size(img, 3) == 3 20 | gray = rgb2gray(img); 21 | else 22 | gray = img; 23 | end 24 | 25 | for trans_idx = 1:num_transforms 26 | 27 | segmentation_png_name = [segmentation_folder '/' camera_data.names{cam_idx}... 28 | '_seg_' num2str(num_superpixels) '_' num2str(trans_idx) '.png']; 29 | 30 | if ~exist(segmentation_png_name, 'file') 31 | transformed_img = transform_image(img, trans_idx); 32 | image_path = [segmentation_folder '/' camera_data.names{cam_idx} '_trans.jpg']; 33 | imwrite(transformed_img, image_path); 34 | 35 | system([segmentation_exe ' ' image_path ' ' num2str(num_superpixels)]); 36 | 37 | trans_width = size(transformed_img, 2); 38 | trans_height = size(transformed_img, 1); 39 | 40 | dat_path = [segmentation_folder '/' camera_data.names{cam_idx} '_trans.dat']; 41 | file = fopen(dat_path, 'r'); 42 | segmentation = fread(file, trans_width * trans_height, 'int'); 43 | fclose(file); 44 | delete(dat_path); 45 | delete(image_path); 46 | 47 | segmentation = reshape(segmentation, trans_width, trans_height)'; 48 | segmentation = undo_transform_image(segmentation, trans_idx); 49 | segmentation = uint8(segmentation); 50 | 51 | imwrite(segmentation, segmentation_png_name); 52 | 53 | subset = segmentation(2:height-1, 2:width-1); 54 | boundary = false(height, width); 55 | boundary(2:height-1, 2:width-1) = boundary(2:height-1, 2:width-1) |... 56 | subset ~= segmentation(1:height-2, 2:width-1); 57 | boundary(2:height-1, 2:width-1) = boundary(2:height-1, 2:width-1) |... 58 | subset ~= segmentation(3:height, 2:width-1); 59 | boundary(2:height-1, 2:width-1) = boundary(2:height-1, 2:width-1) |... 60 | subset ~= segmentation(2:height-1, 1:width-2); 61 | boundary(2:height-1, 2:width-1) = boundary(2:height-1, 2:width-1) |... 62 | subset ~= segmentation(2:height-1, 3:width); 63 | 64 | img_copy = gray; 65 | img_copy(boundary) = 255; 66 | imwrite(img_copy, [segmentation_folder '/' camera_data.names{cam_idx}... 67 | '_seg_' num2str(num_superpixels) '_' num2str(trans_idx) '.jpg']); 68 | end 69 | end 70 | 71 | progress.increment(); 72 | end 73 | progress.delete(); 74 | 75 | end % function 76 | 77 | function [img] = transform_image(img, transform_num) 78 | if size(img,3) == 3 79 | img1 = transform_image(img(:,:,1), transform_num); 80 | img2 = transform_image(img(:,:,2), transform_num); 81 | img3 = transform_image(img(:,:,3), transform_num); 82 | img = cat(3, img1, img2, img3); 83 | return 84 | end 85 | 86 | switch transform_num 87 | case 1 88 | return 89 | case 2 90 | img = rot90(img); 91 | case 3 92 | img = rot90(img, 2); 93 | case 4 94 | img = rot90(img, 3); 95 | case 5 96 | img = fliplr(img); 97 | case 6 98 | img = rot90(img); 99 | img = fliplr(img); 100 | case 7 101 | img = rot90(img, 2); 102 | img = fliplr(img); 103 | case 8 104 | img = rot90(img, 3); 105 | img = fliplr(img); 106 | otherwise 107 | disp('ERROR: invalid transform num') 108 | end 109 | end % function 110 | 111 | function [img] = undo_transform_image(img, transform_num) 112 | switch transform_num 113 | case 1 114 | return 115 | case 2 116 | img = rot90(img, 3); 117 | case 3 118 | img = rot90(img, 2); 119 | case 4 120 | img = rot90(img); 121 | case 5 122 | img = fliplr(img); 123 | case 6 124 | img = fliplr(img); 125 | img = rot90(img, 3); 126 | case 7 127 | img = fliplr(img); 128 | img = rot90(img, 2); 129 | case 8 130 | img = fliplr(img); 131 | img = rot90(img); 132 | otherwise 133 | disp('ERROR: invalid transform num') 134 | end 135 | end % function 136 | -------------------------------------------------------------------------------- /matlab/code/compute_similarity_inliers.m: -------------------------------------------------------------------------------- 1 | function [inliers, similarity] = compute_similarity_inliers(similarity, data, threshold) 2 | 3 | if isempty(similarity) 4 | inliers = false(1, size(data, 2)); 5 | return 6 | end 7 | 8 | left_points = data(1:3, :); 9 | right_points = data(4:6, :); 10 | 11 | N = size(left_points, 2); 12 | 13 | new_left_points = similarity * [left_points; ones(1, N)]; 14 | 15 | diff = right_points - new_left_points; 16 | diff = diff .^ 2; 17 | diff = sum(diff, 1); 18 | diff = sqrt(diff); 19 | 20 | inliers = find(diff <= threshold); 21 | 22 | end 23 | -------------------------------------------------------------------------------- /matlab/code/compute_spanning_tree_conflict2.m: -------------------------------------------------------------------------------- 1 | function [edge_conflict] = compute_spanning_tree_conflict2(... 2 | split_camera_tasks, camera_observations, camera_observation_segments,... 3 | camera_pair_segments, visibility_matrix, image_folder, camera_data) 4 | 5 | num_edges = length(split_camera_tasks); 6 | edge_conflict = zeros(num_edges, 1); 7 | 8 | num_cameras = length(camera_observation_segments); 9 | 10 | init_matlabpool(12); 11 | %init_matlabpool(6); 12 | 13 | progress = ParforProgMon('Conflict: ', num_edges, 1, 300, 80); 14 | 15 | %debug_edge_idx = 7;%find_edge_index(camera_tree, 6, 15); 16 | %debug_overlap = true; 17 | debug_overlap = false; 18 | 19 | parfor edge_idx = 1:num_edges 20 | %for edge_idx = debug_edge_idx 21 | 22 | if debug_overlap 23 | conflict = compute_edge_conflict2(... 24 | split_camera_tasks{edge_idx}, camera_observations, camera_observation_segments,... 25 | camera_pair_segments, visibility_matrix, image_folder, camera_data); 26 | edge_conflict(edge_idx) = conflict; 27 | else 28 | conflict = compute_edge_conflict2(... 29 | split_camera_tasks{edge_idx}, camera_observations, camera_observation_segments,... 30 | camera_pair_segments, visibility_matrix); 31 | edge_conflict(edge_idx) = conflict; 32 | end 33 | 34 | progress.increment(); 35 | end 36 | 37 | progress.delete() 38 | 39 | end % function 40 | -------------------------------------------------------------------------------- /matlab/code/compute_split_group_assignments.m: -------------------------------------------------------------------------------- 1 | function [split_group_assignments] = compute_split_group_assignments(... 2 | split_camera_trees) 3 | 4 | split_group_assignments = zeros(1, size(split_camera_trees{1},1)); 5 | 6 | num_trees = length(split_camera_trees); 7 | for tree_idx = 1:num_trees 8 | [num_groups, group_assignments] = graphconncomp(... 9 | split_camera_trees{tree_idx}, 'Directed', false); 10 | group_sizes = compute_group_sizes(group_assignments); 11 | if sum(group_sizes > 1) > 1 12 | disp('ERROR: more than one group with size greater than 1.') 13 | return 14 | end 15 | [max_group_size, max_group_idx] = max(group_sizes); 16 | if max_group_size == 1 17 | disp('Warning: group of size 1.') 18 | end 19 | valid_cameras = group_assignments == max_group_idx; 20 | if any(valid_cameras & (split_group_assignments > 0)) 21 | disp('ERROR: assigning camera to 2 or more groups') 22 | return 23 | end 24 | split_group_assignments(valid_cameras) = tree_idx; 25 | end 26 | 27 | if any(split_group_assignments == 0) 28 | disp('ERROR: 1 or more cameras not assigned to a group') 29 | end 30 | 31 | end % function 32 | -------------------------------------------------------------------------------- /matlab/code/create_camera_observations.m: -------------------------------------------------------------------------------- 1 | function [camera_observations] = create_camera_observations(... 2 | point_observations, visibility_matrix) 3 | 4 | num_cameras = size(visibility_matrix, 1); 5 | 6 | camera_observations = cell(1, num_cameras); 7 | 8 | num_observations_per_camera = sum(visibility_matrix, 2); 9 | 10 | for cam_idx = 1:num_cameras 11 | num_observations = num_observations_per_camera(cam_idx); 12 | camera_observations{cam_idx} = struct(... 13 | 'num_observations', 0,... 14 | 'point_indices', zeros(1, num_observations, 'int32'),... 15 | 'feature_indices', zeros(1, num_observations, 'int32'),... 16 | 'locations_2d', zeros(2, num_observations, 'single')); 17 | end 18 | 19 | for point_idx = 1:length(point_observations) 20 | for observe_idx = 1:point_observations{point_idx}.num_observations 21 | cam_idx = point_observations{point_idx}.camera_indices(observe_idx); 22 | feature_idx = point_observations{point_idx}.feature_indices(observe_idx); 23 | location_2d = point_observations{point_idx}.locations_2d(:, observe_idx); 24 | 25 | % We have found a new observation for this camera, so increment the 26 | % number of observations found so far for this camera (this count starts 27 | % at 0). 28 | num_observations = camera_observations{cam_idx}.num_observations + 1; 29 | camera_observations{cam_idx}.num_observations = num_observations; 30 | 31 | camera_observations{cam_idx}.point_indices(num_observations) = point_idx; 32 | camera_observations{cam_idx}.feature_indices(num_observations) = feature_idx; 33 | camera_observations{cam_idx}.locations_2d(:,num_observations) = location_2d; 34 | end 35 | end 36 | 37 | for cam_idx = 1:num_cameras 38 | if length(camera_observations{cam_idx}.point_indices) ~=... 39 | camera_observations{cam_idx}.num_observations 40 | disp('ERROR: num_observations does not agree') 41 | end 42 | end 43 | 44 | end % function 45 | -------------------------------------------------------------------------------- /matlab/code/create_point_observations.m: -------------------------------------------------------------------------------- 1 | function [point_observations] = create_point_observations(camera_observations, num_points) 2 | 3 | point_observations = cell(1,num_points); 4 | for i = 1:num_points 5 | point_observations{i} = struct(... 6 | 'num_observations', 0,... 7 | 'camera_indices', [],... 8 | 'feature_indices', [],... 9 | 'locations_2d', []); 10 | end 11 | 12 | for cam_idx = 1:length(camera_observations) 13 | for i = 1:length(camera_observations{cam_idx}.point_indices) 14 | pt_idx = camera_observations{cam_idx}.point_indices(i); 15 | 16 | num = point_observations{pt_idx}.num_observations + 1; 17 | point_observations{pt_idx}.num_observations = num; 18 | 19 | point_observations{pt_idx}.camera_indices(num) = cam_idx; 20 | point_observations{pt_idx}.feature_indices(num) =... 21 | camera_observations{cam_idx}.feature_indices(i); 22 | point_observations{pt_idx}.locations_2d(:,num) =... 23 | camera_observations{cam_idx}.locations_2d(:,i); 24 | end 25 | end 26 | 27 | end % function 28 | -------------------------------------------------------------------------------- /matlab/code/create_thumbnails.m: -------------------------------------------------------------------------------- 1 | function [] = create_thumbnails(camera_data, image_folder, thumbnail_folder, thumbnail_size) 2 | 3 | if ~exist(thumbnail_folder, 'dir') 4 | mkdir(thumbnail_folder); 5 | end 6 | 7 | for i = 1:camera_data.num_cameras 8 | thumbnail_path = [thumbnail_folder '/' camera_data.names{i} '.jpg']; 9 | if ~exist(thumbnail_path, 'file') 10 | img = imread([image_folder '/' camera_data.names{i} '.jpg']); 11 | scale = thumbnail_size / max(size(img,1), size(img,2)); 12 | thumbnail = imresize(img, scale); 13 | imwrite(thumbnail, thumbnail_path); 14 | end 15 | end 16 | 17 | end 18 | -------------------------------------------------------------------------------- /matlab/code/create_visibility_matrix.m: -------------------------------------------------------------------------------- 1 | function [visibility_matrix] = create_visibility_matrix(... 2 | point_observations, camera_data, point_data) 3 | 4 | visibility_matrix = false(camera_data.num_cameras, point_data.num_points); 5 | 6 | for point_idx = 1:length(point_observations) 7 | camera_indices = point_observations{point_idx}.camera_indices; 8 | visibility_matrix(camera_indices, point_idx) = true; 9 | end 10 | 11 | end % function 12 | -------------------------------------------------------------------------------- /matlab/code/edge_label_baseline_angle_class.m: -------------------------------------------------------------------------------- 1 | classdef edge_label_baseline_angle_class 2 | 3 | % Properties 4 | properties(SetAccess = private) 5 | camera_data = 0; 6 | point_data = 0; 7 | visibility_matrix = 0; 8 | end 9 | 10 | % Methods 11 | methods 12 | function [obj] = edge_label_baseline_angle_class(camera_data, point_data, visibility_matrix) 13 | obj.camera_data = camera_data; 14 | obj.point_data = point_data; 15 | obj.visibility_matrix = visibility_matrix; 16 | end 17 | 18 | function [str, important] = label(obj, cam_idx1, cam_idx2) 19 | angle = compute_baseline_angle_between_cameras(... 20 | cam_idx1, cam_idx2, obj.camera_data, obj.point_data, obj.visibility_matrix); 21 | str = sprintf('angle: %.1f', angle); 22 | important = false; 23 | end 24 | end 25 | 26 | end 27 | -------------------------------------------------------------------------------- /matlab/code/edge_label_conflict_class.m: -------------------------------------------------------------------------------- 1 | classdef edge_label_conflict_class 2 | 3 | % Properties 4 | properties(SetAccess = private) 5 | camera_tree = []; 6 | edge_conflict = []; 7 | sorted_conflict_indices = []; 8 | end % properties 9 | 10 | % Methods 11 | methods 12 | function [obj] = edge_label_conflict_class(camera_tree, edge_conflict) 13 | obj.camera_tree = camera_tree; 14 | obj.edge_conflict = edge_conflict; 15 | [~, obj.sorted_conflict_indices] = sort(edge_conflict, 'descend'); 16 | end 17 | 18 | function [str, important] = label(obj, cam_idx1, cam_idx2) 19 | edge_idx = find_edge_index(obj.camera_tree, cam_idx1, cam_idx2); 20 | conflict = obj.edge_conflict(edge_idx); 21 | if conflict == 0 22 | str = ''; 23 | else 24 | str = sprintf('conflict: %.2f', conflict); 25 | end 26 | if length(obj.sorted_conflict_indices) > 5 27 | important = any(obj.sorted_conflict_indices(1:5) == edge_idx); 28 | else 29 | important = obj.sorted_conflict_indices(1) == edge_idx; 30 | end 31 | end 32 | end % methods 33 | 34 | end % class 35 | -------------------------------------------------------------------------------- /matlab/code/enforce_n_view_points.m: -------------------------------------------------------------------------------- 1 | function [new_point_data, new_point_observations, new_visibility_matrix,... 2 | new_camera_observations, new_inlier_matches] = enforce_n_view_points(... 3 | point_data, point_observations, visibility_matrix,... 4 | camera_observations, inlier_matches, min_views_per_point) 5 | 6 | init_matlabpool(12); 7 | 8 | view_counts = sum(visibility_matrix, 1); 9 | valid_point_flags = view_counts >= min_views_per_point; 10 | valid_point_indices = int32(find(valid_point_flags)); 11 | 12 | old_num_points = length(view_counts); 13 | new_num_points = length(valid_point_indices); 14 | 15 | disp(['# Points: ' num2str(old_num_points) ' -> '... 16 | num2str(new_num_points)]) 17 | 18 | if old_num_points == new_num_points 19 | new_point_data = point_data; 20 | new_point_observations = point_observations; 21 | new_visibility_matrix = visibility_matrix; 22 | new_camera_observations = camera_observations; 23 | new_inlier_matches = inlier_matches; 24 | return 25 | end 26 | 27 | new_visibility_matrix = visibility_matrix(:, valid_point_flags); 28 | 29 | new_point_data = point_data; 30 | new_point_data.num_points = sum(valid_point_flags); 31 | new_point_data.xyzs = new_point_data.xyzs(:, valid_point_flags); 32 | new_point_data.rgbs = new_point_data.rgbs(:, valid_point_flags); 33 | 34 | new_point_observations = point_observations(valid_point_flags); 35 | 36 | new_camera_observations = camera_observations; 37 | parfor cam_idx = 1:length(new_camera_observations) 38 | % valid_point_indices is sorted so we can use ismembc and ismembc2 39 | 40 | flags = ismembc(new_camera_observations{cam_idx}.point_indices, valid_point_indices); 41 | indices = ismembc2(new_camera_observations{cam_idx}.point_indices, valid_point_indices); 42 | 43 | %[flags, indices] = ismember(... 44 | % new_camera_observations{cam_idx}.point_indices, valid_point_indices); 45 | 46 | indices = indices(flags); 47 | 48 | new_camera_observations{cam_idx}.num_observations = length(indices); 49 | new_camera_observations{cam_idx}.point_indices = indices; 50 | new_camera_observations{cam_idx}.feature_indices =... 51 | new_camera_observations{cam_idx}.feature_indices(flags); 52 | new_camera_observations{cam_idx}.locations_2d =... 53 | new_camera_observations{cam_idx}.locations_2d(:,flags); 54 | end 55 | 56 | old_num_inlier_matches = length(inlier_matches); 57 | new_inlier_matches = cell(1,old_num_inlier_matches); 58 | valid_inlier_matches_flags = false(1,old_num_inlier_matches); 59 | 60 | parfor idx = 1:old_num_inlier_matches 61 | % valid_point_indices is sorted so we can use ismembc and ismembc2 62 | 63 | flags1 = ismembc(inlier_matches{idx}.point_indices(1,:), valid_point_indices); 64 | flags2 = ismembc(inlier_matches{idx}.point_indices(2,:), valid_point_indices); 65 | 66 | % [flags1, indices1] = ismember(... 67 | % inlier_matches{idx}.point_indices(1,:), valid_point_indices); 68 | % [flags2, indices2] = ismember(... 69 | % inlier_matches{idx}.point_indices(2,:), valid_point_indices); 70 | 71 | % Find inlier matches that had both observations turn into 3-view points 72 | flags = flags1 & flags2; 73 | if ~any(flags) 74 | continue 75 | end 76 | 77 | valid_inlier_matches_flags(idx) = true; 78 | 79 | indices1 = ismembc2(inlier_matches{idx}.point_indices(1,:), valid_point_indices); 80 | indices2 = ismembc2(inlier_matches{idx}.point_indices(2,:), valid_point_indices); 81 | 82 | indices1 = indices1(flags); 83 | indices2 = indices2(flags); 84 | 85 | new_inlier_matches{idx} = struct(... 86 | 'camera_indices', inlier_matches{idx}.camera_indices,... 87 | 'num_matches', length(indices1),... 88 | 'feature_indices', inlier_matches{idx}.feature_indices(:,flags),... 89 | 'point_indices', [indices1; indices2],... 90 | 'locations_2d', inlier_matches{idx}.locations_2d(:,flags)); 91 | end 92 | 93 | new_inlier_matches = new_inlier_matches(valid_inlier_matches_flags); 94 | 95 | end % function 96 | -------------------------------------------------------------------------------- /matlab/code/enforce_n_view_points_no_inliers.m: -------------------------------------------------------------------------------- 1 | function [new_point_data, new_point_observations, new_visibility_matrix,... 2 | new_camera_observations] = enforce_n_view_points_no_inliers(... 3 | point_data, point_observations, visibility_matrix,... 4 | camera_observations, min_views_per_point) 5 | 6 | init_matlabpool(12); 7 | 8 | view_counts = sum(visibility_matrix, 1); 9 | valid_point_flags = view_counts >= min_views_per_point; 10 | valid_point_indices = int32(find(valid_point_flags)); 11 | 12 | old_num_points = length(view_counts); 13 | new_num_points = length(valid_point_indices); 14 | 15 | disp(['# Points: ' num2str(old_num_points) ' -> '... 16 | num2str(new_num_points)]) 17 | 18 | if old_num_points == new_num_points 19 | new_point_data = point_data; 20 | new_point_observations = point_observations; 21 | new_visibility_matrix = visibility_matrix; 22 | new_camera_observations = camera_observations; 23 | return 24 | end 25 | 26 | new_visibility_matrix = visibility_matrix(:, valid_point_flags); 27 | 28 | new_point_data = point_data; 29 | new_point_data.num_points = sum(valid_point_flags); 30 | new_point_data.xyzs = new_point_data.xyzs(:, valid_point_flags); 31 | 32 | disp('RGB disabled') 33 | %new_point_data.rgbs = new_point_data.rgbs(:, valid_point_flags); 34 | 35 | new_point_observations = point_observations(valid_point_flags); 36 | 37 | new_camera_observations = camera_observations; 38 | parfor cam_idx = 1:length(new_camera_observations) 39 | % valid_point_indices is sorted so we can use ismembc and ismembc2 40 | 41 | flags = ismembc(new_camera_observations{cam_idx}.point_indices, valid_point_indices); 42 | indices = ismembc2(new_camera_observations{cam_idx}.point_indices, valid_point_indices); 43 | 44 | %[flags, indices] = ismember(... 45 | % new_camera_observations{cam_idx}.point_indices, valid_point_indices); 46 | 47 | indices = indices(flags); 48 | 49 | new_camera_observations{cam_idx}.num_observations = length(indices); 50 | new_camera_observations{cam_idx}.point_indices = indices; 51 | new_camera_observations{cam_idx}.feature_indices =... 52 | new_camera_observations{cam_idx}.feature_indices(flags); 53 | new_camera_observations{cam_idx}.locations_2d =... 54 | new_camera_observations{cam_idx}.locations_2d(:,flags); 55 | end 56 | 57 | end % function 58 | -------------------------------------------------------------------------------- /matlab/code/find_disconnected_inlier_point_indices.m: -------------------------------------------------------------------------------- 1 | function [disconnected_inlier_point_indices, all_disconnected_inlier_point_indices] =... 2 | find_disconnected_inlier_point_indices(... 3 | disconnected_inliers, common_point_flags, group_assignments,... 4 | group_idx1, group_idx2) 5 | 6 | disconnected_inlier_point_indices = []; 7 | all_disconnected_inlier_point_indices = []; 8 | common_point_indices = find(common_point_flags); 9 | 10 | num_disconnected_inliers = length(disconnected_inliers); 11 | for idx = 1:num_disconnected_inliers 12 | cam_idx1 = disconnected_inliers{idx}.camera_indices(1); 13 | cam_idx2 = disconnected_inliers{idx}.camera_indices(2); 14 | 15 | assignment1 = group_assignments(cam_idx1); 16 | assignment2 = group_assignments(cam_idx2); 17 | 18 | if assignment1 == assignment2 19 | continue 20 | end 21 | 22 | if ~all([assignment1, assignment2] == [group_idx1, group_idx2]) &&... 23 | ~all([assignment1, assignment2] == [group_idx2, group_idx1]) 24 | continue 25 | end 26 | 27 | inlier_point_indices1 = disconnected_inliers{idx}.inlier_point_indices1; 28 | inlier_point_indices2 = disconnected_inliers{idx}.inlier_point_indices2; 29 | 30 | if assignment1 == group_idx1 31 | all_disconnected_inlier_point_indices =... 32 | [all_disconnected_inlier_point_indices [inlier_point_indices1; inlier_point_indices2]]; 33 | elseif assignment2 == group_idx1 34 | all_disconnected_inlier_point_indices =... 35 | [all_disconnected_inlier_point_indices [inlier_point_indices2; inlier_point_indices1]]; 36 | else 37 | disp('ERROR') 38 | end 39 | 40 | flags1 = ismember(inlier_point_indices1, common_point_indices); 41 | flags2 = ismember(inlier_point_indices2, common_point_indices); 42 | 43 | valid_flags = (~flags1) & (~flags2); 44 | 45 | if ~any(valid_flags) 46 | continue 47 | end 48 | 49 | inlier_point_indices1 = inlier_point_indices1(valid_flags); 50 | inlier_point_indices2 = inlier_point_indices2(valid_flags); 51 | 52 | if assignment1 == group_idx1 53 | disconnected_inlier_point_indices =... 54 | [disconnected_inlier_point_indices [inlier_point_indices1; inlier_point_indices2]]; 55 | elseif assignment2 == group_idx1 56 | disconnected_inlier_point_indices =... 57 | [disconnected_inlier_point_indices [inlier_point_indices2; inlier_point_indices1]]; 58 | else 59 | disp('ERROR') 60 | end 61 | end 62 | 63 | disconnected_inlier_point_indices = unique(disconnected_inlier_point_indices', 'rows'); 64 | disconnected_inlier_point_indices = disconnected_inlier_point_indices'; 65 | 66 | all_disconnected_inlier_point_indices = unique(all_disconnected_inlier_point_indices', 'rows'); 67 | all_disconnected_inlier_point_indices = all_disconnected_inlier_point_indices'; 68 | 69 | end % function 70 | -------------------------------------------------------------------------------- /matlab/code/find_disconnected_inliers.m: -------------------------------------------------------------------------------- 1 | function [disconnected_inliers] = find_disconnected_inliers(... 2 | inlier_matches, camera_observations, camera_data, image_folder) 3 | 4 | if ~exist('image_folder', 'var') 5 | image_folder = ''; 6 | end 7 | 8 | num_inlier_matches = length(inlier_matches); 9 | num_cameras = length(camera_observations); 10 | 11 | disconnected_inliers = {}; 12 | 13 | for inlier_match_idx = 1:num_inlier_matches 14 | cam_idx1 = inlier_matches{inlier_match_idx}.camera_indices(1); 15 | cam_idx2 = inlier_matches{inlier_match_idx}.camera_indices(2); 16 | 17 | if cam_idx1 > num_cameras || cam_idx2 > num_cameras 18 | continue 19 | end 20 | 21 | % Get the indices of the features that were inlier matches 22 | inlier_feature_indices1 = inlier_matches{inlier_match_idx}.feature_indices(1,:); 23 | inlier_feature_indices2 = inlier_matches{inlier_match_idx}.feature_indices(2,:); 24 | 25 | % Get the feature indices of the 3d points observed in each camera 26 | point_feature_indices1 = camera_observations{cam_idx1}.feature_indices; 27 | point_feature_indices2 = camera_observations{cam_idx2}.feature_indices; 28 | 29 | % Get the indices of the 3d points observed in each camera 30 | point_indices1 = camera_observations{cam_idx1}.point_indices; 31 | point_indices2 = camera_observations{cam_idx2}.point_indices; 32 | 33 | % Determine which inlier features turned into 3d points 34 | [inlier_flags1, inlier_indices1] = ismember(inlier_feature_indices1, point_feature_indices1); 35 | [inlier_flags2, inlier_indices2] = ismember(inlier_feature_indices2, point_feature_indices2); 36 | 37 | % Determine which inliers had both observations turn into 3d points 38 | inlier_flags = inlier_flags1 & inlier_flags2; 39 | 40 | if ~any(inlier_flags) 41 | continue 42 | end 43 | 44 | % Get the observation indices (index into the point_observation lists for a camera) 45 | % that were part of an inlier that had both observations turn into 3d points 46 | inlier_indices1 = inlier_indices1(inlier_flags); 47 | inlier_indices2 = inlier_indices2(inlier_flags); 48 | 49 | % Get the 3d point indices that belong to the inlier matches 50 | inlier_point_indices1 = point_indices1(inlier_indices1); 51 | inlier_point_indices2 = point_indices2(inlier_indices2); 52 | 53 | % Find inlier matches where the observations turned into separate 3d points 54 | not_equal_flags = inlier_point_indices1 ~= inlier_point_indices2; 55 | 56 | if ~any(not_equal_flags) 57 | continue 58 | end 59 | 60 | inlier_point_indices1 = inlier_point_indices1(not_equal_flags); 61 | inlier_point_indices2 = inlier_point_indices2(not_equal_flags); 62 | 63 | disconnected_inliers{end+1} = struct(... 64 | 'camera_indices', [cam_idx1 cam_idx2],... 65 | 'inlier_point_indices1', inlier_point_indices1,... 66 | 'inlier_point_indices2', inlier_point_indices2); 67 | 68 | if ~isempty(image_folder) 69 | img1 = rgb2gray(imread([image_folder '/' camera_data.names{cam_idx1} '.jpg'])); 70 | img2 = rgb2gray(imread([image_folder '/' camera_data.names{cam_idx2} '.jpg'])); 71 | 72 | locations1 = camera_observations{cam_idx1}.locations_2d; 73 | locations2 = camera_observations{cam_idx2}.locations_2d; 74 | 75 | flags1 = ismember(point_indices1, inlier_point_indices1); 76 | flags2 = ismember(point_indices2, inlier_point_indices2); 77 | 78 | locations1 = locations1(:,flags1); 79 | locations2 = locations2(:,flags2); 80 | 81 | subplot(2,1,1) 82 | imshow(img1) 83 | hold on 84 | plot(locations1(1,:), locations1(2,:), 'or', 'MarkerFaceColor', 'r', 'MarkerSize', 7); 85 | hold off 86 | 87 | subplot(2,1,2) 88 | imshow(img2) 89 | hold on 90 | plot(locations2(1,:), locations2(2,:), 'or', 'MarkerFaceColor', 'r', 'MarkerSize', 7); 91 | hold off 92 | 93 | waitforbuttonpress 94 | end 95 | end 96 | 97 | end % function 98 | -------------------------------------------------------------------------------- /matlab/code/find_edge_index.m: -------------------------------------------------------------------------------- 1 | function [edge_index] = find_edge_index(camera_tree, cam_idx1, cam_idx2) 2 | 3 | [cams1, cams2] = find(camera_tree); 4 | 5 | edge_index = find(... 6 | (cams1 == cam_idx1 | cams1 == cam_idx2) &... 7 | (cams2 == cam_idx1 | cams2 == cam_idx2)); 8 | 9 | end 10 | -------------------------------------------------------------------------------- /matlab/code/find_nearby_indices.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void mexFunction(int num_outputs, mxArray ** outputs, 5 | int num_inputs, const mxArray ** inputs) 6 | { 7 | if (num_inputs != 5) 8 | { 9 | mexErrMsgTxt("Expected 5 input arguments."); 10 | } 11 | if (num_outputs != 3) 12 | { 13 | mexErrMsgTxt("Expected 3 output argument."); 14 | } 15 | 16 | const mxArray * input_indices1 = inputs[0]; 17 | const mxArray * input_indices2 = inputs[1]; 18 | const mxArray * input_max_index = inputs[2]; 19 | const mxArray * input_mat_height = inputs[3]; 20 | const mxArray * input_common_segments = inputs[4]; 21 | 22 | const int num_indices1 = mxGetN(input_indices1); 23 | const int num_indices2 = mxGetN(input_indices2); 24 | const int num_common = mxGetN(input_common_segments); 25 | 26 | const char * indices1_ptr = (const char *)mxGetData(input_indices1); 27 | const char * indices2_ptr = (const char *)mxGetData(input_indices2); 28 | const double * max_index_ptr = (const double *)mxGetData(input_max_index); 29 | const double * mat_height_ptr = (const double *)mxGetData(input_mat_height); 30 | const char * common_segments_ptr = (const char *)mxGetData(input_common_segments); 31 | 32 | const int num_bins = static_cast(*max_index_ptr); 33 | const int mat_height = static_cast(*mat_height_ptr); 34 | 35 | std::vector > bins1; 36 | std::vector > bins2; 37 | bins1.resize(num_bins); 38 | bins2.resize(num_bins); 39 | 40 | std::vector common_bins; 41 | common_bins.resize(num_bins); 42 | 43 | for (int i = 0; i < num_bins; ++i) 44 | { 45 | common_bins[i] = false; 46 | } 47 | 48 | for (int i = 0; i < num_common; ++i) 49 | { 50 | const char bin = common_segments_ptr[i]; 51 | common_bins[bin] = true; 52 | } 53 | 54 | mxArray * output_near_common1 = mxCreateNumericMatrix(0, 0, mxLOGICAL_CLASS, mxREAL); 55 | mxSetM(output_near_common1, 1); 56 | mxSetN(output_near_common1, num_indices1); 57 | mxSetData(output_near_common1, mxMalloc(sizeof(bool) * num_indices1)); 58 | bool * output_near_common1_ptr = (bool *)mxGetData(output_near_common1); 59 | 60 | for (int i = 0; i < num_indices1; ++i) 61 | { 62 | const char bin = indices1_ptr[i]; 63 | if (bin >= 0) 64 | { 65 | /*if (bin < 0 || bin >= num_bins) 66 | { 67 | mexPrintf("%d / %d\n", bin, num_bins); 68 | mexErrMsgTxt("Bin out of range."); 69 | }*/ 70 | bins1[bin].push_back(i + 1); 71 | 72 | if (common_bins[bin]) 73 | { 74 | output_near_common1_ptr[i] = true; 75 | } 76 | else 77 | { 78 | output_near_common1_ptr[i] = false; 79 | } 80 | } 81 | else 82 | { 83 | output_near_common1_ptr[i] = false; 84 | } 85 | } 86 | 87 | mxArray * output_near_common2 = mxCreateNumericMatrix(0, 0, mxLOGICAL_CLASS, mxREAL); 88 | mxSetM(output_near_common2, 1); 89 | mxSetN(output_near_common2, num_indices2); 90 | mxSetData(output_near_common2, mxMalloc(sizeof(bool) * num_indices2)); 91 | bool * output_near_common2_ptr = (bool *)mxGetData(output_near_common2); 92 | 93 | for (int i = 0; i < num_indices2; ++i) 94 | { 95 | const char bin = indices2_ptr[i]; 96 | if (bin >= 0) 97 | { 98 | /*if (bin < 0 || bin >= num_bins) 99 | { 100 | mexPrintf("%d / %d\n", bin, num_bins); 101 | mexErrMsgTxt("Bin out of range."); 102 | }*/ 103 | bins2[bin].push_back(i + 1); 104 | if (common_bins[bin]) 105 | { 106 | output_near_common2_ptr[i] = true; 107 | } 108 | else 109 | { 110 | output_near_common2_ptr[i] = false; 111 | } 112 | } 113 | else 114 | { 115 | output_near_common2_ptr[i] = false; 116 | } 117 | } 118 | 119 | int num_results = 0; 120 | for (int i = 0; i < num_bins; ++i) 121 | { 122 | if (bins1[i].size() > 0 && bins2[i].size() > 0) 123 | { 124 | num_results += bins1[i].size() * bins2[i].size(); 125 | } 126 | } 127 | 128 | mxArray * output_indices = mxCreateNumericMatrix(0, 0, mxINT32_CLASS, mxREAL); 129 | mxSetM(output_indices, num_results); 130 | mxSetN(output_indices, 1); 131 | mxSetData(output_indices, mxMalloc(sizeof(int) * num_results)); 132 | 133 | int * output_ptr = (int *)mxGetData(output_indices); 134 | 135 | int idx = 0; 136 | for (int b = 0; b < num_bins; ++b) 137 | { 138 | const int size1 = bins1[b].size(); 139 | const int size2 = bins2[b].size(); 140 | if (size1 > 0 && size2 > 0) 141 | { 142 | for (int j = 0; j < size2; ++j) 143 | { 144 | for (int i = 0; i < size1; ++i) 145 | { 146 | output_ptr[idx] = bins1[b][i] + (bins2[b][j] - 1) * mat_height; 147 | ++idx; 148 | } 149 | } 150 | } 151 | } 152 | 153 | outputs[0] = output_indices; 154 | outputs[1] = output_near_common1; 155 | outputs[2] = output_near_common2; 156 | } 157 | -------------------------------------------------------------------------------- /matlab/code/find_split_cameras.m: -------------------------------------------------------------------------------- 1 | function [camera_pair_indices] = find_split_cameras(camera_pairs,... 2 | group_assignments, group_sizes, group_idx1, group_idx2) 3 | 4 | %num_camera_pairs = size(camera_pairs, 1); 5 | %camera_pair_flags = false(num_camera_pairs, 1); 6 | 7 | group_assignments(group_sizes < 2) = -1; 8 | camera_pair_assignments = group_assignments(camera_pairs); 9 | 10 | valid_flags1 =... 11 | camera_pair_assignments(:,1) ~= -1 &... 12 | camera_pair_assignments(:,2) ~= -1; 13 | valid_flags2 =... 14 | camera_pair_assignments(:,1) ~= camera_pair_assignments(:,2); 15 | valid_flags3 =... 16 | any(camera_pair_assignments == group_idx1, 2); 17 | valid_flags4 =... 18 | any(camera_pair_assignments == group_idx2, 2); 19 | 20 | camera_pair_flags = valid_flags1 & valid_flags2 & valid_flags3 & valid_flags4; 21 | 22 | % for i = 1:num_camera_pairs 23 | % cam1 = camera_pairs(i,1); 24 | % cam2 = camera_pairs(i,2); 25 | % 26 | % group1 = group_assignments(cam1); 27 | % group2 = group_assignments(cam2); 28 | % 29 | % if group1 == group2 30 | % continue 31 | % end 32 | % 33 | % if group_sizes(group1) < 2 || group_sizes(group2) < 2 34 | % continue 35 | % end 36 | % 37 | % if ~any(group1 == [group_idx1, group_idx2]) ||... 38 | % ~any(group2 == [group_idx1, group_idx2]) 39 | % continue 40 | % end 41 | % 42 | % camera_pair_flags(i) = true; 43 | % end 44 | 45 | camera_pair_indices = find(camera_pair_flags); 46 | 47 | end % function 48 | -------------------------------------------------------------------------------- /matlab/code/generate_split_camera_tasks.m: -------------------------------------------------------------------------------- 1 | function [split_camera_tasks] = generate_split_camera_tasks(... 2 | camera_tree, connected_camera_matrix, camera_data, point_data,... 3 | camera_observations, max_baseline_angle, max_split_cameras_per_edge) 4 | 5 | init_matlabpool(12); 6 | 7 | [cams1, cams2] = find(triu(connected_camera_matrix, 1)); 8 | camera_pairs = [cams1, cams2]; 9 | baseline_angles = compute_baseline_angles_between_camera_pairs2(... 10 | camera_pairs, camera_data, point_data, camera_observations); 11 | 12 | valid_flags = baseline_angles < max_baseline_angle; 13 | camera_pairs = camera_pairs(valid_flags, :); 14 | baseline_angles = baseline_angles(valid_flags); 15 | 16 | disp(['Original # camera pairs: ' num2str(length(baseline_angles))]) 17 | 18 | num_edges = get_num_edges_in_tree(camera_tree); 19 | num_cameras = camera_data.num_cameras; 20 | 21 | split_camera_tasks = cell(1, num_edges); 22 | 23 | parfor edge_idx = 1:num_edges 24 | [group_sizes, group_assignments, cam_idx1, cam_idx2] = split_camera_tree(... 25 | camera_tree, edge_idx, num_cameras); 26 | group_idx1 = group_assignments(cam_idx1); 27 | group_idx2 = group_assignments(cam_idx2); 28 | split_camera_tasks{edge_idx} = generate_split_camera_tasks_helper(... 29 | camera_pairs, group_assignments, group_sizes, group_idx1, group_idx2,... 30 | baseline_angles, max_split_cameras_per_edge); 31 | end 32 | 33 | end % function 34 | -------------------------------------------------------------------------------- /matlab/code/generate_split_camera_tasks_helper.m: -------------------------------------------------------------------------------- 1 | function [split_camera_tasks] = generate_split_camera_tasks_helper(... 2 | camera_pairs, group_assignments, group_sizes, group_idx1, group_idx2,... 3 | baseline_angles, max_split_cameras_per_edge) 4 | 5 | camera_pair_indices = find_split_cameras(camera_pairs,... 6 | group_assignments, group_sizes, group_idx1, group_idx2); 7 | 8 | num_split_pairs = length(camera_pair_indices); 9 | 10 | if num_split_pairs == 0 11 | split_camera_tasks = struct(... 12 | 'camera_pairs', [],... 13 | 'group_assignments', group_assignments,... 14 | 'group_sizes', group_sizes,... 15 | 'group_idx1', group_idx1,... 16 | 'group_idx2', group_idx2); 17 | return 18 | end 19 | 20 | if num_split_pairs > max_split_cameras_per_edge 21 | baseline_angles = baseline_angles(camera_pair_indices); 22 | [~, indices] = sort(baseline_angles, 'ascend'); 23 | indices = indices(1:max_split_cameras_per_edge); 24 | camera_pair_indices = camera_pair_indices(indices); 25 | end 26 | 27 | camera_pairs = camera_pairs(camera_pair_indices, :); 28 | 29 | split_camera_tasks = struct(... 30 | 'camera_pairs', camera_pairs,... 31 | 'group_assignments', group_assignments,... 32 | 'group_sizes', group_sizes,... 33 | 'group_idx1', group_idx1,... 34 | 'group_idx2', group_idx2); 35 | 36 | end % function 37 | -------------------------------------------------------------------------------- /matlab/code/generate_split_camera_tasks_single_edge.m: -------------------------------------------------------------------------------- 1 | function [split_camera_tasks] = generate_split_camera_tasks_single_edge(... 2 | connected_camera_matrix, camera_data, point_data,... 3 | visibility_matrix, max_baseline_angle, max_split_cameras_per_edge,... 4 | group_assignments, group_sizes, group_idx1, group_idx2) 5 | 6 | [cams1, cams2] = find(triu(connected_camera_matrix, 1)); 7 | camera_pairs = [cams1, cams2]; 8 | % Use the slower baseline angle method because it uses the visibility matrix 9 | % which is up-to-date after the merge whereas the camera observations are 10 | % missing the inlier point indices. 11 | baseline_angles = compute_baseline_angles_between_camera_pairs(... 12 | camera_pairs, camera_data, point_data, visibility_matrix); 13 | %baseline_angles = compute_baseline_angles_between_camera_pairs2(... 14 | % camera_pairs, camera_data, point_data, camera_observations); 15 | 16 | valid_flags = baseline_angles < max_baseline_angle; 17 | camera_pairs = camera_pairs(valid_flags, :); 18 | baseline_angles = baseline_angles(valid_flags); 19 | 20 | split_camera_tasks = cell(1, 1); 21 | split_camera_tasks{1} = generate_split_camera_tasks_helper(... 22 | camera_pairs, group_assignments, group_sizes, group_idx1, group_idx2,... 23 | baseline_angles, max_split_cameras_per_edge); 24 | 25 | end % function 26 | -------------------------------------------------------------------------------- /matlab/code/get_num_edges_in_tree.m: -------------------------------------------------------------------------------- 1 | function [num_edges] = get_num_edges_in_tree(camera_tree) 2 | 3 | num_edges = nnz(camera_tree); 4 | 5 | end 6 | -------------------------------------------------------------------------------- /matlab/code/identify_common_points_between_groups.m: -------------------------------------------------------------------------------- 1 | function [common_point_flags] = identify_common_points_between_groups(... 2 | visibility_matrix, group_assignments, group_idx1, group_idx2) 3 | 4 | group_point_flags1 = visibility_matrix(group_assignments == group_idx1, :); 5 | group_point_flags2 = visibility_matrix(group_assignments == group_idx2, :); 6 | 7 | group_point_flags1 = any(group_point_flags1, 1); 8 | group_point_flags2 = any(group_point_flags2, 1); 9 | 10 | common_point_flags = group_point_flags1 & group_point_flags2; 11 | 12 | end % function 13 | -------------------------------------------------------------------------------- /matlab/code/init_matlabpool.m: -------------------------------------------------------------------------------- 1 | function [] = init_matlabpool(num_threads) 2 | 3 | addpath('../ParforProgMon') 4 | 5 | if matlabpool('size') ~= num_threads 6 | my_cluster = parcluster('local'); 7 | my_cluster.NumWorkers = num_threads; 8 | saveProfile(my_cluster); 9 | 10 | if matlabpool('size') > 0 11 | matlabpool close 12 | end 13 | 14 | matlabpool('open', num_threads); 15 | 16 | pctRunOnAll javaaddpath ../ParforProgMon/java 17 | end 18 | 19 | end % function 20 | -------------------------------------------------------------------------------- /matlab/code/normalize_group_assignments.m: -------------------------------------------------------------------------------- 1 | function [new_group_assignments] = normalize_group_assignments(group_assignments) 2 | 3 | group_sizes = compute_group_sizes(group_assignments); 4 | [sorted_sizes, sorted_sizes_idx] = sort(group_sizes, 'descend'); 5 | num_groups = length(group_sizes); 6 | 7 | new_group_assignments = group_assignments; 8 | 9 | for i = 1:num_groups 10 | flags = group_assignments == sorted_sizes_idx(i); 11 | if sorted_sizes(i) > 1 12 | new_group_assignments(flags) = i; 13 | else 14 | new_group_assignments(flags) = 0; 15 | end 16 | end 17 | 18 | end % function 19 | -------------------------------------------------------------------------------- /matlab/code/plot_3_merged_models.m: -------------------------------------------------------------------------------- 1 | function [] = plot_3_merged_models(camera_data, point_data, visibility_matrix,... 2 | group_assignments, group1_idx, group2_idx, group3_idx,... 3 | group1_transform, group2_transform)%,... 4 | %inlier_point_indices) 5 | 6 | %inlier_point_indices = inlier_point_indices(:); 7 | %inlier_point_flags = false(1, point_data.num_points); 8 | %inlier_point_flags(inlier_point_indices) = true; 9 | 10 | camera_flags1 = group_assignments == group1_idx; 11 | camera_flags2 = group_assignments == group2_idx; 12 | camera_flags3 = group_assignments == group3_idx; 13 | 14 | point_flags1 = any(visibility_matrix(camera_flags1, :), 1);% & ~inlier_point_flags; 15 | point_flags2 = any(visibility_matrix(camera_flags2, :), 1);% & ~inlier_point_flags; 16 | point_flags3 = any(visibility_matrix(camera_flags3, :), 1);% & ~inlier_point_flags; 17 | 18 | points1 = point_data.xyzs(:,point_flags1); 19 | points2 = point_data.xyzs(:,point_flags2); 20 | points3 = point_data.xyzs(:,point_flags3); 21 | %inliers = point_data.xyzs(:,inlier_point_flags); 22 | 23 | cameras1 = camera_data.centers(:,camera_flags1); 24 | cameras2 = camera_data.centers(:,camera_flags2); 25 | cameras3 = camera_data.centers(:,camera_flags3); 26 | 27 | points1 = group1_transform * [points1; ones(1, size(points1, 2))]; 28 | points2 = group2_transform * [points2; ones(1, size(points2, 2))]; 29 | 30 | cameras1 = group1_transform * [cameras1; ones(1, size(cameras1, 2))]; 31 | cameras2 = group2_transform * [cameras2; ones(1, size(cameras2, 2))]; 32 | 33 | figure; 34 | plot3(points1(1,:), points1(2,:), points1(3,:), '.r', 'MarkerSize', 1); 35 | hold on 36 | plot3(points2(1,:), points2(2,:), points2(3,:), '.b', 'MarkerSize', 1); 37 | plot3(points3(1,:), points3(2,:), points3(3,:), '.g', 'MarkerSize', 1); 38 | plot3(cameras1(1,:), cameras1(2,:), cameras1(3,:), 'vr', 'MarkerSize', 3, 'MarkerFaceColor', 'r'); 39 | plot3(cameras2(1,:), cameras2(2,:), cameras2(3,:), 'vb', 'MarkerSize', 3, 'MarkerFaceColor', 'b'); 40 | plot3(cameras3(1,:), cameras3(2,:), cameras3(3,:), 'vg', 'MarkerSize', 3, 'MarkerFaceColor', 'g'); 41 | axis equal 42 | axis vis3d 43 | title('3 Merged Models'); 44 | hold off 45 | 46 | end % function 47 | -------------------------------------------------------------------------------- /matlab/code/plot_merged_model_inliers.m: -------------------------------------------------------------------------------- 1 | function [] = plot_merged_model_inliers(camera_data, point_data, visibility_matrix,... 2 | group_assignments, group_idx1, group_idx2, inlier_point_indices) 3 | 4 | inlier_point_indices = inlier_point_indices(:); 5 | inlier_point_flags = false(1, point_data.num_points); 6 | inlier_point_flags(inlier_point_indices) = true; 7 | 8 | camera_flags1 = group_assignments == group_idx1; 9 | camera_flags2 = group_assignments == group_idx2; 10 | 11 | camera_indices1 = find(camera_flags1); 12 | camera_indices2 = find(camera_flags2); 13 | 14 | cameras1 = camera_data.centers(:,camera_flags1); 15 | cameras2 = camera_data.centers(:,camera_flags2); 16 | 17 | lookats1 = zeros(3, length(camera_indices1)); 18 | lookats2 = zeros(3, length(camera_indices2)); 19 | 20 | dist = compute_distance_threshold_3d(camera_data, point_data, 0.05); 21 | 22 | for i = 1:length(camera_indices1) 23 | cam_idx = camera_indices1(i); 24 | lookat = camera_data.orientations{cam_idx} * [0 0 dist]'; 25 | lookats1(:,i) = camera_data.centers(:,cam_idx) + lookat; 26 | end 27 | 28 | for i = 1:length(camera_indices2) 29 | cam_idx = camera_indices2(i); 30 | lookat = camera_data.orientations{cam_idx} * [0 0 dist]'; 31 | lookats2(:,i) = camera_data.centers(:,cam_idx) + lookat; 32 | end 33 | 34 | point_flags1 = any(visibility_matrix(camera_flags1, :), 1) & ~inlier_point_flags; 35 | point_flags2 = any(visibility_matrix(camera_flags2, :), 1) & ~inlier_point_flags; 36 | 37 | points1 = point_data.xyzs(:,point_flags1); 38 | points2 = point_data.xyzs(:,point_flags2); 39 | inlier_points = point_data.xyzs(:,inlier_point_flags); 40 | 41 | figure; 42 | plot3(inlier_points(1,:), inlier_points(2,:), inlier_points(3,:), 'og', 'MarkerSize', 3, 'MarkerFaceColor', 'g') 43 | hold on 44 | plot3(points1(1,:), points1(2,:), points1(3,:), '.r', 'MarkerSize', 1) 45 | plot3(points2(1,:), points2(2,:), points2(3,:), '.b', 'MarkerSize', 1) 46 | plot3(cameras1(1,:), cameras1(2,:), cameras1(3,:), 'vr', 'MarkerSize', 3, 'MarkerFaceColor', 'r') 47 | plot3(cameras2(1,:), cameras2(2,:), cameras2(3,:), 'vb', 'MarkerSize', 3, 'MarkerFaceColor', 'b') 48 | plot3(... 49 | [cameras1(1,:); lookats1(1,:)],... 50 | [cameras1(2,:); lookats1(2,:)],... 51 | [cameras1(3,:); lookats1(3,:)],... 52 | '-r') 53 | plot3(... 54 | [cameras2(1,:); lookats2(1,:)],... 55 | [cameras2(2,:); lookats2(2,:)],... 56 | [cameras2(3,:); lookats2(3,:)],... 57 | '-b') 58 | axis equal 59 | axis vis3d 60 | 61 | % for i = 1:length(camera_indices1) 62 | % cam_idx = camera_indices1(i); 63 | % text(cameras1(1,i), cameras1(2,i), cameras1(3,i), [' ' num2str(cam_idx)], 'FontSize', 8) 64 | % end 65 | % for i = 1:length(camera_indices2) 66 | % cam_idx = camera_indices2(i); 67 | % text(cameras2(1,i), cameras2(2,i), cameras2(3,i), [' ' num2str(cam_idx)], 'FontSize', 8) 68 | % end 69 | 70 | hold off 71 | 72 | end % function 73 | -------------------------------------------------------------------------------- /matlab/code/quaternion_to_matrix.m: -------------------------------------------------------------------------------- 1 | function [R] = quaternion_to_matrix(quat) 2 | 3 | a = quat(1); 4 | b = quat(2); 5 | c = quat(3); 6 | d = quat(4); 7 | 8 | R = [a^2 + b^2 - c^2 - d^2, 2*b*c - 2*a*d, 2*b*d + 2*a*c; 9 | 2*b*c + 2*a*d, a^2 - b^2 + c^2 - d^2, 2*c*d - 2*a*b; 10 | 2*b*d - 2*a*c, 2*c*d + 2*a*b, a^2 - b^2 - c^2 + d^2]; 11 | 12 | end 13 | -------------------------------------------------------------------------------- /matlab/code/ransac.m: -------------------------------------------------------------------------------- 1 | % RANSAC - Robustly fits a model to data with the RANSAC algorithm 2 | % 3 | % Usage: 4 | % 5 | % [M, inliers] = ransac(x, fittingfn, distfn, degenfn s, t, feedback, ... 6 | % maxDataTrials, maxTrials) 7 | % 8 | % Arguments: 9 | % x - Data sets to which we are seeking to fit a model M 10 | % It is assumed that x is of size [d x Npts] 11 | % where d is the dimensionality of the data and Npts is 12 | % the number of data points. 13 | % 14 | % fittingfn - Handle to a function that fits a model to s 15 | % data from x. It is assumed that the function is of the 16 | % form: 17 | % M = fittingfn(x) 18 | % Note it is possible that the fitting function can return 19 | % multiple models (for example up to 3 fundamental matrices 20 | % can be fitted to 7 matched points). In this case it is 21 | % assumed that the fitting function returns a cell array of 22 | % models. 23 | % If this function cannot fit a model it should return M as 24 | % an empty matrix. 25 | % 26 | % distfn - Handle to a function that evaluates the 27 | % distances from the model to data x. 28 | % It is assumed that the function is of the form: 29 | % [inliers, M] = distfn(M, x, t) 30 | % This function must evaluate the distances between points 31 | % and the model returning the indices of elements in x that 32 | % are inliers, that is, the points that are within distance 33 | % 't' of the model. Additionally, if M is a cell array of 34 | % possible models 'distfn' will return the model that has the 35 | % most inliers. If there is only one model this function 36 | % must still copy the model to the output. After this call M 37 | % will be a non-cell object representing only one model. 38 | % 39 | % degenfn - Handle to a function that determines whether a 40 | % set of datapoints will produce a degenerate model. 41 | % This is used to discard random samples that do not 42 | % result in useful models. 43 | % It is assumed that degenfn is a boolean function of 44 | % the form: 45 | % r = degenfn(x) 46 | % It may be that you cannot devise a test for degeneracy in 47 | % which case you should write a dummy function that always 48 | % returns a value of 1 (true) and rely on 'fittingfn' to return 49 | % an empty model should the data set be degenerate. 50 | % 51 | % s - The minimum number of samples from x required by 52 | % fittingfn to fit a model. 53 | % 54 | % t - The distance threshold between a data point and the model 55 | % used to decide whether the point is an inlier or not. 56 | % 57 | % feedback - An optional flag 0/1. If set to one the trial count and the 58 | % estimated total number of trials required is printed out at 59 | % each step. Defaults to 0. 60 | % 61 | % maxDataTrials - Maximum number of attempts to select a non-degenerate 62 | % data set. This parameter is optional and defaults to 100. 63 | % 64 | % maxTrials - Maximum number of iterations. This parameter is optional and 65 | % defaults to 1000. 66 | % 67 | % Returns: 68 | % M - The model having the greatest number of inliers. 69 | % inliers - An array of indices of the elements of x that were 70 | % the inliers for the best model. 71 | % 72 | % For an example of the use of this function see RANSACFITHOMOGRAPHY or 73 | % RANSACFITPLANE 74 | 75 | % References: 76 | % M.A. Fishler and R.C. Boles. "Random sample concensus: A paradigm 77 | % for model fitting with applications to image analysis and automated 78 | % cartography". Comm. Assoc. Comp, Mach., Vol 24, No 6, pp 381-395, 1981 79 | % 80 | % Richard Hartley and Andrew Zisserman. "Multiple View Geometry in 81 | % Computer Vision". pp 101-113. Cambridge University Press, 2001 82 | 83 | % Copyright (c) 2003-2006 Peter Kovesi 84 | % School of Computer Science & Software Engineering 85 | % The University of Western Australia 86 | % pk at csse uwa edu au 87 | % http://www.csse.uwa.edu.au/~pk 88 | % 89 | % Permission is hereby granted, free of charge, to any person obtaining a copy 90 | % of this software and associated documentation files (the "Software"), to deal 91 | % in the Software without restriction, subject to the following conditions: 92 | % 93 | % The above copyright notice and this permission notice shall be included in 94 | % all copies or substantial portions of the Software. 95 | % 96 | % The Software is provided "as is", without warranty of any kind. 97 | % 98 | % May 2003 - Original version 99 | % February 2004 - Tidied up. 100 | % August 2005 - Specification of distfn changed to allow model fitter to 101 | % return multiple models from which the best must be selected 102 | % Sept 2006 - Random selection of data points changed to ensure duplicate 103 | % points are not selected. 104 | % February 2007 - Jordi Ferrer: Arranged warning printout. 105 | % Allow maximum trials as optional parameters. 106 | % Patch the problem when non-generated data 107 | % set is not given in the first iteration. 108 | % August 2008 - 'feedback' parameter restored to argument list and other 109 | % breaks in code introduced in last update fixed. 110 | % December 2008 - Octave compatibility mods 111 | % June 2009 - Argument 'MaxTrials' corrected to 'maxTrials'! 112 | 113 | function [M, inliers] = ransac(x, fittingfn, distfn, degenfn, s, t, feedback, ... 114 | maxDataTrials, maxTrials) 115 | 116 | Octave = exist('OCTAVE_VERSION') ~= 0; 117 | 118 | % Test number of parameters 119 | error ( nargchk ( 6, 9, nargin ) ); 120 | 121 | if nargin < 9; maxTrials = 20000; end; 122 | if nargin < 8; maxDataTrials = 100; end; 123 | if nargin < 7; feedback = 0; end; 124 | 125 | min_num_trials = 10000; 126 | 127 | [rows, npts] = size(x); 128 | 129 | p = 0.999; % Desired probability of choosing at least one sample 130 | % free from outliers 131 | 132 | bestM = NaN; % Sentinel value allowing detection of solution failure. 133 | trialcount = 0; 134 | bestscore = 0; 135 | N = maxTrials; % Dummy initialisation for number of trials. 136 | 137 | M = []; 138 | inliers = []; 139 | 140 | while max(min_num_trials, N) > trialcount 141 | 142 | % Select at random s datapoints to form a trial model, M. 143 | % In selecting these points we have to check that they are not in 144 | % a degenerate configuration. 145 | degenerate = 1; 146 | count = 1; 147 | while degenerate 148 | % Generate s random indicies in the range 1..npts 149 | % (If you do not have the statistics toolbox, or are using Octave, 150 | % use the function RANDOMSAMPLE from my webpage) 151 | if Octave | ~exist('randsample.m') 152 | ind = randomsample(npts, s); 153 | else 154 | ind = randsample(npts, s); 155 | end 156 | 157 | % Test that these points are not a degenerate configuration. 158 | degenerate = feval(degenfn, x(:,ind)); 159 | 160 | if ~degenerate 161 | % Fit model to this random selection of data points. 162 | % Note that M may represent a set of models that fit the data in 163 | % this case M will be a cell array of models 164 | M = feval(fittingfn, x(:,ind)); 165 | 166 | % Depending on your problem it might be that the only way you 167 | % can determine whether a data set is degenerate or not is to 168 | % try to fit a model and see if it succeeds. If it fails we 169 | % reset degenerate to true. 170 | if isempty(M) 171 | degenerate = 1; 172 | end 173 | end 174 | 175 | % Safeguard against being stuck in this loop forever 176 | count = count + 1; 177 | if count > maxDataTrials 178 | warning('Unable to select a nondegenerate data set'); 179 | return 180 | end 181 | end 182 | 183 | % Once we are out here we should have some kind of model... 184 | % Evaluate distances between points and model returning the indices 185 | % of elements in x that are inliers. Additionally, if M is a cell 186 | % array of possible models 'distfn' will return the model that has 187 | % the most inliers. After this call M will be a non-cell object 188 | % representing only one model. 189 | [inliers, M] = feval(distfn, M, x, t); 190 | 191 | % Find the number of inliers to this model. 192 | ninliers = length(inliers); 193 | 194 | if ninliers > bestscore % Largest set of inliers so far... 195 | bestscore = ninliers; % Record data for this model 196 | bestinliers = inliers; 197 | bestM = M; 198 | 199 | % Update estimate of N, the number of trials to ensure we pick, 200 | % with probability p, a data set with no outliers. 201 | fracinliers = ninliers/npts; 202 | pNoOutliers = 1 - fracinliers^s; 203 | pNoOutliers = max(eps, pNoOutliers); % Avoid division by -Inf 204 | pNoOutliers = min(1-eps, pNoOutliers);% Avoid division by 0. 205 | N = log(1-p)/log(pNoOutliers); 206 | end 207 | 208 | trialcount = trialcount+1; 209 | if feedback 210 | fprintf('trial %d out of %d \r',trialcount, ceil(N)); 211 | end 212 | 213 | % Safeguard against being stuck in this loop forever 214 | if trialcount > maxTrials 215 | warning( ... 216 | sprintf('ransac reached the maximum number of %d trials',... 217 | maxTrials)); 218 | break 219 | end 220 | end 221 | fprintf('\n'); 222 | 223 | if ~isnan(bestM) % We got a solution 224 | M = bestM; 225 | inliers = bestinliers; 226 | else 227 | M = []; 228 | inliers = []; 229 | warning('ransac was unable to find a useful solution'); 230 | end 231 | -------------------------------------------------------------------------------- /matlab/code/ransac_3d_similarity.m: -------------------------------------------------------------------------------- 1 | function [M, inliers] = ransac_3d_similarity(matching_points, threshold) 2 | 3 | [M, inliers] = ransac(matching_points, @compute_M, @compute_similarity_inliers, @is_valid_data, 3, threshold, 0, 1000, 30000); 4 | 5 | if length(inliers) > 3 6 | M = refine_M(matching_points(:,inliers)); 7 | [inliers, M] = compute_similarity_inliers(M, matching_points, threshold); 8 | M = refine_M(matching_points(:,inliers)); 9 | [inliers, M] = compute_similarity_inliers(M, matching_points, threshold); 10 | end 11 | 12 | num_inliers = length(inliers); 13 | 14 | display(['Inliers = ' num2str(num_inliers) ' / ' num2str(size(matching_points, 2))]) 15 | 16 | end 17 | 18 | function [M] = compute_M(data) 19 | 20 | if size(data, 2) ~= 3 21 | disp('compute_M expected 3 points') 22 | end 23 | 24 | left_points = data(1:3, :); 25 | right_points = data(4:6, :); 26 | 27 | M = compute_RTS_3_points_3d_same_scale(left_points, right_points); 28 | 29 | end 30 | 31 | function [M] = refine_M(data) 32 | 33 | left_points = data(1:3, :); 34 | right_points = data(4:6, :); 35 | 36 | M = compute_RTS_N_points_3d_same_scale(left_points, right_points); 37 | 38 | end 39 | 40 | % function [inliers, M] = compute_inliers(M, data, threshold) 41 | % 42 | % if isempty(M) 43 | % inliers = false(1, size(data, 2)); 44 | % return 45 | % end 46 | % 47 | % left_points = data(1:3, :); 48 | % right_points = data(4:6, :); 49 | % 50 | % N = size(left_points, 2); 51 | % 52 | % new_left_points = M * [left_points; ones(1, N)]; 53 | % 54 | % diff = right_points - new_left_points; 55 | % diff = diff .^ 2; 56 | % diff = sum(diff, 1); 57 | % diff = sqrt(diff); 58 | % 59 | % inliers = find(diff <= threshold); 60 | % 61 | % end 62 | 63 | function [r] = is_valid_data(data) 64 | 65 | % Return 1 if the data is degenerate 66 | % Return 0 if the data is not degenerate 67 | 68 | if size(data, 2) ~= 3 69 | disp('is_valid_data expected 3 points') 70 | end 71 | 72 | left_points = data(1:3, :); 73 | right_points = data(4:6, :); 74 | 75 | l1 = left_points(:,1); 76 | l2 = left_points(:,2); 77 | l3 = left_points(:,3); 78 | 79 | r1 = right_points(:,1); 80 | r2 = right_points(:,2); 81 | r3 = right_points(:,3); 82 | 83 | % Check if 2 of the points are close to each other 84 | if norm(l2 - l1) < 0.0001 ||... 85 | norm(l3 - l1) < 0.0001 ||... 86 | norm(l3 - l2) < 0.0001 87 | 88 | r = 1; 89 | return 90 | end 91 | if norm(r2 - r1) < 0.0001 ||... 92 | norm(r3 - r1) < 0.0001 ||... 93 | norm(r3 - r2) < 0.0001 94 | 95 | r = 1; 96 | return 97 | end 98 | 99 | l_diff1 = l2 - l1; 100 | l_diff2 = l3 - l1; 101 | l_diff1 = l_diff1 ./ norm(l_diff1); 102 | l_diff2 = l_diff2 ./ norm(l_diff2); 103 | if acos(dot(l_diff1, l_diff2)) < 0.01 104 | r = 1; 105 | return 106 | end 107 | 108 | r_diff1 = r2 - r1; 109 | r_diff2 = r3 - r1; 110 | r_diff1 = r_diff1 ./ norm(r_diff1); 111 | r_diff2 = r_diff2 ./ norm(r_diff2); 112 | if acos(dot(r_diff1, r_diff2)) < 0.01 113 | r = 1; 114 | return 115 | end 116 | 117 | r = 0; 118 | 119 | end 120 | -------------------------------------------------------------------------------- /matlab/code/read_all_inlier_matches.m: -------------------------------------------------------------------------------- 1 | function [all_inlier_matches, all_inlier_matches_camera_indices] = read_all_inlier_matches(filename, camera_data) 2 | 3 | all_inlier_matches = {}; 4 | all_inlier_matches_camera_indices = []; 5 | 6 | file = fopen(filename, 'r'); 7 | while ~feof(file) 8 | line = strtrim(fgets(file)); 9 | if isempty(line) 10 | continue 11 | end 12 | if line(1) == '#' 13 | continue 14 | end 15 | 16 | space = strfind(line, ' '); 17 | camera_name1 = trim_filename(line(space+1 : end)); 18 | cam_idx1 = find(strcmp(camera_name1, camera_data.names)); 19 | 20 | % If the cameras for the inlier images didn't end up in the final NVM 21 | % model then their indices will be empty matrices. 22 | if isempty(cam_idx1) 23 | continue 24 | end 25 | 26 | line = strtrim(fgets(file)); 27 | space = strfind(line, ' '); 28 | camera_name2 = trim_filename(line(space+1 : end)); 29 | cam_idx2 = find(strcmp(camera_name2, camera_data.names)); 30 | 31 | if isempty(cam_idx2) 32 | continue 33 | end 34 | 35 | line = strtrim(fgets(file)); 36 | num_inliers = str2double(line); 37 | 38 | data = fscanf(file, '%d %f %f %d %f %f', [6, num_inliers]); 39 | data = data'; 40 | feature_indices = int32(data(:, logical([1 0 0 1 0 0]))); 41 | feature_indices = feature_indices + 1; 42 | feature_indices = feature_indices'; 43 | locations_2d = single(data(:, logical([0 1 1 0 1 1]))); 44 | locations_2d = locations_2d'; 45 | locations_2d = locations_2d + 1; 46 | 47 | all_inlier_matches{end+1} = struct(... 48 | 'camera_indices', [cam_idx1 cam_idx2],... 49 | 'num_matches', num_inliers,... 50 | 'feature_indices', feature_indices,... 51 | 'locations_2d', locations_2d); 52 | all_inlier_matches_camera_indices =... 53 | [all_inlier_matches_camera_indices; [cam_idx1 cam_idx2]]; 54 | end 55 | fclose(file); 56 | 57 | end % function 58 | -------------------------------------------------------------------------------- /matlab/code/read_inlier_matches.m: -------------------------------------------------------------------------------- 1 | function [inlier_matches] = read_inlier_matches(filename, camera_data, camera_observations) 2 | 3 | inlier_matches = {}; 4 | 5 | file = fopen(filename, 'r'); 6 | while ~feof(file) 7 | line = strtrim(fgets(file)); 8 | if isempty(line) 9 | continue 10 | end 11 | if line(1) == '#' 12 | continue 13 | end 14 | 15 | space = strfind(line, ' '); 16 | camera_name1 = trim_filename(line(space+1 : end)); 17 | cam_idx1 = find(strcmp(camera_name1, camera_data.names)); 18 | 19 | % If the cameras for the inlier images didn't end up in the final NVM 20 | % model then their indices will be empty matrices. 21 | if isempty(cam_idx1) 22 | continue 23 | end 24 | 25 | line = strtrim(fgets(file)); 26 | space = strfind(line, ' '); 27 | camera_name2 = trim_filename(line(space+1 : end)); 28 | cam_idx2 = find(strcmp(camera_name2, camera_data.names)); 29 | 30 | if isempty(cam_idx2) 31 | continue 32 | end 33 | 34 | line = strtrim(fgets(file)); 35 | num_inliers = str2double(line); 36 | 37 | data = fscanf(file, '%d %f %f %d %f %f', [6, num_inliers]); 38 | data = data'; 39 | feature_indices = int32(data(:, logical([1 0 0 1 0 0]))); 40 | feature_indices = feature_indices + 1; 41 | feature_indices = feature_indices'; 42 | locations_2d = single(data(:, logical([0 1 1 0 1 1]))); 43 | locations_2d = locations_2d'; 44 | 45 | % Determine which features turned into 3D points 46 | [flags1, indices1] = ismember(... 47 | feature_indices(1,:), camera_observations{cam_idx1}.feature_indices); 48 | [flags2, indices2] = ismember(... 49 | feature_indices(2,:), camera_observations{cam_idx2}.feature_indices); 50 | 51 | valid_flags = flags1 & flags2; 52 | 53 | if ~any(valid_flags) 54 | continue 55 | end 56 | 57 | indices1 = indices1(valid_flags); 58 | indices2 = indices2(valid_flags); 59 | 60 | point_indices1 = camera_observations{cam_idx1}.point_indices(indices1); 61 | point_indices2 = camera_observations{cam_idx2}.point_indices(indices2); 62 | 63 | % Later on we will only care about inliers that turned into different 64 | % points, so discard extra data now. 65 | different_points_flags = point_indices1 ~= point_indices2; 66 | 67 | if ~any(different_points_flags) 68 | continue 69 | end 70 | 71 | feature_indices = feature_indices(:, valid_flags); 72 | locations_2d = locations_2d(:, valid_flags); 73 | 74 | point_indices1 = point_indices1(different_points_flags); 75 | point_indices2 = point_indices2(different_points_flags); 76 | feature_indices = feature_indices(:, different_points_flags); 77 | locations_2d = locations_2d(:, different_points_flags); 78 | 79 | inlier_matches{end+1} = struct(... 80 | 'camera_indices', [cam_idx1 cam_idx2],... 81 | 'num_matches', sum(different_points_flags),... 82 | 'feature_indices', feature_indices,... 83 | 'point_indices', [point_indices1; point_indices2],... 84 | 'locations_2d', locations_2d); 85 | end 86 | fclose(file); 87 | 88 | end % function 89 | -------------------------------------------------------------------------------- /matlab/code/read_nvm_and_image_dimensions.m: -------------------------------------------------------------------------------- 1 | function [camera_data, point_data, point_observations] =... 2 | read_nvm_and_image_dimensions(nvm_name, image_folder) 3 | 4 | file = fopen(nvm_name, 'r'); 5 | line = strtrim(fgets(file)); 6 | if ~strcmp(line, 'NVM_V3') 7 | disp('ERROR: expected NVM_V3 as first line of file') 8 | fclose(file); 9 | return 10 | end 11 | 12 | num_cameras = fscanf(file, '%d', 1); 13 | raw_camera_data = textscan(file, '%s %f %f %f %f %f %f %f %f %f %f', num_cameras); 14 | 15 | camera_names = raw_camera_data{1}'; 16 | camera_focals = raw_camera_data{2}'; 17 | camera_quats = [raw_camera_data{3}'; raw_camera_data{4}'; raw_camera_data{5}'; raw_camera_data{6}']; 18 | camera_centers = [raw_camera_data{7}'; raw_camera_data{8}'; raw_camera_data{9}']; 19 | camera_distorts = [raw_camera_data{10}'; raw_camera_data{11}']; 20 | 21 | image_dimensions = zeros(2, num_cameras); 22 | 23 | camera_orientations = cell(1, num_cameras); 24 | 25 | for i = 1:num_cameras 26 | camera_names{i} = trim_filename(camera_names{i}); 27 | 28 | camera_orientations{i} = quaternion_to_matrix(camera_quats(:,i)); 29 | camera_orientations{i} = camera_orientations{i}'; 30 | 31 | filename = [image_folder '/' camera_names{i} '.jpg']; 32 | info = imfinfo(filename); 33 | width = info.Width; 34 | height = info.Height; 35 | image_dimensions(:,i) = [width; height]; 36 | end 37 | 38 | camera_data = struct(... 39 | 'num_cameras', num_cameras,... 40 | 'names', {camera_names},... 41 | 'focals', camera_focals,... 42 | 'centers', camera_centers,... 43 | 'orientations', {camera_orientations},... 44 | 'dimensions', image_dimensions); 45 | 46 | num_points = fscanf(file, '%d', 1); 47 | 48 | point_xyzs = zeros(3, num_points); 49 | point_rgbs = zeros(3, num_points); 50 | point_observations = cell(1, num_points); 51 | 52 | for point_idx = 1:num_points 53 | file_data = fscanf(file, '%f %f %f %d %d %d %d', 7); 54 | xyz = file_data(1:3); 55 | rgb = file_data(4:6); 56 | num_observations = int32(file_data(7)); 57 | 58 | file_data = fscanf(file, '%d %d %f %f', [4, num_observations]); 59 | 60 | camera_indices = int32(file_data(1,:) + 1); 61 | feature_indices = int32(file_data(2,:) + 1); 62 | locations_2d = single(... 63 | file_data(3:4,:) + (image_dimensions(:,camera_indices) ./ 2) + 1); 64 | 65 | point_xyzs(:,point_idx) = xyz; 66 | point_rgbs(:,point_idx) = rgb ./ 255; 67 | 68 | point_observations{point_idx} = struct(... 69 | 'num_observations', num_observations,... 70 | 'camera_indices', camera_indices,... 71 | 'feature_indices', feature_indices,... 72 | 'locations_2d', locations_2d); 73 | end 74 | 75 | point_data = struct(... 76 | 'num_points', num_points,... 77 | 'xyzs', point_xyzs,... 78 | 'rgbs', point_rgbs); 79 | 80 | fclose(file); 81 | end % function 82 | -------------------------------------------------------------------------------- /matlab/code/split_camera_tree.m: -------------------------------------------------------------------------------- 1 | function [group_sizes, group_assignments, cam_idx1, cam_idx2] = split_camera_tree(... 2 | camera_tree, edge_index, num_cameras) 3 | 4 | [cams1, cams2] = find(camera_tree); 5 | 6 | cam_idx1 = cams1(edge_index); 7 | cam_idx2 = cams2(edge_index); 8 | 9 | cams1(edge_index) = []; 10 | cams2(edge_index) = []; 11 | 12 | new_tree = sparse([cams1; cams2], [cams2; cams1], 1, num_cameras, num_cameras); 13 | 14 | [num_groups, group_assignments] = graphconncomp(new_tree, 'Directed', false); 15 | group_sizes = zeros(num_groups, 1); 16 | for i = 1:num_groups 17 | group_sizes(i) = sum(group_assignments == i); 18 | end 19 | 20 | end 21 | -------------------------------------------------------------------------------- /matlab/code/transform_camera_group.m: -------------------------------------------------------------------------------- 1 | function [new_camera_data, new_point_data, new_visibility_matrix,... 2 | new_connected_camera_matrix, new_camera_observations] =... 3 | transform_camera_group(camera_data, point_data,... 4 | visibility_matrix, camera_observations, group_assignments,... 5 | group_idx1, group_idx2, similarity,... 6 | disconnected_inlier_point_indices, common_point_flags,... 7 | min_common_points_for_connection) 8 | 9 | % GOAL: Transform camera group 1 (group_idx1) so that it aligns with camera group 2. 10 | 11 | new_camera_data = camera_data; 12 | new_point_data = point_data; 13 | new_visibility_matrix = visibility_matrix; 14 | new_camera_observations = camera_observations; 15 | 16 | % ---------------------------------------- 17 | % Update camera positions and orientations 18 | 19 | for cam_idx = 1:camera_data.num_cameras 20 | if group_assignments(cam_idx) ~= group_idx1 21 | continue 22 | end 23 | 24 | center = camera_data.centers(:,cam_idx); 25 | new_camera_data.centers(:,cam_idx) = similarity * [center; 1]; 26 | 27 | R = camera_data.orientations{cam_idx}; 28 | new_camera_data.orientations{cam_idx} = similarity(:,1:3) * R; 29 | end 30 | 31 | % ---------------------- 32 | % Update point positions 33 | 34 | common_point_indices = find(common_point_flags); 35 | num_common_points = length(common_point_indices); 36 | 37 | old_num_points = size(point_data.xyzs, 2); 38 | new_num_points = old_num_points + num_common_points; 39 | 40 | new_common_point_indices = old_num_points + [1:num_common_points]; 41 | 42 | % Transform the points unique to camera group 1 43 | camera_flags1 = group_assignments == group_idx1; 44 | point_flags1 = any(visibility_matrix(camera_flags1, :), 1); 45 | point_flags1 = point_flags1 & ~common_point_flags; 46 | points1 = point_data.xyzs(:, point_flags1); 47 | points1 = [points1; ones(1, size(points1, 2))]; 48 | points1 = similarity * points1; 49 | new_point_data.xyzs(:, point_flags1) = points1; 50 | 51 | common_points = point_data.xyzs(:, common_point_flags); 52 | common_points = [common_points; ones(1, size(common_points, 2))]; 53 | common_points = similarity * common_points; 54 | new_point_data.xyzs = [new_point_data.xyzs common_points]; 55 | new_point_data.num_points = new_num_points; 56 | 57 | % ------------------------------ 58 | % Update point visibility matrix 59 | 60 | new_visibility_matrix =... 61 | [new_visibility_matrix false(camera_data.num_cameras, num_common_points)]; 62 | 63 | for cam_idx = 1:camera_data.num_cameras 64 | if group_assignments(cam_idx) ~= group_idx1 65 | continue 66 | end 67 | 68 | % Move observations of the common points in the first camera group to the 69 | % newly duplicated points. 70 | flags = new_visibility_matrix(cam_idx, common_point_indices); 71 | new_visibility_matrix(cam_idx, common_point_indices) = false; 72 | new_visibility_matrix(cam_idx, old_num_points+1:new_num_points) = flags; 73 | end 74 | 75 | % Inlier points should be made visible in both images 76 | for i = 1:size(disconnected_inlier_point_indices, 2) 77 | idx1 = disconnected_inlier_point_indices(1,i); 78 | idx2 = disconnected_inlier_point_indices(2,i); 79 | 80 | cameras_seeing1 = new_visibility_matrix(:,idx1); 81 | cameras_seeing2 = new_visibility_matrix(:,idx2); 82 | 83 | new_visibility_matrix(cameras_seeing1, idx2) = true; 84 | new_visibility_matrix(cameras_seeing2, idx1) = true; 85 | end 86 | 87 | % Remove any cameras that aren't in either of the two groups under consideration 88 | current_camera_flags = (group_assignments == group_idx1) | (group_assignments == group_idx2); 89 | new_visibility_matrix(~current_camera_flags, :) = false; 90 | 91 | % ------------------------------ 92 | % Update connected camera matrix 93 | 94 | new_connected_camera_matrix = compute_connected_camera_matrix(... 95 | new_visibility_matrix, min_common_points_for_connection); 96 | 97 | % -------------------------- 98 | % Update camera observations 99 | 100 | parfor cam_idx = 1:camera_data.num_cameras 101 | if group_assignments(cam_idx) ~= group_idx1 102 | continue 103 | end 104 | 105 | % Replace point indices 106 | % We assume that common_point_indices is sorted so that we can use 107 | % ismembc and ismembc2 108 | flags = ismembc(camera_observations{cam_idx}.point_indices, common_point_indices); 109 | indices = ismembc2(camera_observations{cam_idx}.point_indices, common_point_indices); 110 | indices = indices(flags); 111 | %[flags, indices] = ismember(... 112 | % camera_observations{cam_idx}.point_indices, common_point_indices); 113 | %indices = indices(flags); 114 | new_camera_observations{cam_idx}.point_indices(flags) = new_common_point_indices(indices); 115 | 116 | % We need to keep the point indices in sorted order. 117 | [vals, sorted_indices] = sort(new_camera_observations{cam_idx}.point_indices, 'ascend'); 118 | new_camera_observations{cam_idx}.point_indices = vals; 119 | new_camera_observations{cam_idx}.feature_indices =... 120 | new_camera_observations{cam_idx}.feature_indices(sorted_indices); 121 | new_camera_observations{cam_idx}.locations_2d =... 122 | new_camera_observations{cam_idx}.locations_2d(:,sorted_indices); 123 | end 124 | 125 | end % function 126 | -------------------------------------------------------------------------------- /matlab/code/trim_filename.m: -------------------------------------------------------------------------------- 1 | function [name] = trim_filename(filename) 2 | 3 | slashes = strfind(filename, '\'); 4 | if ~isempty(slashes) 5 | filename = filename(slashes(end)+1:end); 6 | end 7 | 8 | slashes = strfind(filename, '/'); 9 | if ~isempty(slashes) 10 | filename = filename(slashes(end)+1:end); 11 | end 12 | 13 | dots = strfind(filename, '.'); 14 | if ~isempty(dots) 15 | filename = filename(1:dots(end)-1); 16 | end 17 | 18 | name = filename; 19 | 20 | end 21 | -------------------------------------------------------------------------------- /matlab/code/visualize_camera_tree.m: -------------------------------------------------------------------------------- 1 | function [] = visualize_camera_tree(... 2 | camera_tree, camera_data, model_name, filename, edge_label_objs, group_assignments, image_folder, graphviz_sfdp_exe) 3 | 4 | [cams1, cams2] = find(camera_tree); 5 | num_edges = length(cams1); 6 | 7 | cameras_with_edges = unique([cams1; cams2]); 8 | 9 | node_names = cell(camera_data.num_cameras, 1); 10 | for i = 1:camera_data.num_cameras 11 | node_names{i} = ['"' num2str(i) '"']; 12 | end 13 | 14 | if isempty(group_assignments) 15 | num_groups = 0; 16 | else 17 | group_assignments = normalize_group_assignments(group_assignments); 18 | num_groups = max(group_assignments); 19 | end 20 | 21 | graphviz_name = [filename '.graphviz']; 22 | output = fopen(graphviz_name, 'w'); 23 | fprintf(output, 'graph G {\n'); 24 | if isempty(image_folder) 25 | fprintf(output, 'graph [overlap=false, sep="+8"];\n'); 26 | else 27 | fprintf(output, 'graph [overlap=false, sep="+20"];\n'); 28 | end 29 | 30 | if isempty(image_folder) 31 | fprintf(output, 'node [ style=filled ];\n'); 32 | else 33 | %fprintf(output, 'node [ shape=box, fixedsize=true, height=2, width=3, style=filled ];\n'); 34 | fprintf(output, 'node [ shape=box, style=filled ];\n'); 35 | %fprintf(output, 'node [ shape=box ];\n'); 36 | %fprintf(output, 'edge [len=4];\n'); 37 | fprintf(output, ['imagepath="' image_folder '/";\n']); 38 | end 39 | 40 | for i = 1:camera_data.num_cameras 41 | if any(i == cameras_with_edges) 42 | fprintf(output, [node_names{i} ' [']); 43 | 44 | if num_groups > 0 45 | if group_assignments(i) ~= 0 46 | if isempty(image_folder) 47 | fprintf(output, ' fillcolor='); 48 | else 49 | fprintf(output, ' color='); 50 | end 51 | 52 | h = group_assignments(i) / (num_groups + 1); 53 | s = 0.7; 54 | v = 1; 55 | fprintf(output, '"%f %f %f"', h, s, v); 56 | 57 | if ~isempty(image_folder) 58 | fprintf(output, ', penwidth=30'); 59 | end 60 | end 61 | end 62 | 63 | if ~isempty(image_folder) 64 | fprintf(output, [' image="' camera_data.names{i} '.jpg"']); 65 | fprintf(output, ', imagescale=true, labelloc=b'); 66 | end 67 | 68 | fprintf(output, '];\n'); 69 | end 70 | end 71 | 72 | for i = 1:num_edges 73 | cam1 = cams1(i); 74 | cam2 = cams2(i); 75 | 76 | fprintf(output, [node_names{cam1} ' -- ' node_names{cam2}]); 77 | 78 | num_labels = length(edge_label_objs); 79 | label_text = ''; 80 | label_important = false; 81 | for j = 1:num_labels 82 | [label, important] = edge_label_objs{j}.label(cam1, cam2); 83 | if ~isempty(label_text) && ~isempty(label) 84 | label_text = [label_text '\n']; 85 | end 86 | label_text = [label_text label]; 87 | label_important = label_important || important; 88 | end 89 | 90 | if isempty(image_folder) 91 | if isempty(label_text) 92 | % No-op 93 | else 94 | if label_important 95 | fprintf(output, [' [ label="' label_text '", fontsize=14, fontcolor=red, penwidth=4, color=red ]']); 96 | else 97 | fprintf(output, [' [ label="' label_text '", fontsize=10 ]']); 98 | end 99 | end 100 | else 101 | if isempty(label_text) 102 | fprintf(output, [' [ penwidth=4 ]']); 103 | else 104 | if label_important 105 | fprintf(output, [' [ label="' label_text '", fontsize=14, fontcolor=red, penwidth=15, color=red ]']); 106 | else 107 | fprintf(output, [' [ label="' label_text '", fontsize=10, penwidth=4 ]']); 108 | end 109 | end 110 | end 111 | 112 | fprintf(output, ';\n'); 113 | end 114 | 115 | fprintf(output, '}\n'); 116 | fclose(output); 117 | 118 | % neato 119 | % dot 120 | % fdp 121 | % sfdp 122 | if isempty(image_folder) 123 | png_name = [filename '.png']; 124 | system([graphviz_sfdp_exe ' ' graphviz_name ' -o' png_name ' -Tpng']); 125 | else 126 | jpg_name = [filename '.jpg']; 127 | system([graphviz_sfdp_exe ' ' graphviz_name ' -o' jpg_name ' -Tjpg']); 128 | end 129 | 130 | delete(graphviz_name) 131 | 132 | end % function 133 | -------------------------------------------------------------------------------- /matlab/code/write_merged_nvm.m: -------------------------------------------------------------------------------- 1 | function [] = write_merged_nvm(output_path,... 2 | camera_data, point_data, point_observations) 3 | 4 | file = fopen(output_path, 'w'); 5 | fprintf(file, 'NVM_V3\n'); 6 | fprintf(file, '\n'); 7 | fprintf(file, '%d\n', camera_data.num_cameras); 8 | 9 | for i = 1:camera_data.num_cameras 10 | fprintf(file, 'iconic_images\\%s.jpg ', camera_data.names{i}); 11 | fprintf(file, '%f ', camera_data.focals(i)); 12 | quat = matrix_to_quaternion(camera_data.orientations{i}'); 13 | fprintf(file, '%f %f %f %f ', quat(1), quat(2), quat(3), quat(4)); 14 | center = camera_data.centers(:,i); 15 | fprintf(file, '%f %f %f ', center(1), center(2), center(3)); 16 | fprintf(file, '0 0\n'); 17 | end 18 | 19 | fprintf(file, '\n'); 20 | fprintf(file, '%d\n', length(point_observations)); 21 | 22 | for i = 1:length(point_observations) 23 | xyz = point_data.xyzs(:,i); 24 | fprintf(file, '%f %f %f ', xyz(1), xyz(2), xyz(3)); 25 | fprintf(file, '0 0 0 '); 26 | num_obs = point_observations{i}.num_observations; 27 | fprintf(file, '%d ', num_obs); 28 | for j = 1:num_obs 29 | cam_idx = point_observations{i}.camera_indices(j); 30 | fprintf(file, '%d ', cam_idx - 1); 31 | fprintf(file, '%d ', point_observations{i}.feature_indices(j) - 1); 32 | loc = point_observations{i}.locations_2d(:,j); 33 | loc = loc - (camera_data.dimensions(:,cam_idx) ./ 2) - 1; 34 | fprintf(file, '%f %f ', loc(1), loc(2)); 35 | end 36 | fprintf(file, '\n'); 37 | end 38 | 39 | fclose(file); 40 | 41 | end % function 42 | -------------------------------------------------------------------------------- /matlab/main.m: -------------------------------------------------------------------------------- 1 | %% ----------------------------------------------------------------------------- 2 | 3 | addpath('code') 4 | if ~exist('code/find_nearby_indices.mexw64', 'file') 5 | mex code/find_nearby_indices.cpp -outdir code 6 | end 7 | 8 | %% ----------------------------------------------------------------------------- 9 | 10 | clear 11 | clc 12 | 13 | main_settings 14 | 15 | %% ----------------------------------------------------------------------------- 16 | 17 | disp(' ') 18 | disp('Loading data...') 19 | timer = tic; 20 | main_load_data 21 | toc(timer) 22 | disp('Loading data done') 23 | 24 | %% ----------------------------------------------------------------------------- 25 | 26 | if enable_images_in_spanning_tree 27 | disp(' ') 28 | disp('Creating thumbnails...') 29 | timer = tic; 30 | create_thumbnails(camera_data, image_folder, thumbnail_folder, 120); 31 | toc(timer) 32 | disp('Creating thumbnails done') 33 | end 34 | 35 | %% ----------------------------------------------------------------------------- 36 | 37 | disp(' ') 38 | disp('Computing segmentations...') 39 | timer = tic; 40 | compute_image_segmentations(camera_data, image_folder,... 41 | segmentation_folder, segmentation_exe); 42 | toc(timer) 43 | disp('Computing segmentations done') 44 | 45 | %% ----------------------------------------------------------------------------- 46 | 47 | main_run 48 | 49 | %% ----------------------------------------------------------------------------- 50 | -------------------------------------------------------------------------------- /matlab/main_load_data.m: -------------------------------------------------------------------------------- 1 | if dataset_folder(end) ~= '/' && dataset_folder(end) ~= '\' 2 | dataset_folder = [dataset_folder '/']; 3 | end 4 | 5 | switch model_name 6 | case 'street' 7 | nvm_path = [dataset_folder 'street/model.nvm']; 8 | image_folder = [dataset_folder 'street/images']; 9 | segmentation_folder = [dataset_folder 'street/segmentations']; 10 | thumbnail_folder = [dataset_folder 'street/thumbnails']; 11 | inlier_matches_path = [dataset_folder 'street/inlier_matches.txt']; 12 | case 'cereal' 13 | nvm_path = [dataset_folder 'cereal/model.nvm']; 14 | image_folder = [dataset_folder 'cereal/images']; 15 | segmentation_folder = [dataset_folder 'cereal/segmentations']; 16 | thumbnail_folder = [dataset_folder 'cereal/thumbnails']; 17 | inlier_matches_path = [dataset_folder 'cereal/inlier_matches.txt']; 18 | case 'indoor' 19 | nvm_path = [dataset_folder 'indoor/model.nvm']; 20 | image_folder = [dataset_folder 'indoor/images']; 21 | segmentation_folder = [dataset_folder 'indoor/segmentations']; 22 | thumbnail_folder = [dataset_folder 'indoor/thumbnails']; 23 | inlier_matches_path = [dataset_folder 'indoor/inlier_matches.txt']; 24 | case 'brandenburg_gate' 25 | nvm_path = [dataset_folder 'brandenburg_gate/model.nvm']; 26 | image_folder = [dataset_folder 'brandenburg_gate/images']; 27 | segmentation_folder = [dataset_folder 'brandenburg_gate/segmentations']; 28 | thumbnail_folder = [dataset_folder 'brandenburg_gate/thumbnails']; 29 | inlier_matches_path = [dataset_folder 'brandenburg_gate/inlier_matches.txt']; 30 | case 'church_on_spilled_blood' 31 | nvm_path = [dataset_folder 'church_on_spilled_blood/model.nvm']; 32 | image_folder = [dataset_folder 'church_on_spilled_blood/images']; 33 | segmentation_folder = [dataset_folder 'church_on_spilled_blood/segmentations']; 34 | thumbnail_folder = [dataset_folder 'church_on_spilled_blood/thumbnails']; 35 | inlier_matches_path = [dataset_folder 'church_on_spilled_blood/inlier_matches.txt']; 36 | case 'radcliffe_camera' 37 | nvm_path = [dataset_folder 'radcliffe_camera/model.nvm']; 38 | image_folder = [dataset_folder 'radcliffe_camera/images']; 39 | segmentation_folder = [dataset_folder 'radcliffe_camera/segmentations']; 40 | thumbnail_folder = [dataset_folder 'radcliffe_camera/thumbnails']; 41 | inlier_matches_path = [dataset_folder 'radcliffe_camera/inlier_matches.txt']; 42 | case 'arc_de_triomphe' 43 | nvm_path = [dataset_folder 'arc_de_triomphe/model.nvm']; 44 | image_folder = [dataset_folder 'arc_de_triomphe/images']; 45 | segmentation_folder = [dataset_folder 'arc_de_triomphe/segmentations']; 46 | thumbnail_folder = [dataset_folder 'arc_de_triomphe/thumbnails']; 47 | inlier_matches_path = [dataset_folder 'arc_de_triomphe/inlier_matches.txt']; 48 | case 'alexander_nevsky_cathedral' 49 | nvm_path = [dataset_folder 'alexander_nevsky_cathedral/model.nvm']; 50 | image_folder = [dataset_folder 'alexander_nevsky_cathedral/images']; 51 | segmentation_folder = [dataset_folder 'alexander_nevsky_cathedral/segmentations']; 52 | thumbnail_folder = [dataset_folder 'alexander_nevsky_cathedral/thumbnails']; 53 | inlier_matches_path = [dataset_folder 'alexander_nevsky_cathedral/inlier_matches.txt']; 54 | case 'berliner_dom' 55 | nvm_path = [dataset_folder 'berliner_dom/model.nvm']; 56 | image_folder = [dataset_folder 'berliner_dom/images']; 57 | segmentation_folder = [dataset_folder 'berliner_dom/segmentations']; 58 | thumbnail_folder = [dataset_folder 'berliner_dom/thumbnails']; 59 | inlier_matches_path = [dataset_folder 'berliner_dom/inlier_matches.txt']; 60 | case 'big_ben' 61 | nvm_path = [dataset_folder 'big_ben/model_iconics.nvm']; 62 | image_folder = [dataset_folder 'big_ben/images']; 63 | segmentation_folder = [dataset_folder 'big_ben/segmentations']; 64 | thumbnail_folder = [dataset_folder 'big_ben/thumbnails']; 65 | inlier_matches_path = [dataset_folder 'big_ben/inlier_matches_iconics.txt']; 66 | otherwise 67 | disp('ERROR: model_name not found in main_init.m') 68 | end 69 | 70 | disp(['Model: ' model_name]) 71 | 72 | figures_folder = ['figures/' model_name]; 73 | if ~exist(figures_folder, 'dir') 74 | mkdir(figures_folder) 75 | end 76 | 77 | [camera_data, point_data, point_observations] =... 78 | read_nvm_and_image_dimensions(nvm_path, image_folder); 79 | visibility_matrix = create_visibility_matrix(... 80 | point_observations, camera_data, point_data); 81 | camera_observations = create_camera_observations(... 82 | point_observations, visibility_matrix); 83 | inlier_matches = read_inlier_matches(... 84 | inlier_matches_path, camera_data, camera_observations); 85 | [all_inlier_matches, all_inlier_matches_camera_indices] = read_all_inlier_matches(... 86 | inlier_matches_path, camera_data); 87 | 88 | disp(['# Cameras: ' num2str(camera_data.num_cameras)]) 89 | disp(['# Points: ' num2str(point_data.num_points)]) 90 | -------------------------------------------------------------------------------- /matlab/main_process_merging_result.m: -------------------------------------------------------------------------------- 1 | % Handle cases where there are 3 or more merged models 2 | 3 | if num_split_trees == 1 4 | disp(' ') 5 | disp('Done, no need to process merging result') 6 | return 7 | end 8 | 9 | [num_groups, group_assignments] = graphconncomp(sparse(merged_num_inliers), 'Directed', false); 10 | group_sizes = compute_group_sizes(group_assignments); 11 | 12 | if max(group_sizes) == 3 && num_groups == 1 13 | merged_success = merged_num_inliers > 0; 14 | [~, middle_group] = max(sum(merged_success)); 15 | groups = setdiff([1 2 3], middle_group); 16 | first_group = groups(1); 17 | second_group = groups(2); 18 | 19 | group_assignments = compute_split_group_assignments(split_camera_trees); 20 | 21 | first_group_transform = merged_similarities{first_group, middle_group}; 22 | second_group_transform = merged_similarities{second_group, middle_group}; 23 | 24 | if middle_group < first_group 25 | first_group_transform = inv([first_group_transform; [0 0 0 1]]); 26 | first_group_transform = first_group_transform(1:3, :); 27 | end 28 | if middle_group < second_group 29 | second_group_transform = inv([second_group_transform; [0 0 0 1]]); 30 | second_group_transform = second_group_transform(1:3, :); 31 | end 32 | 33 | plot_3_merged_models(camera_data, point_data, visibility_matrix, group_assignments,... 34 | first_group, second_group, middle_group,... 35 | first_group_transform, second_group_transform); 36 | end 37 | -------------------------------------------------------------------------------- /matlab/main_run.m: -------------------------------------------------------------------------------- 1 | %% ----------------------------------------------------------------------------- 2 | 3 | total_timer = tic; 4 | 5 | %% ----------------------------------------------------------------------------- 6 | 7 | disp(' ') 8 | disp('Computing camera spanning tree...') 9 | timer = tic; 10 | camera_tree = compute_camera_spanning_tree(camera_observations); 11 | toc(timer) 12 | disp('Computing camera spanning tree done') 13 | 14 | %% ----------------------------------------------------------------------------- 15 | 16 | if enable_spanning_tree_visualization 17 | disp(' ') 18 | disp('Visualizing camera spanning tree...') 19 | timer = tic; 20 | visualize_camera_tree(camera_tree, camera_data, model_name,... 21 | [figures_folder '/' model_name '_spanning_tree'],... 22 | {edge_label_baseline_angle_class(camera_data, point_data, visibility_matrix)}, [],... 23 | '', graphviz_sfdp_exe); 24 | if enable_images_in_spanning_tree 25 | visualize_camera_tree(camera_tree, camera_data, model_name,... 26 | [figures_folder '/' model_name '_spanning_tree'],... 27 | {edge_label_baseline_angle_class(camera_data, point_data, visibility_matrix)}, [],... 28 | thumbnail_folder, graphviz_sfdp_exe); 29 | end 30 | toc(timer) 31 | disp('Visualizing camera spanning tree done') 32 | end 33 | 34 | %% ----------------------------------------------------------------------------- 35 | 36 | disp(' ') 37 | disp('Enforcing n-view points...') 38 | timer = tic; 39 | if isempty(inlier_matches_path) 40 | [point_data, point_observations, visibility_matrix,... 41 | camera_observations] = enforce_n_view_points_no_inliers(... 42 | point_data, point_observations, visibility_matrix,... 43 | camera_observations, min_views_per_point); 44 | else 45 | [point_data, point_observations, visibility_matrix,... 46 | camera_observations, inlier_matches] = enforce_n_view_points(... 47 | point_data, point_observations, visibility_matrix,... 48 | camera_observations, inlier_matches, min_views_per_point); 49 | end 50 | toc(timer) 51 | disp('Enforcing n-view points done') 52 | 53 | %% ----------------------------------------------------------------------------- 54 | 55 | disp(' ') 56 | disp('Computing connected camera matrix...') 57 | timer = tic; 58 | connected_camera_matrix = compute_connected_camera_matrix2(... 59 | camera_observations, min_common_points_for_connection); 60 | toc(timer) 61 | disp('Computing connected camera matrix done') 62 | 63 | %% ----------------------------------------------------------------------------- 64 | 65 | disp(' ') 66 | disp('Computing camera observation segments...') 67 | timer = tic; 68 | camera_observation_segments = compute_camera_observation_segments2(... 69 | camera_observations, camera_data, segmentation_folder); 70 | toc(timer) 71 | disp('Computing camera observation segments done') 72 | 73 | %% ----------------------------------------------------------------------------- 74 | 75 | disp(' ') 76 | disp('Main splitting...') 77 | disp(' ') 78 | splitting_timer = tic; 79 | 80 | main_run_splitting2 81 | 82 | toc(splitting_timer) 83 | disp('Main splitting done') 84 | disp(' ') 85 | 86 | %% ----------------------------------------------------------------------------- 87 | 88 | disp(' ') 89 | disp('Main merging...') 90 | disp(' ') 91 | merging_timer = tic; 92 | 93 | main_run_merging2 94 | 95 | toc(merging_timer) 96 | disp('Main merging done') 97 | disp(' ') 98 | 99 | %% ----------------------------------------------------------------------------- 100 | 101 | disp(' ') 102 | disp('Process merging...') 103 | disp(' ') 104 | merging_timer = tic; 105 | 106 | main_process_merging_result 107 | 108 | toc(merging_timer) 109 | disp('Process merging done') 110 | disp(' ') 111 | 112 | %% ----------------------------------------------------------------------------- 113 | 114 | disp('TOTAL TIME') 115 | toc(total_timer) 116 | 117 | %% ----------------------------------------------------------------------------- 118 | 119 | % Create a new NVM file with the merged result. This is still exerimental, and 120 | % may not work for all datasets. 121 | 122 | %new_point_observations = create_point_observations(new_camera_observations, new_point_data.num_points); 123 | %write_merged_nvm('merged.nvm', new_camera_data, new_point_data, new_point_observations); 124 | -------------------------------------------------------------------------------- /matlab/main_run_merging2.m: -------------------------------------------------------------------------------- 1 | num_split_trees = length(split_camera_trees); 2 | 3 | if num_split_trees == 1 4 | disp(' ') 5 | disp('Done, no need to do merging') 6 | return 7 | end 8 | 9 | disp(' ') 10 | disp('Merging...') 11 | 12 | group_assignments = compute_split_group_assignments(split_camera_trees); 13 | group_sizes = compute_group_sizes(group_assignments); 14 | 15 | disconnected_inliers = find_disconnected_inliers(... 16 | inlier_matches, camera_observations, camera_data); 17 | 18 | distance_threshold_3d =... 19 | compute_distance_threshold_3d(camera_data, point_data, ransac_distance_percentage); 20 | 21 | merged_num_inliers = zeros(num_split_trees, num_split_trees); 22 | merged_inlier_indices = cell(num_split_trees, num_split_trees); 23 | merged_similarities = cell(num_split_trees, num_split_trees); 24 | 25 | for group_idx1 = 1:num_split_trees - 1 26 | for group_idx2 = group_idx1+1:num_split_trees 27 | 28 | % Find disconnected inliers between these two camera groups 29 | common_point_flags = identify_common_points_between_groups(... 30 | visibility_matrix, group_assignments, group_idx1, group_idx2); 31 | [disconnected_inlier_point_indices, all_disconnected_inlier_point_indices] =... 32 | find_disconnected_inlier_point_indices(... 33 | disconnected_inliers, common_point_flags, group_assignments,... 34 | group_idx1, group_idx2); 35 | 36 | if isempty(disconnected_inlier_point_indices) 37 | disp(' ') 38 | disp('No disconnected inliers') 39 | break 40 | end 41 | 42 | all_disconnected_inlier_points1 =... 43 | point_data.xyzs(:,all_disconnected_inlier_point_indices(1,:)); 44 | all_disconnected_inlier_points2 =... 45 | point_data.xyzs(:,all_disconnected_inlier_point_indices(2,:)); 46 | 47 | all_disconnected_inlier_points = [all_disconnected_inlier_points1; all_disconnected_inlier_points2]; 48 | 49 | disconnected_inlier_points1 =... 50 | point_data.xyzs(:,disconnected_inlier_point_indices(1,:)); 51 | disconnected_inlier_points2 =... 52 | point_data.xyzs(:,disconnected_inlier_point_indices(2,:)); 53 | 54 | disconnected_inlier_points = [disconnected_inlier_points1; disconnected_inlier_points2]; 55 | 56 | merge_attempt_idx = 0; 57 | while true 58 | merge_attempt_idx = merge_attempt_idx + 1; 59 | 60 | if merge_attempt_idx > max_num_merge_tries 61 | disp(' ') 62 | disp('Merging failed, exceeded maximum number of merge attempts') 63 | break 64 | end 65 | 66 | if size(disconnected_inlier_points, 2) < min_common_points_for_connection 67 | disp(' ') 68 | disp(['Merging failed, not enough points: ' num2str(size(disconnected_inlier_points, 2))]) 69 | break 70 | end 71 | 72 | % ------------------------------------------------------------------ 73 | % Attempt to find a similarity transform 74 | disp(' ') 75 | disp('Running RANSAC...') 76 | timer = tic; 77 | [similarity, similarity_inliers] = ransac_3d_similarity(... 78 | disconnected_inlier_points, distance_threshold_3d); 79 | toc(timer) 80 | disp('Running RANSAC done') 81 | 82 | if isempty(similarity) 83 | disp('Merging failed, empty similarity') 84 | break 85 | end 86 | 87 | fprintf('%.8f, %.8f, %.8f, %.8f;\n%.8f, %.8f, %.8f, %.8f;\n%.8f, %.8f, %.8f, %.8f;\n',... 88 | similarity(1,1), similarity(1,2), similarity(1,3), similarity(1,4),... 89 | similarity(2,1), similarity(2,2), similarity(2,3), similarity(2,4),... 90 | similarity(3,1), similarity(3,2), similarity(3,3), similarity(3,4)); 91 | 92 | all_similarity_inliers = compute_similarity_inliers(... 93 | similarity, all_disconnected_inlier_points, distance_threshold_3d); 94 | 95 | num_inliers = length(all_similarity_inliers); 96 | 97 | disp(' ') 98 | disp(['Expanded inliers: ' num2str(num_inliers) ' / ' num2str(size(all_disconnected_inlier_point_indices,2))]) 99 | 100 | % Merging failed, not enough inliers, stop merging attempts 101 | if num_inliers < min_common_points_for_connection 102 | disp(['Merging failed, not enough inliers: ' num2str(num_inliers)]) 103 | break 104 | end 105 | 106 | % ------------------------------------------------------------------ 107 | disp(' ') 108 | disp('Transforming camera group...') 109 | timer = tic; 110 | [new_camera_data, new_point_data, new_visibility_matrix,... 111 | new_connected_camera_matrix, new_camera_observations] =... 112 | transform_camera_group(camera_data, point_data,... 113 | visibility_matrix, camera_observations, group_assignments,... 114 | group_idx1, group_idx2, similarity,... 115 | all_disconnected_inlier_point_indices(:,all_similarity_inliers),... 116 | common_point_flags, min_common_points_for_connection); 117 | toc(timer) 118 | disp('Transforming camera group done') 119 | 120 | %% ----------------------------------------------------------------- 121 | 122 | disp(' ') 123 | disp('Computing camera observation segments...') 124 | timer = tic; 125 | new_camera_observation_segments = compute_camera_observation_segments2(... 126 | new_camera_observations, new_camera_data, segmentation_folder); 127 | toc(timer) 128 | disp('Computing camera observation segments done') 129 | 130 | % ------------------------------------------------------------------ 131 | disp(' ') 132 | disp('Generating split camera tasks...') 133 | timer = tic; 134 | split_camera_tasks = generate_split_camera_tasks_single_edge(... 135 | new_connected_camera_matrix, new_camera_data, new_point_data,... 136 | new_visibility_matrix, max_baseline_angle, max_split_cameras_per_edge,... 137 | group_assignments, group_sizes, group_idx1, group_idx2); 138 | toc(timer) 139 | disp('Generating split camera tasks done') 140 | 141 | % ------------------------------------------------------------------ 142 | disp(' ') 143 | disp('Computing camera pair segments...') 144 | timer = tic; 145 | new_camera_pair_segments = compute_camera_pair_segments2(... 146 | split_camera_tasks, new_camera_data, new_point_data,... 147 | new_camera_observations, segmentation_folder); 148 | toc(timer) 149 | disp('Computing camera pair segments done') 150 | 151 | % ------------------------------------------------------------------ 152 | disp(' ') 153 | disp('Computing edge conflict...') 154 | timer = tic; 155 | [conflict, num_split_cameras] = compute_edge_conflict2_merging(... 156 | split_camera_tasks{1}, new_camera_observations,... 157 | new_camera_observation_segments, new_camera_pair_segments,... 158 | new_visibility_matrix, all_inlier_matches, all_inlier_matches_camera_indices,... 159 | segmentation_folder, camera_data);%, image_folder); 160 | toc(timer) 161 | disp('Computing edge conflict done') 162 | 163 | % ------------------------------------------------------------------ 164 | % Merging failed, too much conflict, try to merge again 165 | if conflict >= conflict_threshold 166 | disp(' ') 167 | disp(['Merging failed, too much conflict: ' num2str(conflict)]) 168 | plot_merged_model_inliers(new_camera_data, new_point_data, new_visibility_matrix,... 169 | group_assignments, group_idx1, group_idx2,... 170 | all_disconnected_inlier_point_indices(:,all_similarity_inliers)); 171 | title(['Too much conflict: ' num2str(conflict) ', inliers = '... 172 | num2str(length(similarity_inliers)) ' / ' num2str(size(disconnected_inlier_points,2))]) 173 | disconnected_inlier_point_indices(:,similarity_inliers) = []; 174 | disconnected_inlier_points(:,similarity_inliers) = []; 175 | continue 176 | end 177 | 178 | % ------------------------------------------------------------------ 179 | % Merging failed, no overlapping cameras, try to merge again 180 | if num_split_cameras == 0 181 | disp(' ') 182 | disp('Merging failed, no overlapping cameras') 183 | plot_merged_model_inliers(new_camera_data, new_point_data, new_visibility_matrix,... 184 | group_assignments, group_idx1, group_idx2,... 185 | all_disconnected_inlier_point_indices(:,all_similarity_inliers)); 186 | title(['No overlapping cameras, inliers = '... 187 | num2str(length(similarity_inliers)) ' / ' num2str(size(disconnected_inlier_points,2))]) 188 | disconnected_inlier_point_indices(:,similarity_inliers) = []; 189 | disconnected_inlier_points(:,similarity_inliers) = []; 190 | continue 191 | end 192 | 193 | % ------------------------------------------------------------------ 194 | % Merging succeeded 195 | disp(' ') 196 | disp(['Merging succeeded, inliers = ' num2str(num_inliers) ', conflict = ' num2str(conflict)]) 197 | plot_merged_model_inliers(new_camera_data, new_point_data, new_visibility_matrix,... 198 | group_assignments, group_idx1, group_idx2,... 199 | all_disconnected_inlier_point_indices(:,all_similarity_inliers)); 200 | title(['Merging succeeded, inliers = ' num2str(num_inliers) ', conflict = ' num2str(conflict)]) 201 | merged_num_inliers(group_idx1, group_idx2) = num_inliers; 202 | merged_num_inliers(group_idx2, group_idx1) = num_inliers; 203 | merged_inlier_indices{group_idx1, group_idx2} = all_disconnected_inlier_point_indices(:,all_similarity_inliers); 204 | merged_inlier_indices{group_idx2, group_idx1} = all_disconnected_inlier_point_indices(:,all_similarity_inliers); 205 | merged_similarities{group_idx1, group_idx2} = similarity; 206 | merged_similarities{group_idx2, group_idx1} = similarity; 207 | break 208 | end 209 | end 210 | end 211 | -------------------------------------------------------------------------------- /matlab/main_run_splitting2.m: -------------------------------------------------------------------------------- 1 | disp(' ') 2 | disp('Splitting...') 3 | 4 | camera_tree_splitting_tasks = {}; 5 | camera_tree_splitting_tasks{end+1} = camera_tree; 6 | split_camera_trees = {}; 7 | iteration_number = 1; 8 | 9 | while ~isempty(camera_tree_splitting_tasks) 10 | current_camera_tree = camera_tree_splitting_tasks{end}; 11 | camera_tree_splitting_tasks(end) = []; 12 | 13 | % -------------------------------------------------------------------------- 14 | disp(' ') 15 | disp('Generating split camera tasks...') 16 | timer = tic; 17 | split_camera_tasks = generate_split_camera_tasks(... 18 | current_camera_tree, connected_camera_matrix, camera_data, point_data,... 19 | camera_observations, max_baseline_angle, max_split_cameras_per_edge); 20 | toc(timer) 21 | disp('Generating split camera tasks done') 22 | 23 | % -------------------------------------------------------------------------- 24 | disp(' ') 25 | disp('Computing camera pair segments...') 26 | timer = tic; 27 | camera_pair_segments = compute_camera_pair_segments2(... 28 | split_camera_tasks, camera_data, point_data, camera_observations, segmentation_folder); 29 | toc(timer) 30 | disp('Computing camera pair segments done') 31 | 32 | % -------------------------------------------------------------------------- 33 | disp(' ') 34 | disp('Computing spanning tree conflict...') 35 | timer = tic; 36 | edge_conflict = compute_spanning_tree_conflict2(... 37 | split_camera_tasks,... 38 | camera_observations, camera_observation_segments, camera_pair_segments,... 39 | visibility_matrix, image_folder, camera_data); 40 | toc(timer) 41 | disp('Computing spanning tree conflict done') 42 | 43 | [max_conflict_val, conflicting_edge_idx] = max(edge_conflict); 44 | [group_sizes, group_assignments] = split_camera_tree(current_camera_tree, conflicting_edge_idx, camera_data.num_cameras); 45 | 46 | extra = ''; 47 | if max_conflict_val < conflict_threshold 48 | extra = '_done'; 49 | end 50 | 51 | % -------------------------------------------------------------------------- 52 | if enable_spanning_tree_visualization 53 | disp(' ') 54 | disp('Visualizing spanning tree conflict...') 55 | timer = tic; 56 | visualize_camera_tree(current_camera_tree, camera_data, model_name,... 57 | [figures_folder '/' model_name '_conflict_' num2str(iteration_number) extra],... 58 | {edge_label_conflict_class(current_camera_tree, edge_conflict)}, group_assignments,... 59 | [], graphviz_sfdp_exe); 60 | if enable_images_in_spanning_tree 61 | visualize_camera_tree(current_camera_tree, camera_data, model_name,... 62 | [figures_folder '/' model_name '_conflict_' num2str(iteration_number) extra],... 63 | {edge_label_conflict_class(current_camera_tree, edge_conflict)}, group_assignments,... 64 | thumbnail_folder, graphviz_sfdp_exe); 65 | end 66 | toc(timer) 67 | disp('Visualizing spanning tree conflict done') 68 | end 69 | 70 | % -------------------------------------------------------------------------- 71 | disp(' ') 72 | disp(['Max Conflict: ' num2str(max_conflict_val)]) 73 | 74 | if max_conflict_val >= conflict_threshold 75 | disp('Further splitting required...') 76 | 77 | [sorted_sizes, sorted_sizes_idx] = sort(group_sizes, 'descend'); 78 | disp(['Group Sizes: ' num2str(sorted_sizes(1:2)')]) 79 | 80 | group1_flags = group_assignments == sorted_sizes_idx(1); 81 | group2_flags = group_assignments == sorted_sizes_idx(2); 82 | 83 | camera_tree1 = current_camera_tree; 84 | camera_tree2 = current_camera_tree; 85 | 86 | camera_tree1(~group1_flags, :) = 0; 87 | camera_tree1(:, ~group1_flags) = 0; 88 | camera_tree2(~group2_flags, :) = 0; 89 | camera_tree2(:, ~group2_flags) = 0; 90 | 91 | camera_tree_splitting_tasks{end+1} = camera_tree1; 92 | camera_tree_splitting_tasks{end+1} = camera_tree2; 93 | else 94 | disp('Done splitting this tree.') 95 | split_camera_trees{end+1} = current_camera_tree; 96 | end 97 | 98 | iteration_number = iteration_number + 1; 99 | end 100 | -------------------------------------------------------------------------------- /matlab/main_settings.m: -------------------------------------------------------------------------------- 1 | %model_name = 'street'; 2 | %model_name = 'cereal'; 3 | %model_name = 'indoor'; 4 | %model_name = 'brandenburg_gate'; 5 | %model_name = 'church_on_spilled_blood'; 6 | %model_name = 'radcliffe_camera'; 7 | %model_name = 'arc_de_triomphe'; 8 | %model_name = 'alexander_nevsky_cathedral'; 9 | %model_name = 'berliner_dom'; 10 | model_name = 'big_ben'; 11 | 12 | conflict_threshold = 7.0; 13 | min_common_points_for_connection = 8; 14 | max_baseline_angle = 20; % degrees 15 | max_split_cameras_per_edge = 100; 16 | ransac_distance_percentage = 0.015; 17 | max_num_merge_tries = 100; 18 | min_views_per_point = 3; 19 | 20 | enable_spanning_tree_visualization = true; 21 | enable_images_in_spanning_tree = true; 22 | 23 | dataset_folder = './sfm_duplicate_structure_correction_datasets'; 24 | segmentation_exe = './sfm_duplicate_structure_correction/SLICO-Superpixels/precompiled_bin/SLICO.exe'; 25 | graphviz_sfdp_exe = './graphviz-2.34/release/bin/sfdp.exe'; 26 | -------------------------------------------------------------------------------- /matlab/precompiled_mex/find_nearby_indices.mexw64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jheinly/sfm_duplicate_structure_correction/1e4376729b2c2e690181ff6ba6acb4dc644b3640/matlab/precompiled_mex/find_nearby_indices.mexw64 --------------------------------------------------------------------------------