Forum

Author Topic: Python : chunk.addPhotos with multicamera system  (Read 12775 times)

Sylvain M.

  • Newbie
  • *
  • Posts: 18
    • View Profile
Python : chunk.addPhotos with multicamera system
« on: June 24, 2025, 06:01:31 PM »
Hi everyone,

Based on the script available at this address [1], I've set up a processing chain to build Drone orthophotos using a Python script.
I'm equipped with a DJI Mavic 3M drone, and I sometimes fly multispectral missions, which generates not only RGB photos (in JPG format), but also TIF images for each spectral band (Red, RedEdge, NIR, Green).
If I import the photos manually into a Metashape project, I can define it as a multi-camera system.

However, I don't know how to code this in Python.

Does anyone have a code snippet that handles this functionality?

Or, if anyone is able to help me ‘from scratch’, here's how the Mavic 3M's photo folders are structured:
- all images are in the same input folder.
- the “rgb” images are the only ones in JPG format (filegroup = “rgb”)
- the “green” images are in TIF format and their name ends with “_MS_G.TIF” (filegroup = “green”)
- nir' images are in TIF format and their name ends with “_MS_NIR.TIF” (filegroup = “nir”)
- red' images are in TIF format and their name ends with “_MS_R.TIF” (filegroup = “red”)
- re' images are in TIF format and their name ends with “_MS_RE.TIF” (filegroup = “re”)

This is what it would look like as a Python function:
Code: [Select]
def load_images_from_folder(folder):
    images = []
    for filename in os.listdir(folder):
        if filename.endswith('.JPG'):
            images.append((os.path.join(folder, filename), 'rgb'))
        elif filename.endswith('_MS_G.TIF'):
            images.append((os.path.join(folder, filename), 'green'))
        elif filename.endswith('_MS_NIR.TIF'):
            images.append((os.path.join(folder, filename), 'nir'))
        elif filename.endswith('_MS_R.TIF'):
            images.append((os.path.join(folder, filename), 'red'))
        elif filename.endswith('_MS_RE.TIF'):
            images.append((os.path.join(folder, filename), 're'))
    return images

Thanks in advance to anyone who can help me!

Sylvain M.

[1] https://github.com/agisoft-llc/metashape-scripts/blob/master/src/samples/general_workflow.py

vineg

  • Jr. Member
  • **
  • Posts: 76
    • View Profile
Re: Python : chunk.addPhotos with multicamera system
« Reply #1 on: June 24, 2025, 07:31:46 PM »
Hi!

There is a snippet in the manual page 22

https://www.agisoft.com/pdf/metashape_python_api_2_2_1.pdf

With a title "The following example describes how to create multispectal camera layout..."
Maybe that's it?

Egor

Alexey Pasumansky

  • Agisoft Technical Support
  • Hero Member
  • *****
  • Posts: 15600
    • View Profile
Re: Python : chunk.addPhotos with multicamera system
« Reply #2 on: June 24, 2025, 08:28:15 PM »
Hello Sylvain,

You can also check script example in another forum thread:
https://www.agisoft.com/forum/index.php?topic=16697.msg71605#msg71605
Best regards,
Alexey Pasumansky,
Agisoft LLC

Sylvain M.

  • Newbie
  • *
  • Posts: 18
    • View Profile
Re: Python : chunk.addPhotos with multicamera system
« Reply #3 on: June 25, 2025, 04:52:47 PM »
That's it, I've managed (with a little help from iA) to write this script.
Here's what it looks like:

Code: [Select]
import Metashape
import os

doc = Metashape.Document()
chunk = doc.addChunk()

image_folder = r'D:\PATH\FOLDER'
files = os.listdir(image_folder)

image_groups = {}

for file in files:
    if file.endswith('_D.JPG'):
        prefix = file[:-6]
        if prefix not in image_groups:
            image_groups[prefix] = {'rgb': None, 'green': None, 'nir': None, 'red': None, 're': None}
        image_groups[prefix]['rgb'] = os.path.join(image_folder, file)
    elif file.endswith('_MS_G.TIF'):
        prefix = file[:-9]
        if prefix not in image_groups:
            image_groups[prefix] = {'rgb': None, 'green': None, 'nir': None, 'red': None, 're': None}
        image_groups[prefix]['green'] = os.path.join(image_folder, file)
    elif file.endswith('_MS_NIR.TIF'):
        prefix = file[:-11]
        if prefix not in image_groups:
            image_groups[prefix] = {'rgb': None, 'green': None, 'nir': None, 'red': None, 're': None}
        image_groups[prefix]['nir'] = os.path.join(image_folder, file)
    elif file.endswith('_MS_R.TIF'):
        prefix = file[:-9]
        if prefix not in image_groups:
            image_groups[prefix] = {'rgb': None, 'green': None, 'nir': None, 'red': None, 're': None}
        image_groups[prefix]['red'] = os.path.join(image_folder, file)
    elif file.endswith('_MS_RE.TIF'):
        prefix = file[:-10]
        if prefix not in image_groups:
            image_groups[prefix] = {'rgb': None, 'green': None, 'nir': None, 'red': None, 're': None}
        image_groups[prefix]['re'] = os.path.join(image_folder, file)

