Use Python to Streamline Your Agisoft Metashape Workflow: Part I
Standardize settings, align images, and batch process projects

Use Python to enhance efficiency, accuracy, customization, and scalability of your Metashape workflow
Agisoft Metashape provides the software tools to create high resolution drone orthomosaics and/or detailed 3D point clouds and mesh models, making it ideal for a wide range of users. Like most modern software packages, the intuitive layout of the Metashape graphical user interface (GUI) makes it sufficient for most users. Aleena Rayamajhi wrote a comprehensive post that can get you started using the standard GUI.
After getting familiar with the GUI you should notice that many of the processing steps are repetitive. Repetitive tasks should be automated. You may also notice that a mistake during processing, like setting the wrong tie point or key point limit, can lead to incorrect results and a lot of wasted time.
The Professional version of Metashape includes a Python API that can be used to streamline your workflow. If you don’t use it already, you should! Using the Metashape Python API will streamline your workflow, allowing you to batch process multiple projects. A scripted workflow also ensures consistent and replicable processing by applying the same settings.
The Python API allows you to automatically save your project after each step, providing peace of mind. Processing large sets of images can take time. It’s not uncommon for processing steps to run overnight, even with a beefy computer. When using the GUI, you must save your project manually after each processing step is completed. Saving manually is usually not a problem until your computer loses power in the early morning hours, before you wake up to manually save your project. The Python API allows you to save your project automatically after each step is completed, ensuring that all the time invested in processing your imagery is not lost.
In this post, you will learn how to harness the power of Metashape’s Python API to automate the initial alignment step of the workflow.
Before proceeding, read the user manuals and make sure that you’ve configured Metashape properly for your computer. If you’re new to Metashape I recommend reading the Agisoft tutorials and watching some YouTube videos.
I also highly recommend reading the USGS Open File Report on Processing Coastal Imagery in Agisoft Metashape. This Open File Report provides a comprehensive description of the GUI environment and the processing workflow for drone aerial imagery of coastal environments. Some of the settings may not apply to other use cases (like turntables or multi-camera rigs) but the configuration of GPU acceleration, writing log files, default views, etc. should apply to all users.
Scripted Alignment in 3 Easy Steps

Understanding Chunks
Metashape documents use ‘Chunks’ to group cameras, tie points, reference data, and other information. Documents and Chunks are also objects in the Python API with attributes that can be set/retrieved, as illustrated below.
doc = Metashape.app.document
for chunk in doc.chunks:
if chunk.label == 'chunk1':
# do stuffThe name that you assign to a chunk will be stored as chunk.label and should, therefore, make sense.

Since this is the first run in this project, let’s call the chunk ‘run1.’ Open Metashape, right click on ‘Chunk 1’ in the Workspace Panel, click ‘Rename’, enter ‘run1’ and press ‘Enter.’

Next, right click on ‘run1’ and select Add →Add Photos. Navigate to the directory that contains the photos that you want to process, select the appropriate photos and then click ‘Open.’
After adding photos to the chunk ‘run1’ save your project. You will need to specify the path to your project and the project file name in your python code so use a naming convention that makes sense and is easy to code. In this example I saved my project using the following convention, which uses the project creation date and a text descriptor:
'20230828_mcourse.psx'
# datestring_descriptor.psx
# yyyymmdd_descriptor.psxIn this case, I used the four-digit year, two-digit month, and two-digit day (zero-padded as necessary) and the descriptor ‘mcourse’ for Metashape Course.

