File size: 4,535 Bytes
5a827da
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fb4ab4b
5a827da
 
 
 
 
 
 
 
 
 
 
fb4ab4b
5a827da
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fb4ab4b
 
 
5a827da
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fb4ab4b
 
 
 
5a827da
 
 
 
fb4ab4b
 
 
 
 
 
 
 
 
5a827da
 
 
 
fb4ab4b
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import gradio as gr
import open3d as o3d
import numpy as np
import pandas as pd
from PIL import Image
from gradio.components import File, Slider, Image, Dataframe, Model3D
import tempfile

def point_cloud_to_image(point_cloud):
    # Create Open3D visualization object
    vis = o3d.visualization.Visualizer()
    vis.create_window()
    vis.add_geometry(point_cloud)

    # Render the visualization and get the image
    vis.poll_events()
    vis.update_renderer()
    img = vis.capture_screen_float_buffer()

    # Convert image to PIL Image format
    pil_img = Image.fromarray(np.uint8(np.asarray(img)*255))

    return pil_img

def create_file_mesh_from_pcd(pcd, alpha): 
    
    temp_file = tempfile.NamedTemporaryFile(suffix=".obj", delete=False)
    file_path = temp_file.name
    temp_file.close()
    
    # print(f"alpha={alpha:.3f}")
    mesh = o3d.geometry.TriangleMesh.create_from_point_cloud_alpha_shape(pcd, alpha)
    mesh.compute_vertex_normals()
    o3d.io.write_triangle_mesh(file_path, mesh, write_triangle_uvs=True)
    return file_path

def plane_detection(pointcloud_path, voxel_size=0.05, distance_threshold=0.01, num_iterations=1000, alpha=2):
    # Load point cloud from file
    pcd = o3d.io.read_point_cloud(pointcloud_path.name)

    # Downsample the point cloud to reduce computational load
    pcd = pcd.voxel_down_sample(voxel_size=voxel_size)

    # Find plane using RANSAC algorithm
    plane_model, inliers = pcd.segment_plane(distance_threshold=distance_threshold,
                                             ransac_n=3,
                                             num_iterations=num_iterations)

    # Get inlier and outlier point cloud
    inlier_cloud = pcd.select_by_index(inliers)
    outlier_cloud = pcd.select_by_index(inliers, invert=True)
    # extract the coefficients of the plane
    a, b, c, d = plane_model
    plane_model = np.array([[a], [b], [c], [d]])
    df = pd.DataFrame(plane_model.reshape(1, 4), columns=["a", "b", "c", "d"])
    input_path = create_file_mesh_from_pcd(pcd, alpha)
    inlier_path = create_file_mesh_from_pcd(inlier_cloud, alpha)
    outlier_path = create_file_mesh_from_pcd(outlier_cloud, alpha)
    # Return inlier point cloud, outlier point cloud, and plane model
    # return point_cloud_to_image(inlier_cloud), point_cloud_to_image(outlier_cloud), df
    return input_path, inlier_path, outlier_path, df

outputs = [
    # show pcd inlier point cloud
    Model3D(label="Input Cloud", clear_color=[1.0, 1.0, 1.0, 1.0]),
    # show pcd inlier point cloud
    Model3D(label="Inlier Cloud", clear_color=[1.0, 1.0, 1.0, 1.0]),
    # show pcd outlier point cloud
    Model3D(label="Outlier Cloud", clear_color=[1.0, 1.0, 1.0, 1.0]),
    # show the centroids and counts, which is a numpy array
    Dataframe(label="Coefficients of the plane model", type="pandas")
]

# Create Gradio interface
iface = gr.Interface(plane_detection, 
                     inputs=[
                         File(label="Point cloud file (.ply or .pcd format)"),
                         Slider(label="Voxel size", minimum=0.001, maximum=50, step=1, value=2),
                         Slider(label="Distance threshold", minimum=0.001, maximum=50, step=0.01, value=5),
                         Slider(label="Number of iterations", minimum=1, maximum=10000, step=1, value=100),
                         Slider(label="Alpha for surface reconstruction", minimum=0.02, maximum=100, step=0.01, value=2),
                     ],
                     outputs=outputs,
                     title="Plane Detection using RANSAC",
                     description="This app takes as input a point cloud file (.ply or .pcd format), voxel size, distance threshold, and number of iterations, finds a plane using RANSAC algorithm, displays the inlier and outlier point clouds, and returns the inlier point cloud, outlier point cloud, and the plane model.",
                     allow_flagging="never",
                     examples=[
                        # ["Pointclouds/p1.ply", 2, 5, 100, 2]
                        ["Pointclouds/cloud_bin_0.ply", 0.001, 0.03, 100, 0.05],
                        ["Pointclouds/cloud_bin_20.ply", 0.001, 0.03, 100, 0.05],
                        ["Pointclouds/cloud_bin_30.ply", 0.001, 0.03, 100, 0.05],
                        ["Pointclouds/cloud_bin_40.ply", 0.001, 0.03, 100, 0.05],
                        ["Pointclouds/cloud_bin_50.ply", 0.001, 0.03, 100, 0.05],
                        ],
                     )


# Launch the interface
iface.launch()