Agisoft Metashape

Agisoft Metashape => Python and Java API => Topic started by: LFSantosgeo on December 11, 2017, 03:46:28 PM

Title: Creating and Managing Multiple Chunks
Post by: LFSantosgeo on December 11, 2017, 03:46:28 PM
Hello!

I'm finding difficulty to add a large number of chunks in loop.
 
Code: [Select]
    from_range = 1000
    to_range = 351000
    interval = 1000

    list_labels = list(range(from_range, to_range, interval))
    lenght = len(list_labels)
    print("Will be created {} chunks for this process".format(lenght))

    chunk = PS.app.document.chunks
    for chunk in range(lenght):
        doc.addChunk()
 
UPDATED: managed to create multiple chunks...
Title: Re: Creating and Managing Multiple Chunks
Post by: LFSantosgeo on December 11, 2017, 05:42:06 PM
Now I'm getting trouble with assigning each chunk a new label based on a list:
Code: [Select]
    for chunk in doc.chunks:
        for values in range(len(list_labels)):
            for label in chunk.label:
                labels = "Chunk: " + str(int(values / 1000)) + " / 0"
            chunk.label = labels
Any help would be appreciated!
Title: Re: Creating and Managing Multiple Chunks
Post by: Alexey Pasumansky on December 11, 2017, 06:20:38 PM
Hello lfsantosgeo,

What is in the list_labels?
Title: Re: Creating and Managing Multiple Chunks
Post by: Alexey Pasumansky on December 11, 2017, 06:43:30 PM
Maybe you need to try that:

doc = PhotoScan.app.document
Code: [Select]
for i in range(len(doc.chunks)):
    doc.chunks[i].label =  "Chunk: " + str(int(list_labels[i]/1000)) + " / 0"
Title: Re: Creating and Managing Multiple Chunks
Post by: LFSantosgeo on December 12, 2017, 02:21:14 PM
doc = PhotoScan.app.document
for i in range(len(doc.chunks)):
    doc.chunks.label =  "Chunk: " + str(int(list_labels/1000)) + " / 0"

The code gives this error: "Error: 'list' object has no attribute 'label'"

Title: Re: Creating and Managing Multiple Chunks
Post by: Alexey Pasumansky on December 12, 2017, 04:29:58 PM
Hello lfsantosgeo,

Should be
Code: [Select]
doc.chunks[i].label
Title: Re: Creating and Managing Multiple Chunks
Post by: LFSantosgeo on December 12, 2017, 06:22:04 PM
Thank you, Alexey! That works now!

And that's my code:

Code: [Select]
    try:
        nchunks = (len(doc.chunks))  # returns number of chunks
        range_chunks = range(0, nchunks)  # gives range of a number of chunks
        for i in range_chunks:  # adding the labels to each chunk
            lbl_formatting = "Chunk: {} / 0".format(int(list_labels[i] / 1000))
            doc.chunks[i].label = lbl_formatting
        print("Chunk labels modified!")
    except Exception as exc2:
        print("Error:{}".format(exc2))

