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.
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.
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:
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:
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
print('2',dem_origin, dem_target)
not work. I get only date from
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
with concurrent.futures.ThreadPoolExecutor(multiprocessing.cpu_count()) as executor:
executor.map(lambda camera: process_camera(chunk, camera), chunk.cameras)
And use just
for camera in chunk.cameras:
process_camera(chunk, camera)
And I got this error:
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!
# 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
