Forum

Author Topic: Metashape 2.0 Laser Scan Referencing  (Read 7673 times)

mitchgalea

  • Newbie
  • *
  • Posts: 16
    • View Profile
Metashape 2.0 Laser Scan Referencing
« on: February 21, 2023, 02:32:49 AM »
Hello,

I am using Metashape 2.0 Terrestrial laser scans feature to align TLS scans captured with the Leica RTC360, with images captured from other sources. I have followed the procedure listed here https://agisoft.freshdesk.com/support/solutions/articles/31000168474-terrestrial-laser-scans-processing-in-metashape-2-0-0 . It works and I can align the TLS scans with the images. My issue though is the position of the laser scans after alignment is different, this makes sense because we reset alignment, but is there a way to add the reference information to the laser scans so that after alignment the laser scans keep the initial position. I have tried adding reference information to the laser scan images based on the initial position, but this doesn't do anything (seems that images attached to laser scans are ignored when it comes to reference).

Any help would be appreciated

mitchgalea

  • Newbie
  • *
  • Posts: 16
    • View Profile
Re: Metashape 2.0 Laser Scan Referencing
« Reply #1 on: February 21, 2023, 08:12:16 AM »
I figured out how to fix this. I had to compute the chunk transform that would ensure that the laser scans are in the correct position. To do this prior to alignment I duplicated the chunk, and then aligned the original chunk. From there I had to use the python console.

Code: [Select]
# gets chunks to use
non_aligned_chunk = Metashape.app.document.chunks[1]
aligned_chunk = Metashape.app.document.chunks[0]

# function to get camera based on label
def get_camera(chunk,label):
    for camera in chunk.cameras:
        if camera.label == label:
            return camera
    return None

# gets a spherical from a laser scan for both chunks
non_aligned_camera = get_camera(non_aligned_chunk, "Scan_001")
aligned_camera = get_camera(aligned_chunk, "Scan_001")

# non aligned camera is in the correct position so we work out chunk transform to equal non aligned camera position
aligned_chunk.transform.matrix = non_aligned_camera.transform * aligned_camera.transform.inv()

bassistas

  • Newbie
  • *
  • Posts: 42
    • View Profile
Re: Metashape 2.0 Laser Scan Referencing
« Reply #2 on: April 11, 2023, 07:16:59 AM »
I figured out how to fix this. I had to compute the chunk transform that would ensure that the laser scans are in the correct position. To do this prior to alignment I duplicated the chunk, and then aligned the original chunk. From there I had to use the python console.

Code: [Select]
# gets chunks to use
non_aligned_chunk = Metashape.app.document.chunks[1]
aligned_chunk = Metashape.app.document.chunks[0]

# function to get camera based on label
def get_camera(chunk,label):
    for camera in chunk.cameras:
        if camera.label == label:
            return camera
    return None

# gets a spherical from a laser scan for both chunks
non_aligned_camera = get_camera(non_aligned_chunk, "Scan_001")
aligned_camera = get_camera(aligned_chunk, "Scan_001")

# non aligned camera is in the correct position so we work out chunk transform to equal non aligned camera position
aligned_chunk.transform.matrix = non_aligned_camera.transform * aligned_camera.transform.inv()

Can you please give me some more details on how you managed to do this? I duplicated the chunk, I aligned them using markers and then I tried to run your script but I get this error: 'NoneType' object has no attribut 'transform'

mitchgalea

  • Newbie
  • *
  • Posts: 16
    • View Profile
Re: Metashape 2.0 Laser Scan Referencing
« Reply #3 on: May 07, 2023, 04:03:03 AM »
Hello,

Not too sure about the issue you are facing. It seems that the function get_camera is returning None for either non_aligned_camera or aligned_camera. Please ensure that the label is correct, ie in my example I was using "Scan_001", that is the name of the scan image.

Tas

  • Newbie
  • *
  • Posts: 49
    • View Profile
Re: Metashape 2.0 Laser Scan Referencing
« Reply #4 on: November 02, 2023, 05:58:46 PM »
I'm hoping to revive this thread, as I attempted to use the script but didn't do so successfully. It's also a topic that multiple folks are attempting to tackle (https://www.agisoft.com/forum/index.php?topic=15939.msg68793#msg68793).

