11'''
2- # Created : 2023-1-26 16:38
3- # Updated: 2024-04-15 12:06
2+ # @date : 2023-1-26 16:38
3+ # @author: Qingwen Zhang (https://kin-zhang.github.io/)
44# Copyright (C) 2023-now, RPL, KTH Royal Institute of Technology
5- # Author: Qingwen ZHANG (https://kin-zhang.github.io/)
5+ # @detail:
6+ # 1. Play the data you want in open3d, and save the view control to json file.
7+ # 2. Use the json file to view the data again.
8+ # 3. Save the screen shot and view file for later check and animation.
69#
710# code gits: https://gist.github.com/Kin-Zhang/77e8aa77a998f1a4f7495357843f24ef
811#
9- # Description as follows:
10-
11- This file is for open3d view control set from view_file, which should be json
12- 1. use normal way to open any geometry and set view by mouse you want
13- 2. `CTRL+C` it will copy the view detail at this moment.
14- 3. `CTRL+V` to json file, you can create new one
15- 4. give the json file path
16-
17- Check this part: http://www.open3d.org/docs/release/tutorial/visualization/visualization.html#Store-view-point
18-
19- Test if you want by run this script: by press 'V' on keyboard, will set from json
20-
2112# CHANGELOG:
13+ # 2024-08-23 21:41(Qingwen): remove totally on view setting from scratch but use open3d>=0.18.0 version for set_view from json text func.
2214# 2024-04-15 12:06(Qingwen): show a example json text. add hex_to_rgb, color_map_hex, color_map (for color points if needed)
23- # 2024-01-27 0:41(Qingwen): update MyVisualizer class, reference from kiss-icp
24- [python/kiss-icp/tools/visualizer.py](https://github.com/PRBonn/kiss-icp/blob/main/python/kiss_icp/tools/visualizer.py)
15+ # 2024-01-27 0:41(Qingwen): update MyVisualizer class, reference from kiss-icp: https://github.com/PRBonn/kiss-icp/blob/main/python/kiss_icp/tools/visualizer.py
2516'''
2617
2718import open3d as o3d
28- import json
29- import os , sys
19+ import os , time
3020from typing import List , Callable
3121from functools import partial
3222
3323def hex_to_rgb (hex_color ):
3424 hex_color = hex_color .lstrip ("#" )
3525 return tuple (int (hex_color [i :i + 2 ], 16 ) / 255.0 for i in (0 , 2 , 4 ))
3626
37- color_map_hex = ['#a6cee3' , '#de2d26' , '#1f78b4' ,'#b2df8a' ,'#33a02c' ,'#fb9a99' ,'#e31a1c' ,'#fdbf6f' ,'#ff7f00' ,'#cab2d6' , '#6a3d9a' , '#ffff99' , '#b15928' , \
38- '#8dd3c7 ' ,'#ffffb3 ' ,'#bebada ' ,'#fb8072' , '#80b1d3 ' ,'#fdb462 ' ,'#b3de69 ' ,'#fccde5 ' ,'#d9d9d9' , '#bc80bd' , '#ccebc5' , '#ffed6f' ]
39- color_map = [ hex_to_rgb ( color ) for color in color_map_hex ]
27+ color_map_hex = ['#a6cee3' , '#de2d26' , '#1f78b4' ,'#b2df8a' ,'#33a02c' ,'#fb9a99' ,'#e31a1c' ,'#fdbf6f' ,'#ff7f00' ,\
28+ '#cab2d6 ' ,'#6a3d9a ' ,'#ffff99 ' ,'#b15928' , '#8dd3c7 ' ,'#ffffb3 ' ,'#bebada ' ,'#fb8072 ' ,'#80b1d3' ,\
29+ '#fdb462' , '#b3de69' , '#fccde5' , '#d9d9d9' , '#bc80bd' , '#ccebc5' , '#ffed6f' ]
4030
41- class ViewControl :
42- def __init__ (self , vctrl : o3d .visualization .ViewControl , view_file = None ):
43- self .vctrl = vctrl
44- self .params = None
45- if view_file is not None :
46- print (f"Init with view_file from: { view_file } " )
47- self .parse_file (view_file )
48- self .set_param ()
49- else :
50- print ("Init without view_file" )
51-
52- def read_viewTfile (self , view_file ):
53- if view_file is None :
54- return
55- self .parse_file (view_file )
56- self .set_param ()
57-
58- def save_viewTfile (self , view_file ):
59- return
60-
61- def parse_file (self , view_file ):
62- if view_file is None :
63- print (f"\033 [91mNo specific view file. Skip to setup viewpoint in open3d. \033 [0m" )
64- return
65- if (os .path .exists (view_file )):
66- with open ((view_file )) as user_file :
67- file_contents = user_file .read ()
68- self .params = json .loads (file_contents )
69- else :
70- print (f"\033 [91mDidn't find the file, please check it again: { view_file } \033 [0m" )
71- print (f"NOTE: If you still have this error, please give the absulote path for view_file" )
72- sys .exit ()
73-
74- def set_param (self ):
75- self .vctrl .change_field_of_view (self .params ['trajectory' ][0 ]['field_of_view' ])
76- self .vctrl .set_front (self .params ['trajectory' ][0 ]['front' ])
77- self .vctrl .set_lookat (self .params ['trajectory' ][0 ]['lookat' ])
78- self .vctrl .set_up (self .params ['trajectory' ][0 ]['up' ])
79- self .vctrl .set_zoom (self .params ['trajectory' ][0 ]['zoom' ])
31+ color_map = [hex_to_rgb (color ) for color in color_map_hex ]
8032
33+
8134class MyVisualizer :
82- def __init__ (self , view_file = None , window_title = "Default" ):
35+ def __init__ (self , view_file = None , window_title = "Default" , save_folder = "logs/imgs" ):
8336 self .params = None
8437 self .vis = o3d .visualization .VisualizerWithKeyCallback ()
8538 self .vis .create_window (window_name = window_title )
86- self .o3d_vctrl = ViewControl (self .vis .get_view_control (), view_file = view_file )
8739 self .view_file = view_file
8840
8941 self .block_vis = True
9042 self .play_crun = False
9143 self .reset_bounding_box = True
44+ self .save_img_folder = save_folder
45+ os .makedirs (self .save_img_folder , exist_ok = True )
9246 print (
9347 f"\n { window_title .capitalize ()} initialized. Press:\n "
9448 "\t [SPACE] to pause/start\n "
95- "\t [ESC] to exit\n "
49+ "\t [ESC/Q] to exit\n "
50+ "\t [P] to save screen and viewpoint\n "
9651 "\t [N] to step\n "
9752 )
9853 self ._register_key_callback (["Ā" , "Q" , "\x1b " ], self ._quit )
54+ self ._register_key_callback (["P" ], self ._save_screen )
9955 self ._register_key_callback ([" " ], self ._start_stop )
10056 self ._register_key_callback (["N" ], self ._next_frame )
10157
@@ -104,7 +60,8 @@ def show(self, assets: List):
10460
10561 for asset in assets :
10662 self .vis .add_geometry (asset )
107- self .o3d_vctrl .read_viewTfile (self .view_file )
63+ if self .view_file is not None :
64+ self .vis .set_view_status (open (self .view_file ).read ())
10865
10966 self .vis .update_renderer ()
11067 self .vis .poll_events ()
@@ -122,7 +79,7 @@ def update(self, assets: List, clear: bool = True):
12279 if self .reset_bounding_box :
12380 self .vis .reset_view_point (True )
12481 if self .view_file is not None :
125- self .o3d_vctrl . read_viewTfile ( self .view_file )
82+ self .vis . set_view_status ( open ( self .view_file ). read () )
12683 self .reset_bounding_box = False
12784
12885 self .vis .update_renderer ()
@@ -135,15 +92,27 @@ def update(self, assets: List, clear: bool = True):
13592 def _register_key_callback (self , keys : List , callback : Callable ):
13693 for key in keys :
13794 self .vis .register_key_callback (ord (str (key )), partial (callback ))
95+
13896 def _next_frame (self , vis ):
13997 self .block_vis = not self .block_vis
98+
14099 def _start_stop (self , vis ):
141100 self .play_crun = not self .play_crun
101+
142102 def _quit (self , vis ):
143103 print ("Destroying Visualizer. Thanks for using ^v^." )
144104 vis .destroy_window ()
145105 os ._exit (0 )
146106
107+ def _save_screen (self , vis ):
108+ timestamp = time .strftime ("%Y-%m-%d-%H-%M-%S" , time .localtime ())
109+ png_file = f"{ self .save_img_folder } /ScreenShot_{ timestamp } .png"
110+ view_json_file = f"{ self .save_img_folder } /ScreenView_{ timestamp } .json"
111+ with open (view_json_file , 'w' ) as f :
112+ f .write (vis .get_view_status ())
113+ vis .capture_screen_image (png_file )
114+ print (f"ScreenShot saved to: { png_file } , Please check it." )
115+
147116if __name__ == "__main__" :
148117 json_content = """{
149118 "class_name" : "ViewTrajectory",
@@ -171,29 +140,6 @@ def _quit(self, vis):
171140 f .write (json_content )
172141 sample_ply_data = o3d .data .PLYPointCloud ()
173142 pcd = o3d .io .read_point_cloud (sample_ply_data .path )
174- # 1. define
175- viz = o3d .visualization .VisualizerWithKeyCallback ()
176- # 2. create
177- viz .create_window (window_name = "TEST ON Change View point through JSON, Press V Please" )
178- # 3. add geometry
179- viz .add_geometry (pcd )
180- # 4. get control !!! must step by step
181- ctr = viz .get_view_control ()
182-
183- o3d_vctrl = ViewControl (ctr )
184-
185- def set_view (viz ):
186- #Your update routine
187- o3d_vctrl .read_viewTfile (view_json_file )
188- viz .update_renderer ()
189- viz .poll_events ()
190- viz .run ()
191-
192- viz .register_key_callback (ord ('V' ), set_view )
193- viz .run ()
194- viz .destroy_window ()
195- print ("\033 [92mAll o3d_view codes run successfully, Close now..\033 [0m See you!" )
196-
197- # or:
198- # viz = MyVisualizer(view_file, window_title="Check Pose")
199- # viz.show([*pcds, *draw_tfs])
143+
144+ viz = MyVisualizer (view_json_file , window_title = "Qingwen's View" )
145+ viz .show ([pcd ])
0 commit comments