UPDATE: added the code for labeling every chunk in workspace based on a list
Title: Re: Creating and Managing Multiple Chunks
Post by: LFSantosgeo on December 18, 2017, 04:31:09 PM
Based on the information collected in another forum post by Alexey for the Exif tags: (sorry didn't get the address)
Quote
PhotoScan reads the following EXIF tags:
FocalLength - that is put to the corresponding field of the Camera Calibration window. Whereas for the Sensor Pixel Size uses either a pair of the following tags:
FocalPlaneXResolution and FocalPlaneYResolution, or if they are missing, uses the next one: FocalLengthIn35mmFilm.
The parameters mentioned above are used to define the initial values for the autocalibration procedure.

Also GPS tags are read:
GPSAltitude, GPSLatitude and GPSLongitude.

Made the following code to implement preselection based on photo's Exif information existence. And the from the PhotoScan 1.3 manual:

Quote
Pair preselection
The alignment process of large photo sets can take a long time.
A significant portion of this time period is spent on matching of detected features across the photos. Image pair preselection option may speed up this process due to selection of a subset of image pairs to be matched.

--> In the Generic preselection mode the overlapping pairs of photos are selected by matching photos using lower accuracy setting first.

--> In the Reference preselection mode the overlapping pairs of photos are selected based on the measured camera locations (if present).
[...]


Code: [Select]
    # check if images in every chunk added have Exif reference to use
    # Reference Preselection as a plus to optimize image alignment
    for i in range_chunks:
        camera = chunk.cameras[i]
        if camera.photo.meta["Exif/GPSLatitude"]:  # check for Lat info on Exif
            # generic preselection [True, False]
            gnr_pslc = True
            # reference prelection [True, False]
            ref_pslc = True
        else:  # if there's no exif information then use No Preselection enabled
            gnr_pslc = False
            ref_pslc = False

The code was based on a test that's shown bellow for the best performance regarding time and errors.
Title: Re: Creating and Managing Multiple Chunks
Post by: LFSantosgeo on December 18, 2017, 07:44:54 PM
I made some tests using geotagged photos (from the drone's onboard GPS system) regarding preselection.

With these parameters:
High Accuracy (keeps 100% of each image, not upscales or dowscales)
Total cameras (photos): 155 geotagged
Key points = 10,000 (not that much to optimize time in the processing)
Tie points = 0

-----------------------------------------------------
No preselection
-----------------------------------------------------
148 aligned cameras of 155
Points 50,476 of 55,628

RMS reprojection error: 0.115293 (0.602434 pix)
Max reprojection error: 0.348031 (19.6074 pix)
Mean key point size: 4.19666 pix

Effective overlap 2.58956

Match time: 00:23:56
Align time: 00:01:46
Total time: 00:25:42 -- compatible time with the Reference preselection only

-----------------------------------------------------
Generic preselection only
-----------------------------------------------------
148 of 155 aligned cameras
Points 50,780 of a total of 54,274 possible

RMS reprojection error: 0.115442 (0.60689 pix)
Max reprojection error: 0.348413 (19.5868 pix)
Mean key point size: 4.19952 pix

Effective overlap: 2.59327

Matching time: 00:37:49
Alignment time: 00:01:49
Total time: 00:39:38

-----------------------------------------------------
Reference preselection only
-----------------------------------------------------
148 of 155 aligned
Points 50,670 of 54,789

RMS reprojection error: 0.115329 (0.610028 pix)
Max reprojection error: 0.348384 (20.2262 pix)
Mean key point size: 4.19839 pix

Effective overlap: 2.59209

Matching time: 00:23:48
Alignment time: 00:01:49
Total time: 00:25:37

-----------------------------------------------------
Generic + Reference both selected!
-----------------------------------------------------
148 of 155 aligned
Points 50,790 of 54,269

RMS reprojection error: 0.115142 (0.605183 pix)
Max reprojection error: 0.347645 (19.5746 pix)
Mean key point size: 4.19816 pix

Effective overlap: 2.59146

Matching time: 00:18:39
Alignment time: 00:02:07
Total time: 00:20:46

That justifies the code to use generic + reference if there's geotagged photos. And if not, no preselection.
Title: Re: Creating and Managing Multiple Chunks
Post by: LFSantosgeo on December 18, 2017, 11:22:08 PM
Now I'm stuck with exporting the Show Info for every chunk on a single txt file:

Code: [Select]
    # path to write file
    path_report = path_export
    path_report += "\Showinfo_chunks_{}.txt".format(prjrun)
    print("\nCreating export file and analyzing chunks...\n")
    # open file
    try:
        # getting chunk labels
        lis_label = []
        for i in range_chunks:
            lis_label.append(doc.chunks[i].label)
        print(lis_label)

        # returning aligned cameras for each chunk
        list_align = []
        for i in range_chunks:
            chunk = doc.chunks[i]
            for cameras in chunk.cameras:
                if camera.transform:
                    align_cams = len(chunk.cameras)
            list_align.append(align_cams)

        # returning total cameras for each chunk
        list_cams = []
        for i in range_chunks:
            chunk = doc.chunks[i]
            cam_total = len(chunk.cameras)
            list_cams.append(cam_total)

        # alignment time for each chunk
        list_align_dur = []
        for i in range_chunks:
            chunk = doc.chunks[i]
            align_dur = chunk.point_cloud.meta["align/duration"]
            list_align_dur.append(align_dur)

        # matching time for each chunk
        list_match_dur = []
        for i in range_chunks:
            chunk = doc.chunks[i]
            match_dur = chunk.point_cloud.meta["match/duration"]
            list_match_dur.append(match_dur)

        # list comprehension to avoid None values (substitutes for 0)
        # and to convert its strings into float to sum values
        align_time = [0 if i is None else i for i in list_align_dur]
        align_time = [float(i) for i in align_time]  # converting to float
        match_time = [0 if i is None else i for i in list_match_dur]
        match_time = [float(i) for i in match_time]  # convert to float

        # sum lists to get total time for each chunk
        total_time = [sum(i) for i in zip(align_time, match_time)]

        # number of tie-points (sparse cloud) for each chunk
        list_sp_points = []
        for i in range_chunks:
            chunk = doc.chunks[i]
            point_cloud = chunk.point_cloud
            points = point_cloud.points
            sp_points = len(points)
            list_sp_points.append(sp_points)

    except Exception:
        print("Error: unable to get data from chunks!")
        raise

    try:
        with open(path_report, "wt", newline="") as showinfo:
            lists = [lis_label, list_align, list_cams, align_time,
                     match_time, total_time, list_sp_points]
            for i in zip(*lists):
                showinfo.write("\n{}\t{}\t{}\t{}\t{}\t{}\t{}\n\n".format(*i))
        print("Successfully generated and exported to TXT report!")
    except Exception:
        raise


UPDATE: managed to get:
- number of aligned cameras
- number of cameras
- alignment time
- matching time
- align + match = total time
- sparse cloud number of points


I'm still stuck with:
- RMS reprojection error
- Max reprojection error
- Mean key point size
- effective overlap
Title: Re: Creating and Managing Multiple Chunks
Post by: LFSantosgeo on December 20, 2017, 04:22:36 PM
For reprojection error, got the following code from: http://www.agisoft.com/forum/index.php?topic=5267.msg26153#msg26153
Code: [Select]
        # open empty lists to get exported when done
        list_npoints = []
        list_index = []
        list_x = []
        list_y = []
        list_z = []
        list_error = []


        for i in range_chunks:  # for every chunk in workspace
        # number of tie-points (sparse cloud) for each chunk
            chunk = doc.chunks[i]
            point_cloud = chunk.point_cloud
            points = point_cloud.points
            npoints = len(points)
            list_npoints.append(npoints)

        # Reprojection error
            M = chunk.transform.matrix
            crs = chunk.crs
            projections = point_cloud.projections
            tracks = point_cloud.tracks

            points_coords = {}
            points_errors = {}

            for photo in chunk.cameras:
                if not photo.transform:
                    continue

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

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

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

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

                list_index.append(point_index)

                for point_index in range(npoints):
                    if not points[point_index].valid:
                        continue

                    if chunk.crs:
                        w = M * points[point_index].coord
                        w.size = 3
                        X, Y, Z = chunk.crs.project(w)
                    else:
                        X, Y, Z, w = M * points[point_index].coord

            error = math.sqrt(points_errors[point_index].x / points_errors[point_index].y)

            list_x.append(X)
            list_y.append(Y)
            list_z.append(Z)
            list_error.append(error)


For chunk test gives error = 1.6664504017324355
And testing again, a different value = 1.2779145775553513
Actually, everytime I run the code I get a different value for the "error".

In the Show Info pane comes as RMS = 0.145085 (4.41861 pix) and Max = 0.437942 (54.9417 pix)

What is wrong? Or the code returns in different format?
Title: Re: Creating and Managing Multiple Chunks
Post by: LFSantosgeo on January 13, 2018, 06:25:01 AM
Any comments on the matter presented above? ?
Title: Re: Creating and Managing Multiple Chunks
Post by: LFSantosgeo on February 02, 2018, 01:14:55 PM
When importing markers XML file into PhotoScan I get this error:

Error: Missing sensor id

Have I lost the file and have to start over?
Title: Re: Creating and Managing Multiple Chunks
Post by: Alexey Pasumansky on February 02, 2018, 02:36:19 PM
Hello lfsantosgeo,

Was the XML exported from the same PhotoScan version? Which version (including the build number) you are currently using?
Title: Re: Creating and Managing Multiple Chunks
Post by: LFSantosgeo on February 02, 2018, 03:13:35 PM
Hello Alexey!

It was created with version 1.3.2 and now I'm using 1.4.0 b5076.x64.
Title: Re: Creating and Managing Multiple Chunks
Post by: Alexey Pasumansky on February 02, 2018, 03:24:57 PM
Hello lfsantosgeo,

That might be the reason of the problem. As a workaround, you can import the XML to the 1.3.x version project, then open it in the version 1.4 and export XML in new format.
Title: Re: Creating and Managing Multiple Chunks
Post by: Alexey Pasumansky on February 02, 2018, 03:25:59 PM
And as for the previous comments on the reprojection error calculation, are you still observing the difference between GUI output and script?
Title: Re: Creating and Managing Multiple Chunks
Post by: LFSantosgeo on February 02, 2018, 04:23:08 PM
That might be the reason of the problem. As a workaround, you can import the XML to the 1.3.x version project, then open it in the version 1.4 and export XML in new format.

As always, thank you for the reply Alexey!
I've opened a saved project in 1.3x on the 1.4 version and exported markers through the File > Export > Export Markers...

And then I tested it on a new project: added photos, converted to markers coordinate system and then went to import File > Import > Import Markers...
It opened all of the markers! Great! But there are some problems... The error (m), error (pix) and projections are quite different from what's is shown in the previous version of PS (1.3.x). Look at the attached image!


 
Title: Re: Creating and Managing Multiple Chunks
Post by: Alexey Pasumansky on February 02, 2018, 05:55:08 PM
Hello lfsantosgeo,

The number in the Projections column in the Reference pane shows the number of projections on the aligned photos. According to the screenshot is seems that all nine photos are not aligned.
Title: Re: Creating and Managing Multiple Chunks
Post by: LFSantosgeo on February 02, 2018, 06:39:12 PM
The number in the Projections column in the Reference pane shows the number of projections on the aligned photos. According to the screenshot is seems that all nine photos are not aligned.

Alexey,

On the last screenshot, from my last post, I filtered the photos on Photos Pane to show only the ones related to the marker #113 (Filter photos by selection...). So in the Photos Pane it shows 9 photos aligned with its valid and pinned markers and projections from marker #113.

But in the Reference Pane the number of projections for marker #113 is 0 (despite having in the photos pane the 9 aligned with its projections). This happens not only for #113 but also for the rest of the markers.

This was aligned with 10,000 keypoints / 4,000 tie-point limite / lowest (just to go fast and see if the markers were correctly imported).


To be clear about it... I added another 2 screenshots comparing the project made with 1.3.2 and a new one:
1. the first shows the project that was saved on 1.3.2 which opened normally on 1.4. With the reference pane showing the errors, projections etc as it was saved last time. That was aligned with Highest / 80,000 keypoints / 8,000 tie-points.

2. the second shows a new project created, with the same photos, same steps (add chunk, add photos, convert coordinates, align photos, add markers -- exported from the opened 1.3.2 project). The alignment with HIghest / 40,000 / 4,000. The screenshot shows the difference in errors.

Considering that in the 1.3.2 PS version in different projects, with different alignment parameters when importing the markes XML all the results were the same! Always with the values of the 1. first screenshot.

Questions:
A) Are the differences caused by different alignment parameters?
B) Or are they caused by the XML format from 1.3.2 to 1.4.0?
C) Or are the differences caused by different PS versions?
D) Am I missing something?

