Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Messages - LFSantosgeo

Pages: [1] 2 3 ... 5
Python and Java API / Re: Reprojection Errors (script x chunk info)
« on: December 09, 2019, 02:27:45 PM »
Thank you Alexey!

Looking forward for your test results.

Python and Java API / Re: Reprojection Errors (script x chunk info)
« on: December 05, 2019, 09:53:46 PM »
Anything on this? I guess my code is wrong but I've double checked it and can't figure out what is wrong with it.
I trying to get reprojection error by points to text file with: point_id, X, Y, Z, error

Python and Java API / Re: Reprojection Errors (script x chunk info)
« on: December 03, 2019, 11:35:31 PM »
So I've changed my code to get point errors...

Code: [Select]
def getPointErrors(path, i=[0]):  # função: erro por ponto
    i[0] += 1

    f = open(path + "/_1_PONTOS_" + str(i) + ".txt", "wt")

    point_cloud = chunk.point_cloud
    points = point_cloud.points
    npoints = len(points)
    projections = chunk.point_cloud.projections
    M = chunk.transform.matrix  # matriz de transformação
    point_ids = [-1] * len(point_cloud.tracks)
    point_errors = {}

    for point_id in range(0, npoints):
        point_ids[points[point_id].track_id] = point_id

    for cam in chunk.cameras:
        if not cam.transform:

        for proj in projections[cam]:
            track_id = proj.track_id
            point_id = point_ids[track_id]
            if point_id < 0:
            point = points[point_id]
            if not point.valid:
            error = cam.error(point.coord, proj.coord).norm() ** 2
            if point_id not in point_errors.keys():
                point_errors[point_id] = [error]

    for point_id in range(npoints):
        if not points[point_id].valid:
            w = M * points[point_id].coord
            w.size = 3
            X, Y, Z =

        errpto = sum(point_errors[point_id]) / len(point_errors[point_id])
        errpto = errpto ** (5/10)  # sqrt
                "{:.6f}\t{:.6f}\n".format(point_id, X, Y, Z, errpto))

But when I average the point errors they differ a bit (0.55pix) from the chunk info (0.53pix).

Python and Java API / Re: Reprojection Errors (script x chunk info)
« on: November 23, 2019, 07:55:51 AM »
Hello Luiz,

Can you please check, if the following script gives you the correct values for max and RMS reprojection errors:
Yes the code you provided calculates precisely RMS and max reprojection for the chunk.

I think that the different comes from the confusion - max. error is calculated per projection and not per point.
I'm guessing you are quite right about the difference using points vs projections on the codes. Ok then, max reprojection error is the max error value within all projections and RMS is the reprojection error averaged over all valid tie points (and their projections) in chunk. Then with the code I'm using I get the reprojection error for each valid tie point (where every single one has at least 2 or more projections and respectively reprojections errors averaged into one value). Is this right?

Just to clear a doubt of mine: the gradual selection (API and GUI) for reprojection error  goes through each one of the projections and removes them by the defined threshold? How does it select points then?

Thank you

I'm guessing sigma0 is in pixels as Metashape weights tie point accuracy in pixels... Can anyone confirm it?

Python and Java API / Reprojection Errors (script x chunk info)
« on: November 20, 2019, 01:39:54 PM »

I'm running the following script to get reprojection errors by point of the point cloud:

Code: [Select]
def tiepointsRMS(path, i=[0]):
    i[0] += 1
    Generates a TXT file with point index of Sparse Cloud, associated
    coordinates and calculated reprojection error (pIndex, X, Y, Z, error)
    point_cloud = chunk.point_cloud
    projections = point_cloud.projections
    points = point_cloud.points
    npoints = len(points)

    M = chunk.transform.matrix

    file = open(path + str(i) + ".txt", "wt")
    print("Tiepoints reprojection error calculations started...")

    t0 = time.time()

    points_errors = {}

    for photo in chunk.cameras:

        if not photo.transform:

        T = photo.transform.inv()
        calib = photo.sensor.calibration

        pIndex = 0
        for proj in projections[photo]:
            track_id = proj.track_id
            while pIndex < npoints and points[pIndex].track_id < track_id:
                pIndex += 1
            if pIndex < npoints and points[pIndex].track_id == track_id:
                if not points[pIndex].valid:

                coord = T * points[pIndex].coord
                coord.size = 3
                dist = calib.error(coord, proj.coord).norm() ** 2
                v = M * points[pIndex].coord
                v.size = 3

                if pIndex in points_errors.keys():
                    pIndex = int(pIndex)
                    points_errors[pIndex].x += dist
                    points_errors[pIndex].y += 1
                    points_errors[pIndex] = PS.Vector([dist, 1])

    for pIndex in range(npoints):

        if not points[pIndex].valid:

            w = M * points[pIndex].coord
            w.size = 3
            X, Y, Z =
            X, Y, Z, w = M * points[pIndex].coord

        error = math.sqrt(points_errors[pIndex].x /

                   "{:.6f}\t{:.6f}\n".format(pIndex, X, Y, Z, error))

    t1 = time.time()

    print("Script finished in " + str(int(t1-t0)) + " seconds.")

