Skip to content

PointCloudCompensating

Compensate for the point cloud drift caused by changes of camera or ambient temperature.

# Copyright (c) RVBUST, Inc - All rights reserved.
import PyRVC as RVC
import os
import numpy as np
import cv2


class CameraHelper:
    x2 = RVC.X2()
    x2_opts = None

    def __init__(self):
        RVC.SystemInit()

    def __del__(self):
        if self.x2.IsOpen():
            self.x2.Close()
        if self.x2.IsValid():
            RVC.X2.Destroy(self.x2)
        RVC.SystemShutdown()

    def Open(self):
        # List Devices
        opt = RVC.SystemListDeviceTypeEnum.All
        ret, devices = RVC.SystemListDevices(opt)
        if len(devices) == 0:
            print("Can not find any RVC X Camera!")
            return False

        # Create and open camera
        self.x2 = RVC.X2.Create(devices[0])
        if self.x2.IsValid() == False:
            print("RVC X Camera is not valid!")
            return False
        ret = self.x2.Open()
        if ret and self.x2.IsOpen() == True:
            print("RVC X Camera is opened!")
        else:
            print("RVC X Camera is not opened!")
            return False        
        # Load capture options
        ret, self.x2_opts = self.x2.LoadCaptureOptionParameters()
        # Set the coordinate system to the camera coordinate system
        self.x2_opts.transform_to_camera = RVC.CameraID_Left
        custom_transform_opt = RVC.X2_CustomTransformOptions()
        custom_transform_opt.coordinate_select = RVC.X2CustomTransformCoordinate.CoordinateSelect_Disabled
        ret = self.x2.SetCustomTransformation(custom_transform_opt)        
        return ret

    def Capture(self):
        is_capture_success = self.x2.Capture(self.x2_opts)
        if not is_capture_success:
            return RVC.PointMap(), RVC.Image()
        return self.x2.GetPointMap(), self.x2.GetImage(RVC.CameraID_Left)

def CompensateForX2():
    camera_helper = CameraHelper()
    is_open_success = camera_helper.Open()
    if not is_open_success:
        print("RVC X Camera fails to open!")
        return -1

    compensator = RVC.Compensator_FixedMarkers()

    # Capture a reference point map in static scene and initialize compensator.
    pm, image = camera_helper.Capture()
    ret = compensator.Initialize(pm, image, 0) # 0 for calibration board, 1 for concentric circles
    if ret != 0:
        print(f"Initialize fails! Error code: {ret}.")
        return -1
    print("Initialize successfully!")

    save_address = "Data"
    os.makedirs(save_address, exist_ok=True)
    # It is recommended to update the model within every 50 captures.
    # The value 50 is not fixed and needs to take into account the speed of the ambient temperature change and the camera shooting rhythm.
    # In this sample program, there are only 10 frames in between as a demonstration.
    interval_between_compensation = 10  # 100
    pm, image = camera_helper.Capture()
    pm.SaveWithImage(f"{save_address}/pointcloud_0.ply", image, RVC.PointMapUnitEnum.Meter, True)
    image.SaveImage(save_address + "/image_0.png")
    for _ in range(interval_between_compensation):
        camera_helper.Capture()

    # Capture the fixed markers and update compensation model.
    pm, image = camera_helper.Capture()
    ret, drift_distance = compensator.Update(pm, image)
    if ret != 0:
        print(f"Update compensation model fails! Error code: {ret}.")
        return -1
    print(f"Current drift distance: {drift_distance}")
    print("Update compensation model successfully!")

    # After update compensation model, we can compensate for the point cloud.
    pm, image = camera_helper.Capture()
    pm.SaveWithImage(f"{save_address}/pointcloud_n_before_compensate.ply", image, RVC.PointMapUnitEnum.Meter, True)
    image.SaveImage(save_address + "/image_n.png")
    ret, pm = compensator.Apply(pm)
    pm.SaveWithImage(f"{save_address}/pointcloud_n_after_compensate.ply", image, RVC.PointMapUnitEnum.Meter, True)
    print("Compensate pm successfully!")

    return 0


if __name__ == "__main__":
    """
    Use case: Compensate for the point cloud drift caused by changes of camera or ambient temperature

    Process: 
    1. Capture the fixed markers to initialize; 
    2. Use the camera normally and take n frames;
    3. Keep the camera in the same position as it was initialized and capture the same fixed markers to update the model; 
    4. Continue to use the camera to take n frames, and for each frame we can apply the updated model to compensate;
    5. Repeat the process of 3 and 4.
    It is recommended that n should be within 50. And the initialization step is recommended to be done after hand-eye calibration.
    """
    CompensateForX2()