Looking forward for the reply!

Title: Re: Creating and Managing Multiple Chunks
Post by: Alexey Pasumansky on February 02, 2018, 07:05:37 PM
Hello lfsantosgeo,

In this post - http://www.agisoft.com/forum/index.php?topic=8124.msg39960#msg39960 -  neither of the images containing the marker is aligned. But in your latest post I see that on both screenshots there are 9 projections for the marker, since all the corresponding images are aligned.

As for the difference in the errors, I think that the following situation is being observed:
- the images were aligned and optimized in the version 1.3.2, then marker projections have been exported to XML,
- when you import the XML back to the new project aligned with the different parameters - you load only the projections of the markers, not their 3D positions. The position of the marker in 3D is defined by it's projections on the images.
Also I see that in the second case the georeferencing is performed both on the cameras and markers, but it seems to give considerably smaller impact (due to the difference in the accuracy for cameras and markers) then the different alignment results.
Title: Re: Creating and Managing Multiple Chunks
Post by: LFSantosgeo on February 02, 2018, 08:08:04 PM
In this post - http://www.agisoft.com/forum/index.php?topic=8124.msg39960#msg39960 -  neither of the images containing the marker is aligned.

That's true! Just realized it now! Thanks for pointing it out.

But in your latest post I see that on both screenshots there are 9 projections for the marker, since all the corresponding images are aligned.