I ran the script with a slightly different workflow and didn't get anticipated results. Is anyone willing to provide some insight into how I might be misusing or misinterpreting the Python code?
  • I imported laser scans and independent photos per the workflow documented here:  https://agisoft.freshdesk.com/support/solutions/articles/31000168474-terrestrial-laser-scans-processing-in-metashape-2-0-0#Processing-of-terrestrial-laser-scans-with-images
  • I discovered this thread after performing several other time-intensive tasks (point cloud generation, manual classification, meshing trials, etc.). Consequently, I tried duplicating the chunk, re-importing a laser scan in its original position, and applying a transform matrix post-alignment.
  • I'll give an example of one of the many trials I ran that correlates with the edited code below. Steps:  1) align laser scans and photos, 2) duplicate the chunk, 3) re-import a laser scan into the duplicate chunk and re-name it so there wasn't a duplicate "camera" name, 4) confirm that the re-imported laser scan loaded in the correct position by reviewing the associated estimated coordinates and rotation values in the Reference Pane, 5) run the script below in reference to the aligned chunk[0] / aligned laser scan and the duplicate chunk[5] / re-imported laser scan.

I won't confuse matters with the myriad of other solutions I attempted - any input is greatly appreciated!

Code: [Select]
# gets chunks to use
non_aligned_chunk = Metashape.app.document.chunks[0]
aligned_chunk = Metashape.app.document.chunks[5]

# function to get camera based on label
def get_camera(chunk,label):
    for camera in chunk.cameras:
        if camera.label == label:
            return camera
    return None

# gets a spherical from a laser scan for both chunks
non_aligned_camera = get_camera(non_aligned_chunk, "Ground-Ext-100")
aligned_camera = get_camera(aligned_chunk, "Ground-Ext-001")

# non aligned camera is in the correct position so we work out chunk transform to equal non aligned camera position
aligned_chunk.transform.matrix = non_aligned_camera.transform * aligned_camera.transform.inv()
« Last Edit: November 02, 2023, 06:18:55 PM by Tas »

bassistas

  • Newbie
  • *
  • Posts: 42
    • View Profile
Re: Metashape 2.0 Laser Scan Referencing
« Reply #5 on: November 03, 2023, 10:15:19 PM »
I'm hoping to revive this thread, as I attempted to use the script but didn't do so successfully. It's also a topic that multiple folks are attempting to tackle (https://www.agisoft.com/forum/index.php?topic=15939.msg68793#msg68793).

I ran the script with a slightly different workflow and didn't get anticipated results. Is anyone willing to provide some insight into how I might be misusing or misinterpreting the Python code?
  • I imported laser scans and independent photos per the workflow documented here:  https://agisoft.freshdesk.com/support/solutions/articles/31000168474-terrestrial-laser-scans-processing-in-metashape-2-0-0#Processing-of-terrestrial-laser-scans-with-images
  • I discovered this thread after performing several other time-intensive tasks (point cloud generation, manual classification, meshing trials, etc.). Consequently, I tried duplicating the chunk, re-importing a laser scan in its original position, and applying a transform matrix post-alignment.
  • I'll give an example of one of the many trials I ran that correlates with the edited code below. Steps:  1) align laser scans and photos, 2) duplicate the chunk, 3) re-import a laser scan into the duplicate chunk and re-name it so there wasn't a duplicate "camera" name, 4) confirm that the re-imported laser scan loaded in the correct position by reviewing the associated estimated coordinates and rotation values in the Reference Pane, 5) run the script below in reference to the aligned chunk[0] / aligned laser scan and the duplicate chunk[5] / re-imported laser scan.

I won't confuse matters with the myriad of other solutions I attempted - any input is greatly appreciated!

Code: [Select]
# gets chunks to use
non_aligned_chunk = Metashape.app.document.chunks[0]
aligned_chunk = Metashape.app.document.chunks[5]

# function to get camera based on label
def get_camera(chunk,label):
    for camera in chunk.cameras:
        if camera.label == label:
            return camera
    return None

# gets a spherical from a laser scan for both chunks
non_aligned_camera = get_camera(non_aligned_chunk, "Ground-Ext-100")
aligned_camera = get_camera(aligned_chunk, "Ground-Ext-001")

# non aligned camera is in the correct position so we work out chunk transform to equal non aligned camera position
aligned_chunk.transform.matrix = non_aligned_camera.transform * aligned_camera.transform.inv()

