Forum

Author Topic: Python scripts without starting the Metashape application  (Read 1473 times)

katemosolova

  • Newbie
  • *
  • Posts: 5
    • View Profile
Python scripts without starting the Metashape application
« on: December 16, 2024, 11:48:27 AM »
I would like to obtain the coordinates of the corners of the photo from the project in Metashape. I have discovered scripts for generating footprints. I have also modified them to suit my needs.


Code: [Select]
import Metashape
import multiprocessing
import concurrent.futures
I would like to obtain the coordinates of the corners of the photograph from the project in Metashape. I have discovered scripts for generating footprints. I have also modified them to suit my needs.
def create_footprints():
    """
    Creates four-vertex shape for each aligned camera (footprint) in the active chunk
    and puts all these shapes to a new separate shape layer
    """

    doc = Metashape.Document()
    doc.open("My_project.psx", ignore_lock=True)
    if not len(doc.chunks):
        raise Exception("No chunks!")

    print("Script started...")
    chunk = doc.chunk

    if not chunk.shapes:
        chunk.shapes = Metashape.Shapes()
        chunk.shapes.crs = chunk.crs
    T = chunk.transform.matrix

    if chunk.elevation:
        surface = chunk.elevation
    elif chunk.model:
        surface = chunk.model
    elif chunk.point_cloud:
        surface = chunk.point_cloud
    else:
        surface = chunk.tie_points

    chunk_crs = chunk.crs.geoccs
    if chunk_crs is None:
        chunk_crs = Metashape.CoordinateSystem('WGS84')

    def process_camera(chunk, camera):
        if camera.type != Metashape.Camera.Type.Regular or not camera.transform:
            return  # skipping NA cameras

        sensor = camera.sensor
        w, h = sensor.width, sensor.height
        if sensor.film_camera:
            if "File/ImageWidth" in camera.photo.meta and "File/ImageHeight" in camera.photo.meta:
                w, h = int(camera.photo.meta["File/ImageWidth"]), int(camera.photo.meta["File/ImageHeight"])
            else:
                image = camera.photo.image()
                w, h = image.width, image.height
        corners = list()
        for (x, y) in [[0, 0], [w - 1, 0], [w - 1, h - 1], [0, h - 1]]:
            ray_origin = camera.unproject(Metashape.Vector([x, y, 0]))
            ray_target = camera.unproject(Metashape.Vector([x, y, 1]))
            if type(surface) == Metashape.Elevation:
                dem_origin = T.mulp(ray_origin)
                dem_target = T.mulp(ray_target)
                dem_origin = Metashape.OrthoProjection.transform(dem_origin, chunk_crs, surface.projection)
                dem_target = Metashape.OrthoProjection.transform(dem_target, chunk_crs, surface.projection)
                corner = surface.pickPoint(dem_origin, dem_target)
                if corner:
                    corner = Metashape.OrthoProjection.transform(corner, surface.projection, chunk_crs)
                    corner = T.inv().mulp(corner)
            else:
                corner = surface.pickPoint(ray_origin, ray_target)
            if not corner:
                corner = chunk.tie_points.pickPoint(ray_origin, ray_target)
            if not corner:
                break
            corner = chunk.crs.project(T.mulp(corner))
            corners.append(corner)

        if len(corners) == 4:
            print(camera.label, corners)
        else:
            print("Skipping camera " + camera.label)

    with concurrent.futures.ThreadPoolExecutor(multiprocessing.cpu_count()) as executor:
        executor.map(lambda camera: process_camera(chunk, camera), chunk.cameras)

    Metashape.app.update()
    print("Script finished!")

create_footprints()

When I execute this code in the console of Metashape, I receive the necessary coordinates of the corners.

Code: [Select]
LoadProject: path = My_project.psx
loaded project in 0 sec
Finished processing in 0 sec (exit code 1)
Script started...
photo_name1 [Vector([lat_data_corners(0,0), lon_data_corners(0,0), evl_data_corners(0,0)]), Vector([lat_data_corners(w - 1, 0), lon_data_corners(w - 1, 0), evl_data_corners(w - 1, 0)]), Vector([lat_data_corners(w - 1, h - 1), lon_data_corners(w - 1, h - 1), evl_data_corners(w - 1, h - 1)]), Vector([lat_data_corners(0, h - 1), lon_data_corners(0, h - 1), evl_data_corners(0, h - 1)])]
...
photo_name99 [Vector([lat_data_corners(0,0), lon_data_corners(0,0), evl_data_corners(0,0)]), Vector([lat_data_corners(w - 1, 0), lon_data_corners(w - 1, 0), evl_data_corners(w - 1, 0)]), Vector([lat_data_corners(w - 1, h - 1), lon_data_corners(w - 1, h - 1), evl_data_corners(w - 1, h - 1)]), Vector([lat_data_corners(0, h - 1), lon_data_corners(0, h - 1), evl_data_corners(0, h - 1)])]
Script finished!

But if I want to run this script frome console of my computer (w/o start Metashape) I got this:

Code: [Select]
LoadProject: path = My_project.psx
loaded project in 0.001 sec
Script started...
Script finished!

I attempted to discern the source of the error. I inserted several print statements into my code:


Code: [Select]
if type(surface) == Metashape.Elevation:
                dem_origin = T.mulp(ray_origin)
                dem_target = T.mulp(ray_target)
                print('1',dem_origin, dem_target)
                dem_origin = Metashape.OrthoProjection.transform(dem_origin, chunk_crs, surface.projection)
                dem_target = Metashape.OrthoProjection.transform(dem_target, chunk_crs, surface.projection)
                corner = surface.pickPoint(dem_origin, dem_target)
                print('2',dem_origin, dem_target)
                print(corner)
                if corner:
                    corner = Metashape.OrthoProjection.transform(corner, surface.projection, chunk_crs)
                    corner = T.inv().mulp(corner)
                    print(corner)

And now I know that
Code: [Select]
print('2',dem_origin, dem_target) not work. I get only date from
Code: [Select]
print('1',dem_origin, dem_target)
Could you please help me to understand how to get data from photos using Python scripts without starting the Metashape application?


UPDATE:

I remove
Code: [Select]
    with concurrent.futures.ThreadPoolExecutor(multiprocessing.cpu_count()) as executor:
        executor.map(lambda camera: process_camera(chunk, camera), chunk.cameras)

And use just

Code: [Select]

    for camera in chunk.cameras:
        process_camera(chunk, camera)


And I got this error:

Code: [Select]
    dem_origin = Metashape.OrthoProjection.transform(dem_origin, surface.projection, chunk_crs)
TypeError: transform() argument 3 must be Metashape.Metashape.OrthoProjection, not Metashape.Metashape.CoordinateSystem


Why does this code work well in the Metashape app and not like a Python script?


UPDATE2:

My application has is 2.1.2 version

My venv for running python scripts has 2.0.3 version


UPDATE3:

I updated the version in my virtual environment and received the expected results.

To summarize, when you are copying code, make sure to do it thoroughly!

Code: [Select]
# Checking compatibility
compatible_major_version = "2.1"
found_major_version = ".".join(Metashape.app.version.split('.')[:2])
if found_major_version != compatible_major_version:
    raise Exception("Incompatible Metashape version: {} != {}".format(found_major_version, compatible_major_version))


Thank you for attention :)
« Last Edit: December 16, 2024, 12:17:20 PM by katemosolova »