kopia lustrzana https://github.com/OpenDroneMap/WebODM
Export plant health results
rodzic
692c9264b3
commit
59a746897b
|
@ -18,6 +18,7 @@ from .formulas import lookup_formula, get_algorithm_list
|
||||||
from .tasks import TaskNestedView
|
from .tasks import TaskNestedView
|
||||||
from rest_framework import exceptions
|
from rest_framework import exceptions
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
|
from worker.tasks import export_raster_index
|
||||||
|
|
||||||
ZOOM_EXTRA_LEVELS = 2
|
ZOOM_EXTRA_LEVELS = 2
|
||||||
|
|
||||||
|
@ -410,21 +411,19 @@ class Tiles(TaskNestedView):
|
||||||
)
|
)
|
||||||
|
|
||||||
class Export(TaskNestedView):
|
class Export(TaskNestedView):
|
||||||
def get(self, request, pk=None, project_pk=None):
|
def post(self, request, pk=None, project_pk=None):
|
||||||
"""
|
"""
|
||||||
Export an orthophoto after applying a formula
|
Export an orthophoto after applying a formula
|
||||||
"""
|
"""
|
||||||
task = self.get_and_check_task(request, pk)
|
task = self.get_and_check_task(request, pk)
|
||||||
|
|
||||||
nodata = None
|
formula = request.data.get('formula')
|
||||||
|
bands = request.data.get('bands')
|
||||||
formula = self.request.query_params.get('formula')
|
# rescale = request.data.get('rescale')
|
||||||
bands = self.request.query_params.get('bands')
|
|
||||||
rescale = self.request.query_params.get('rescale')
|
|
||||||
|
|
||||||
if formula == '': formula = None
|
if formula == '': formula = None
|
||||||
if bands == '': bands = None
|
if bands == '': bands = None
|
||||||
if rescale == '': rescale = None
|
# if rescale == '': rescale = None
|
||||||
|
|
||||||
if not formula:
|
if not formula:
|
||||||
raise exceptions.ValidationError("You need to specify a formula parameter")
|
raise exceptions.ValidationError("You need to specify a formula parameter")
|
||||||
|
@ -437,17 +436,13 @@ class Export(TaskNestedView):
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
raise exceptions.ValidationError(str(e))
|
raise exceptions.ValidationError(str(e))
|
||||||
|
|
||||||
if formula is not None and rescale is None:
|
# if formula is not None and rescale is None:
|
||||||
rescale = "-1,1"
|
# rescale = "-1,1"
|
||||||
|
|
||||||
if nodata is not None:
|
|
||||||
nodata = np.nan if nodata == "nan" else float(nodata)
|
|
||||||
|
|
||||||
url = get_raster_path(task, "orthophoto")
|
url = get_raster_path(task, "orthophoto")
|
||||||
|
|
||||||
if not os.path.isfile(url):
|
if not os.path.isfile(url):
|
||||||
raise exceptions.NotFound()
|
raise exceptions.NotFound()
|
||||||
|
|
||||||
export_raster_index(url, expr, "/webodm/app/media/project/2/task/5392337b-cd3f-42ef-879d-b36149ef442f/assets/odm_orthophoto/export.tif")
|
celery_task_id = export_raster_index.delay(url, expr).task_id
|
||||||
|
return Response({'celery_task_id': celery_task_id})
|
||||||
return HttpResponse("OK")
|
|
|
@ -49,7 +49,7 @@ class GetTaskResult(APIView):
|
||||||
return Response({'error': 'Task not ready'})
|
return Response({'error': 'Task not ready'})
|
||||||
|
|
||||||
if file is not None:
|
if file is not None:
|
||||||
filename = os.path.basename(file)
|
filename = request.query_params.get('filename', os.path.basename(file))
|
||||||
filesize = os.stat(file).st_size
|
filesize = os.stat(file).st_size
|
||||||
|
|
||||||
f = open(file, "rb")
|
f = open(file, "rb")
|
||||||
|
|
|
@ -4,6 +4,8 @@ import '../css/LayersControlLayer.scss';
|
||||||
import Histogram from './Histogram';
|
import Histogram from './Histogram';
|
||||||
import { Checkbox, ExpandButton } from './Toggle';
|
import { Checkbox, ExpandButton } from './Toggle';
|
||||||
import Utils from '../classes/Utils';
|
import Utils from '../classes/Utils';
|
||||||
|
import Workers from '../classes/Workers';
|
||||||
|
import ErrorMessage from './ErrorMessage';
|
||||||
import $ from 'jquery';
|
import $ from 'jquery';
|
||||||
|
|
||||||
export default class LayersControlLayer extends React.Component {
|
export default class LayersControlLayer extends React.Component {
|
||||||
|
@ -39,7 +41,8 @@ export default class LayersControlLayer extends React.Component {
|
||||||
bands: params.bands || "",
|
bands: params.bands || "",
|
||||||
hillshade: params.hillshade || "",
|
hillshade: params.hillshade || "",
|
||||||
histogramLoading: false,
|
histogramLoading: false,
|
||||||
exportLoading: false
|
exportLoading: false,
|
||||||
|
error: ""
|
||||||
};
|
};
|
||||||
|
|
||||||
this.rescale = params.rescale || "";
|
this.rescale = params.rescale || "";
|
||||||
|
@ -79,6 +82,11 @@ export default class LayersControlLayer extends React.Component {
|
||||||
this.updateHistogramReq.abort();
|
this.updateHistogramReq.abort();
|
||||||
this.updateHistogramReq = null;
|
this.updateHistogramReq = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.exportReq){
|
||||||
|
this.exportReq.abort();
|
||||||
|
this.exportReq = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleLayerClick = () => {
|
handleLayerClick = () => {
|
||||||
|
@ -188,9 +196,29 @@ export default class LayersControlLayer extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
handleExport = e => {
|
handleExport = e => {
|
||||||
this.setState({exportLoading: true});
|
this.setState({exportLoading: true, error: ""});
|
||||||
|
|
||||||
|
this.exportReq = $.ajax({
|
||||||
|
type: 'POST',
|
||||||
|
url: `/api/projects/${this.meta.task.project}/tasks/${this.meta.task.id}/orthophoto/export`,
|
||||||
|
data: this.getLayerParams()
|
||||||
|
}).done(result => {
|
||||||
|
if (result.celery_task_id){
|
||||||
|
Workers.waitForCompletion(result.celery_task_id, error => {
|
||||||
|
if (error) this.setState({exportLoading: false, error});
|
||||||
|
else{
|
||||||
|
this.setState({exportLoading: false});
|
||||||
|
Workers.downloadFile(result.celery_task_id, "odm_orthophoto_" + encodeURIComponent(this.state.formula) + ".tif");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}else if (result.error){
|
||||||
|
this.setState({exportLoading: false, error: result.error});
|
||||||
|
}else{
|
||||||
|
this.setState({exportLoading: false, error: "Invalid response: " + result});
|
||||||
|
}
|
||||||
|
}).fail(error => {
|
||||||
|
this.setState({exportLoading: false, error: JSON.stringify(error)});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
render(){
|
render(){
|
||||||
|
@ -216,6 +244,8 @@ export default class LayersControlLayer extends React.Component {
|
||||||
colorMap={cmapValues}
|
colorMap={cmapValues}
|
||||||
onUpdate={this.handleHistogramUpdate} />
|
onUpdate={this.handleHistogramUpdate} />
|
||||||
|
|
||||||
|
<ErrorMessage bind={[this, "error"]} />
|
||||||
|
|
||||||
{formula !== "" && algorithms ?
|
{formula !== "" && algorithms ?
|
||||||
<div className="row form-group form-inline">
|
<div className="row form-group form-inline">
|
||||||
<label className="col-sm-3 control-label">Algorithm:</label>
|
<label className="col-sm-3 control-label">Algorithm:</label>
|
||||||
|
|
|
@ -4,6 +4,7 @@ import Storage from 'webodm/classes/Storage';
|
||||||
import L from 'leaflet';
|
import L from 'leaflet';
|
||||||
import './ContoursPanel.scss';
|
import './ContoursPanel.scss';
|
||||||
import ErrorMessage from 'webodm/components/ErrorMessage';
|
import ErrorMessage from 'webodm/components/ErrorMessage';
|
||||||
|
import Workers from 'webodm/classes/Workers';
|
||||||
|
|
||||||
export default class ContoursPanel extends React.Component {
|
export default class ContoursPanel extends React.Component {
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
|
@ -115,32 +116,6 @@ export default class ContoursPanel extends React.Component {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
waitForCompletion = (taskId, celery_task_id, cb) => {
|
|
||||||
let errorCount = 0;
|
|
||||||
|
|
||||||
const check = () => {
|
|
||||||
$.ajax({
|
|
||||||
type: 'GET',
|
|
||||||
url: `/api/plugins/contours/task/${taskId}/contours/check/${celery_task_id}`
|
|
||||||
}).done(result => {
|
|
||||||
if (result.error){
|
|
||||||
cb(result.error);
|
|
||||||
}else if (result.ready){
|
|
||||||
cb();
|
|
||||||
}else{
|
|
||||||
// Retry
|
|
||||||
setTimeout(() => check(), 2000);
|
|
||||||
}
|
|
||||||
}).fail(error => {
|
|
||||||
console.warn(error);
|
|
||||||
if (errorCount++ < 10) setTimeout(() => check(), 2000);
|
|
||||||
else cb(JSON.stringify(error));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
check();
|
|
||||||
}
|
|
||||||
|
|
||||||
addGeoJSONFromURL = (url, cb) => {
|
addGeoJSONFromURL = (url, cb) => {
|
||||||
const { map } = this.props;
|
const { map } = this.props;
|
||||||
|
|
||||||
|
@ -197,7 +172,7 @@ export default class ContoursPanel extends React.Component {
|
||||||
data: data
|
data: data
|
||||||
}).done(result => {
|
}).done(result => {
|
||||||
if (result.celery_task_id){
|
if (result.celery_task_id){
|
||||||
this.waitForCompletion(taskId, result.celery_task_id, error => {
|
Workers.waitForCompletion(result.celery_task_id, error => {
|
||||||
if (error) this.setState({[loadingProp]: false, error});
|
if (error) this.setState({[loadingProp]: false, error});
|
||||||
else{
|
else{
|
||||||
const fileUrl = `/api/plugins/contours/task/${taskId}/contours/download/${result.celery_task_id}`;
|
const fileUrl = `/api/plugins/contours/task/${taskId}/contours/download/${result.celery_task_id}`;
|
||||||
|
@ -214,7 +189,7 @@ export default class ContoursPanel extends React.Component {
|
||||||
this.setState({[loadingProp]: false});
|
this.setState({[loadingProp]: false});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
}, `/api/plugins/contours/task/${taskId}/contours/check/`);
|
||||||
}else if (result.error){
|
}else if (result.error){
|
||||||
this.setState({[loadingProp]: false, error: result.error});
|
this.setState({[loadingProp]: false, error: result.error});
|
||||||
}else{
|
}else{
|
||||||
|
|
|
@ -151,6 +151,7 @@ def execute_grass_script(script, serialized_context = {}, out_key='output'):
|
||||||
@app.task
|
@app.task
|
||||||
def export_raster_index(input, expression):
|
def export_raster_index(input, expression):
|
||||||
try:
|
try:
|
||||||
|
logger.info("Exporting raster index {} with expression: {}".format(input, expression))
|
||||||
tmpfile = tempfile.mktemp('_raster_index.tif', dir=settings.MEDIA_TMP)
|
tmpfile = tempfile.mktemp('_raster_index.tif', dir=settings.MEDIA_TMP)
|
||||||
export_raster_index_sync(input, expression, tmpfile)
|
export_raster_index_sync(input, expression, tmpfile)
|
||||||
return {'file': tmpfile}
|
return {'file': tmpfile}
|
||||||
|
|
Ładowanie…
Reference in New Issue