pythonprogress-barvtktqdm

How to Integrate a VTK Progress Observer with tqdm for Real-Time Progress Visualization?


I am using Python and would like to follow the progress of a vtk function as it proceeds, perhaps through the tqdm package. I have heard about progress observers (or, well, spotted from the inheritance graph of the vtk filter) in vtk but have never used them before. Can someone provide a detailed example showing how to integrate a vtk progress observer with tqdm?


Solution

  • To track the progress of a vtk function in Python using the tqdm package, you can use VTK's AddObserver method with a custom progress observer. Let's create a minimal custom progress observer.

    import vtk
    import numpy as np
    from vtk.util import numpy_support
    import tqdm
    
    # Define a class to handle progress updates
    class vtkProgressObserver:
        def __init__(self, description="Processing"):
            self.progress = 0
            self.pbar = tqdm.tqdm(total=100, desc=description)
    
        def execute(self, caller, event):
            # Get the progress from the VTK object and update the progress bar
            progress = int(caller.GetProgress() * 100)
            if progress > self.progress:
                self.pbar.update(progress - self.progress)
                self.progress = progress
    
        def close(self):
            self.pbar.close()
    

    As you see, this class initializes a tqdm progress bar and updates it based on progress events emitted by the VTK object. Speecifically, the VTK object will call the execute function and provide the arguments. The meaning of the execute method is to retrieve the current progress using caller.GetProgress() and updates the bar incrementally.

    Let's now tell the VTK object to use this class as observer:

    #Main function to demonstrate progress tracking
    def main():
        # Create a synthetic 3D volume
        shape = (200, 200, 200)
        volume_data = np.random.random(shape).astype(np.float32)
        vtk_array = numpy_support.numpy_to_vtk(volume_data.ravel(), deep=True, array_type=vtk.VTK_FLOAT)
    
        # Convert numpy array to vtkImageData
        image_data = vtk.vtkImageData()
        image_data.SetDimensions(shape)
        image_data.GetPointData().SetScalars(vtk_array)
    
        # Apply a Gaussian smoothing filter
        gaussian_filter = vtk.vtkImageGaussianSmooth()
        gaussian_filter.SetInputData(image_data)
        gaussian_filter.SetRadiusFactors(5.0, 5.0, 5.0)
    
        # Attach the progress observer (!!!)
        progress_observer = vtkProgressObserver(description="Smoothing Volume")
        gaussian_filter.AddObserver("ProgressEvent", progress_observer.execute)
    
        # Execute the filter
        gaussian_filter.Update()
        progress_observer.close()
    
        print("Smoothing complete!")
    
    if __name__ == "__main__":
        main()