使用Polyscope做一个点云处理的小软件
import numpy as np
import polyscope as ps
import polyscope.imgui as psim
import tkinter as tk
from tkinter import filedialog
# A bunch of parameters which we will manipulate via the UI defined below.
# There is nothing special about these variables, you could manipulate any other
# kind of Python values the same way, such as entries in a dict, or class members.
is_true1 = False
is_true2 = True
ui_int = 7
ui_float1 = -3.2
ui_float2 = 0.8
ui_color3 = (1., 0.5, 0.5)
ui_color4 = (0.3, 0.5, 0.5, 0.8)
ui_angle_rad = 0.2
ui_text = "some input text"
ui_options = ["option A", "option B", "option C"]
ui_options_selected = ui_options[1]
def import_data():
# 弹出文件选择框
root = tk.Tk()
root.withdraw() # 隐藏主窗口
file_path = filedialog.askopenfilename(
filetypes=[("ASC files", "*.asc")],
title="选择一个ASC文件"
)
if not file_path:
print("未选择文件")
return
# 读取ASC文件数据
try:
# 假设ASC文件每一行是 X, Y, Z 格式的点云数据
points = np.loadtxt(file_path)
# 注册点云到Polyscope
ps.register_point_cloud("my points", points)
print(f"已加载点云数据: {file_path}")
except Exception as e:
print(f"读取文件失败: {e}")
def my_function2():
# ... do something important here ...
# points = np.random.rand(3000000, 3) * 100
# ps.register_point_cloud("my points", points)
# # visualize!
# ps_cloud = ps.register_point_cloud("my points", points)
print("executing function2")
# Define our callback function, which Polyscope will repeatedly execute while running the UI.
# We can write any code we want here, but in particular it is an opportunity to create ImGui
# interface elements and define a custom UI.
def callback():
# If we want to use local variables & assign to them in the UI code below,
# we need to mark them as nonlocal. This is because of how Python scoping
# rules work, not anything particular about Polyscope or ImGui.
# Of course, you can also use any other kind of python variable as a controllable
# value in the UI, such as a value from a dictionary, or a class member. Just be
# sure to assign the result of the ImGui call to the value, as in the examples below.
#
# If these variables are defined at the top level of a Python script file (i.e., not
# inside any method), you will need to use the `global` keyword instead of `nonlocal`.
global is_true1, is_true2, ui_int, ui_float1, ui_float2, ui_color3, ui_color4, ui_text, ui_options_selected, ui_angle_rad
# == Settings
# Use settings like this to change the UI appearance.
# Note that it is a push/pop pair, with the matching pop() below.
psim.PushItemWidth(150)
# == Show text in the UI
psim.TextUnformatted("Point Read")
# psim.TextUnformatted("An important value: {}".format(42))
psim.Separator()
# == Buttons
if(psim.Button("import")):
# This code is executed when the button is pressed
import_data()
# By default, each element goes on a new line. Use this
# to put the next element on the _same_ line.
psim.SameLine()
if(psim.Button("Another button")):
# This code is executed when the button is pressed
print("Hello")
psim.SameLine()
if(psim.Button("C button")):
# This code is executed when the button is pressed
my_function2()
# == Set parameters
# These commands allow the user to adjust the value of variables.
# It is important that we assign the return result to the variable to
# update it.
# For most elements, the return is actually a tuple `(changed, newval)`,
# where `changed` indicates whether the setting was modified on this
# frame, and `newval` gives the new value of the variable (or the same
# old value if unchanged).
#
# For numeric inputs, ctrl-click on the box to type in a value.
# Checkbox
changed, is_true1 = psim.Checkbox("flag1", is_true1)
if(changed): # optionally, use this conditional to take action on the new value
pass
psim.SameLine()
changed, is_true2 = psim.Checkbox("flag2", is_true2)
# Input ints
changed, ui_int = psim.InputInt("ui_int", ui_int, step=1, step_fast=10)
# Input floats using two different styles of widget
changed, ui_float1 = psim.InputFloat("ui_float1", ui_float1)
psim.SameLine()
changed, ui_float2 = psim.SliderFloat("ui_float2", ui_float2, v_min=-5, v_max=5)
# Input colors
changed, ui_color3 = psim.ColorEdit3("ui_color3", ui_color3)
psim.SameLine()
changed, ui_color4 = psim.ColorEdit4("ui_color4", ui_color4)
# Input text
changed, ui_text = psim.InputText("enter text", ui_text)
# Combo box to choose from options
# There, the options are a list of strings in `ui_options`,
# and the currently selected element is stored in `ui_options_selected`.
psim.PushItemWidth(200)
changed = psim.BeginCombo("Pick one", ui_options_selected)
if changed:
for val in ui_options:
_, selected = psim.Selectable(val, ui_options_selected==val)
if selected:
ui_options_selected = val
psim.EndCombo()
psim.PopItemWidth()
# Use tree headers to logically group options
# This a stateful option to set the tree node below to be open initially.
# The second argument is a flag, which works like a bitmask.
# Many ImGui elements accept flags to modify their behavior.
psim.SetNextItemOpen(True, psim.ImGuiCond_FirstUseEver)
# The body is executed only when the sub-menu is open. Note the push/pop pair!
if(psim.TreeNode("Collapsible sub-menu")):
psim.TextUnformatted("Detailed information")
if(psim.Button("sub-button")):
print("hello")
# There are many different UI elements offered by ImGui, many of which
# are bound in python by Polyscope. See ImGui's documentation in `imgui.h`,
# or the polyscope bindings in `polyscope/src/cpp/imgui.cpp`.
changed, ui_angle_rad = psim.SliderAngle("ui_float2", ui_angle_rad,
v_degrees_min=-90, v_degrees_max=90)
psim.TreePop()
psim.PopItemWidth()
ps.set_program_name("iPoint")
ps.set_build_gui(False)
ps.set_open_imgui_window_for_user_callback(False)
ps.set_ground_plane_mode("none")
ps.init()
ps.set_user_callback(callback)
ps.show()