While it succeeds to calculate the reprojection error for each tie point, when I compare the max error value obtained with script (14,5876 pix) with the max error provided by chunk info (21.8388 pix) they don't match. Is that supposed to happen? Looking forward for the reply.


Hey there, Alexey!

In what units the sigma0 is present by accessing it by chunk.meta? Pixels, meters? Or is it unitless?
0.116893 -> 0.115939


try this workflow … i use it for every lens …concerning color … there is a bunch of LUTs out there for any camera you own.
regards nj

From the workflow above it states: "Capture the images of the pattern at a distance roughly equal to the distance from your camera to the objects of interest." Following this statement unables to use it with UAV images since UAV/camera distance to objects or area of interest might vary from 20 to 120m of distance (or even more).

Some posts say that is good to use precalibration since it might avoid errors on reconstructed points (like doming). Considering this I guess the calibration is necessary even though quite difficult to perform the same distance photography of the checkboard using UAV.

1. Does it matter to calibrate the camera with the same distance from camera to imaging object?
2. Can I get initial values for camera calibration (using Lens) and then use self-calibration afterwards to refine the parameters values when processing aerial data? (I got the impression that this is viable from the Metashape manual).

Any comments on the matter above?

Python and Java API / Re: Reprojection error
« on: March 11, 2019, 05:47:34 AM »
You should multiply it by the GSD.

Thinking of what rongilad wrote:

Code: [Select]
import Metashape as PS
import math

doc =
chunk = doc.chunk

def getGSD(chunk):
    Based on:
    # Get average camera altitude from estimated positions (not source)
    N_cameras = 0
    CamAlt = 0
    for idx, camera in enumerate(chunk.cameras):
        if camera.transform:
            N_cameras += 1
            mmulp = chunk.transform.matrix.mulp
            est =
            CamAlt += est.z

    CamAlt /= N_cameras

    # Get focal length in mm (imported from EXIF?)
    FocalLength = chunk.sensors[0].focal_length

    # Get focal length in pix values after calib (current value)
    FocalPix = chunk.sensors[0].calibration.f

    # Get the average ground altitude baed on every point on point cloud
    GroundAlt = 0
    for point in chunk.point_cloud.points:
        pPos =[:3]))
        GroundAlt += pPos.z

    GroundAlt = GroundAlt / len(chunk.point_cloud.points)

    # Get the average flight height above ground
    FlightHeight = CamAlt - GroundAlt

    # Get the average image width and height
    ImageW = 0
    ImageH = 0
    for idx, camera in enumerate(chunk.cameras):
        ImageW += chunk.cameras[idx].photo.image().width
        ImageH += chunk.cameras[idx].photo.image().height

    ImageW /= len(chunk.cameras)
    ImageH /= len(chunk.cameras)

    # Default sensor size (mm) for Phantom 4

    # CMOS Sensor Sony EXMOR RS IMX377CQT Type 1/2.3" 12.35MP (4:3 or 1.33)
    # FOV = 94.0
    # Pixel size: 1.55 x 1.55 um

    # Two recording modes:
    #    1/2.3" = 12.32MP
    #    1/2.5" =  9.05MP

    # Total number of pixels           4152 x 3062 = 12.71MP
    # Effective pixels       (1/2.3")  4056 x 3046 = 12.35MP
    # Active pixels          (1/2.3")  4024 x 3036 = 12.22MP
    #    Sensor width  = 6.24 mm - 4024 pixels
    #    Sensor height = 4.71 mm - 3036 pixels
    #    Diagonal size = 7.81 mm - 5040.82 pixels

    # Recommended recording  (1/2.3")  4000 x 3000 = 12.00MP (4:3 ratio)
    # Pixel size in micrometers
    PixelSize = 1.55  # square pixel (H = V)
    # Calculated sensor dimensions in milimeters
    SensorW = ImageW * PixelSize / 1000               # 4000 pixels
    SensorH = ImageH * PixelSize / 1000               # 3000 pixels
    SensorD = math.sqrt(SensorW ** 2 + SensorH ** 2)  # 5000 pixels

    # Calculate average GSD (cm/pix)
    avgGSD = (SensorW * FlightHeight * 100) / (FocalLength * ImageW)

    # Calculate average GSD (from focal lenght in pixels after sensor calib)
    avgGSD2 = FlightHeight * 100 / FocalPix

    # Calculate footprint width and height
    FootprintW = (ImageW * avgGSD) / 100
    FootprintH = (ImageH * avgGSD) / 100

    print(55 * "-")
    print("                     GSD Report")
    print(55 * "-")
    print("Sensor Dimensions (mm): {} x {}, {}". format(SensorW, SensorH, SensorD))
    print("Focal Length (mm): {}". format(FocalLength))
    print("Focal Length - adjusted (pix): {:.2f}". format(FocalPix))
    print("Average Camera Altitude (m): {:.2f}". format(CamAlt))
    print("Average Ground Altitude (m): {:.2f}". format(GroundAlt))
    print("Average Flight Height (m): {:.2f}". format(FlightHeight))
    print("Image Dimensions (pix): {:.0f}x{:.0f}". format(ImageW, ImageH))
    print("Ground Sampling Distance (cm/pix): {:.2f}". format(avgGSD))
    print("Ground Sampling Distance - adjusted (cm/pix): {:.2f}". format(avgGSD2))
    print("Footprint (m): {:.2f}x{:.2f}". format(FootprintW, FootprintH))
    print(55 * "-")


