kopia lustrzana https://github.com/OpenDroneMap/NodeODM
				
				
				
			Test mode, bug fixing, automatic linting
							rodzic
							
								
									3230c4b45a
								
							
						
					
					
						commit
						36ffae3389
					
				|  | @ -0,0 +1,16 @@ | |||
| module.exports = function(grunt) { | ||||
| 
 | ||||
| 	require('time-grunt')(grunt); | ||||
| 
 | ||||
| 	grunt.initConfig({ | ||||
| 		jshint: { | ||||
| 			options: { | ||||
| 				jshintrc: ".jshintrc" | ||||
| 		    }, | ||||
| 			all: ['Gruntfile.js', 'libs/**/*.js', 'docs/**/*.js', 'index.js', 'config.js'] | ||||
| 		} | ||||
| 	}); | ||||
| 
 | ||||
| 	grunt.loadNpmTasks('grunt-contrib-jshint'); | ||||
| 	grunt.registerTask('default', ['jshint']); | ||||
| }; | ||||
							
								
								
									
										10
									
								
								README.md
								
								
								
								
							
							
						
						
									
										10
									
								
								README.md
								
								
								
								
							|  | @ -97,6 +97,16 @@ http://www.buildsucceeded.com/2015/solved-pm2-startup-at-boot-time-centos-7-red- | |||
| 
 | ||||
| You can monitor the process using `pm2 status`. | ||||
| 
 | ||||
| ### Test Mode | ||||
| 
 | ||||
| If you want to make a contribution, but don't want to setup OpenDroneMap, or perhaps you are working on a Windows machine, or if you want to run automated tests, you can turn test mode on: | ||||
| 
 | ||||
| ``` | ||||
| node index.js --test | ||||
| ``` | ||||
| 
 | ||||
| While in test mode all calls to OpenDroneMap's code will be simulated (see the /tests directory for the mock data that is returned). | ||||
| 
 | ||||
| ### Test Images | ||||
| 
 | ||||
