|
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): |
|
|
|
vis = o3d.visualization.Visualizer() |
|
vis.create_window() |
|
vis.add_geometry(point_cloud) |
|
|
|
|
|
vis.poll_events() |
|
vis.update_renderer() |
|
img = vis.capture_screen_float_buffer() |
|
|
|
|
|
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() |
|
|
|
|
|
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): |
|
|
|
pcd = o3d.io.read_point_cloud(pointcloud_path.name) |
|
|
|
|
|
pcd = pcd.voxel_down_sample(voxel_size=voxel_size) |
|
|
|
|
|
plane_model, inliers = pcd.segment_plane(distance_threshold=distance_threshold, |
|
ransac_n=3, |
|
num_iterations=num_iterations) |
|
|
|
|
|
inlier_cloud = pcd.select_by_index(inliers) |
|
outlier_cloud = pcd.select_by_index(inliers, invert=True) |
|
|
|
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 input_path, inlier_path, outlier_path, df |
|
|
|
outputs = [ |
|
|
|
Model3D(label="Input Cloud", clear_color=[1.0, 1.0, 1.0, 1.0]), |
|
|
|
Model3D(label="Inlier Cloud", clear_color=[1.0, 1.0, 1.0, 1.0]), |
|
|
|
Model3D(label="Outlier Cloud", clear_color=[1.0, 1.0, 1.0, 1.0]), |
|
|
|
Dataframe(label="Coefficients of the plane model", type="pandas") |
|
] |
|
|
|
|
|
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/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], |
|
], |
|
) |
|
|
|
|
|
|
|
iface.launch() |
|
|