Agisoft Metashape > Python and Java API

Building and Exporting Orthomosaic using Network Processing

(1/2) > >>

farmflightadam:
Hello and please forgive me as I am new to Python and Photogrammetry. I am a Systems/DevOps Engineer and a PHP/Javascript developer. My background is building production environments for everything from websites to enterprise applications as well as mobile applications. For the last few months, I have been building a tile processing pipeline that we feed imagery into that is stitched using Pix4d. The tile processing pipeline takes the images fed into it and creates the map tiles so that we can load the imagery into our web application. Moving forward, we want to replace Pix4d with an in-house built and managed stitching pipeline. We have looked at other software and now we're testing Metashape.

Currently, I have three AWS EC2 instances running (a master controller and 2 processing nodes) that all share and AWS EFS mount for shared storage. I have some imagery from a Sony camera on the shared filesystem and I have a Python script that successfully creates a Metashape project (though I do know if it is complete and accurate). You can see that code here: https://pb.recoilnetworks.com/?118554ebbf7cd5c9#5hfzwilEuY1Tt0hi35moHKWhA6kkOApNPlDvi1XmLRQ=

Now, I am trying to write another script that simply exports a single bigtiff Orthomosaic. Here's the current code:


--- Code: ---import Metashape
import sys


def do_create_export(project, dir_root, dir_save, ipaddr):
    tasks = list()

    doc = Metashape.Document()
    doc.open(project, read_only=False, ignore_lock=True)

    chunk = doc.chunk

    # Match Photos
    task = Metashape.Tasks.MatchPhotos()
    task.keypoint_limit = 40000
    task.tiepoint_limit = 4000

    net_task = Metashape.NetworkTask()
    net_task.name = task.name
    net_task.params = task.encode()
    net_task.frames.append((chunk.key, 0))
    tasks.append(net_task)

    # Align Cameras
    task = Metashape.Tasks.AlignCameras()
    task.adaptive_fitting = False

    net_task = Metashape.NetworkTask()
    net_task.name = task.name
    net_task.params = task.encode()
    net_task.frames.append((chunk.key, 0))
    tasks.append(net_task)

    # Depth Maps
    task = Metashape.Tasks.BuildDepthMaps()
    task.filter_mode = Metashape.FilterMode.MildFiltering

    net_task = Metashape.NetworkTask()
    net_task.name = task.name
    net_task.params = task.encode()
    net_task.frames.append((chunk.key, 0))
    tasks.append(net_task)

    # Dense Cloud
    task = Metashape.Tasks.BuildDenseCloud()
    task.point_colors = True

    net_task = Metashape.NetworkTask()
    net_task.name = task.name
    net_task.params = task.encode()
    net_task.frames.append((chunk.key, 0))
    tasks.append(net_task)

    # DEM
    task = Metashape.Tasks.BuildDem()
    task.source_data = Metashape.DataSource.DenseCloudData
    task.interpolation = Metashape.Interpolation.Extrapolated
    task.projection = chunk.crs

    net_task = Metashape.NetworkTask()
    net_task.name = task.name
    net_task.params = task.encode()
    net_task.frames.append((chunk.key, 0))
    tasks.append(net_task)

    # Build Orthomosaic
    task = Metashape.Tasks.BuildOrthomosaic()
    task.resolution = 0.05
    task.projection = chunk.crs
    task.blending_mode = Metashape.BlendingMode.MosaicBlending

    net_task = Metashape.NetworkTask()
    net_task.name = task.name
    net_task.params = task.encode()
    net_task.frames.append((chunk.key, 0))
    tasks.append(net_task)

    # Export Orthomosaic
    compression = Metashape.ImageCompression()
    compression.tiff_compression = Metashape.ImageCompression.TiffCompressionJPEG
    compression.jpeg_quality = 100
    compression.tiff_big = True

    task = Metashape.Tasks.ExportRaster()
    task.path = dir_save + 'orthomosaic.tif'
    task.image_compression = compression
    task.image_format = Metashape.ImageFormatTIFF
    task.projection = chunk.crs
    task.save_world = False
    task.save_alpha = False
    task.white_background = True
    task.save_kml = False
    task.source_data = Metashape.ElevationData

    net_task = Metashape.NetworkTask()
    net_task.name = task.name
    net_task.params = task.encode()
    net_task.frames.append((chunk.key, 0))
    tasks.append(net_task)

    client = Metashape.NetworkClient()
    client.connect(ipaddr)
    batch_id = client.createBatch(project[len(dir_root):], tasks)
    client.resumeBatch(batch_id)