From above script the calculated GSD is different from what shows in PDF report. Calculated GSD is a higher value. I guess it is because my average flight height (depending on average cameras and points altitudes -- coordinates z) is greater than what it actually is. Any insight on calculating GSD?

Python and Java API / Re: Reprojection error
« on: March 10, 2019, 02:25:08 PM »
Thank you for the reply rongilad!

You script works perfectly for pixel values for RMSE and Max reprojection errors, despite the max value is a bit off by 0.03 as shown on the "show info...". You should use math.sqrt(max(error)), then the values are exactly the same.

But I'm trying to get the non pixel values for the reprojection errors.

Python and Java API / Reprojection error
« on: March 10, 2019, 01:46:14 PM »

I got the following code to calculate max and rms reprojection errors:

Code: [Select]

def RMS_MAX_reprojection_error(chunk):

    cameras = chunk.cameras
    point_cloud = chunk.point_cloud
    points = point_cloud.points
    projections_per_camera = point_cloud.projections
    tracks = point_cloud.tracks

    point_squared_errors = [[] for i in range(len(points))]
    point_key_point_size = [[] for i in range(len(points))]
    track_cameras = [[] for i in range(len(tracks))]
    track_projections = [[] for i in range(len(tracks))]

    for camera_id, camera in enumerate(cameras):
        if camera not in projections_per_camera:

        projections = projections_per_camera[camera]

        for projection_id, projection in enumerate(projections):

            track_id = projection.track_id

    for i, point in enumerate(points):
        if point.valid is False:  # se válido faz a estatística abaixo

        track_id = point.track_id

        for idx in range(len(track_cameras[track_id])):
            camera_id = track_cameras[track_id][idx]
            projection_id = track_projections[track_id][idx]
            camera = cameras[camera_id]
            projections = projections_per_camera[camera]
            projection = projections[projection_id]
            key_point_size = projection.size
            error = camera.error(point.coord, projection.coord) / key_point_size
            point_squared_errors[i].append(error.norm() ** 2)

    total_squared_error = sum([sum(el) for el in point_squared_errors])
    # nº projeções
    total_errors = sum([len(el) for el in point_squared_errors])
    max_squared_error = max([max(el+[0])
                            for i, el in enumerate(point_squared_errors)])

    rms_reprojection_error = math.sqrt(total_squared_error/total_errors)
    max_reprojection_error = math.sqrt(max_squared_error)

    return rms_reprojection_error, \

Sometimes it doesn't work at all at getting the values and sometimes it does. I haven't manage to figure out why. Can anyone help out?

Python and Java API / Re: Markers XML to Text File
« on: February 14, 2019, 06:26:41 PM »
Hello Alexey,

It works! Thank you very much!

Hello Luiz,

You can try to use this script sample:

Code: [Select]
file = open(path, "wt")
chunk =
photos_total = len(chunk.cameras) #number of photos in chunk
markers_total = len(chunk.markers) #number of markers in chunk

if (markers_total):
file.write(chunk.label + "\n")

for i in range (0, markers_total):    #processing every marker in chunk
cur_marker = chunk.markers[i]
cur_projections = cur_marker.projections   #list of marker projections
marker_name = cur_marker.label

for camera in cur_marker.projections.keys(): #
#for j in range (0, len(photos_list)): #processing every projection of the current marker
x, y = cur_projections[camera].coord #x and y coordinates of the current projection in pixels
label = camera.label

file.write(marker_name + "," + label + "," + "{:.4f}".format(x) + "," + "{:.4f}".format(y) + "\n")  #writing output


Python and Java API / Markers XML to Text File
« on: February 14, 2019, 06:08:40 AM »

Is there any script to export MetaShape XML markers into text file with marker labels, photo labels and 2D coordinates from markers projections in the photos? Output something like:

#marker_label  #photo_label  #img_x  # img_y

I've run into lots of exemples of the opposite procedure...
Thanks in advance!

Thank you Alexey!

Hello Luiz,

Please check:
Code: [Select]

Pages: [1] 2 3 ... 5