Browse Source

Add a panorama generation pipeline based on hugin scripts

Baptiste Jonglez 10 years ago
parent
commit
3b55aed718
3 changed files with 77 additions and 3 deletions
  1. 6 1
      panorama/admin.py
  2. 6 1
      panorama/models.py
  3. 65 1
      panorama/tasks.py

+ 6 - 1
panorama/admin.py

@@ -34,7 +34,12 @@ class PanoramaAdmin(admin.ModelAdmin):
     fields = ('name', ('image', 'image_width', 'image_height'),
               'loop', ('latitude', 'longitude'), 'altitude')
     readonly_fields = ('image_width', 'image_height')
-    actions = ('regenerate_tiles', )
+    actions = ('generate_panorama', 'regenerate_tiles')
+
+    def generate_panorama(self, request, queryset):
+        for pano in queryset:
+            pano.generate_panorama()
+        self.message_user(request, "Launched panorama generation, it will take a few minutes")
 
     def regenerate_tiles(self, request, queryset):
         for pano in queryset:

+ 6 - 1
panorama/models.py

@@ -12,7 +12,7 @@ from django.core.validators import MinValueValidator, MaxValueValidator
 from django.core.urlresolvers import reverse
 from django.utils.encoding import python_2_unicode_compatible
 
-from .tasks import generate_tiles
+from .tasks import generate_tiles, panorama_pipeline
 from .utils import makedirs, path_exists
 
 
@@ -151,6 +151,11 @@ class Panorama(ReferencePoint):
         makedirs(self.tiles_dir(), exist_ok=True)
         generate_tiles.delay(self.image.path, self.tiles_dir())
 
+    def generate_panorama(self):
+        output = os.path.join(settings.MEDIA_ROOT, "pano", "{}.tif".format(self.id))
+        panorama_pipeline.delay([p.photo.path for p in self.photos.all()],
+                                output)
+
     def get_absolute_url(self):
         return reverse('panorama:view_pano', args=[str(self.pk)])
 

+ 65 - 1
panorama/tasks.py

@@ -1,7 +1,11 @@
 # -*- coding: utf-8 -*-
 from __future__ import unicode_literals, division, print_function, absolute_import
 
-from celery import shared_task
+import os
+import subprocess
+import tempfile
+
+from celery import shared_task, chain
 
 from .gen_tiles import gen_tiles
 
@@ -9,3 +13,63 @@ from .gen_tiles import gen_tiles
 @shared_task
 def generate_tiles(*args, **kwargs):
     return gen_tiles(*args, **kwargs)
+
+# Pipeline of hugin-based panorama generation
+# TODO: do something with the return code of the subprocess calls
+
+@shared_task
+def pto_gen(output_pto, images):
+    subprocess.call(["pto_gen", "-o", output_pto] + images)
+    return output_pto
+
+@shared_task
+def cpfind(input_pto, output_pto):
+    subprocess.call(["cpfind", "-o", output_pto, "--multirow", "--celeste", input_pto])
+    return output_pto
+
+@shared_task
+def cpclean(input_pto, output_pto):
+    subprocess.call(["cpclean", "-o", output_pto, input_pto])
+    return output_pto
+
+@shared_task
+def linefind(input_pto, output_pto):
+    subprocess.call(["linefind", "-o", output_pto, input_pto])
+    return output_pto
+
+@shared_task
+def autooptimiser(input_pto, output_pto):
+    subprocess.call(["autooptimiser", "-a", "-m", "-l", "-s", "-o", output_pto, input_pto])
+    return output_pto
+
+@shared_task
+def autocrop(input_pto, output_pto):
+    subprocess.call(["pano_modify", "--canvas=AUTO", "--crop=AUTO", "-o", output_pto, input_pto])
+    return output_pto
+
+@shared_task
+def generate_pano(input_pto, dirname, output_image):
+    project_name = output_image[output_image.rfind(".tif")]
+    output_name = os.path.join(dirname, project_name)
+    # hugin_executor is only available since hugin 2015.0
+    # return subprocess.call(["hugin_executor", "--prefix", output_name, input_pto])
+    makefile_name = os.path.join(dirname, "celery_pano.mk")
+    subprocess.call(["pto2mk", "-o", makefile_name, "-p", project_name, input_pto])
+    return subprocess.call(["make", "-f", makefile_name])
+
+@shared_task
+def panorama_pipeline(images, output_image):
+    """Automatically assemble a panorama, using Hugin in headless mode.
+    [output_image] is the name of the desired output image.  Must be a .tif
+    image for now.
+    """
+    d = tempfile.mkdtemp(prefix='celery_hugin')
+    pto = lambda filename: os.path.join(d, filename + ".pto")
+    pipeline = pto_gen.s(pto("pto_gen"), images) | \
+               cpfind.s(pto("cpfind")) | \
+               cpclean.s(pto("cpclean")) | \
+               linefind.s(pto("linefind")) | \
+               autooptimiser.s(pto("autooptimiser")) | \
+               autocrop.s(pto("autocrop")) | \
+               generate_pano.s(d, output_image)
+    return pipeline()