Skip to content

Commit 89b61ad

Browse files
Added an option to decimate pointcloud sequences
1 parent b139518 commit 89b61ad

File tree

2 files changed

+55
-16
lines changed

2 files changed

+55
-16
lines changed

Converter/Sequence_Converter.py

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import pymeshlab as ml
44
import numpy as np
55
from threading import Lock
6+
import threading
67
from multiprocessing.pool import ThreadPool
78
import Sequence_Metadata
89
from PIL import Image
@@ -28,13 +29,15 @@ class SequenceConverter:
2829
convertToASTC = False
2930
convertToSRGB = False
3031

32+
decimatePointcloud = False
33+
decimatePercentage = 0
34+
3135
maxThreads = 8
32-
activeThreadLock = Lock()
3336
loadMeshLock = Lock()
3437
activeThreads = 0
3538

3639

37-
def start_conversion(self, model_paths_list, image_paths_list, input_path, output_path, resource_Path, processFinishedCB, threadCount, convertDDS, convertASTC, convertSRGB):
40+
def start_conversion(self, model_paths_list, image_paths_list, input_path, output_path, resource_Path, processFinishedCB, threadCount, convertDDS, convertASTC, convertSRGB, decimatePointcloud, decimatePercentage):
3841

3942
self.metaData = Sequence_Metadata.MetaData()
4043
self.terminateProcessing = False
@@ -47,6 +50,8 @@ def start_conversion(self, model_paths_list, image_paths_list, input_path, outpu
4750
self.convertToDDS = convertDDS
4851
self.convertToASTC = convertASTC
4952
self.convertToSRGB = convertSRGB
53+
self.decimatePointcloud = decimatePointcloud
54+
self.decimatePercentage = decimatePercentage
5055

5156
modelCount = len(model_paths_list)
5257
self.metaData.headerSizes = [None] * modelCount
@@ -117,7 +122,7 @@ def convert_model(self, file):
117122

118123
ms = ml.MeshSet()
119124

120-
self.loadMeshLock.acquire()
125+
self.loadMeshLock.acquire() # If we don't lock the mesh loading process, crashes might occur
121126

122127
try:
123128
ms.load_new_mesh(inputfile)
@@ -197,15 +202,18 @@ def convert_model(self, file):
197202
#to PLY with our very stringent structure. This is needed because we want to keep the
198203
#work on the Unity side as low as possible, so we basically want to load the data from disk into the memory
199204
#without needing to change anything
200-
201205
with open(outputfile, 'wb') as f:
202206

207+
#If pointcloud decimation is enabled, calculate how many points were going to write
208+
if(self.decimatePointcloud):
209+
vertexCount = int(len(vertices) * (self.decimatePercentage / 100))
210+
203211
#constructing the ascii header
204212
header = "ply" + "\n"
205213
header += "format binary_little_endian 1.0" + "\n"
206214
header += "comment Exported for use in Unity Geometry Streaming Plugin" + "\n"
207215

208-
header += "element vertex " + str(len(vertices)) + "\n"
216+
header += "element vertex " + str(vertexCount) + "\n"
209217
header += "property float x" + "\n"
210218
header += "property float y" + "\n"
211219
header += "property float z" + "\n"
@@ -230,9 +238,7 @@ def convert_model(self, file):
230238

231239
f.write(headerASCII)
232240

233-
234241
#Constructing the mesh data, as binary array
235-
236242
if(is_pointcloud == True):
237243

238244
verticePositionsBytes = np.frombuffer(vertices.tobytes(), dtype=np.uint8)
@@ -248,6 +254,11 @@ def convert_model(self, file):
248254
#Interweave arrays, so that each row contains position + color
249255
body = np.concatenate((verticePositionsBytes, verticeColorsBytes), axis = 1)
250256

257+
#Decimate n random elements to reduce points (if enabled)
258+
if(self.decimatePointcloud):
259+
np.random.shuffle(body)
260+
body = body[0:vertexCount]
261+
251262
#Flatten the array into a 1D array
252263
body.ravel()
253264

@@ -284,7 +295,7 @@ def convert_model(self, file):
284295

285296
self.metaData.set_metadata_Model(vertexCount, indiceCount, headerSize, bounds, geoType, has_UVs, listIndex)
286297

287-
self.convert_model_finished(False, "")
298+
self.convert_model_finished(False, "")
288299

289300

290301
def convert_model_finished(self, error, errorText):

Converter/Sequence_Converter_UI.py

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ class ConverterUI:
1919
progress_bar_ID = 0
2020
thread_count_ID = 0
2121
srgb_check_ID = 0
22+
pointcloud_decimation_ID = 0
23+
decimation_percentage_ID = 0
2224

2325
### +++++++++++++++++++++++++ PACKAGE INTO SINGLE EXECUTABLE ++++++++++++++++++++++++++++++++++
2426
#Use this prompt in the terminal to package this script into a single executable for your system
@@ -45,6 +47,8 @@ class ConverterUI:
4547
generateDDS = True
4648
generateASTC = True
4749
convertToSRGB = False
50+
decimatePointcloud = False
51+
decimatePercentage = 100
4852

4953
validModelTypes = ["obj", "3ds", "fbx", "glb", "gltf", "obj", "ply", "ptx", "stl", "xyz", "pts"]
5054
validImageTypes = ["jpg", "jpeg", "png", "bmp", "tga"]
@@ -83,6 +87,14 @@ def set_ASTC_enabled_cb(self, sender, app_data):
8387
def set_SRGB_enabled_cb(self, sender, app_data):
8488
self.convertToSRGB = app_data
8589

90+
def set_Decimation_enabled_cb(self, sender, app_data):
91+
self.decimatePointcloud = app_data
92+
self.write_config_bool("decimatePointcloud", app_data)
93+
94+
def set_Decimation_percentage_cb(self, sender, app_data):
95+
self.decimatePercentage = app_data
96+
self.write_settings_string("decimatePercentage", str(app_data))
97+
8698
def start_conversion_cb(self):
8799

88100
if(self.isRunning):
@@ -108,7 +120,7 @@ def start_conversion_cb(self):
108120

109121
self.totalFileCount = len(self.modelPathList) + len(self.imagePathList)
110122
self.processedFileCount = 0
111-
self.converter.start_conversion(self.modelPathList, self.imagePathList, self.inputSequencePath, self.get_output_path(), self.resourcesPath, self.single_conversion_finished_cb, dpg.get_value(self.thread_count_ID), self.generateDDS, self.generateASTC, self.convertToSRGB)
123+
self.converter.start_conversion(self.modelPathList, self.imagePathList, self.inputSequencePath, self.get_output_path(), self.resourcesPath, self.single_conversion_finished_cb, dpg.get_value(self.thread_count_ID), self.generateDDS, self.generateASTC, self.convertToSRGB, self.decimatePointcloud, self.decimatePercentage)
112124

113125
self.info_text_set("Converting...")
114126
self.set_progressbar(0)
@@ -163,7 +175,7 @@ def set_input_files(self, new_input_path):
163175
self.set_proposed_output_files(new_input_path)
164176

165177
self.inputPathValid = True
166-
self.write_config_string("input", new_input_path)
178+
self.write_path_string("input", new_input_path)
167179

168180
else:
169181
self.info_text_clear()
@@ -240,19 +252,27 @@ def load_config(self):
240252
self.config['Paths']['input'] = ""
241253
self.config['Settings']['DDS'] = "true"
242254
self.config['Settings']['ASTC'] = "true"
255+
self.config['Settings']['decimatePointcloud'] = "false"
256+
self.config['Settings']['decimatePercentage'] = "100"
243257
self.save_config()
244258

245259
self.config.read(self.configPath)
246260

247-
def read_config_string(self, key):
261+
def read_path_string(self, key):
248262
return self.config['Paths'][key]
249263

264+
def read_settings_string(self, key):
265+
return self.config['Settings'][key]
266+
250267
def read_config_bool(self, key):
251268
return self.config['Settings'].getboolean(key)
252269

253-
def write_config_string(self, key, value):
270+
def write_path_string(self, key, value):
254271
self.config['Paths'][key] = value
255272

273+
def write_settings_string(self, key, value):
274+
self.config['Settings'][key] = value
275+
256276
def write_config_bool(self, key, value):
257277
self.config['Settings'][key] = str(value)
258278

@@ -342,10 +362,12 @@ def RunUI(self):
342362
self.load_config()
343363
self.generateDDS = self.read_config_bool("DDS")
344364
self.generateASTC = self.read_config_bool("ASTC")
365+
self.decimatePointcloud = self.read_config_bool("decimatePointcloud")
366+
self.decimatePercentage = int(self.read_settings_string("decimatePercentage"))
345367

346368
dpg.create_context()
347369
dpg.configure_app(manual_callback_management=True)
348-
dpg.create_viewport(height=450, width=500, title="Geometry Sequence Converter")
370+
dpg.create_viewport(height=480, width=500, title="Geometry Sequence Converter")
349371
dpg.setup_dearpygui()
350372

351373
with dpg.window(label="Geometry Sequence Converter", tag="main_window", min_size= [500, 500]):
@@ -361,9 +383,15 @@ def RunUI(self):
361383

362384
dpg.add_checkbox(label="Generate textures for desktop devices (DDS)", default_value=self.generateDDS, callback=self.set_DDS_enabled_cb)
363385
dpg.add_checkbox(label="Generate textures mobile devices (ASTC)", default_value=self.generateASTC, callback=self.set_ASTC_enabled_cb)
364-
self.srgb_check_ID = dpg.add_checkbox(label="Convert to SRGB profile", default_value=self.generateASTC, callback=self.set_SRGB_enabled_cb)
386+
self.srgb_check_ID = dpg.add_checkbox(label="Convert to SRGB profile", default_value=self.convertToSRGB, callback=self.set_SRGB_enabled_cb)
365387

366-
dpg.add_spacer(height=30)
388+
dpg.add_spacer(height=5)
389+
390+
self.pointcloud_decimation_ID = dpg.add_checkbox(label="Decimate Pointcloud", default_value=self.decimatePointcloud, callback=self.set_Decimation_enabled_cb)
391+
dpg.add_same_line()
392+
self.decimation_percentage_ID = dpg.add_input_int(label=" %", default_value=self.decimatePercentage, min_value=0, max_value=100, width=80, callback=self.set_Decimation_percentage_cb)
393+
394+
#dpg.add_spacer(height=5)
367395

368396
self.text_error_log_ID = dpg.add_text("", color=[255, 0, 0], wrap=450)
369397
self.text_info_log_ID = dpg.add_text("", color=[255, 255, 255], wrap=450)
@@ -380,7 +408,7 @@ def RunUI(self):
380408
dpg.show_viewport()
381409
dpg.set_primary_window("main_window", True)
382410

383-
self.set_input_files(self.read_config_string("input"))
411+
self.set_input_files(self.read_path_string("input"))
384412

385413
while dpg.is_dearpygui_running():
386414
dpg.render_dearpygui_frame()

0 commit comments

Comments
 (0)