Cameras are aligned due to higher alignment parameters! That's why the projections are shown on the Reference Pane.

As for the difference in the errors, I think that the following situation is being observed:
- the images were aligned and optimized in the version 1.3.2, then marker projections have been exported to XML,

That's what I've done... Aligned (with a default set of parameters+ highest) and optimized

- when you import the XML back to the new project aligned with the different parameters - you load only the projections of the markers, not their 3D positions. The position of the marker in 3D is defined by it's projections on the images.

I did a step further. Maybe this is what I was missing... I optimized the cameras and the errors diminished significantly! Total error for all markes came down to 0.03m according to expectations. Nonetheless not exactly like it was before due to different alignment parameters set (?) even with the cameras unchecked.

Also I see that in the second case the georeferencing is performed both on the cameras and markers, but it seems to give considerably smaller impact (due to the difference in the accuracy for cameras and markers) then the different alignment results.
I know about the difference in accuracy for cameras and markers. I only highlighted on the second screenshot because it was, for both of cameras and markers, different from the first screenshot. Even the cameras errors were different from the original project.

I guess I was indeed missing a step after all. The optimize after uncheck the cameras and importing the markers.

By the way, talking about optimizing. I have this data set made with Phantom 4 that I'm aware that it has a rolling shutter effect becaused it has an electronic shutter. I was reading here (http://www.agisoft.com/forum/index.php?topic=7653.msg37151#msg37151) that it might have a huge effect. I wonder how to activate it through Python coding?