| You can find some test drone images [here](https://github.com/dakotabenjamin/odm_data). | ||||
|  |  | |||
							
								
								
									
										19
									
								
								index.js
								
								
								
								
							
							
						
						
									
										19
									
								
								index.js
								
								
								
								
							|  | @ -36,6 +36,7 @@ let morgan = require('morgan'); | |||
| let TaskManager = require('./libs/TaskManager'); | ||||
| let Task = require('./libs/Task'); | ||||
| let odmOptions = require('./libs/odmOptions'); | ||||
| let Directories = require('./libs/Directories'); | ||||
| 
 | ||||
| let winstonStream = { | ||||
|     write: function(message, encoding){ | ||||
|  | @ -51,14 +52,14 @@ app.use('/swagger.json', express.static('docs/swagger.json')); | |||
| let upload = multer({ | ||||
| 	storage: multer.diskStorage({ | ||||
| 	  destination: (req, file, cb) => { | ||||
| 	  	let path = `tmp/${req.id}/`; | ||||
| 	  	fs.exists(path, exists => { | ||||
| 	  	let dstPath = path.join("tmp", req.id); | ||||
| 	  	fs.exists(dstPath, exists => { | ||||
| 	  		if (!exists){ | ||||
| 	  			fs.mkdir(path, undefined, () => { | ||||
| 	  				cb(null, path); | ||||
| 	  			fs.mkdir(dstPath, undefined, () => { | ||||
| 	  				cb(null, dstPath); | ||||
| 	  			}); | ||||
| 	  		}else{ | ||||
| 	    		cb(null, path); | ||||
| 	    		cb(null, dstPath); | ||||
| 	  		} | ||||
| 	  	}); | ||||
| 	  }, | ||||
|  | @ -115,10 +116,10 @@ let server; | |||
| app.post('/task/new', addRequestId, upload.array('images'), (req, res) => { | ||||
| 	if (req.files.length === 0) res.json({error: "Need at least 1 file."}); | ||||
| 	else{ | ||||
| 		let srcPath = `tmp/${req.id}`; | ||||
| 		let destPath = `data/${req.id}`; | ||||
| 		let destImagesPath = `${destPath}/images`; | ||||
| 		let destGpcPath = `${destPath}/gpc`; | ||||
| 		let srcPath = path.join("tmp", req.id); | ||||
| 		let destPath = path.join(Directories.data, req.id); | ||||
| 		let destImagesPath = path.join(destPath, "images"); | ||||
| 		let destGpcPath = path.join(destPath, "gpc"); | ||||
| 
 | ||||
| 		async.series([ | ||||
| 			cb => { | ||||
|  |  | |||
|  | @ -0,0 +1,28 @@ | |||
| /*  | ||||
| Node-OpenDroneMap Node.js App and REST API to access OpenDroneMap.  | ||||
| Copyright (C) 2016 Node-OpenDroneMap Contributors | ||||
| 
 | ||||
| This program is free software: you can redistribute it and/or modify | ||||
| it under the terms of the GNU General Public License as published by | ||||
| the Free Software Foundation, either version 3 of the License, or | ||||
| (at your option) any later version. | ||||
| 
 | ||||
| This program is distributed in the hope that it will be useful, | ||||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
| GNU General Public License for more details. | ||||
| 
 | ||||
| You should have received a copy of the GNU General Public License | ||||
| along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
| */ | ||||
| "use strict"; | ||||
| let config = require('../config'); | ||||
| let path = require('path'); | ||||
| 
 | ||||
| class Directories{ | ||||
| 	static get data(){ | ||||
| 		return !config.test ? "data" : path.join("tests", "data"); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| module.exports = Directories; | ||||
							
								
								
									
										27
									
								
								libs/Task.js
								
								
								
								
							
							
						
						
									
										27
									
								
								libs/Task.js
								
								
								
								
							|  | @ -17,6 +17,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>. | |||
| */ | ||||
| "use strict"; | ||||
| 
 | ||||
| let config = require('../config'); | ||||
| let async = require('async'); | ||||
| let assert = require('assert'); | ||||
| let logger = require('./logger'); | ||||
|  | @ -26,6 +27,7 @@ let rmdir = require('rimraf'); | |||
| let odmRunner = require('./odmRunner'); | ||||
| let archiver = require('archiver'); | ||||
| let os = require('os'); | ||||
| let Directories = require('./Directories'); | ||||
| 
 | ||||
| let statusCodes = require('./statusCodes'); | ||||
| 
 | ||||
|  | @ -99,25 +101,25 @@ module.exports = class Task{ | |||
| 	// Get path where images are stored for this task
 | ||||
| 	// (relative to nodejs process CWD)
 | ||||
| 	getImagesFolderPath(){ | ||||
| 		return `${this.getProjectFolderPath()}/images`; | ||||
| 		return path.join(this.getProjectFolderPath(), "images"); | ||||
| 	} | ||||
| 
 | ||||
| 	// Get path where GPC file(s) are stored
 | ||||
| 	// (relative to nodejs process CWD)
 | ||||
| 	getGpcFolderPath(){ | ||||
| 		return `${this.getProjectFolderPath()}/gpc`; | ||||
| 		return path.join(this.getProjectFolderPath(), "gpc"); | ||||
| 	} | ||||
| 
 | ||||
| 	// Get path of project (where all images and assets folder are contained)
 | ||||
| 	// (relative to nodejs process CWD)
 | ||||
| 	getProjectFolderPath(){ | ||||
| 		return `data/${this.uuid}`; | ||||
| 		return path.join(Directories.data, this.uuid); | ||||
| 	} | ||||
| 
 | ||||
| 	// Get the path of the archive where all assets
 | ||||
| 	// outputted by this task are stored.
 | ||||
| 	getAssetsArchivePath(){ | ||||
| 		return `${this.getProjectFolderPath()}/all.zip`; | ||||
| 		return path.join(this.getProjectFolderPath(), "all.zip"); | ||||
| 	} | ||||
| 
 | ||||
| 	// Deletes files and folders related to this task
 | ||||
|  | @ -207,16 +209,21 @@ module.exports = class Task{ | |||
| 
 | ||||
| 			archive.on('error', err => { | ||||
| 				this.setStatus(statusCodes.FAILED); | ||||
| 				logger.error(`Could not archive .zip file: ${err.message}`); | ||||
| 				finished(err); | ||||
| 			}); | ||||
| 
 | ||||
| 			archive.pipe(output); | ||||
| 			archive | ||||
| 			  .directory(`${this.getProjectFolderPath()}/odm_orthophoto`, 'odm_orthophoto') | ||||
| 			  .directory(`${this.getProjectFolderPath()}/odm_georeferencing`, 'odm_georeferencing') | ||||
| 			  .directory(`${this.getProjectFolderPath()}/odm_texturing`, 'odm_texturing') | ||||
| 			  .directory(`${this.getProjectFolderPath()}/odm_meshing`, 'odm_meshing') | ||||
| 			  .finalize(); | ||||
| 			['odm_orthophoto', 'odm_georeferencing', 'odm_texturing', 'odm_meshing'].forEach(folderToArchive => { | ||||
| 				let sourcePath = !config.test ?  | ||||
| 								this.getProjectFolderPath() :  | ||||
| 								path.join("tests", "processing_results"); | ||||
| 				 | ||||
| 				archive.directory( | ||||
| 						path.join(sourcePath, folderToArchive), | ||||
| 					folderToArchive); | ||||
| 			}); | ||||
| 			archive.finalize(); | ||||
| 		}; | ||||
| 
 | ||||
| 		if (this.status.code === statusCodes.QUEUED){ | ||||
|  |  | |||
|  | @ -26,9 +26,9 @@ let Task = require('./Task'); | |||
| let statusCodes = require('./statusCodes'); | ||||
| let async = require('async'); | ||||
| let schedule = require('node-schedule'); | ||||
| let Directories = require('./Directories'); | ||||
| 
 | ||||
| const DATA_DIR = "data"; | ||||
| const TASKS_DUMP_FILE = `${DATA_DIR}/tasks.json`; | ||||
| const TASKS_DUMP_FILE = path.join(Directories.data, "tasks.json"); | ||||
| const CLEANUP_TASKS_IF_OLDER_THAN = 1000 * 60 * 60 * 24 * config.cleanupTasksAfter; // days
 | ||||
| 
 | ||||
| module.exports = class TaskManager{ | ||||
|  | @ -85,11 +85,11 @@ module.exports = class TaskManager{ | |||
| 	removeOrphanedDirectories(done){ | ||||
| 		logger.info("Checking for orphaned directories to be removed..."); | ||||
| 
 | ||||
| 		fs.readdir(DATA_DIR, (err, entries) => { | ||||
| 		fs.readdir(Directories.data, (err, entries) => { | ||||
| 			if (err) done(err); | ||||
| 			else{ | ||||
| 				async.eachSeries(entries, (entry, cb) => { | ||||
| 					let dirPath = path.join(DATA_DIR, entry); | ||||
| 					let dirPath = path.join(Directories.data, entry); | ||||
| 					if (fs.statSync(dirPath).isDirectory() && | ||||
| 						entry.match(/^[\w\d]+\-[\w\d]+\-[\w\d]+\-[\w\d]+\-[\w\d]+$/) && | ||||
| 						!this.tasks[entry]){ | ||||
|  |  | |||
|  | @ -26,7 +26,7 @@ let path = require('path'); | |||
| // Configure custom File transport to write plain text messages
 | ||||
| let logPath = ( config.logger.logDirectory ?  | ||||
| 				config.logger.logDirectory :  | ||||
| 				`${__dirname}/../` ); | ||||
| 				path.join(__dirname, "..") ); | ||||
| 
 | ||||
| // Check that log file directory can be written to
 | ||||
| try { | ||||
|  |  | |||
|  | @ -189,6 +189,7 @@ module.exports = { | |||
| 			// Scan through all possible options
 | ||||
| 			for (let odmOption of odmOptions){ | ||||
| 				// Was this option selected by the user?
 | ||||
| 				/*jshint loopfunc: true */ | ||||
| 				let opt = options.find(o => o.name === odmOption.name); | ||||
| 				if (opt){ | ||||
| 					try{ | ||||
|  |  | |||
|  | @ -28,7 +28,7 @@ module.exports = { | |||
| 	run: function(options, done, outputReceived){ | ||||
| 		assert(options["project-path"] !== undefined, "project-path must be defined"); | ||||
| 
 | ||||
| 		let command = [`${config.odm_path}/run.py`]; | ||||
| 		let command = [path.join(config.odm_path, "run.py")]; | ||||
| 		for (var name in options){ | ||||
| 			let value = options[name]; | ||||
| 
 | ||||
|  | @ -48,8 +48,18 @@ module.exports = { | |||
| 		if (config.test){ | ||||
| 			logger.info("Test mode is on, command will not execute"); | ||||
| 
 | ||||
| 			// TODO: simulate test output
 | ||||
| 			done(null, 0, null); | ||||
| 			let outputTestFile = path.join("..", "tests", "odm_output.txt"); | ||||
| 			fs.readFile(path.resolve(__dirname, outputTestFile), 'utf8', (err, text) => { | ||||
| 				if (!err){ | ||||
| 					let lines = text.split("\n"); | ||||
| 					lines.forEach(line => outputReceived(line)); | ||||
| 					 | ||||
| 					done(null, 0, null); | ||||
| 				}else{ | ||||
| 					logger.warn(`Error: ${err.message}`); | ||||
| 					done(err); | ||||
| 				} | ||||
| 			}); | ||||
| 
 | ||||
| 			return; // Skip rest
 | ||||
| 		} | ||||
|  | @ -71,22 +81,18 @@ module.exports = { | |||
| 		// In test mode, we don't call ODM, 
 | ||||
| 		// instead we return a mock
 | ||||
| 		if (config.test){ | ||||
| 			let optionsTestFile = "../tests/odm_options.json"; | ||||
| 			let optionsTestFile = path.join("..", "tests", "odm_options.json"); | ||||
| 			fs.readFile(path.resolve(__dirname, optionsTestFile), 'utf8', (err, json) => { | ||||
| 				if (!err){ | ||||
| 					try{ | ||||
| 						let options = JSON.parse(json); | ||||
| 						 | ||||
| 						// We also mark each description with "TEST" (to make sure we know this is not real data)
 | ||||
| 						options.forEach(option => { option.help = "## TEST ##" + (option.help !== undefined ? ` ${option.help}` : ""); }); | ||||
| 
 | ||||
| 						done(null, options); | ||||
| 					}catch(e){ | ||||
| 						console.log(`Invalid test options ${optionsTestFile}: ${err.message}`); | ||||
| 						logger.warn(`Invalid test options ${optionsTestFile}: ${err.message}`); | ||||
| 						done(e); | ||||
| 					} | ||||
| 				}else{ | ||||
| 					console.log(`Error: ${err.message}`); | ||||
| 					logger.warn(`Error: ${err.message}`); | ||||
| 					done(err); | ||||
| 				} | ||||
| 			}); | ||||
|  | @ -95,7 +101,7 @@ module.exports = { | |||
| 		} | ||||
| 
 | ||||
| 		// Launch
 | ||||
| 		let childProcess = spawn("python", [`${__dirname}/../helpers/odmOptionsToJson.py`, | ||||
| 		let childProcess = spawn("python", [path.join(__dirname, "..", "helpers", "odmOptionsToJson.py"), | ||||
| 				"--project-path", config.odm_path]); | ||||
| 		let output = []; | ||||
| 
 | ||||
|  |  | |||
|  | @ -34,6 +34,9 @@ | |||
|     "winston": "^2.2.0" | ||||
|   }, | ||||
|   "devDependencies": { | ||||
|     "nodemon": "^1.9.2" | ||||
|     "grunt": "^1.0.1", | ||||
|     "grunt-contrib-jshint": "^1.0.0", | ||||
|     "nodemon": "^1.9.2", | ||||
|     "time-grunt": "^1.4.0" | ||||
|   } | ||||
| } | ||||
|  |  | |||
|  | @ -2216,9 +2216,9 @@ | |||
|                 } | ||||
|                 if (!self.showPreview) { | ||||
|                     self.addToStack(file); | ||||
|                     setTimeout(function () { | ||||
|                     // setTimeout(function () {
 | ||||
|                         readFile(i + 1); | ||||
|                     }, 100); | ||||
|                     // }, 100);
 | ||||
|                     self._raise('fileloaded', [file, previewId, i, reader]); | ||||
|                     return; | ||||
|                 } | ||||
|  |  | |||
|  | @ -302,8 +302,7 @@ $(function(){ | |||
|             $("#btnUpload").removeAttr('disabled') | ||||
|                             .val(btnUploadLabel); | ||||
|         }) | ||||
|         .on('filebatchuploaderror', function(e, data, msg){ | ||||
|         }); | ||||
|         .on('filebatchuploaderror', console.warn); | ||||
| 
 | ||||
|     // Load options
 | ||||
|     function Option(properties){ | ||||
|  |  | |||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							|  | @ -0,0 +1,279 @@ | |||
| DJI_0131.JPG - DJI_0313.JPG has 1 candidate matches | ||||
| DJI_0131.JPG - DJI_0177.JPG has 3 candidate matches | ||||
| DJI_0131.JPG - DJI_0302.JPG has 0 candidate matches | ||||
| DJI_0131.JPG - DJI_0210.JPG has 0 candidate matches | ||||
| DJI_0131.JPG - DJI_0164.JPG has 1 candidate matches | ||||
| DJI_0131.JPG - DJI_0222.JPG has 0 candidate matches | ||||
| DJI_0131.JPG - DJI_0211.JPG has 1 candidate matches | ||||
| Matching DJI_0290.JPG  -  205 / 252 | ||||
| DJI_0290.JPG - DJI_0325.JPG has 1 candidate matches | ||||
| DJI_0290.JPG - DJI_0336.JPG has 0 candidate matches | ||||
| Matching DJI_0153.JPG  -  206 / 252 | ||||
| DJI_0153.JPG - DJI_0188.JPG has 1 candidate matches | ||||
| DJI_0153.JPG - DJI_0245.JPG has 3 candidate matches | ||||
| DJI_0153.JPG - DJI_0199.JPG has 0 candidate matches | ||||
| DJI_0153.JPG - DJI_0337.JPG has 0 candidate matches | ||||
| DJI_0153.JPG - DJI_0291.JPG has 2 candidate matches | ||||
| DJI_0153.JPG - DJI_0234.JPG has 0 candidate matches | ||||
| Matching DJI_0321.JPG  -  207 / 252 | ||||
| DJI_0321.JPG - DJI_0340.JPG has 2 candidate matches | ||||
| Matching DJI_0345.JPG  -  208 / 252 | ||||
| Matching DJI_0325.JPG  -  209 / 252 | ||||
| DJI_0325.JPG - DJI_0336.JPG has 5 candidate matches | ||||
| Matching DJI_0215.JPG  -  210 / 252 | ||||
| DJI_0215.JPG - DJI_0261.JPG has 0 candidate matches | ||||
| DJI_0215.JPG - DJI_0308.JPG has 1 candidate matches | ||||
| DJI_0215.JPG - DJI_0353.JPG has 1 candidate matches | ||||
| DJI_0215.JPG - DJI_0218.JPG has 3 candidate matches | ||||
| Matching DJI_0284.JPG  -  211 / 252 | ||||
| DJI_0284.JPG - DJI_0329.JPG has 1 candidate matches | ||||
| DJI_0284.JPG - DJI_0286.JPG has 0 candidate matches | ||||
| DJI_0284.JPG - DJI_0332.JPG has 2 candidate matches | ||||
| Matching DJI_0156.JPG  -  212 / 252 | ||||
| DJI_0156.JPG - DJI_0294.JPG has 1 candidate matches | ||||
| DJI_0156.JPG - DJI_0231.JPG has 2 candidate matches | ||||
| DJI_0156.JPG - DJI_0248.JPG has 0 candidate matches | ||||
| DJI_0156.JPG - DJI_0185.JPG has 13 candidate matches | ||||
| DJI_0156.JPG - DJI_0276.JPG has 0 candidate matches | ||||
| DJI_0156.JPG - DJI_0202.JPG has 3 candidate matches | ||||
| Matching DJI_0108.JPG  -  213 / 252 | ||||
| DJI_0108.JPG - DJI_0188.JPG has 0 candidate matches | ||||
| DJI_0108.JPG - DJI_0279.JPG has 0 candidate matches | ||||
| DJI_0108.JPG - DJI_0153.JPG has 0 candidate matches | ||||
| DJI_0108.JPG - DJI_0200.JPG has 0 candidate matches | ||||
| DJI_0108.JPG - DJI_0199.JPG has 0 candidate matches | ||||
| DJI_0108.JPG - DJI_0234.JPG has 0 candidate matches | ||||
| DJI_0108.JPG - DJI_0291.JPG has 0 candidate matches | ||||
| DJI_0108.JPG - DJI_0142.JPG has 5 candidate matches | ||||
| Matching DJI_0174.JPG  -  214 / 252 | ||||
| DJI_0174.JPG - DJI_0213.JPG has 0 candidate matches | ||||
| DJI_0174.JPG - DJI_0220.JPG has 0 candidate matches | ||||
| DJI_0174.JPG - DJI_0259.JPG has 0 candidate matches | ||||
| DJI_0174.JPG - DJI_0266.JPG has 1 candidate matches | ||||
| DJI_0174.JPG - DJI_0305.JPG has 0 candidate matches | ||||
| Matching DJI_0324.JPG  -  215 / 252 | ||||
| DJI_0324.JPG - DJI_0337.JPG has 1 candidate matches | ||||
| Matching DJI_0116.JPG  -  216 / 252 | ||||
| DJI_0116.JPG - DJI_0134.JPG has 0 candidate matches | ||||
| DJI_0116.JPG - DJI_0299.JPG has 0 candidate matches | ||||
| DJI_0116.JPG - DJI_0271.JPG has 0 candidate matches | ||||
| DJI_0116.JPG - DJI_0161.JPG has 1 candidate matches | ||||
| DJI_0116.JPG - DJI_0208.JPG has 0 candidate matches | ||||
| DJI_0116.JPG - DJI_0225.JPG has 0 candidate matches | ||||
| DJI_0116.JPG - DJI_0345.JPG has 0 candidate matches | ||||
| DJI_0116.JPG - DJI_0254.JPG has 1 candidate matches | ||||
| DJI_0116.JPG - DJI_0179.JPG has 1 candidate matches | ||||
| Matching DJI_0247.JPG  -  217 / 252 | ||||
| DJI_0247.JPG - DJI_0278.JPG has 1 candidate matches | ||||
| DJI_0247.JPG - DJI_0323.JPG has 0 candidate matches | ||||
| DJI_0247.JPG - DJI_0339.JPG has 0 candidate matches | ||||
| DJI_0247.JPG - DJI_0338.JPG has 0 candidate matches | ||||
| Matching DJI_0220.JPG  -  218 / 252 | ||||
| DJI_0220.JPG - DJI_0266.JPG has 0 candidate matches | ||||
| DJI_0220.JPG - DJI_0351.JPG has 1 candidate matches | ||||
| DJI_0220.JPG - DJI_0305.JPG has 0 candidate matches | ||||
| DJI_0220.JPG - DJI_0310.JPG has 0 candidate matches | ||||
| Matching DJI_0128.JPG  -  219 / 252 | ||||
| DJI_0128.JPG - DJI_0174.JPG has 1 candidate matches | ||||
| DJI_0128.JPG - DJI_0213.JPG has 0 candidate matches | ||||
| DJI_0128.JPG - DJI_0310.JPG has 0 candidate matches | ||||
| DJI_0128.JPG - DJI_0167.JPG has 1 candidate matches | ||||
| DJI_0128.JPG - DJI_0351.JPG has 0 candidate matches | ||||
| DJI_0128.JPG - DJI_0305.JPG has 0 candidate matches | ||||
| DJI_0128.JPG - DJI_0260.JPG has 0 candidate matches | ||||
| DJI_0128.JPG - DJI_0220.JPG has 0 candidate matches | ||||
| Matching DJI_0183.JPG  -  220 / 252 | ||||
| DJI_0183.JPG - DJI_0250.JPG has 0 candidate matches | ||||
| DJI_0183.JPG - DJI_0274.JPG has 1 candidate matches | ||||
| DJI_0183.JPG - DJI_0229.JPG has 0 candidate matches | ||||
| DJI_0183.JPG - DJI_0204.JPG has 7 candidate matches | ||||
| DJI_0183.JPG - DJI_0319.JPG has 2 candidate matches | ||||
| DJI_0183.JPG - DJI_0341.JPG has 0 candidate matches | ||||
| DJI_0183.JPG - DJI_0296.JPG has 0 candidate matches | ||||
| Matching DJI_0252.JPG  -  221 / 252 | ||||
| DJI_0252.JPG - DJI_0317.JPG has 0 candidate matches | ||||
| DJI_0252.JPG - DJI_0343.JPG has 1 candidate matches | ||||
| DJI_0252.JPG - DJI_0318.JPG has 0 candidate matches | ||||
| DJI_0252.JPG - DJI_0298.JPG has 0 candidate matches | ||||
| DJI_0252.JPG - DJI_0273.JPG has 7 candidate matches | ||||
| Matching DJI_0308.JPG  -  222 / 252 | ||||
| DJI_0308.JPG - DJI_0353.JPG has 6 candidate matches | ||||
| Matching DJI_0194.JPG  -  223 / 252 | ||||
| DJI_0194.JPG - DJI_0239.JPG has 7 candidate matches | ||||
| DJI_0194.JPG - DJI_0285.JPG has 0 candidate matches | ||||
| DJI_0194.JPG - DJI_0286.JPG has 0 candidate matches | ||||
| DJI_0194.JPG - DJI_0331.JPG has 2 candidate matches | ||||
| DJI_0194.JPG - DJI_0240.JPG has 1 candidate matches | ||||
| DJI_0194.JPG - DJI_0329.JPG has 0 candidate matches | ||||
| DJI_0194.JPG - DJI_0330.JPG has 0 candidate matches | ||||
| Matching DJI_0175.JPG  -  224 / 252 | ||||
| DJI_0175.JPG - DJI_0212.JPG has 2 candidate matches | ||||
| DJI_0175.JPG - DJI_0221.JPG has 1 candidate matches | ||||
| DJI_0175.JPG - DJI_0267.JPG has 1 candidate matches | ||||
| DJI_0175.JPG - DJI_0349.JPG has 1 candidate matches | ||||
| DJI_0175.JPG - DJI_0304.JPG has 0 candidate matches | ||||
| Matching DJI_0246.JPG  -  225 / 252 | ||||
| DJI_0246.JPG - DJI_0292.JPG has 1 candidate matches | ||||
| DJI_0246.JPG - DJI_0324.JPG has 0 candidate matches | ||||
| DJI_0246.JPG - DJI_0279.JPG has 1 candidate matches | ||||
| Matching DJI_0208.JPG  -  226 / 252 | ||||
| DJI_0208.JPG - DJI_0271.JPG has 0 candidate matches | ||||
| DJI_0208.JPG - DJI_0225.JPG has 0 candidate matches | ||||
| DJI_0208.JPG - DJI_0254.JPG has 1 candidate matches | ||||
| DJI_0208.JPG - DJI_0345.JPG has 2 candidate matches | ||||
| DJI_0208.JPG - DJI_0316.JPG has 0 candidate matches | ||||
| Matching DJI_0225.JPG  -  227 / 252 | ||||
| DJI_0225.JPG - DJI_0345.JPG has 0 candidate matches | ||||
| DJI_0225.JPG - DJI_0299.JPG has 1 candidate matches | ||||
| DJI_0225.JPG - DJI_0316.JPG has 0 candidate matches | ||||
| DJI_0225.JPG - DJI_0254.JPG has 1 candidate matches | ||||
| DJI_0225.JPG - DJI_0271.JPG has 0 candidate matches | ||||
| Matching DJI_0210.JPG  -  228 / 252 | ||||
| DJI_0210.JPG - DJI_0347.JPG has 0 candidate matches | ||||
| DJI_0210.JPG - DJI_0223.JPG has 1 candidate matches | ||||
| DJI_0210.JPG - DJI_0256.JPG has 0 candidate matches | ||||
| DJI_0210.JPG - DJI_0269.JPG has 0 candidate matches | ||||
| Matching DJI_0185.JPG  -  229 / 252 | ||||
| DJI_0185.JPG - DJI_0248.JPG has 0 candidate matches | ||||
| DJI_0185.JPG - DJI_0231.JPG has 1 candidate matches | ||||
| DJI_0185.JPG - DJI_0276.JPG has 1 candidate matches | ||||
| DJI_0185.JPG - DJI_0294.JPG has 1 candidate matches | ||||
| DJI_0185.JPG - DJI_0321.JPG has 0 candidate matches | ||||
| DJI_0185.JPG - DJI_0202.JPG has 26 candidate matches | ||||
| Robust matching time : 0.00102090835571s | ||||
| Full matching 23 / 26, time: 0.113751173019s | ||||
| Matching DJI_0333.JPG  -  230 / 252 | ||||
| Matching DJI_0137.JPG  -  231 / 252 | ||||
| DJI_0137.JPG - DJI_0250.JPG has 0 candidate matches | ||||
| DJI_0137.JPG - DJI_0158.JPG has 16 candidate matches | ||||
| DJI_0137.JPG - DJI_0183.JPG has 3 candidate matches | ||||
| DJI_0137.JPG - DJI_0296.JPG has 0 candidate matches | ||||
| DJI_0137.JPG - DJI_0204.JPG has 2 candidate matches | ||||
| DJI_0137.JPG - DJI_0319.JPG has 0 candidate matches | ||||
| DJI_0137.JPG - DJI_0229.JPG has 0 candidate matches | ||||
| DJI_0137.JPG - DJI_0274.JPG has 0 candidate matches | ||||
| Matching DJI_0150.JPG  -  232 / 252 | ||||
| DJI_0150.JPG - DJI_0191.JPG has 1 candidate matches | ||||
| DJI_0150.JPG - DJI_0288.JPG has 1 candidate matches | ||||
| DJI_0150.JPG - DJI_0334.JPG has 0 candidate matches | ||||
| DJI_0150.JPG - DJI_0237.JPG has 0 candidate matches | ||||
| DJI_0150.JPG - DJI_0196.JPG has 0 candidate matches | ||||
| DJI_0150.JPG - DJI_0242.JPG has 1 candidate matches | ||||
| Matching DJI_0249.JPG  -  233 / 252 | ||||
| DJI_0249.JPG - DJI_0321.JPG has 1 candidate matches | ||||
| DJI_0249.JPG - DJI_0340.JPG has 1 candidate matches | ||||
| DJI_0249.JPG - DJI_0276.JPG has 3 candidate matches | ||||
| Matching DJI_0283.JPG  -  234 / 252 | ||||
| DJI_0283.JPG - DJI_0328.JPG has 0 candidate matches | ||||
| DJI_0283.JPG - DJI_0333.JPG has 0 candidate matches | ||||
| DJI_0283.JPG - DJI_0287.JPG has 1 candidate matches | ||||
| Matching DJI_0256.JPG  -  235 / 252 | ||||
| DJI_0256.JPG - DJI_0301.JPG has 0 candidate matches | ||||
| DJI_0256.JPG - DJI_0346.JPG has 2 candidate matches | ||||
| DJI_0256.JPG - DJI_0347.JPG has 0 candidate matches | ||||
| DJI_0256.JPG - DJI_0314.JPG has 0 candidate matches | ||||
| DJI_0256.JPG - DJI_0269.JPG has 4 candidate matches | ||||
| Matching DJI_0235.JPG  -  236 / 252 | ||||
| DJI_0235.JPG - DJI_0336.JPG has 1 candidate matches | ||||
| DJI_0235.JPG - DJI_0326.JPG has 1 candidate matches | ||||
| DJI_0235.JPG - DJI_0281.JPG has 0 candidate matches | ||||
| DJI_0235.JPG - DJI_0290.JPG has 0 candidate matches | ||||
| DJI_0235.JPG - DJI_0244.JPG has 2 candidate matches | ||||
| Matching DJI_0277.JPG  -  237 / 252 | ||||
| DJI_0277.JPG - DJI_0322.JPG has 0 candidate matches | ||||
| DJI_0277.JPG - DJI_0339.JPG has 0 candidate matches | ||||
| DJI_0277.JPG - DJI_0293.JPG has 3 candidate matches | ||||
| Matching DJI_0296.JPG  -  238 / 252 | ||||
| DJI_0296.JPG - DJI_0319.JPG has 1 candidate matches | ||||
| DJI_0296.JPG - DJI_0342.JPG has 0 candidate matches | ||||
| Matching DJI_0157.JPG  -  239 / 252 | ||||
| DJI_0157.JPG - DJI_0295.JPG has 0 candidate matches | ||||
| DJI_0157.JPG - DJI_0340.JPG has 0 candidate matches | ||||
| DJI_0157.JPG - DJI_0184.JPG has 12 candidate matches | ||||
| DJI_0157.JPG - DJI_0230.JPG has 0 candidate matches | ||||
| DJI_0157.JPG - DJI_0203.JPG has 3 candidate matches | ||||
| DJI_0157.JPG - DJI_0249.JPG has 0 candidate matches | ||||
| DJI_0157.JPG - DJI_0275.JPG has 0 candidate matches | ||||
| Matching DJI_0273.JPG  -  240 / 252 | ||||
| DJI_0273.JPG - DJI_0318.JPG has 1 candidate matches | ||||
| DJI_0273.JPG - DJI_0343.JPG has 2 candidate matches | ||||
| DJI_0273.JPG - DJI_0298.JPG has 0 candidate matches | ||||
| Matching DJI_0148.JPG  -  241 / 252 | ||||
| DJI_0148.JPG - DJI_0331.JPG has 0 candidate matches | ||||
| DJI_0148.JPG - DJI_0193.JPG has 7 candidate matches | ||||
| DJI_0148.JPG - DJI_0285.JPG has 0 candidate matches | ||||
| DJI_0148.JPG - DJI_0194.JPG has 1 candidate matches | ||||
| DJI_0148.JPG - DJI_0330.JPG has 1 candidate matches | ||||
| DJI_0148.JPG - DJI_0286.JPG has 0 candidate matches | ||||
| DJI_0148.JPG - DJI_0240.JPG has 3 candidate matches | ||||
| DJI_0148.JPG - DJI_0239.JPG has 0 candidate matches | ||||
| DJI_0148.JPG - DJI_0329.JPG has 3 candidate matches | ||||
| DJI_0148.JPG - DJI_0332.JPG has 1 candidate matches | ||||
| Matching DJI_0162.JPG  -  242 / 252 | ||||
| DJI_0162.JPG - DJI_0179.JPG has 16 candidate matches | ||||
| DJI_0162.JPG - DJI_0255.JPG has 1 candidate matches | ||||
| DJI_0162.JPG - DJI_0208.JPG has 3 candidate matches | ||||
| DJI_0162.JPG - DJI_0315.JPG has 0 candidate matches | ||||
| DJI_0162.JPG - DJI_0224.JPG has 0 candidate matches | ||||
| DJI_0162.JPG - DJI_0254.JPG has 2 candidate matches | ||||
| DJI_0162.JPG - DJI_0300.JPG has 2 candidate matches | ||||
| Matching DJI_0236.JPG  -  243 / 252 | ||||
| DJI_0236.JPG - DJI_0289.JPG has 2 candidate matches | ||||
| DJI_0236.JPG - DJI_0243.JPG has 1 candidate matches | ||||
| DJI_0236.JPG - DJI_0282.JPG has 2 candidate matches | ||||
| DJI_0236.JPG - DJI_0327.JPG has 1 candidate matches | ||||
| DJI_0236.JPG - DJI_0335.JPG has 0 candidate matches | ||||
| Matching DJI_0298.JPG  -  244 / 252 | ||||
| DJI_0298.JPG - DJI_0343.JPG has 0 candidate matches | ||||
| DJI_0298.JPG - DJI_0344.JPG has 0 candidate matches | ||||
| DJI_0298.JPG - DJI_0317.JPG has 2 candidate matches | ||||
| Matching DJI_0228.JPG  -  245 / 252 | ||||
| DJI_0228.JPG - DJI_0251.JPG has 6 candidate matches | ||||
| DJI_0228.JPG - DJI_0274.JPG has 0 candidate matches | ||||
| DJI_0228.JPG - DJI_0342.JPG has 0 candidate matches | ||||
| DJI_0228.JPG - DJI_0319.JPG has 0 candidate matches | ||||
| Matching DJI_0322.JPG  -  246 / 252 | ||||
| DJI_0322.JPG - DJI_0339.JPG has 3 candidate matches | ||||
| Matching DJI_0176.JPG  -  247 / 252 | ||||
| DJI_0176.JPG - DJI_0222.JPG has 1 candidate matches | ||||
| DJI_0176.JPG - DJI_0211.JPG has 2 candidate matches | ||||
| DJI_0176.JPG - DJI_0312.JPG has 1 candidate matches | ||||
| DJI_0176.JPG - DJI_0257.JPG has 0 candidate matches | ||||
| DJI_0176.JPG - DJI_0258.JPG has 1 candidate matches | ||||
| DJI_0176.JPG - DJI_0268.JPG has 0 candidate matches | ||||
| DJI_0176.JPG - DJI_0303.JPG has 0 candidate matches | ||||
| Matching DJI_0272.JPG  -  248 / 252 | ||||
| DJI_0272.JPG - DJI_0344.JPG has 0 candidate matches | ||||
| DJI_0272.JPG - DJI_0317.JPG has 0 candidate matches | ||||
| DJI_0272.JPG - DJI_0298.JPG has 3 candidate matches | ||||
| DJI_0272.JPG - DJI_0299.JPG has 3 candidate matches | ||||
| Matching DJI_0124.JPG  -  249 / 252 | ||||
| DJI_0124.JPG - DJI_0307.JPG has 0 candidate matches | ||||
| DJI_0124.JPG - DJI_0263.JPG has 1 candidate matches | ||||
| DJI_0124.JPG - DJI_0215.JPG has 0 candidate matches | ||||
| DJI_0124.JPG - DJI_0169.JPG has 1 candidate matches | ||||
| DJI_0124.JPG - DJI_0126.JPG has 1 candidate matches | ||||
| DJI_0124.JPG - DJI_0170.JPG has 0 candidate matches | ||||
| DJI_0124.JPG - DJI_0261.JPG has 1 candidate matches | ||||
| DJI_0124.JPG - DJI_0125.JPG has 2 candidate matches | ||||
| DJI_0124.JPG - DJI_0172.JPG has 1 candidate matches | ||||
| DJI_0124.JPG - DJI_0216.JPG has 0 candidate matches | ||||
| DJI_0124.JPG - DJI_0171.JPG has 0 candidate matches | ||||
| DJI_0124.JPG - DJI_0218.JPG has 1 candidate matches | ||||
| Matching DJI_0310.JPG  -  250 / 252 | ||||
| DJI_0310.JPG - DJI_0351.JPG has 1 candidate matches | ||||
| Matching DJI_0241.JPG  -  251 / 252 | ||||
| DJI_0241.JPG - DJI_0333.JPG has 1 candidate matches | ||||
| DJI_0241.JPG - DJI_0328.JPG has 0 candidate matches | ||||
| DJI_0241.JPG - DJI_0284.JPG has 1 candidate matches | ||||
| DJI_0241.JPG - DJI_0332.JPG has 2 candidate matches | ||||
| DJI_0241.JPG - DJI_0287.JPG has 1 candidate matches | ||||
| Matching DJI_0118.JPG  -  252 / 252 | ||||
| DJI_0118.JPG - DJI_0178.JPG has 0 candidate matches | ||||
| DJI_0118.JPG - DJI_0301.JPG has 0 candidate matches | ||||
| DJI_0118.JPG - DJI_0269.JPG has 1 candidate matches | ||||
| DJI_0118.JPG - DJI_0256.JPG has 1 candidate matches | ||||
| DJI_0118.JPG - DJI_0210.JPG has 0 candidate matches | ||||
| DJI_0118.JPG - DJI_0132.JPG has 3 candidate matches | ||||
| DJI_0118.JPG - DJI_0223.JPG has 1 candidate matches | ||||
| DJI_0118.JPG - DJI_0163.JPG has 1 candidate matches | ||||
		Ładowanie…
	
		Reference in New Issue
	
	 Piero Toffanin
						Piero Toffanin