Forum

Author Topic: Transfering 2D-image markers (x/y-pixel) to 3D-real-world-coordinates  (Read 4384 times)

Garfields_Lasagna

  • Newbie
  • *
  • Posts: 6
    • View Profile
Dear Agisoft-team,

My starting point is a georeferenced densecloud and orthomosaick calculated out of geotagged images.

Within the project I'd like to perform the following steps within a python script:

1. Import a text-file with 2D-marker (cameraname/x-Position in Pixel/Y-position in Pixel)
2. Place marker according to the list's position on a camera/image (--> marker will be projected within dense cloud and orthomosaic)
3. Export a list of 3D, real-world-coordinates of generated marker

Some additional questions:
- Is this generally possible? In most cases the marker will be placed in just one image and would conesequently be shown as a white flag ...
- Do you happen to know the relevant command lines for the image x/y attachment and the placing of the markers on the exact image position?

Thanks,
GL

Alexey Pasumansky

  • Agisoft Technical Support
  • Hero Member
  • *****
  • Posts: 14847
    • View Profile
Re: Transfering 2D-image markers (x/y-pixel) to 3D-real-world-coordinates
« Reply #1 on: October 25, 2021, 03:54:28 PM »
Hello Garfields_Lasagna,

Do you have single or multiple projections for each marker (I mean it's 2D location on the original images)?
Best regards,
Alexey Pasumansky,
Agisoft LLC

Garfields_Lasagna

  • Newbie
  • *
  • Posts: 6
    • View Profile
Re: Transfering 2D-image markers (x/y-pixel) to 3D-real-world-coordinates
« Reply #2 on: October 27, 2021, 11:41:29 AM »
Hi Alexey,

yes, it is a 2D-location on the original image. Normally it would be identified within one single image (so a single projection).

Alexey Pasumansky

  • Agisoft Technical Support
  • Hero Member
  • *****
  • Posts: 14847
    • View Profile
Re: Transfering 2D-image markers (x/y-pixel) to 3D-real-world-coordinates
« Reply #3 on: November 01, 2021, 05:14:52 PM »
Hello Garfields_Lasagna,

Please check, if the following script works as expected for your needs:

Code: [Select]
#input file format:
#camera name, x-Position in Pixel, Y-position in Pixel
#
#output file format:
#marker label, x-world, y-world, z-world

import Metashape, os

def read_2D_export_3D(chunk, path):
if not path:
print("Invalid path, script aborted")
return 0
if not os.path.isfile(path):
print("Invalid path, script aborted")
return 0
if not chunk:
print("Empty document, script aborted")
return 0
cameras = [camera for camera in chunk.cameras if camera.transform and camera.type == Metashape.Camera.Type.Regular] #list of aligned cameras
if not cameras:
print("Empty chunk, script aborted")
return 0
if not chunk.dense_cloud:
print("Dense cloud is missing, script aborted")
return 0

surface = chunk.dense_cloud
crs = chunk.crs
T = chunk.transform.matrix
input = open(path, "rt")
if os.path.splitext(path)[1]:
out_path = os.path.splitext(path)[0] + "_out.txt"
else:
out_path = path + "_out.txt"
output = open(out_path, "wt")

lines = input.readlines()
for line in lines:
if len(line) < 4:
continue
label, x_coord, y_coord = line.strip().split(",",3)
x_coord = float(x_coord)
y_coord = float(y_coord)

for camera in cameras:
if camera.label == label:
marker = chunk.addMarker()
ray_origin = camera.unproject(Metashape.Vector([x_coord, y_coord, 0]))
ray_target = camera.unproject(Metashape.Vector([x_coord, y_coord, 1]))
coord = crs.project(T.mulp(surface.pickPoint(ray_origin, ray_target)))
marker.label = label
marker.projections[camera] =  Metashape.Marker.Projection(Metashape.Vector([x_coord,y_coord]), True)
marker.reference.location = coord
marker.reference.enabled = True
output.write("{:s},{:.6f},{:.6f},{:.6f}\n".format(marker.label, coord.x, coord.y, coord.z))
break
output.flush()
output.close()
input.close()


print("Script finished")
return 1

chunk = Metashape.app.document.chunk
path = Metashape.app.getOpenFileName("Select the file with 2D marker coordinates:", filter="(*.txt) Text files;; (*.*) All files")

read_2D_export_3D(chunk, path)

The input text file is expected to be in the following format:
Code: [Select]
DSC01578.JPG,100.12,200.223
DSC02579.JPG,234.13,300.245
DSC02580.JPG,300.14,456.289
DSC03581.JPG,500.15,600.267

The output file is created in the same directory where the input file is located with "_out" suffix.
Best regards,
Alexey Pasumansky,
Agisoft LLC

Garfields_Lasagna

  • Newbie
  • *
  • Posts: 6
    • View Profile
Re: Transfering 2D-image markers (x/y-pixel) to 3D-real-world-coordinates
« Reply #4 on: November 16, 2021, 02:17:57 PM »
Dear Alexey,

thank you! Your proposed script works fine. At first I had some trouble as I added the file-type in the input-file, but once I skipped that, everything worked as supposed!

- Do you happen to know the command line/code where I can set the coordinate system of the output file? So that the the output coordinates would be in EPSG 32632 (UTM32).
- Is it possible to add the precision of each marker into the outputfile? I saw that each marker had a precsion in the reference menu, but don't know whether this could be extraced also via the script

Anyway those are rather small details. Thanks again for your script!

Best regards
GL




SBinary

  • Newbie
  • *
  • Posts: 5
    • View Profile
Re: Transfering 2D-image markers (x/y-pixel) to 3D-real-world-coordinates
« Reply #5 on: April 12, 2022, 09:15:44 AM »
Hello Garfields_Lasagna,

Please check, if the following script works as expected for your needs:

Code: [Select]
#input file format:
#camera name, x-Position in Pixel, Y-position in Pixel
#
#output file format:
#marker label, x-world, y-world, z-world

import Metashape, os

def read_2D_export_3D(chunk, path):
if not path:
print("Invalid path, script aborted")
return 0
if not os.path.isfile(path):
print("Invalid path, script aborted")
return 0
if not chunk:
print("Empty document, script aborted")
return 0
cameras = [camera for camera in chunk.cameras if camera.transform and camera.type == Metashape.Camera.Type.Regular] #list of aligned cameras
if not cameras:
print("Empty chunk, script aborted")
return 0
if not chunk.dense_cloud:
print("Dense cloud is missing, script aborted")
return 0

surface = chunk.dense_cloud
crs = chunk.crs
T = chunk.transform.matrix
input = open(path, "rt")
if os.path.splitext(path)[1]:
out_path = os.path.splitext(path)[0] + "_out.txt"
else:
out_path = path + "_out.txt"
output = open(out_path, "wt")

lines = input.readlines()
for line in lines:
if len(line) < 4:
continue
label, x_coord, y_coord = line.strip().split(",",3)
x_coord = float(x_coord)
y_coord = float(y_coord)

for camera in cameras:
if camera.label == label:
marker = chunk.addMarker()
ray_origin = camera.unproject(Metashape.Vector([x_coord, y_coord, 0]))
ray_target = camera.unproject(Metashape.Vector([x_coord, y_coord, 1]))
coord = crs.project(T.mulp(surface.pickPoint(ray_origin, ray_target)))
marker.label = label
marker.projections[camera] =  Metashape.Marker.Projection(Metashape.Vector([x_coord,y_coord]), True)
marker.reference.location = coord
marker.reference.enabled = True
output.write("{:s},{:.6f},{:.6f},{:.6f}\n".format(marker.label, coord.x, coord.y, coord.z))
break
output.flush()
output.close()
input.close()


print("Script finished")
return 1

chunk = Metashape.app.document.chunk
path = Metashape.app.getOpenFileName("Select the file with 2D marker coordinates:", filter="(*.txt) Text files;; (*.*) All files")

read_2D_export_3D(chunk, path)

The input text file is expected to be in the following format:
Code: [Select]
DSC01578.JPG,100.12,200.223
DSC02579.JPG,234.13,300.245
DSC02580.JPG,300.14,456.289
DSC03581.JPG,500.15,600.267

The output file is created in the same directory where the input file is located with "_out" suffix.

Thank you very muck for this script!

Strangely enough, I cannot get it working - and cannot figure out why. I would really appreciate if you could help.

I have a .txt file with
DJI_0271.JPG,2075.00,814.00
DJI_0274.JPG,2047.00,1849.00
DJI_0422.JPG,2016.00,2500.00
DJI_0731.JPG,1895.00,2066.00
DJI_0265.JPG,2111.00,2579.00

The script runs successfully, but the output .txt file is empty.

The images are geotagged (from drone), and the project's coordinate system is set to the default WGS 84.

Do you have any idea why the output .txt tile is empty?

Paulo

  • Hero Member
  • *****
  • Posts: 1320
    • View Profile
Re: Transfering 2D-image markers (x/y-pixel) to 3D-real-world-coordinates
« Reply #6 on: April 12, 2022, 10:42:54 AM »
Hello SBinary,

does your chunk have a dense cloud...? The script uses the dense cloud to find the 3D intersection of marker projection (2D) onto the 3d surface represented by dense cloud....

Without dense cloud there is no intersection....

PS. probable cause your chunk  camera labels are stipped of their extension i.e. camera DJI_0271.JPG has label DJI_0271. if this is the case then modify
Code: [Select]
if camera.label == label:with
Code: [Select]
if camera.label == label.split(sep='.')[0]:
« Last Edit: April 12, 2022, 11:37:01 AM by Paulo »
Best Regards,
Paul Pelletier,
Surveyor

SBinary

  • Newbie
  • *
  • Posts: 5
    • View Profile
Re: Transfering 2D-image markers (x/y-pixel) to 3D-real-world-coordinates
« Reply #7 on: April 12, 2022, 12:10:35 PM »
Hello SBinary,

does your chunk have a dense cloud...? The script uses the dense cloud to find the 3D intersection of marker projection (2D) onto the 3d surface represented by dense cloud....

Without dense cloud there is no intersection....

PS. probable cause your chunk  camera labels are stipped of their extension i.e. camera DJI_0271.JPG has label DJI_0271. if this is the case then modify
Code: [Select]
if camera.label == label:with
Code: [Select]
if camera.label == label.split(sep='.')[0]:

Thank you so much! This was it,
Code: [Select]
if camera.label == label.split(sep='.')[0]:
Once again, thank you!