Code: [Select]
    chunk.optimizeCameras(fit_f=True, fit_cx=True, fit_cy=True,
                                                         fit_b1=True, fit_b2=True, fit_k1=True,
                                                         fit_k2=True, fit_k3=True, fit_k4=False,
                                                         fit_p1=True, fit_p2=True, fit_p3=False,
                                                         fit_p4=False)

I saw in the 1.4.0 API:
Quote
Sensor.rolling_shutter
Enable rolling shutter compensation.
Title: Re: Creating and Managing Multiple Chunks
Post by: Alexey Pasumansky on February 02, 2018, 09:08:23 PM
Hello Luiz,

When you are optimizing the alignment - the relative positions of the cameras are changed, so the same projections of the markers would result in different 3D point for the marker (estimated location), so the error value (source - estimated) would be also different.


In the version 1.4 you can enable the rolling shutter compensation before the optimization:
Code: [Select]
sensor.rolling_shutter = Truethen it will be estimated automatically during the optimization. In principle, the rolling shutter property can be modified before the initial alignment, then it will be taken into account during that stage.
Title: Re: Creating and Managing Multiple Chunks
Post by: LFSantosgeo on February 02, 2018, 10:29:32 PM
When you are optimizing the alignment - the relative positions of the cameras are changed, so the same projections of the markers would result in different 3D point for the marker (estimated location), so the error value (source - estimated) would be also different.

Ok! That justifies the marker's errors difference between the original and the new project.
Then would you recommend to import the markers anyway thus optimize or to start from ground zero and place them again hoping to achieve equivalent total error?

In the version 1.4 you can enable the rolling shutter compensation before the optimization:
Code: [Select]
sensor.rolling_shutter = Truethen it will be estimated automatically during the optimization. In principle, the rolling shutter property can be modified before the initial alignment, then it will be taken into account during that stage.

Title: Re: Creating and Managing Multiple Chunks
Post by: LFSantosgeo on February 06, 2018, 01:13:53 PM
Putting it to use... Before the alignment process.

Code: [Select]
    # enabling rolling shutter compensation
    try:
        for sensor in chunk.sensors:
            rolling_shutter = True
    except Exception as e:
        print("Error:", e)
        raise

    print("Rolling shutter compensation done!")
Title: Re: Creating and Managing Multiple Chunks
Post by: LFSantosgeo on February 15, 2018, 07:59:48 PM
And as for the previous comments on the reprojection error calculation, are you still observing the difference between GUI output and script?

Hello, Alexey;

I'm still observing differences between GUI and script.
Also when running the script several times I get different tie-points for the same group of photos and parameters.

See the attached image! I also attached the python code... Now when running it in PS the user view after running it shows the cameras completely messed up (as a globe).
Title: Re: Creating and Managing Multiple Chunks
Post by: LFSantosgeo on March 06, 2018, 04:56:03 PM
Just figure it out:

Code: [Select]
    # configuring the coodinate system for the project
    try:
        n_crs = PS.app.getCoordinateSystem("Select GCP Coordinate System...")
        print("GCP Coordinate System:\n{}".format(n_crs))
    except Exception:
        print("Error: unable to define GCP coordinate system")
        raise

    crs = chunk.crs  # chunk current coordinate system
    chunk = doc.chunk  # defining where the transform will happen


    # convert coordinate system for loaded images (cameras)
    for camera in chunk.cameras:
        csys = PS.CoordinateSystem
        camera.reference.location = csys.transform(camera.reference.location,
                                                   chunk.crs, n_crs)

    # convert coordinate system for chunk
    doc.chunk.crs = n_crs

    print("OLD COORDINATE SYSTEM:\n{}.".format(crs))
    print("\nNEW COORDINATE SYSTEM:\n{}\n".format(n_crs))

EDIT: code to fix the reference problem from previous post