if len(sys.argv) > 2:
    psx = sys.argv[1]
    rdir = sys.argv[2]
    sdir = sys.argv[3]
    sip = sys.argv[4]
    do_create_export(psx, rdir, sdir, sip)
else:
    print("-- missing arguments - provide project file path, root path, save path, and server ip --")

--- End code ---

And here's the output:


--- Code: ---2021-05-20 08:28:08 [172.16.2.101:50920] finished #1 MatchPhotos
2021-05-20 08:28:10 [172.16.2.101:50920] finished #1 MatchPhotos.initialize (1/1)
2021-05-20 08:28:11 [172.16.2.101:50920] finished #1 MatchPhotos.cleanup (1/1)
2021-05-20 08:28:12 [172.16.2.101:50920] finished #1 AlignCameras
2021-05-20 08:28:13 [172.16.2.101:50920] finished #1 AlignCameras.initialize (1/1)
2021-05-20 08:28:14 [172.16.2.101:50920] finished #1 AlignCameras.update (1/1)
2021-05-20 08:28:15 [172.16.2.101:50920] finished #1 AlignCameras.finalize (1/1)
2021-05-20 08:28:16 [172.16.2.101:50920] finished #1 AlignCameras.cleanup (1/1)
2021-05-20 08:28:17 [172.16.2.101:50920] finished #1 BuildDepthMaps
2021-05-20 08:28:18 [172.16.2.101:50920] finished #1 BuildDepthMaps.initialize (1/1)
2021-05-20 08:28:20 [172.16.2.101:50920] finished #1 BuildDepthMaps.finalize (1/1)
2021-05-20 08:28:21 [172.16.2.101:50920] finished #1 BuildDepthMaps.cleanup (1/1)
2021-05-20 08:28:22 [172.16.2.101:50920] finished #1 BuildDenseCloud
2021-05-20 08:28:23 [172.16.2.101:50920] finished #1 BuildDenseCloud.initialize (1/1): Zero resolution
2021-05-20 08:28:24 [172.16.2.101:50920] finished #1 BuildDenseCloud.cleanup (1/1)
2021-05-20 08:28:25 [172.16.2.101:50920] finished #1 BuildDem
2021-05-20 08:28:26 [172.16.2.101:50920] finished #1 BuildDem.initialize (1/1): Null dense cloud
2021-05-20 08:28:27 [172.16.2.101:50920] finished #1 BuildDem.cleanup (1/1)
2021-05-20 08:28:28 [172.16.2.101:50920] finished #1 BuildOrthomosaic
2021-05-20 08:28:30 [172.16.2.101:50920] finished #1 BuildOrthomosaic.initialize (1/1): Null model
2021-05-20 08:28:31 [172.16.2.101:50920] finished #1 BuildOrthomosaic.cleanup (1/1)
2021-05-20 08:28:32 [172.16.2.101:50920] finished #1 ExportRaster: Null elevation

--- End code ---

I am not sure why the DenseCloud says there's a "Zero resolution" and not sure about the other issues the follow. Any help is greatly appreciated!

Also, if you have experience with Metashape and the Python SDK, please reply. We will be looking for a Python developer soon to help us build this pipeline, if we can get this to work.

Alexey Pasumansky:
Hello farmflightadam,

Please try to modify the line for Align Cameras task to the following:

--- Code: ---net_task.chunks.append(chunk.key)
--- End code ---

If it still doesn't help, would it be possible to you to open the partially processed project in Metashape GUI and check, if there are depth maps in the project and that they are not empty (represented by false colors).

farmflightadam:
Okay, change has been made however, I am still seeing the same out. Here's the output from the network monitor:


