diff --git a/app/api/imageuploads.py b/app/api/imageuploads.py index 36ad737a..fd43e299 100644 --- a/app/api/imageuploads.py +++ b/app/api/imageuploads.py @@ -9,6 +9,24 @@ from app.models.task import assets_directory_path from PIL import Image from django.http import HttpResponse from .tasks import download_file_response +import numpy as np + +def normalize(img): + """ + Linear normalization + http://en.wikipedia.org/wiki/Normalization_%28image_processing%29 + """ + arr = np.array(img) + # size = 2 ** (arr[0][0].dtype.itemsize * 8) - 1 + arr = arr.astype('float') + + # Do not touch the alpha channel + minval = arr.min() + maxval = arr.max() + if minval != maxval: + arr -= minval + arr *= (255.0/(maxval-minval)) + return Image.fromarray(arr) class Thumbnail(TaskNestedView): def get(self, request, pk=None, project_pk=None, image_filename=""): @@ -38,6 +56,9 @@ class Thumbnail(TaskNestedView): raise exceptions.ValidationError("Invalid query parameters") with Image.open(image_path) as img: + if img.mode != 'RGB': + img = normalize(img) + img = img.convert('RGB') img.thumbnail((thumb_size, thumb_size)) output = io.BytesIO() img.save(output, format='JPEG', quality=quality) diff --git a/app/static/app/js/ModelView.jsx b/app/static/app/js/ModelView.jsx index 8b85180f..228a53d9 100644 --- a/app/static/app/js/ModelView.jsx +++ b/app/static/app/js/ModelView.jsx @@ -6,8 +6,8 @@ import AssetDownloadButtons from './components/AssetDownloadButtons'; import Standby from './components/Standby'; import ShareButton from './components/ShareButton'; import ImagePopup from './components/ImagePopup'; -import PropTypes from 'prop-types'; import epsg from 'epsg'; +import PropTypes from 'prop-types'; import $ from 'jquery'; require('./vendor/OBJLoader'); @@ -214,6 +214,8 @@ class ModelView extends React.Component { let material = e.pointcloud.material; material.size = 1; + this.loadCameras(); // TODO REMOVE + viewer.fitToScreen(); }); }); @@ -293,7 +295,7 @@ class ModelView extends React.Component { loadCameras(){ const { task } = this.props; - function getMatrix(translation, rotation) { + function getMatrix(translation, rotation, scale) { var axis = new THREE.Vector3(-rotation[0], -rotation[1], -rotation[2]); @@ -301,6 +303,11 @@ class ModelView extends React.Component { axis.normalize(); var matrix = new THREE.Matrix4().makeRotationAxis(axis, angle); matrix.setPosition(new THREE.Vector3(translation[0], translation[1], translation[2])); + + if (scale != 1.0){ + matrix.scale(new THREE.Vector3(scale, scale, scale)); + } + return matrix.transpose(); } @@ -313,22 +320,12 @@ class ModelView extends React.Component { fileloader.load(`/api/projects/${task.project}/tasks/${task.id}/download/shots.geojson`, ( data ) => { const geojson = JSON.parse(data); - const gjproj = proj4.defs("EPSG:4326"); - - let pcproj = this.pointCloud.projection; - - if (!pcproj){ - console.log("NO PROJ!!!"); - // TODO ? - } - - const toScene = proj4(gjproj, pcproj); const cameraObj = dae.children[0]; cameraObj.material.forEach(m => { m.transparent = true; m.opacity = 0.7; }); - + // const cameraObj = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), new THREE.MeshNormalMaterial()); // TODO: instancing doesn't seem to work :/ @@ -337,15 +334,14 @@ class ModelView extends React.Component { let i = 0; geojson.features.forEach(feat => { - const coords = feat.geometry.coordinates; - - const utm = toScene.forward([coords[0], coords[1]]); - utm.push(coords[2]); // z in meters doesn't change - const material = cameraObj.material.map(m => m.clone()); const cameraMesh = new THREE.Mesh(cameraObj.geometry, material); cameraMesh.matrixAutoUpdate = false; - cameraMesh.matrix.set(...getMatrix(utm, feat.properties.rotation).elements); + let scale = 1.0; + if (!this.pointCloud.projection) scale = 0.05; + + cameraMesh.matrix.set(...getMatrix(feat.properties.translation, feat.properties.rotation, scale).elements); + viewer.scene.scene.add(cameraMesh); cameraMesh._feat = feat; diff --git a/app/static/app/js/classes/PipelineSteps.js b/app/static/app/js/classes/PipelineSteps.js index 2e174114..314712df 100644 --- a/app/static/app/js/classes/PipelineSteps.js +++ b/app/static/app/js/classes/PipelineSteps.js @@ -3,58 +3,42 @@ export default { return [{ action: "dataset", label: "Load Dataset", - icon: "fa fa-database", - beginsWith: "Running ODM Load Dataset Cell", - endsWith: "Running ODM Load Dataset Cell - Finished" + icon: "fa fa-database" }, { action: "opensfm", label: "Structure From Motion / MVS", - icon: "fa fa-camera", - beginsWith: "Running ODM OpenSfM Cell", - endsWith: "Running ODM Meshing Cell" + icon: "fa fa-camera" }, { action: "odm_meshing", label: "Meshing", - icon: "fa fa-cube", - beginsWith: "Running ODM Meshing Cell", - endsWith: "Running ODM Meshing Cell - Finished" + icon: "fa fa-cube" }, { action: "mvs_texturing", label: "Texturing", - icon: "fab fa-connectdevelop", - beginsWith: "Running MVS Texturing Cell", - endsWith: "Running ODM Texturing Cell - Finished" + icon: "fab fa-connectdevelop" }, { action: "odm_georeferencing", label: "Georeferencing", - icon: "fa fa-globe", - beginsWith: "Running ODM Georeferencing Cell", - endsWith: "Running ODM Georeferencing Cell - Finished" + icon: "fa fa-globe" }, { action: "odm_dem", label: "DEM", - icon: "fa fa-chart-area", - beginsWith: "Running ODM DEM Cell", - endsWith: "Running ODM DEM Cell - Finished" + icon: "fa fa-chart-area" }, { action: "odm_orthophoto", label: "Orthophoto", - icon: "far fa-image", - beginsWith: "Running ODM Orthophoto Cell", - endsWith: "Running ODM OrthoPhoto Cell - Finished" + icon: "far fa-image" }, { action: "odm_report", label: "Report", - icon: "far fa-file-alt", - beginsWith: "Running ODM Report Cell", - endsWith: "Running ODM Report Cell - Finished" + icon: "far fa-file-alt" } ]; }