camera = []
for group in image_groups.values():
    if group['rgb']:
        camera.append([group['rgb'], group['green'], group['nir'], group['red'], group['re']])

C = len(camera)

images = [None] * sum(len(cam) for cam in camera)

index = 0
for cam_list in camera:
    for path in cam_list:
        if path:
            images[index] = path
            index += 1

filegroups = [C] * (len(images) // C)

chunk.addPhotos(filenames=images, filegroups=filegroups, layout=Metashape.MultiplaneLayout)

doc.save(r'D:\PATH\Project.psx')

Don't hesitate to let me know if you see any improvements or errors!

Sylvain M.

  • Newbie
  • *
  • Posts: 18
    • View Profile
Re: Python : chunk.addPhotos with multicamera system
« Reply #4 on: June 26, 2025, 05:40:16 PM »
Unfortunately, my script doesn't work in all situations.
Most of the time, the 5 ‘simultaneous’ photos of the different spectral bands have the same timestamp, to the nearest second.
But there are cases where there can be a one-second difference (probably 1 hundredth of a second in reality), and so my groupings don't work.
Case in point:
Code: [Select]
DJI_20250611121953_0275_D.JPG
DJI_20250611121954_0275_MS_G.TIF
DJI_20250611121954_0275_MS_NIR.TIF
DJI_20250611121954_0275_MS_R.TIF
DJI_20250611121954_0275_MS_RE.TIF
(the first RGB photo is at 12h19m53s and the TIFs are at 12h19m54s)

I can try to adapt by only taking into account the fixed characters in a sequence (date and number, in this case 0275).
But I get the impression that this would not be optimal : could I ask what approach you would recommend for this situation?

Metashape, when I import my images manually, automatically detects the multi-camera system, and handles groupings well, even if the timestamp is different.
Is there any way of knowing Metashape grouping criterias  ?

Sylvain M.

  • Newbie
  • *
  • Posts: 18
    • View Profile
Re: Python : chunk.addPhotos with multicamera system
« Reply #5 on: June 27, 2025, 06:48:06 PM »
Here is, i think, a better approch :
Code: [Select]
import os
import Metashape

# Paths to the folders containing the MS images
image_folders = [
    r"D:\PATH\FOLDER1",
    r"D:\PATH\FOLDER2"
]

# Access the document and add a chunk
doc = Metashape.Document()
chunk = doc.addChunk()

# File extensions to search for
extensions = ('.jpg', '.tif')

# List to store found files
files = []

# Collect all relevant files from the folders
for folder in image_folders:
    for file in os.listdir(folder):
        if file.lower().endswith(extensions):
            files.append(os.path.join(folder, file))

# Initialize lists for each type of image
rgb = []
green = []
nir = []
red = []
red_edge = []

# Sort files by their type
for file in files:
    if file.endswith("_D.JPG"):
        rgb.append(file)
    elif file.endswith("_MS_G.TIF"):
        green.append(file)
    elif file.endswith("_MS_NIR.TIF"):
        nir.append(file)
    elif file.endswith("_MS_R.TIF"):
        red.append(file)
    elif file.endswith("_MS_RE.TIF"):
        red_edge.append(file)

# Verify that each type has the same number of images
assert len(rgb) == len(green) == len(nir) == len(red) == len(red_edge), "The number of images per type is not the same."

# Create a combined list of images alternating the types
images = []
for i in range(len(rgb)):
    images.append(rgb[i])
    images.append(green[i])
    images.append(nir[i])
    images.append(red[i])
    images.append(red_edge[i])

# Define the image groups
groups = [5] * len(rgb)

# Add the images to the chunk
chunk.addPhotos(filenames=images, filegroups=groups, layout=Metashape.MultiplaneLayout)

# Save the project
doc.save(r'D:\PATH\Project.psx')