--- Code: ---2021-05-20 19:21:41 [172.16.2.101:32992] finished #0 MatchPhotos
2021-05-20 19:21:42 [172.16.2.101:32992] finished #0 MatchPhotos.initialize (1/1)
2021-05-20 19:21:43 [172.16.2.101:32992] finished #0 MatchPhotos.cleanup (1/1)
2021-05-20 19:21:44 [172.16.2.101:32992] finished #0 AlignCameras
2021-05-20 19:21:46 [172.16.2.101:32992] finished #0 AlignCameras.initialize (1/1)
2021-05-20 19:21:47 [172.16.2.101:32992] finished #0 AlignCameras.update (1/1)
2021-05-20 19:21:48 [172.16.2.101:32992] finished #0 AlignCameras.finalize (1/1)
2021-05-20 19:21:49 [172.16.2.101:32992] finished #0 AlignCameras.cleanup (1/1)
2021-05-20 19:21:50 [172.16.2.101:32992] finished #0 BuildDepthMaps
2021-05-20 19:21:51 [172.16.2.101:32992] finished #0 BuildDepthMaps.initialize (1/1)
2021-05-20 19:21:52 [172.16.2.101:32992] finished #0 BuildDepthMaps.finalize (1/1)
2021-05-20 19:21:53 [172.16.2.101:32992] finished #0 BuildDepthMaps.cleanup (1/1)
2021-05-20 19:21:54 [172.16.2.101:32992] finished #0 BuildDenseCloud
2021-05-20 19:21:55 [172.16.2.101:32992] finished #0 BuildDenseCloud.initialize (1/1): Zero resolution
2021-05-20 19:21:57 [172.16.2.101:32992] finished #0 BuildDenseCloud.cleanup (1/1)
2021-05-20 19:21:58 [172.16.2.101:32992] finished #0 BuildDem
2021-05-20 19:21:59 [172.16.2.101:32992] finished #0 BuildDem.initialize (1/1): Null dense cloud
2021-05-20 19:22:00 [172.16.2.101:32992] finished #0 BuildDem.cleanup (1/1)
2021-05-20 19:22:01 [172.16.2.101:32992] finished #0 BuildOrthomosaic
2021-05-20 19:22:02 [172.16.2.101:32992] finished #0 BuildOrthomosaic.initialize (1/1): Null model
2021-05-20 19:22:03 [172.16.2.101:32992] finished #0 BuildOrthomosaic.cleanup (1/1)
2021-05-20 19:22:04 [172.16.2.101:32992] finished #0 ExportRaster: Null elevation

--- End code ---

And here's the output from the CLI:


