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