I am using images from a DJI Phantom 3 drone in this example. Metashape automatically extracts the GPS positions of each image, which are stored in the EXIF data. Depending on your camera and use case, the reference data for your images may be stored separately. If so, load image positions in the ‘Reference’ window before proceeding. The camera and lens parameters are also usually stored in the EXIF data. If the camera and lens parameters are not stored in your images EXIF data, add this information before proceeding. To do so, navigate to Tools →Camera Calibration. Otherwise, save your project and proceed to the code.
The Python Code
The python code below allows you to set the parameters used to align images. The parameters below are equivalent to the following settings in the GUI:
- Match_accuracy = 1 → High accuracy
- gen_pre = True → Generic preselection enabled
- ref_pre = True → Reference preselection enabled
- mask_filt = True and mask_tie = True → Apply Masks to Tie Points (under the Advanced alignment settings)
- key_lim = 60,000 → Key point limit = 60k (Advanced settings)
- tie_lim = 0 → Tie point limit = 0 (Advanced settings)
The code also allows you to perform the camera optimization step after the initial alignment is completed. To disable camera optimization set ‘optimus = False’
Note the following:
- The project path/name expects a list, allowing multiple projects to be processed
- Similarly, the chunk labels ‘clbls’ also expects a list so multiple chunks can be processed in each project.
- The project is saved after each processing step is completed.
- If enabled, the current chunk is duplicated before camera optimization.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import Metashape
# Alignment parameters
match_accuracy = 1 # matching accuracy (upscaling/downscaling)
gen_pre = True # generic preselection
ref_pre = True # reference preselection
mask_filt = True # Filter points by mask
mask_tie = True # Apply masks to tie points
filter_stationary = False # Exclude stationary tie points
key_lim = 60000 # Key point limit
tie_lim = 0 # Tie point limit
keep_key = False # Keep key points
match_reset = False # Reset current matches
min_point_proj = 2 # Minimum number of point projections
distort_adapt_fit = False # Adaptive fitting of distortion coefficients
# Camera interior/exterior orientations and lens distortion options
optimus = True
opt_correct_fit = True # Enable optimization of additional corrections
opt_adapt_fit = True # Enable adaptive fitting of distortion coefficients
tie_cov = True # Estimate tie point covariance
def copy_new_chunk(chunk, old_label, new_label):
new_chunk = chunk.copy()
clbl_i = str("".join([old_label,new_label]))
new_chunk.label = clbl_i
return clbl_i
def find_chunk(doc, label):
if type(doc) != Metashape.Document:
print("Not a valid MetaShape file!")
return False
if type(label) != str:
print("Please provide a string as input!")
return False
for chunk in doc.chunks:
if chunk.label == label:
print(f"Chunk {label} was found.")
return(chunk)
print(f"Chunk {label} was not found!")
return None
def align_images(chunk, match_accuracy, gen_pre, ref_pre, mask_filt, mask_tie, filter_stationary, key_lim, tie_lim, keep_key, match_reset):
chunk.matchPhotos(downscale = match_accuracy,
generic_preselection = gen_pre,
reference_preselection = ref_pre,
filter_mask = mask_filt,
mask_tiepoints = mask_tie,
filter_stationary_points = filter_stationary,
keypoint_limit = key_lim,
tiepoint_limit = tie_lim,
keep_keypoints = keep_key,
reset_matches = match_reset
)
chunk.alignCameras(min_image = min_point_proj,
adaptive_fitting = distort_adapt_fit)
# Main body of program
# path and file name of your Metashape project. The loop expects a list of projects
Projs = ["/data2/metashape_course/20230828_mcourse.psx"
]
# chunk(s) to process within a project - list
clbls = [
"run1",
]
doc = Metashape.app.document
# project loop
for proj in Projs:
doc.open(proj)
proj_name = proj.split("/")[len(proj.split("/"))-1]
proj_path = "/".join(proj.split("/")[:-1])
for clbl in clbls:
for chunk in doc.chunks:
if chunk.label != clbl:
continue
print("")
print("Now processing project <", proj_name, ">...")
# find chunk by name
chunk = find_chunk(doc, clbl)
# sets selected chunk as active
doc.chunk = chunk
align_images(chunk, match_accuracy, gen_pre, ref_pre, mask_filt, mask_tie, filter_stationary, key_lim, tie_lim, keep_key, match_reset)
doc.save() # save after alignment
if optimus:
oc_clbl = copy_new_chunk(chunk,clbl,"-OC") # copy to new chunk before proceeding
chunk = find_chunk(doc, oc_clbl)
doc.chunk = chunk
chunk.optimizeCameras(tiepoint_covariance=tie_cov,fit_f=True,fit_cx=True,fit_cy=True,fit_b1=True,fit_b2=True,fit_k1=True,fit_k2=True,fit_k3=True,fit_k4=True,fit_p1=True,fit_p2=True,adaptive_fitting=opt_adapt
doc.save()Running the Code in Metashape
- To run the code in Metashape, copy it into your python or text editor and save it as ‘metashape_align.py’
- Change the path to your project in the Projs variable (Projs expects a list)
- Open Metashape and navigate to Tools → Run Script
- In the window that opens, select the script ‘metashape_align.py’ and in the ‘Arguments’ dialog box enter ‘-r’
- Click ‘Ok’

If everything works correctly then Metashape will start to align your images!

Depending on the size of your project and the quality/overlap of your images you should eventually see something like the following screenshot.

Wrapping Up
Now you should be able to automate image alignment in Agisoft Metashape using python.