What works for me is something very simple, first I mark some of my targets on the laser scans right after I import them in metashape and then I duplicate the chunk to preserve the original orientation of the scans. When the alignment of photos and laser scans from the first chunk is finished I align the first chunk with the second (duplicated) using my previously placed targes (which are now present in both chunks) and using the second chunk as a reference.


Tas

  • Newbie
  • *
  • Posts: 49
    • View Profile
Re: Metashape 2.0 Laser Scan Referencing
« Reply #6 on: November 04, 2023, 01:00:52 AM »
Thanks for the reply, bassistas. For whatever reason, that workflow did not work for me. I can't explain why - there's something odd occurring with estimated position/rotation data being reset in the Reference pane GUI, but I've no idea if that's related.

However, I'm thrilled to say that I did find a solution that I could replicate - I simply had to Reset Transform for the chunk before running the script. I can't explain why that's the case at the moment (I didn't perform any transformation after chunk alignment).

If anyone else finds this useful, I've slightly modified the script for a workflow that doesn't require duplicating the chunk before alignment. I've also done my best to annotate the script with very basic explanations and instructions in hopes that it'll help anyone who comes across this.

Code: [Select]
#WORKFLOW INSTRUCTIONS (or at least this is what worked for me in Metashape v2.0)
# 1. Follow instructions to align terrestrial laser scans (TLS) and photos per
#    https://agisoft.freshdesk.com/support/solutions/articles/31000168474-terrestrial-laser-scans-processing-in-metashape-2-0-0#Processing-of-terrestrial-laser-scans-with-images
# 2. Choose an aligned laser scan to re-import into the chunk. Verify that it loads in its original position.
# 3. Rename the duplicate laser scan as "GeoRef_Scan" ...in the code below, this duplicate scan is referenced by the "GeoRef_camera" variable.
#    Right-click on the laser scan name in the Workspace pane and confirm that "Lock Transform" is checked in the laser scan contextual menu.
# 3A. In the code below, edit the "aligned_camera" variable definition as described in the in-line code explanation.
# 3B. In the code below, edit the chunk ID number as described in the in-line code explanation.
# 4. For good measure, save the file in case something goes wrong and you need to close & revert to the saved version.
# 5. Reset Transform (Model -> Transform Object -> Reset Transform).
#    Resetting the transform may clear all estimated coordinate/rotation values (viewed in the Reference pane when "view estimated" button is selected) -
# not sure why that happens in the GUI, but the values must still be stored.
# 6. Run this script (copy the script text into a .txt file and save it - in Metashape, use shortkey ctrl+r to bring up the script dialog).
#    Check that the chunk is transformed by comparing the estimated coordinate/rotation values in the
#    Reference Pane for the originally aligned laser scan and the duplicate laser scan.
#    Of course, the corresponding camera symbols and point clouds should also be perfectly aligned when viewed in model space.


#Defines chunk to reference.
#  The "[5]" is the chunk ID, which is determined by the list position of the chunk in the Workspace tab.
#  The chunk ID list starts at 0, not 1. I'm sure there's a way to make this more user-friendly (e.g., reference currently selected chunk), but that's for another day.
chunk = Metashape.app.document.chunks[0]  #Replace "0" if the chunk isn't listed first in Workspace tab.

#Defines a function to get camera (i.e., laser scan) based on label
def get_camera(chunk,label):
    for camera in chunk.cameras:
        if camera.label == label:
            return camera
    return None

#Defines variables to reference the original and duplicate laser scans
GeoRef_camera = get_camera(chunk, "GeoRef_Scan")
aligned_camera = get_camera(chunk, "Ground-Ext-001")  #Replace "Ground-Ext-001" with the name of the original, aligned laser scan

#Transform (i.e., shift & rotate) the chunk to align the original/aligned laser scan with the duplicate/untransformed laser scan.
#  Appending the ".transform" to the scan ID variables references a 4x4 matrix that defines the position and rotation of the laser scan.
#  So this code defines a chunk transform matrix by multiplying the matrix for the correct position by the inverse of the matrix for the transformed position that
#  resulted from the alignment process. Multiplying by the inverted matrix essentially negates the transformation.
#  For example, if you were to multiply a transform matrix by its own inverse, the result would be an identity matrix storing no position/rotation (i.e., correlating to the 0,0 origin)
chunk.transform.matrix = GeoRef_camera.transform * aligned_camera.transform.inv()
« Last Edit: March 24, 2024, 06:26:36 PM by Tas »