--- Code: ---2021-05-20 19:21:41 MatchPhotos: accuracy = High, preselection = generic, reference, keypoint limit = 40000, tiepoint limit = 4000, apply masks = 0, filter tie points = 1, filter stationary points = 1
2021-05-20 19:21:41 Matching photos...
2021-05-20 19:21:41 processing finished in 0.272402 sec
2021-05-20 19:21:42 MatchPhotos.initialize (1/1): accuracy = High, preselection = generic, reference, keypoint limit = 40000, tiepoint limit = 4000, apply masks = 0, filter tie points = 1, filter stationary points = 1
2021-05-20 19:21:42 processing finished in 0.221081 sec
2021-05-20 19:21:43 MatchPhotos.cleanup (1/1): accuracy = High, preselection = generic, reference, keypoint limit = 40000, tiepoint limit = 4000, apply masks = 0, filter tie points = 1, filter stationary points = 1
2021-05-20 19:21:43 processing finished in 0.221829 sec
2021-05-20 19:21:44 AlignCameras: adaptive fitting = 0
2021-05-20 19:21:44 Estimating camera locations...
2021-05-20 19:21:44 processing finished in 0.215476 sec
2021-05-20 19:21:45 AlignCameras.initialize (1/1): adaptive fitting = 0
2021-05-20 19:21:45 processing matches... done in 0.003786 sec
2021-05-20 19:21:45 selecting camera groups... done in 0.000938 sec
2021-05-20 19:21:45 scheduled 0 alignment groups
2021-05-20 19:21:45 saved camera partition in 0.013206 sec
2021-05-20 19:21:46 processing finished in 0.216372 sec
2021-05-20 19:21:46 AlignCameras.update (1/1): adaptive fitting = 0
2021-05-20 19:21:46 loaded camera partition in 0.002102 sec
2021-05-20 19:21:47 processing finished in 0.2136 sec
2021-05-20 19:21:47 AlignCameras.finalize (1/1): adaptive fitting = 0
2021-05-20 19:21:48 loaded camera partition in 0.002523 sec
2021-05-20 19:21:48 processing finished in 0.21477 sec
2021-05-20 19:21:49 AlignCameras.cleanup (1/1): adaptive fitting = 0
2021-05-20 19:21:49 processing finished in 0.216865 sec
2021-05-20 19:21:50 BuildDepthMaps: quality = Medium, depth filtering = Mild, PM version
2021-05-20 19:21:50 Generating depth maps...
2021-05-20 19:21:50 processing finished in 0.217966 sec
2021-05-20 19:21:51 BuildDepthMaps.initialize (1/1): quality = Medium, depth filtering = Mild, PM version
2021-05-20 19:21:51 Preparing 0 cameras info...
2021-05-20 19:21:51 cameras data loaded in 0.000764 s
2021-05-20 19:21:51 cameras graph built in 0.000211 s
2021-05-20 19:21:51 No cameras left
2021-05-20 19:21:51 cameras info prepared in 0.002181 s
2021-05-20 19:21:51 saved cameras info in 0.015778
2021-05-20 19:21:51 Partitioning 0 cameras...
2021-05-20 19:21:51 number of mini clusters: 0
2021-05-20 19:21:51 0 groups
2021-05-20 19:21:51 cameras partitioned in 0.000213 s
2021-05-20 19:21:51 saved depth map partition in 0.01144 sec
2021-05-20 19:21:51 processing finished in 0.219158 sec
2021-05-20 19:21:52 BuildDepthMaps.finalize (1/1): quality = Medium, depth filtering = Mild, PM version
2021-05-20 19:21:52 loaded depth map partition in 0.002566 sec
2021-05-20 19:21:52 processing finished in 0.217146 sec
2021-05-20 19:21:53 BuildDepthMaps.cleanup (1/1): quality = Medium, depth filtering = Mild, PM version
2021-05-20 19:21:53 processing finished in 0.21954 sec
2021-05-20 19:21:54 BuildDenseCloud: point colors = 1
2021-05-20 19:21:54 Generating dense point cloud...
2021-05-20 19:21:54 processing finished in 0.219276 sec
2021-05-20 19:21:55 BuildDenseCloud.initialize (1/1): point colors = 1
2021-05-20 19:21:55 Generating dense point cloud...
2021-05-20 19:21:55 initializing...
2021-05-20 19:21:55 selected 0 cameras in 7.4e-05 sec
2021-05-20 19:21:55 Error: Zero resolution
2021-05-20 19:21:55 processing finished in 0.218614 sec
2021-05-20 19:21:56 BuildDenseCloud.cleanup (1/1): point colors = 1
2021-05-20 19:21:57 processing finished in 0.220858 sec
2021-05-20 19:21:57 BuildDem: source data = Dense cloud, interpolation = Extrapolated, resolution = 0
2021-05-20 19:21:57 Generating DEM...
2021-05-20 19:21:58 processing finished in 0.21771 sec
2021-05-20 19:21:59 BuildDem.initialize (1/1): source data = Dense cloud, interpolation = Extrapolated, resolution = 0
2021-05-20 19:21:59 initializing...
2021-05-20 19:21:59 Error: Null dense cloud
2021-05-20 19:21:59 processing finished in 0.220108 sec
2021-05-20 19:22:00 BuildDem.cleanup (1/1): source data = Dense cloud, interpolation = Extrapolated, resolution = 0
2021-05-20 19:22:00 processing finished in 0.223007 sec
2021-05-20 19:22:01 BuildOrthomosaic: surface = Mesh, blending mode = Mosaic, refine seamlines = 0, ghosting filter = 0, resolution = 0.05
2021-05-20 19:22:01 Generating orthomosaic...
2021-05-20 19:22:01 processing finished in 0.214354 sec
2021-05-20 19:22:02 BuildOrthomosaic.initialize (1/1): surface = Mesh, blending mode = Mosaic, refine seamlines = 0, ghosting filter = 0, resolution = 0.05
2021-05-20 19:22:02 initializing...
2021-05-20 19:22:02 Error: Null model
2021-05-20 19:22:02 processing finished in 0.213471 sec
2021-05-20 19:22:03 BuildOrthomosaic.cleanup (1/1): surface = Mesh, blending mode = Mosaic, refine seamlines = 0, ghosting filter = 0, resolution = 0.05
2021-05-20 19:22:03 processing finished in 0.216932 sec
2021-05-20 19:22:04 ExportRaster: image_format = TIFF, path = /data/projects/rusty-johnson-east-of-house/orthomosaic.tif, save_alpha = off, source_data = Elevation
2021-05-20 19:22:04 Error: Null elevation
2021-05-20 19:22:04 processing finished in 0.222748 sec

