Skip to content

ExtractClusters

Repository source: ExtractClusters

Description

This example extracts clusters of points. The points lie on spheres that are randomly placed. Each cluster has a different color. The number of extracted clusters may be less that the number of random spheres, if the points on one sphere are within the specified distance of points on another sphere.

Other languages

See (Cxx)

Question

If you have a question about this example, please use the VTK Discourse Forum

Code

ExtractClusters.py

#!/usr/bin/env python3

from pathlib import Path

# noinspection PyUnresolvedReferences
import vtkmodules.vtkInteractionStyle
# noinspection PyUnresolvedReferences
import vtkmodules.vtkRenderingOpenGL2
# noinspection PyUnresolvedReferences
import vtkmodules.vtkRenderingVolumeOpenGL2
from vtkmodules.vtkCommonColor import vtkNamedColors
from vtkmodules.vtkCommonCore import vtkLookupTable, vtkMinimalStandardRandomSequence
from vtkmodules.vtkFiltersCore import vtkAppendPolyData, vtkGlyph3D
from vtkmodules.vtkFiltersPoints import vtkDensifyPointCloudFilter, vtkEuclideanClusterExtraction
from vtkmodules.vtkFiltersSources import vtkSphereSource, vtkPointSource
from vtkmodules.vtkIOGeometry import (
    vtkBYUReader,
    vtkOBJReader,
    vtkSTLReader
)
from vtkmodules.vtkIOLegacy import vtkPolyDataReader
from vtkmodules.vtkIOPLY import vtkPLYReader
from vtkmodules.vtkIOXML import vtkXMLPolyDataReader
from vtkmodules.vtkRenderingCore import (
    vtkActor,
    vtkGlyph3DMapper,
    vtkRenderer,
    vtkRenderWindow,
    vtkRenderWindowInteractor, vtkPolyDataMapper
)


def main():
    colors = vtkNamedColors()

    randomSequence = vtkMinimalStandardRandomSequence(seed=4355412)
    # randomSequence.SetSeed(8775070)

    limits = 10
    radius = 0.5

    append = vtkAppendPolyData()
    for i in range(0, 30):
        points = vtkPointSource()

        points.SetNumberOfPoints(800)
        points.SetRadius(2.5 * radius)
        # A random position.
        x = randomSequence.GetRangeValue(-limits, limits)
        randomSequence.Next()
        y = randomSequence.GetRangeValue(-limits, limits)
        randomSequence.Next()
        z = randomSequence.GetRangeValue(-limits, limits)
        randomSequence.Next()
        points.center = (x, y, z)
        points.SetDistributionToShell()

        append.AddInputConnection(points.GetOutputPort())

    cluster = vtkEuclideanClusterExtraction(radius=radius, color_clusters=True)
    append >> cluster
    # cluster.SetInputConnection(append.GetOutputPort())
    cluster.SetExtractionModeToAllClusters()
    # cluster.SetRadius(radius)
    # cluster.ColorClustersOn()
    cluster.update()

    print(f'Found {cluster.number_of_extracted_clusters} clusters within radius {radius}')

    # Create a lookup table to map point data to colors.
    lut = vtkLookupTable()
    tableSize = cluster.number_of_extracted_clusters
    lut.SetNumberOfTableValues(tableSize)
    lut.Build()

    # Fill in the lookup table.
    for i in range(0, tableSize):
        r = randomSequence.GetRangeValue(0.25, 1.0)
        randomSequence.Next()
        g = randomSequence.GetRangeValue(0.25, 1.0)
        randomSequence.Next()
        b = randomSequence.GetRangeValue(0.25, 1.0)
        randomSequence.Next()
        lut.SetTableValue(i, r, g, b, 1.0)

    sphere = vtkSphereSource(radius=radius / 2.0)
    # sphere.SetRadius(radius / 2.0)

    glyphs = vtkGlyph3D(input_connection=cluster.output_port, source_connection=sphere.output_port, scaling=False)
    # glyphs.SetInputConnection(cluster.GetOutputPort())
    # glyphs.SetSourceConnection(sphere.GetOutputPort())
    # glyphs.ScalingOff()
    glyphs.Update()

    mapper = vtkPolyDataMapper(scalar_range=(0, tableSize - 1), lookup_table=lut)
    glyphs >> mapper

    actor = vtkActor(mapper=mapper)

    # Create the graphics stuff.
    ren1 = vtkRenderer(background=colors.GetColor3d('SlateGray'))
    renWin = vtkRenderWindow(size=(640, 512), window_name='ExtractClusters')
    renWin.AddRenderer(ren1)

    iren = vtkRenderWindowInteractor()
    iren.render_window = renWin

    # Add the actors to the renderer.
    ren1.AddActor(actor)

    # Generate an interesting view.
    ren1.ResetCamera()
    ren1.active_camera.Azimuth(120)
    ren1.active_camera.Elevation(30)
    ren1.active_camera.Dolly(1.5)
    ren1.ResetCameraClippingRange()

    renWin.Render()
    iren.Initialize()
    iren.Start()


if __name__ == '__main__':
    main()