--- End code ---

farmflightadam:
Hey Alexey, we're making progress! We opened the project in the GUI and noticed that the images were not loaded. We went ahead and loaded the images then copied the project files back to our shared storage and we are now stitching. Here's the code that creates the project. How do we get this code to create the project and add the images to the project?


--- Code: ---import Metashape
import glob
import sys
import os
import time

print(":: create project using sony rgb imagery ::")

time.sleep(1)


def do_create_project(directory, project):
    if not (os.path.isdir(directory)):
        print("-- image directory provided is invalid --")
        return 0

    if not project.lower().endswith(".psx"):
        project += ".psx"

    print(":: collecting imagery from directory ", directory, " ::")

    time.sleep(1)

    images = [photo for photo in glob.iglob(directory + "*.*", recursive=True)
              if os.path.isfile(photo) and os.path.splitext(photo)[1][1:].upper() in ["JPG", "JPEG"]]

    if not len(images):
        print("-- no images (TIF/TIFF) found in directory provided --")
        return 0

    print(":: found ", len(images), " images ::")

    time.sleep(1)

    print(":: creating new metashape project ::")

    doc = Metashape.Document()
    doc.save(project)

    chunk = doc.addChunk()
    chunk.label = os.path.basename(directory)
    chunk.loadReferenceExif()
    chunk.crs = Metashape.CoordinateSystem("EPSG::4326")

    doc.save()

    print(":: project created successfully ::")
    return 1


if len(sys.argv) > 2:
    direc = sys.argv[1]
    psx = sys.argv[2]
    do_create_project(direc, psx)
else:
    print("-- missing arguments - provide image directory path and project file to create --")

--- End code ---

farmflightadam:
Hey Alexey,

I have been working on trying to get an NDVI (RedEdge) image to export but I am running into an issue. Here's the code


--- Code: ---    chunk = doc.chunks[0]
    chunk.raster_transform.formula = ["(B4-B2)/(B4+B2)"]
    chunk.raster_transform.calibrateRange()
    chunk.raster_transform.enabled = True

    task = Metashape.Tasks.ExportRaster()
    task.path = dir_save + 'ndvi.tif'
    task.source_data = Metashape.DataSource.OrthomosaicData
    task.image_compression = compression
    task.image_format = Metashape.ImageFormat.ImageFormatTIFF
    task.raster_transform = Metashape.RasterTransformValue
    task.projection = chunk.crs
    task.save_world = False
    task.save_alpha = False
    task.save_kml = False
    task.white_background = False

    net_task = Metashape.NetworkTask()
    net_task.name = task.name
    net_task.params = task.encode()
    net_task.frames.append((chunk.key, 0))
    tasks.append(net_task)

--- End code ---

The error I am getting is something about a missing color transform. If you could help, I would greatly appreciate it.

Thank you,

Adam M.

Navigation

[0] Message Index

[#] Next page

Go to full version