diff --git a/config.ini b/config.ini index cfff5d3..deccac3 100644 --- a/config.ini +++ b/config.ini @@ -1,35 +1,54 @@ [FILE] -; Source of point clouds -POINTCLOUD_FOLDER = pointclouds/ -; Sink for label files -LABEL_FOLDER = labels/ +; source of point clouds +pointcloud_folder = pointclouds/ +; sink for label files +label_folder = labels/ [POINTCLOUD] -; Drawing size for points in point cloud -POINT_SIZE = 4 -; Point color for colorless point clouds (r,g,b) -COLORLESS_COLOR = 0.9, 0.9, 0.9 -; Colerize colorless point clouds by height value -COLORLESS_COLORIZE = True -STD_TRANSLATION = 0.03 -STD_ZOOM = 0.0025 +; drawing size for points in point cloud +point_size = 4.0 +; point color for colorless point clouds (r,g,b) +colorless_color = 0.9, 0.9, 0.9 +; colerize colorless point clouds by height value +colorless_colorize = True +; standard step for point cloud translation (for mouse move) +std_translation = 0.03 +; standard step for zooming (for scrolling) +std_zoom = 0.0025 [LABEL] -LABEL_FORMAT = centroid_abs -OBJECT_CLASSES = cart, box -STD_OBJECT_CLASS = cart -Z_ROTATION_ONLY = True -EXPORT_PRECISION = 8 -VIEWING_PRECISION = 3 -MIN_BOUNDINGBOX_DIMENSION = 0.01 -STD_BOUNDINGBOX_LENGTH = 0.75 -STD_BOUNDINGBOX_WIDTH = 0.55 -STD_BOUNDINGBOX_HEIGHT = 0.15 -STD_TRANSLATION = 0.03 -STD_ROTATION = 0.5 -STD_SCALING = 0.03 +; format for exporting labels. choose from (vertices, centroid_rel, centroid_abs, kitti) +label_format = centroid_abs +; list of object classes for autocompletion in the text field +object_classes = cart, box +; default object class for new bounding boxes +std_object_class = cart +; number of decimal places for exporting the bounding box parameter. +export_precision = 8 +; default length of the bounding box (for picking mode) +std_boundingbox_length = 0.75 +; default width of the bounding box (for picking mode) +std_boundingbox_width = 0.55 +; default height of the bounding box (for picking mode) +std_boundingbox_height = 0.15 +; standard step for translating the bounding box with button or key (in meter) +std_translation = 0.03 +; standard step for rotating the bounding box with button or key (in degree) +std_rotation = 0.5 +; standard step for scaling the bounding box with button +std_scaling = 0.03 +; minimum value for the length, width and height of a bounding box +min_boundingbox_dimension = 0.01 + +[USER_INTERFACE] +; only allow z-rotation of bounding boxes. set false to also label x- & y-rotation +z_rotation_only = True +; visualizes the pointcloud floor (x-y-plane) as a grid +show_floor = True +; visualizes the object's orientation with an arrow +show_orientation = True +; background color of the point cloud viewer (rgb) +background_color = 100, 100, 100 +; number of decimal places shown for the parameters of the active bounding box +viewing_precision = 2 -[SETTINGS] -BACKGROUND_COLOR = 100, 100, 100 -SHOW_FLOOR = True -SHOW_ORIENTATION = True diff --git a/docs/documentation.md b/docs/documentation.md index fa30b84..5df1f30 100644 --- a/docs/documentation.md +++ b/docs/documentation.md @@ -36,28 +36,29 @@ The following parameters can be changed: | Parameter | Description | Default/ Example | | :---: | --- | :---: | | **[FILE]** | -| `POINTCLOUD_FOLDER` | Source of point clouds | *pointclouds/* | -| `LABEL_FOLDER`| Sink for label files | *labels/* | +| `POINTCLOUD_FOLDER` | Folder from which the point cloud files are loaded. | *pointclouds/* | +| `LABEL_FOLDER`| Folder where the label files will be saved. | *labels/* | | **[POINTCLOUD]** | -| `POINT_SIZE` | Drawing size for points in point cloud | *4* | -| `COLORLESS_COLOR` | Point color for colorless point clouds (r,g,b) | *0.9, 0.9, 0.9* | -| `COLORLESS_COLORIZE` | Colerize colorless point clouds by height value | *True* | -| `STD_TRANSLATION` | Standard step for point cloud translation | *0.03* | -| `STD_ZOOM` | Standard step for zooming | *0.0025* | +| `POINT_SIZE` | Drawing size for points in point cloud (rasterized diameter). | *4* | +| `COLORLESS_COLOR` | Point color for colorless point clouds (r,g,b). | *0.9, 0.9, 0.9* | +| `COLORLESS_COLORIZE` | Colerize colorless point clouds by height value. | *True* | +| `STD_TRANSLATION` | Standard step for point cloud translation (with mouse move). | *0.03* | +| `STD_ZOOM` | Standard step for zooming (with mouse scroll). | *0.0025* | | **[LABEL]** | -| `LABEL_FORMAT` | Format for exporting labels. Choose from (`vertices`, `centroid_rel`, `centroid_abs`, `kitti`) | *centroid_abs* | -| `OBJECT_CLASSES` | List of object classes for autocompletion | *class1, class2, ...* | -| `STD_OBJECT_CLASS` | Default object class | *default_class* | -| `Z_ROTATION_ONLY` | Only allow z-rotation of bounding box. Deactivate to also label x- & y-rotation | *True* | -| `EXPORT_PRECISION` | Number of decimal places for export label. | *8* | -| `MIN_BOUNDINGBOX_DIMENSION` | Minimum bounding box dimension. | *0.01* | -| `STD_BOUNDINGBOX_LENGTH` | Default lenght of the bounding box (for picking mode) | *0.75* | -| `STD_BOUNDINGBOX_WIDTH` | Default width of the bounding box (for picking mode) | *0.55* | -| `STD_BOUNDINGBOX_HEIGHT`| Default height of the bounding box (for picking mode) | *0.15* | -| `STD_TRANSLATION`| Standard step for translating the bounding box | *0.03* | -| `STD_ROTATION` | Standard step for rotating the bounding box | *0.5* | -| `STD_SCALING` | Standard step for scaling the bounding box | *0.03* | +| `LABEL_FORMAT` | Format for exporting labels, choose from `vertices`, `centroid_rel`, `centroid_abs` or `kitti`. | *centroid_abs* | +| `OBJECT_CLASSES` | List of object classes for autocompletion in the class text field. | *class1, class2, ...* | +| `STD_OBJECT_CLASS` | Default object class for new bounding boxes. | *default_class* | +| `EXPORT_PRECISION` | Number of decimal places for exporting the bounding box parameters. | *8* | +| `STD_BOUNDINGBOX_LENGTH` | Default length of the bounding box (for picking mode). | *0.75* | +| `STD_BOUNDINGBOX_WIDTH` | Default width of the bounding box (for picking mode). | *0.55* | +| `STD_BOUNDINGBOX_HEIGHT`| Default height of the bounding box (for picking mode). | *0.15* | +| `STD_TRANSLATION`| Standard step for translating the bounding box (with key or button press). | *0.03* | +| `STD_ROTATION` | Standard step for rotating the bounding box (with key press). | *0.5* | +| `STD_SCALING` | Standard step for scaling the bounding box (with button press). | *0.03* | +| `MIN_BOUNDINGBOX_DIMENSION` | Minimum value for the length, width and height of a bounding box. | *0.01* | | **[SETTINGS]** | -| `BACKGROUND_COLOR` | Background color of the point cloud viewer (rgb) | *100, 100, 100* | -| `SHOW_FLOOR` | Visualizes the floor (x-y-plane) as a grid | *True* | -| `SHOW_ORIENTATION` | Visualizes the object's orientation as an arrow | *True* | +| `Z_ROTATION_ONLY` | Only allow z-rotation of bounding box; deactivate to also label x- & y-rotation. | *True* | +| `SHOW_FLOOR` | Visualizes the floor (x-y-plane) as a grid. | *True* | +| `SHOW_ORIENTATION` | Visualizes the object's orientation as an arrow. | *True* | +| `BACKGROUND_COLOR` | Background color of the point cloud viewer (rgb). | *100, 100, 100* | +| `VIEWING_PRECISION` | Number of decimal places shown on the right side for the parameters of the active bounding box. | *3* | \ No newline at end of file diff --git a/labelCloud/control/bbox_controller.py b/labelCloud/control/bbox_controller.py index 8e0c819..14561cf 100644 --- a/labelCloud/control/bbox_controller.py +++ b/labelCloud/control/bbox_controller.py @@ -8,7 +8,7 @@ import numpy as np from utils import oglhelper -from control import config_parser +from control.config_manager import config from model.bbox import BBox if TYPE_CHECKING: @@ -22,29 +22,27 @@ def wrapper(*args, **kwargs): # plays function if active bbox exists return func(*args, **kwargs) else: print("There is currently no active bounding box to manipulate.") + return wrapper def only_zrotation_decorator(func): def wrapper(*args, **kwargs): # plays function if active bbox exists - if not args[0].only_z_rotation: + if not config.getboolean("USER_INTERFACE", "z_rotation_only"): return func(*args, **kwargs) else: print("Rotations around the x- or y-axis are not supported in this mode.") + return wrapper class BoundingBoxController: - Z_ROTATION = config_parser.get_label_settings("Z_ROTATION_ONLY") - STD_TRANSLATION = config_parser.get_label_settings("STD_TRANSLATION") - STD_ROTATION = config_parser.get_label_settings("STD_ROTATION") - STD_SCALING = config_parser.get_label_settings("STD_SCALING") + STD_SCALING = config.getfloat("LABEL", "std_scaling") def __init__(self): self.view = None self.bboxes = [] self.active_bbox_id = -1 # -1 means zero bboxes - self.only_z_rotation = BoundingBoxController.Z_ROTATION self.pcdc = None # GETTERS @@ -71,11 +69,6 @@ def get_classname(self): def set_view(self, view: 'GUI'): self.view = view - self.view.action_zrotation.setChecked(self.only_z_rotation) - - def set_rotation_mode(self, state: bool): - self.only_z_rotation = state - print("Z-rotation only mode set to %s." % state) def add_bbox(self, bbox: BBox): if isinstance(bbox, BBox): @@ -83,12 +76,12 @@ def add_bbox(self, bbox: BBox): self.set_active_bbox(self.bboxes.index(bbox)) self.view.update_status("Bounding Box added, it can now be corrected.", mode="correction") - def update_bbox(self, bbox_id, bbox): + def update_bbox(self, bbox_id: int, bbox: BBox): if isinstance(bbox, BBox) and (0 <= bbox_id < len(self.bboxes)): self.bboxes[bbox_id] = bbox self.update_label_list() - def delete_bbox(self, bbox_id): + def delete_bbox(self, bbox_id: int): if 0 <= bbox_id < len(self.bboxes): del self.bboxes[bbox_id] if bbox_id == self.active_bbox_id: @@ -100,7 +93,7 @@ def delete_current_bbox(self): selected_item_id = self.view.label_list.currentRow() self.delete_bbox(selected_item_id) - def set_active_bbox(self, bbox_id): + def set_active_bbox(self, bbox_id: int): if 0 <= bbox_id < len(self.bboxes): self.active_bbox_id = bbox_id self.update_all() @@ -114,7 +107,7 @@ def set_classname(self, new_class: str): self.update_label_list() @has_active_bbox_decorator - def set_center(self, cx, cy, cz): + def set_center(self, cx: float, cy: float, cz: float): self.get_active_bbox().center = (cx, cy, cz) def set_bboxes(self, bboxes: List[BBox]): @@ -167,20 +160,23 @@ def update_rotation(self, axis: str, value: float): @only_zrotation_decorator @has_active_bbox_decorator - def rotate_around_x(self, dangle=STD_ROTATION, clockwise=False): + def rotate_around_x(self, dangle: float = None, clockwise: bool = False): + dangle = dangle or config.getfloat("LABEL", "std_rotation") if clockwise: dangle *= -1 self.get_active_bbox().set_x_rotation(self.get_active_bbox().get_x_rotation() + dangle) @only_zrotation_decorator @has_active_bbox_decorator - def rotate_around_y(self, dangle=STD_ROTATION, clockwise=False): + def rotate_around_y(self, dangle: float = None, clockwise: bool = False): + dangle = dangle or config.getfloat("LABEL", "std_rotation") if clockwise: dangle *= -1 self.get_active_bbox().set_y_rotation(self.get_active_bbox().get_y_rotation() + dangle) @has_active_bbox_decorator - def rotate_around_z(self, dangle=STD_ROTATION, clockwise=False, absolute=False): + def rotate_around_z(self, dangle: float = None, clockwise: bool = False, absolute: bool = False): + dangle = dangle or config.getfloat("LABEL", "std_rotation") if clockwise: dangle *= -1 if absolute: @@ -207,7 +203,8 @@ def rotate_with_mouse(self, x_angle: float, y_angle: float): # TODO: Make more self.rotate_around_z(x_angle) @has_active_bbox_decorator - def translate_along_x(self, distance=STD_TRANSLATION, left=False): + def translate_along_x(self, distance: float = None, left: bool = False): + distance = distance or config.getfloat("LABEL", "std_translation") if left: distance *= -1 cosz, sinz, bu = self.pcdc.get_perspective() @@ -215,7 +212,8 @@ def translate_along_x(self, distance=STD_TRANSLATION, left=False): self.get_active_bbox().set_y_translation(self.get_active_bbox().center[1] + distance * sinz) @has_active_bbox_decorator - def translate_along_y(self, distance=STD_TRANSLATION, forward=False): + def translate_along_y(self, distance: float = None, forward: bool = False): + distance = distance or config.getfloat("LABEL", "std_translation") if forward: distance *= -1 cosz, sinz, bu = self.pcdc.get_perspective() @@ -223,14 +221,16 @@ def translate_along_y(self, distance=STD_TRANSLATION, forward=False): self.get_active_bbox().set_y_translation(self.get_active_bbox().center[1] + distance * bu * cosz) @has_active_bbox_decorator - def translate_along_z(self, distance=STD_TRANSLATION, down=False): + def translate_along_z(self, distance: float = None, down: bool = False): + distance = distance or config.getfloat("LABEL", "std_translation") if down: distance *= -1 self.get_active_bbox().set_z_translation(self.get_active_bbox().center[2] + distance) # Scale bbox while keeping ratios @has_active_bbox_decorator - def scale(self, length_increase=STD_SCALING, decrease=False): + def scale(self, length_increase: float = None, decrease: bool = False): + length_increase = length_increase or config.getfloat("LABEL", "std_scaling") if decrease: length_increase *= -1 length, width, height = self.get_active_bbox().get_dimensions() diff --git a/labelCloud/control/config_manager.py b/labelCloud/control/config_manager.py new file mode 100644 index 0000000..720fe3f --- /dev/null +++ b/labelCloud/control/config_manager.py @@ -0,0 +1,48 @@ +"""Load configuration from .ini file.""" +import configparser + +# Read local file `config.ini`. +import os +from typing import List, Union, Optional + + +class ExtendedConfigParser(configparser.ConfigParser): + + def getlist(self, section, option, raw=False, vars=None, fallback=None) -> List: + raw_value = self.get(section, option, raw=raw, vars=vars, fallback=fallback) + if "," in raw_value: + values = [x.strip() for x in raw_value.split(',')] + try: + return [float(item) for item in values] + except ValueError: + return values + return raw_value + + +class ConfigManager(object): + PATH_TO_CONFIG = "config.ini" + PATH_TO_DEFAULT_CONFIG = "ressources/default_config.ini" + + def __init__(self): + self.config = ExtendedConfigParser(comment_prefixes='/', allow_no_value=True) + self.read_from_file() + + def read_from_file(self): + if os.path.isfile(ConfigManager.PATH_TO_CONFIG): + self.config.read(ConfigManager.PATH_TO_CONFIG) + else: + self.config.read(ConfigManager.PATH_TO_DEFAULT_CONFIG) + + def write_into_file(self): + with open(ConfigManager.PATH_TO_CONFIG, 'w') as configfile: + self.config.write(configfile, space_around_delimiters=True) + + def reset_to_default(self): + self.config.read(ConfigManager.PATH_TO_DEFAULT_CONFIG) + + def get_file_settings(self, key: str) -> str: + return self.config["FILE"][key] + + +config_manager = ConfigManager() +config = config_manager.config diff --git a/labelCloud/control/config_parser.py b/labelCloud/control/config_parser.py deleted file mode 100644 index b27af4c..0000000 --- a/labelCloud/control/config_parser.py +++ /dev/null @@ -1,68 +0,0 @@ -"""Load configuration from .ini file.""" -import configparser - -# Read local file `config.ini`. -import os -from typing import List, Union - -PATH_TO_CONFIG = "config.ini" - -config = configparser.ConfigParser() - -if os.path.isfile(PATH_TO_CONFIG): - config.read("config.ini") -else: - config.read("ressources/default_config.ini") - - -# Parses string to list if it contains a "," -def float_parser_decorator(func): - def wrapper(*args, **kwargs): - value = func(*args, **kwargs) - if value in ["True", "False"]: - return value == "True" - try: - return float(value) - except TypeError: - return value - except ValueError: - return value - - return wrapper - - -# Parses string to list if it contains a "," -def list_parser_decorator(func): - def wrapper(*args, **kwargs): - value = func(*args, **kwargs) - if "," in value: - values = [x.strip() for x in value.split(',')] - try: - return [float(item) for item in values] - except ValueError: - return values - return value - - return wrapper - - -def get_file_settings(key: str) -> str: - return config["FILE"][key] - - -@float_parser_decorator -@list_parser_decorator -def get_pointcloud_settings(key: str) -> Union[str, float, List]: - return config["POINTCLOUD"][key] - - -@float_parser_decorator -@list_parser_decorator -def get_label_settings(key: str) -> Union[str, float, List]: - return config["LABEL"][key] - - -@float_parser_decorator -@list_parser_decorator -def get_app_settings(key: str) -> str: - return config["SETTINGS"][key] diff --git a/labelCloud/control/drawing_manager.py b/labelCloud/control/drawing_manager.py index babc550..51533c2 100644 --- a/labelCloud/control/drawing_manager.py +++ b/labelCloud/control/drawing_manager.py @@ -6,6 +6,7 @@ import utils.math3d as math3d import utils.oglhelper as ogl from control.bbox_controller import BoundingBoxController +from control.config_manager import config from model.bbox import BBox if TYPE_CHECKING: @@ -133,17 +134,17 @@ def register_tmp_point(self, new_tmp_point: List[float]) -> None: def register_scrolling(self, distance: float) -> None: self.bbox_z_rotation += distance // 30 - def draw_preview(self) -> None: + def draw_preview(self) -> None: # TODO: Refactor if self.tmp_p1: - tmp_bbox = BBox(*np.add(self.tmp_p1, [0, BBox.STD_WIDTH / 2, -BBox.STD_HEIGHT / 3])) - # tmp_bbox = BBox(*self.tmp_p1) + tmp_bbox = BBox(*np.add(self.tmp_p1, [0, config.getfloat("LABEL", "STD_BOUNDINGBOX_WIDTH") / 2, + -config.getfloat("LABEL", "STD_BOUNDINGBOX_HEIGHT") / 3])) tmp_bbox.set_z_rotation(self.bbox_z_rotation) ogl.draw_cuboid(tmp_bbox.get_vertices(), draw_vertices=True, vertex_color=(1, 1, 0, 1)) # Draw bbox with fixed dimensions and rotation at x,y in world space - def get_bbox(self) -> BBox: - final_bbox = BBox(*np.add(self.point_1, [0, BBox.STD_WIDTH / 2, -BBox.STD_HEIGHT / 3])) - # final_bbox = BBox(*self.point_1) + def get_bbox(self) -> BBox: # TODO: Refactor + final_bbox = BBox(*np.add(self.point_1, [0, config.getfloat("LABEL", "STD_BOUNDINGBOX_WIDTH") / 2, + -config.getfloat("LABEL", "STD_BOUNDINGBOX_HEIGHT") / 3])) final_bbox.set_z_rotation(self.bbox_z_rotation) return final_bbox @@ -223,7 +224,7 @@ def get_bbox(self) -> BBox: bbox = BBox(*center, length=length, width=width, height=abs(height)) bbox.set_z_rotation(math3d.radians_to_degrees(z_angle)) - if not self.view.controller.bbox_controller.only_z_rotation: + if not config.getboolean("USER_INTERFACE", "z_rotation_only"): # Also calculate y_angle y_angle = np.arctan(len_vec_2d[2] / len_vec_2d[0]) bbox.set_y_rotation(-math3d.radians_to_degrees(y_angle)) diff --git a/labelCloud/control/label_manager.py b/labelCloud/control/label_manager.py index 7b8caf9..be2c747 100644 --- a/labelCloud/control/label_manager.py +++ b/labelCloud/control/label_manager.py @@ -7,15 +7,15 @@ import numpy as np from utils import math3d -from control import config_parser +from control.config_manager import config from model.bbox import BBox class LabelManager: LABEL_FORMATS = ["vertices", "centroid_rel", "centroid_abs", "kitti"] # supported export formats - STD_LABEL_FORMAT = config_parser.get_label_settings("LABEL_FORMAT") - STD_LABEL_FOLDER = config_parser.get_file_settings("LABEL_FOLDER") - EXPORT_PRECISION = int(config_parser.get_label_settings("EXPORT_PRECISION")) # Number of decimal places + STD_LABEL_FORMAT = config.get("LABEL", "label_format") + EXPORT_PRECISION = config.getint("LABEL", "export_precision") # Number of decimal places + STD_LABEL_FOLDER = config.get("FILE", "label_folder") def __init__(self, strategy: str = STD_LABEL_FORMAT, path_to_label_folder: str = STD_LABEL_FOLDER): self.label_folder = path_to_label_folder diff --git a/labelCloud/control/pcd_manager.py b/labelCloud/control/pcd_manager.py index 4bbe074..6eea158 100644 --- a/labelCloud/control/pcd_manager.py +++ b/labelCloud/control/pcd_manager.py @@ -5,14 +5,14 @@ import ntpath import os import sys -from typing import List, Tuple, TYPE_CHECKING, Set +from typing import List, Tuple, TYPE_CHECKING import numpy as np import open3d as o3d -from PyQt5.QtWidgets import QCompleter, QMessageBox +from PyQt5.QtWidgets import QMessageBox from shutil import copyfile -from control import config_parser +from control.config_manager import config from control.label_manager import LabelManager from model.bbox import BBox from model.point_cloud import PointCloud @@ -34,12 +34,6 @@ def find_pcd_files(path: str) -> List[str]: return sorted(pcd_files) -def get_unique_classnames(bboxes: List[BBox]) -> Set[str]: - for box in bboxes: - BBox.LIST_OF_CLASSES.add(box.get_classname()) - return BBox.LIST_OF_CLASSES - - def show_no_pcd_dialog(): msg = QMessageBox() msg.setIcon(QMessageBox.Warning) @@ -63,11 +57,11 @@ def color_pointcloud(points, z_min, z_max): class PointCloudManger: PCD_EXTENSIONS = (".pcd", ".ply", ".pts", ".xyz", ".xyzn", ".xyzrgb", ".bin") - PCD_FOLDER = config_parser.get_file_settings("POINTCLOUD_FOLDER") + PCD_FOLDER = config.get("FILE", "POINTCLOUD_FOLDER") ORIGINALS_FOLDER = "original_pointclouds" - TRANSLATION_FACTOR = config_parser.get_pointcloud_settings("STD_TRANSLATION") - ZOOM_FACTOR = config_parser.get_pointcloud_settings("STD_ZOOM") - COLORIZE = config_parser.get_pointcloud_settings("COLORLESS_COLORIZE") + TRANSLATION_FACTOR = config.getfloat("POINTCLOUD", "STD_TRANSLATION") + ZOOM_FACTOR = config.getfloat("POINTCLOUD", "STD_ZOOM") + COLORIZE = config.getboolean("POINTCLOUD", "COLORLESS_COLORIZE") def __init__(self): # Point cloud management @@ -80,6 +74,7 @@ def __init__(self): self.label_manager = LabelManager() # Point cloud control self.pointcloud = None + self.collected_object_classes = set() # GETTER def pcds_left(self) -> bool: @@ -134,7 +129,7 @@ def set_view(self, view: 'GUI') -> None: def save_labels_into_file(self, bboxes: List[BBox]): self.label_manager.export_labels(self.get_current_path(), bboxes) - self.update_label_completer(get_unique_classnames(bboxes)) + self.view.update_label_completer({bbox.get_classname() for bbox in bboxes}) # MANIPULATOR def load_pointcloud(self, path_to_pointcloud: str) -> PointCloud: @@ -264,8 +259,6 @@ def get_perspective(self): return cosz, sinz, bottom_up # UPDATE GUI - def update_label_completer(self, classnames: Set[str]): - self.view.curr_class_edit.setCompleter(QCompleter(classnames)) def update_pcd_infos(self): self.view.set_pcd_label(self.get_current_name()) diff --git a/labelCloud/model/bbox.py b/labelCloud/model/bbox.py index 5cfd875..d201357 100644 --- a/labelCloud/model/bbox.py +++ b/labelCloud/model/bbox.py @@ -3,7 +3,7 @@ import OpenGL.GL as GL import numpy as np -from control import config_parser +from control.config_manager import config from utils import math3d from utils import oglhelper @@ -16,23 +16,18 @@ class BBox: BBOX_SIDES = {"top": [4, 5, 6, 7], "bottom": [0, 1, 2, 3], "right": [2, 3, 7, 6], # vertices of each side "back": [0, 3, 7, 4], "left": [0, 1, 5, 4], "front": [1, 2, 6, 5]} - MIN_DIMENSION = config_parser.get_label_settings("MIN_BOUNDINGBOX_DIMENSION") - STD_LENGTH = config_parser.get_label_settings("STD_BOUNDINGBOX_LENGTH") - STD_WIDTH = config_parser.get_label_settings("STD_BOUNDINGBOX_WIDTH") - STD_HEIGHT = config_parser.get_label_settings("STD_BOUNDINGBOX_HEIGHT") + MIN_DIMENSION = config.getfloat("LABEL", "MIN_BOUNDINGBOX_DIMENSION") - LIST_OF_CLASSES = set(config_parser.get_label_settings("OBJECT_CLASSES")) - STD_OBJECT_CLASS = config_parser.get_label_settings("STD_OBJECT_CLASS") - - def __init__(self, cx, cy, cz, length=STD_LENGTH, width=STD_WIDTH, height=STD_HEIGHT): + def __init__(self, cx: float, cy: float, cz: float, + length: float = None, width: float = None, height: float = None): self.center = cx, cy, cz - self.length = length - self.width = width - self.height = height + self.length = length or config.getfloat("LABEL", "STD_BOUNDINGBOX_LENGTH") + self.width = width or config.getfloat("LABEL", "STD_BOUNDINGBOX_WIDTH") + self.height = height or config.getfloat("LABEL", "STD_BOUNDINGBOX_HEIGHT") self.x_rotation = 0 self.y_rotation = 0 self.z_rotation = 0 - self.classname = BBox.STD_OBJECT_CLASS + self.classname = config.get("LABEL", "STD_OBJECT_CLASS") self.verticies = None self.set_axis_aligned_verticies() diff --git a/labelCloud/model/point_cloud.py b/labelCloud/model/point_cloud.py index 885f992..0cc63ee 100644 --- a/labelCloud/model/point_cloud.py +++ b/labelCloud/model/point_cloud.py @@ -3,7 +3,7 @@ import numpy as np import OpenGL.GL as GL -from control import config_parser +from control.config_manager import config # Get size of float (4 bytes) for VBOs SIZE_OF_FLOAT = ctypes.sizeof(ctypes.c_float) @@ -22,8 +22,6 @@ def create_buffer(attributes): class PointCloud: - POINT_SIZE = config_parser.get_pointcloud_settings("POINT_SIZE") - COLOR_FOR_COLORLESS_PCD = config_parser.get_pointcloud_settings("COLORLESS_COLOR") def __init__(self, path): self.path_to_pointcloud = path @@ -112,13 +110,13 @@ def draw_pointcloud(self): GL.glTranslate(*(pcd_center * -1)) # move point cloud to center for rotation - GL.glPointSize(PointCloud.POINT_SIZE) + GL.glPointSize(config.getfloat("POINTCLOUD", "POINT_SIZE")) GL.glBindBuffer(GL.GL_ARRAY_BUFFER, self.vbo) if self.colorless: stride = 3 * SIZE_OF_FLOAT # (12 bytes) : [x, y, z] * sizeof(float) GL.glPointSize(1) - GL.glColor3d(*PointCloud.COLOR_FOR_COLORLESS_PCD) # IDEA: Color by (height) position + GL.glColor3d(*config.getlist("POINTCLOUD", "COLORLESS_COLOR")) # IDEA: Color by (height) position else: stride = 6 * SIZE_OF_FLOAT # (24 bytes) : [x, y, z, r, g, b] * sizeof(float) diff --git a/labelCloud/ressources/default_config.ini b/labelCloud/ressources/default_config.ini index cfff5d3..deccac3 100644 --- a/labelCloud/ressources/default_config.ini +++ b/labelCloud/ressources/default_config.ini @@ -1,35 +1,54 @@ [FILE] -; Source of point clouds -POINTCLOUD_FOLDER = pointclouds/ -; Sink for label files -LABEL_FOLDER = labels/ +; source of point clouds +pointcloud_folder = pointclouds/ +; sink for label files +label_folder = labels/ [POINTCLOUD] -; Drawing size for points in point cloud -POINT_SIZE = 4 -; Point color for colorless point clouds (r,g,b) -COLORLESS_COLOR = 0.9, 0.9, 0.9 -; Colerize colorless point clouds by height value -COLORLESS_COLORIZE = True -STD_TRANSLATION = 0.03 -STD_ZOOM = 0.0025 +; drawing size for points in point cloud +point_size = 4.0 +; point color for colorless point clouds (r,g,b) +colorless_color = 0.9, 0.9, 0.9 +; colerize colorless point clouds by height value +colorless_colorize = True +; standard step for point cloud translation (for mouse move) +std_translation = 0.03 +; standard step for zooming (for scrolling) +std_zoom = 0.0025 [LABEL] -LABEL_FORMAT = centroid_abs -OBJECT_CLASSES = cart, box -STD_OBJECT_CLASS = cart -Z_ROTATION_ONLY = True -EXPORT_PRECISION = 8 -VIEWING_PRECISION = 3 -MIN_BOUNDINGBOX_DIMENSION = 0.01 -STD_BOUNDINGBOX_LENGTH = 0.75 -STD_BOUNDINGBOX_WIDTH = 0.55 -STD_BOUNDINGBOX_HEIGHT = 0.15 -STD_TRANSLATION = 0.03 -STD_ROTATION = 0.5 -STD_SCALING = 0.03 +; format for exporting labels. choose from (vertices, centroid_rel, centroid_abs, kitti) +label_format = centroid_abs +; list of object classes for autocompletion in the text field +object_classes = cart, box +; default object class for new bounding boxes +std_object_class = cart +; number of decimal places for exporting the bounding box parameter. +export_precision = 8 +; default length of the bounding box (for picking mode) +std_boundingbox_length = 0.75 +; default width of the bounding box (for picking mode) +std_boundingbox_width = 0.55 +; default height of the bounding box (for picking mode) +std_boundingbox_height = 0.15 +; standard step for translating the bounding box with button or key (in meter) +std_translation = 0.03 +; standard step for rotating the bounding box with button or key (in degree) +std_rotation = 0.5 +; standard step for scaling the bounding box with button +std_scaling = 0.03 +; minimum value for the length, width and height of a bounding box +min_boundingbox_dimension = 0.01 + +[USER_INTERFACE] +; only allow z-rotation of bounding boxes. set false to also label x- & y-rotation +z_rotation_only = True +; visualizes the pointcloud floor (x-y-plane) as a grid +show_floor = True +; visualizes the object's orientation with an arrow +show_orientation = True +; background color of the point cloud viewer (rgb) +background_color = 100, 100, 100 +; number of decimal places shown for the parameters of the active bounding box +viewing_precision = 2 -[SETTINGS] -BACKGROUND_COLOR = 100, 100, 100 -SHOW_FLOOR = True -SHOW_ORIENTATION = True diff --git a/labelCloud/ressources/interface.ui b/labelCloud/ressources/interface.ui index 2437fda..aa96f2e 100644 --- a/labelCloud/ressources/interface.ui +++ b/labelCloud/ressources/interface.ui @@ -1524,20 +1524,19 @@ QListWidget#label_list::item:selected { Labels - - Settings - + + @@ -1628,6 +1627,11 @@ QListWidget#label_list::item:selected { Align Point Cloud + + + Change Settings ... + + diff --git a/labelCloud/ressources/settings_interface.ui b/labelCloud/ressources/settings_interface.ui new file mode 100644 index 0000000..a43e3a4 --- /dev/null +++ b/labelCloud/ressources/settings_interface.ui @@ -0,0 +1,742 @@ + + + SettingsDialog + + + + 0 + 0 + 888 + 620 + + + + Change Settings + + + + + + QLayout::SetMaximumSize + + + 0 + + + + + Rasterized diameter of each point from the point cloud. + + + Point Size + + + + + + + number of decimal places shown for the parameters of the active bounding box. + + + + + + + Standard step for zooming. + + + 4 + + + 0.010000000000000 + + + + + + + Point color for colorless point clouds (r,g,b). + + + + + + + + 0 + 0 + + + + + 75 + true + + + + File Settings + + + + + + + Point color for colorless point clouds (r,g,b). + + + Point Color +(for colorless point clouds) + + + + + + + Background color of the point cloud viewer (rgb). + + + + + + + Visualizes the pointcloud floor (x-y-plane) as a grid. + + + Show Point Cloud Floor (x-y-Plane) + + + + + + + Colerize colorless point clouds by height value. + + + Colorize colorless point clouds by height + + + + + + + + 75 + true + + + + margin-top: 10px + + + User Interface + + + + + + + + 0 + 0 + + + + + 75 + true + + + + margin-top: 10px + + + Point Cloud Settings + + + + + + + Path to the folder where the label files will be saved. + + + Label Folder + + + + + + + Standard step for point cloud translation. + + + 4 + + + 0.010000000000000 + + + + + + + number of decimal places shown for the parameters of the active bounding box. + + + Viewing Precision of +Bounding Box Parameter + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Standard step for point cloud translation. + + + Standard Translation + + + + + + + Standard step for zooming. + + + Standard Zoom Factor + + + + + + + Path to the folder that contains the point cloud files. + + + Point Cloud Folder + + + + + + + Rasterized diameter of each point from the point cloud. + + + 2 + + + 500.000000000000000 + + + + + + + Visualizes the object's orientation with an arrow. + + + Show Bounding Box Orientation + + + + + + + Path to the folder that contains the point cloud files. + + + + + + + Background color of the point cloud viewer (rgb). + + + Background Color + + + + + + + Path to the folder where the label files will be saved. + + + + + + + + true + + + + Note: Some settings might require a restart to take effect! + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 40 + 20 + + + + + + + + QLayout::SetMaximumSize + + + 0 + + + + + Only allow z-rotation of bounding boxes. Deactivate to also label x- & y-rotation. + + + Z-Rotation-Only Mode (otherwise rotation around x, y and z) + + + + + + + Format for exporting labels. + + + Label Format + + + + + + + Default width of the bounding box (for picking mode). + + + Standard Bounding Box Width + + + + + + + Number of decimal places shown for the parameters of the active bounding box. + + + + + + + Standard step for translating the bounding box (meter). + + + Standard Translation Step + + + + + + + Format for exporting labels. + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 30 + + + + + + + + Minimum value for the length, width and height of a bounding box. + + + 3 + + + 0.001000000000000 + + + + + + + Standard step for rotating the bounding box (degree). + + + Standard Rotation Step + + + + + + + Default object class for new bounding boxes. + + + + + + + Standard step for scaling the bounding box. + + + 3 + + + 500.000000000000000 + + + 0.010000000000000 + + + + + + + Standard step for translating the bounding box (meter). + + + 3 + + + 500.000000000000000 + + + 0.100000000000000 + + + + + + + Default length of the bounding box (for picking mode). + + + Standard Bounding Box Length + + + + + + + Standard step for rotating the bounding box (degree). + + + 3 + + + 364.000000000000000 + + + 0.100000000000000 + + + + + + + Minimum value for the length, width and height of a bounding box. + + + Min. Bounding Box Dimensions + + + + + + + + 0 + 0 + + + + List of object classes for autocompletion in the text field. + + + QAbstractScrollArea::AdjustToContents + + + + + + + Default height of the bounding box (for picking mode). + + + 3 + + + 500.000000000000000 + + + 0.100000000000000 + + + + + + + Number of decimal places shown for the parameters of the active bounding box. + + + Export Precision + + + + + + + Default length of the bounding box (for picking mode). + + + 3 + + + 500.000000000000000 + + + 0.100000000000000 + + + + + + + Standard step for scaling the bounding box. + + + Standard Scaling Step + + + + + + + + 0 + 0 + + + + Default object class for new bounding boxes. + + + Standard Object Class + + + + + + + List of object classes for autocompletion in the text field. + + + Object Classes + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + + + + 0 + 0 + + + + + 75 + true + + + + Label Settings + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Save + + + + + + + Default height of the bounding box (for picking mode). + + + Standard Bounding Box Height + + + + + + + Default width of the bounding box (for picking mode). + + + 3 + + + 500.000000000000000 + + + 0.100000000000000 + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 40 + + + + + + + + + 0 + 0 + + + + Reset to Default + + + + + + + + + + + buttonBox + accepted() + SettingsDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + SettingsDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + checkBox_colorizecolorless + toggled(bool) + lineEdit_pointcolor + setHidden(bool) + + + 199 + 246 + + + 281 + 217 + + + + + checkBox_colorizecolorless + toggled(bool) + label_pointcolor + setDisabled(bool) + + + 199 + 246 + + + 87 + 217 + + + + + diff --git a/labelCloud/view/gui.py b/labelCloud/view/gui.py index b948b3f..e218323 100644 --- a/labelCloud/view/gui.py +++ b/labelCloud/view/gui.py @@ -3,8 +3,10 @@ from PyQt5 import QtWidgets, uic, QtCore, QtGui from PyQt5.QtCore import QEvent, Qt +from PyQt5.QtWidgets import QCompleter -from control import config_parser +from control.config_manager import config +from view.settings_dialog import SettingsDialog from view.viewer import GLWidget if TYPE_CHECKING: @@ -22,8 +24,20 @@ def string_is_float(string: str, recect_negative: bool = False) -> bool: return True +def set_floor_visibility(state: bool) -> None: + print("SHOW_FLOOR: %s" % state) + config.set("USER_INTERFACE", "show_floor", str(state)) + + +def set_orientation_visibility(state: bool) -> None: + config.set("USER_INTERFACE", "show_orientation", str(state)) + + +def set_zrotation_only(state: bool) -> None: + config.set("USER_INTERFACE", "z_rotation_only", str(state)) + + class GUI(QtWidgets.QMainWindow): - VIEWING_PRECISION = int(config_parser.get_label_settings("VIEWING_PRECISION")) def __init__(self, control: 'Controller'): super(GUI, self).__init__() @@ -57,6 +71,7 @@ def __init__(self, control: 'Controller'): self.action_showfloor = self.findChild(QtWidgets.QAction, "action_showfloor") self.action_showorientation = self.findChild(QtWidgets.QAction, "action_showorientation") self.action_alignpcd = self.findChild(QtWidgets.QAction, "action_alignpcd") + self.action_change_settings = self.findChild(QtWidgets.QAction, "action_changesettings") # STATUS BAR self.status = self.findChild(QtWidgets.QStatusBar, "statusbar") @@ -128,6 +143,8 @@ def __init__(self, control: 'Controller'): # Connect all events to functions self.connect_events() + self.set_checkbox_states() # tick in menu + self.update_label_completer() # initialize label completer with classes in config # Start event cycle self.timer = QtCore.QTimer(self) @@ -184,16 +201,23 @@ def connect_events(self): self.rot_z_edit.editingFinished.connect(lambda: self.update_bbox_parameter("rot_z")) # MENU BAR - self.action_zrotation.toggled.connect(self.controller.bbox_controller.set_rotation_mode) + self.action_zrotation.toggled.connect(set_zrotation_only) self.action_deletelabels.triggered.connect(self.controller.bbox_controller.reset) - self.action_showfloor.toggled.connect(self.set_floor_visibility) - self.action_showorientation.toggled.connect(self.set_orientation_visibility) + self.action_showfloor.toggled.connect(set_floor_visibility) + self.action_showorientation.toggled.connect(set_orientation_visibility) self.action_alignpcd.toggled.connect(self.controller.align_mode.change_activation) + self.action_change_settings.triggered.connect(self.open_settings_dialog) + + def set_checkbox_states(self): + self.action_showfloor.setChecked(config.getboolean("USER_INTERFACE", "show_floor")) + self.action_showorientation.setChecked(config.getboolean("USER_INTERFACE", "show_orientation")) + self.action_zrotation.setChecked(config.getboolean("USER_INTERFACE", "z_rotation_only")) # Collect, filter and forward events to viewer def eventFilter(self, event_object, event): # Keyboard Events - if (event.type() == QEvent.KeyPress) and not self.line_edited_activated(): + # if (event.type() == QEvent.KeyPress) and (not self.line_edited_activated()): + if (event.type() == QEvent.KeyPress) and (event_object == self): # TODO: Cleanup old filter self.controller.key_press_event(event) self.update_bbox_stats(self.controller.bbox_controller.get_active_bbox()) return True # TODO: Recheck pyqt behaviour @@ -224,13 +248,11 @@ def closeEvent(self, a0: QtGui.QCloseEvent) -> None: self.timer.stop() a0.accept() - # VISUALIZATION METHODS - - def set_floor_visibility(self, state: bool) -> None: - self.glWidget.draw_floor = state + def open_settings_dialog(self): + dialog = SettingsDialog(self) + dialog.exec() - def set_orientation_visibility(self, state: bool) -> None: - self.glWidget.draw_orientation = state + # VISUALIZATION METHODS def set_pcd_label(self, pcd_name: str) -> None: self.label_curr_pcd.setText("Current: %s" % pcd_name) @@ -248,21 +270,29 @@ def update_curr_class_edit(self, force: str = None): else: self.curr_class_edit.setText(self.controller.bbox_controller.get_active_bbox().get_classname()) + def update_label_completer(self, classnames=None): + if classnames is None: + classnames = set() + classnames.update(config.getlist("LABEL", "object_classes")) + print("COMPLETER CLASSNAMES: %s" % str(classnames)) + self.curr_class_edit.setCompleter(QCompleter(classnames)) + def update_bbox_stats(self, bbox): + viewing_precision = config.getint("USER_INTERFACE", "viewing_precision") if bbox and not self.line_edited_activated(): - self.pos_x_edit.setText(str(round(bbox.get_center()[0], GUI.VIEWING_PRECISION))) - self.pos_y_edit.setText(str(round(bbox.get_center()[1], GUI.VIEWING_PRECISION))) - self.pos_z_edit.setText(str(round(bbox.get_center()[2], GUI.VIEWING_PRECISION))) + self.pos_x_edit.setText(str(round(bbox.get_center()[0], viewing_precision))) + self.pos_y_edit.setText(str(round(bbox.get_center()[1], viewing_precision))) + self.pos_z_edit.setText(str(round(bbox.get_center()[2], viewing_precision))) - self.length_edit.setText(str(round(bbox.get_dimensions()[0], GUI.VIEWING_PRECISION))) - self.width_edit.setText(str(round(bbox.get_dimensions()[1], GUI.VIEWING_PRECISION))) - self.height_edit.setText(str(round(bbox.get_dimensions()[2], GUI.VIEWING_PRECISION))) + self.length_edit.setText(str(round(bbox.get_dimensions()[0], viewing_precision))) + self.width_edit.setText(str(round(bbox.get_dimensions()[1], viewing_precision))) + self.height_edit.setText(str(round(bbox.get_dimensions()[2], viewing_precision))) self.rot_x_edit.setText(str(round(bbox.get_x_rotation(), 1))) self.rot_y_edit.setText(str(round(bbox.get_y_rotation(), 1))) self.rot_z_edit.setText(str(round(bbox.get_z_rotation(), 1))) - self.volume_label.setText(str(round(bbox.get_volume(), GUI.VIEWING_PRECISION))) + self.volume_label.setText(str(round(bbox.get_volume(), viewing_precision))) def update_bbox_parameter(self, parameter: str): str_value = None diff --git a/labelCloud/view/settings_dialog.py b/labelCloud/view/settings_dialog.py new file mode 100644 index 0000000..7cd0f90 --- /dev/null +++ b/labelCloud/view/settings_dialog.py @@ -0,0 +1,94 @@ +from PyQt5 import uic +from PyQt5.QtWidgets import QDialog + +from control.config_manager import config, config_manager +from control.label_manager import LabelManager + + +class SettingsDialog(QDialog): + + def __init__(self, parent=None): + super().__init__(parent) + self.parent_gui = parent + uic.loadUi("labelCloud/ressources/settings_interface.ui", self) + self.fill_with_current_settings() + + self.buttonBox.accepted.connect(self.save) + self.buttonBox.rejected.connect(self.chancel) + self.reset_button.clicked.connect(self.reset) + + def fill_with_current_settings(self): + # File + self.lineEdit_pointcloudfolder.setText(config.get("FILE", "pointcloud_folder")) + self.lineEdit_labelfolder.setText(config.get("FILE", "label_folder")) + + # Pointcloud + self.doubleSpinBox_pointsize.setValue(config.getfloat("POINTCLOUD", "POINT_SIZE")) + self.lineEdit_pointcolor.setText(config["POINTCLOUD"]["colorless_color"]) + self.checkBox_colorizecolorless.setChecked(config.getboolean("POINTCLOUD", "colorless_colorize")) + self.doubleSpinBox_standardtranslation.setValue(config.getfloat("POINTCLOUD", "std_translation")) + self.doubleSpinBox_standardzoom.setValue(config.getfloat("POINTCLOUD", "std_zoom")) + + # Label + self.comboBox_labelformat.addItems(LabelManager.LABEL_FORMATS) # TODO: Fix visualization + self.comboBox_labelformat.setCurrentText(config.get("LABEL", "label_format")) + self.plainTextEdit_objectclasses.setPlainText(config.get("LABEL", "object_classes")) + self.lineEdit_standardobjectclass.setText(config.get("LABEL", "std_object_class")) + self.spinBox_exportprecision.setValue(config.getint("LABEL", "export_precision")) + self.doubleSpinBox_minbboxdimensions.setValue(config.getfloat("LABEL", "min_boundingbox_dimension")) + self.doubleSpinBox_stdbboxlength.setValue(config.getfloat("LABEL", "std_boundingbox_length")) + self.doubleSpinBox_stdbboxwidth.setValue(config.getfloat("LABEL", "std_boundingbox_width")) + self.doubleSpinBox_stdbboxheight.setValue(config.getfloat("LABEL", "std_boundingbox_height")) + self.doubleSpinBox_stdbboxtranslation.setValue(config.getfloat("LABEL", "std_translation")) + self.doubleSpinBox_stdbboxrotation.setValue(config.getfloat("LABEL", "std_rotation")) + self.doubleSpinBox_stdbboxscaling.setValue(config.getfloat("LABEL", "std_scaling")) + + # User Interface + self.checkBox_zrotationonly.setChecked(config.getboolean("USER_INTERFACE", "z_rotation_only")) + self.checkBox_showfloor.setChecked(config.getboolean("USER_INTERFACE", "show_floor")) + self.checkBox_showbboxorientation.setChecked(config.getboolean("USER_INTERFACE", "show_orientation")) + self.spinBox_viewingprecision.setValue(config.getint("USER_INTERFACE", "viewing_precision")) + self.lineEdit_backgroundcolor.setText(config.get("USER_INTERFACE", "background_color")) + + def save(self) -> None: + # File + config["FILE"]["pointcloud_folder"] = self.lineEdit_pointcloudfolder.text() + config["FILE"]["label_folder"] = self.lineEdit_labelfolder.text() + + # Pointcloud + config["POINTCLOUD"]["point_size"] = str(self.doubleSpinBox_pointsize.value()) + config["POINTCLOUD"]["colorless_color"] = self.lineEdit_pointcolor.text() + config["POINTCLOUD"]["colorless_colorize"] = str(self.checkBox_colorizecolorless.isChecked()) + config["POINTCLOUD"]["std_translation"] = str(self.doubleSpinBox_standardtranslation.value()) + config["POINTCLOUD"]["std_zoom"] = str(self.doubleSpinBox_standardzoom.value()) + + # Label + config["LABEL"]["label_format"] = self.comboBox_labelformat.currentText() + config["LABEL"]["object_classes"] = self.plainTextEdit_objectclasses.toPlainText() + config["LABEL"]["std_object_class"] = self.lineEdit_standardobjectclass.text() + config["LABEL"]["export_precision"] = str(self.spinBox_exportprecision.value()) + config["LABEL"]["min_boundingbox_dimension"] = str(self.doubleSpinBox_minbboxdimensions.value()) + config["LABEL"]["std_boundingbox_length"] = str(self.doubleSpinBox_stdbboxlength.value()) + config["LABEL"]["std_boundingbox_width"] = str(self.doubleSpinBox_stdbboxwidth.value()) + config["LABEL"]["std_boundingbox_height"] = str(self.doubleSpinBox_stdbboxheight.value()) + config["LABEL"]["std_translation"] = str(self.doubleSpinBox_stdbboxtranslation.value()) + config["LABEL"]["std_rotation"] = str(self.doubleSpinBox_stdbboxrotation.value()) + config["LABEL"]["std_scaling"] = str(self.doubleSpinBox_stdbboxscaling.value()) + + # User Interface + config["USER_INTERFACE"]["z_rotation_only"] = str(self.checkBox_zrotationonly.isChecked()) + config["USER_INTERFACE"]["show_floor"] = str(self.checkBox_showfloor.isChecked()) + config["USER_INTERFACE"]["show_orientation"] = str(self.checkBox_showbboxorientation.isChecked()) + config["USER_INTERFACE"]["background_color"] = self.lineEdit_backgroundcolor.text() + config["USER_INTERFACE"]["viewing_precision"] = str(self.spinBox_viewingprecision.value()) + + config_manager.write_into_file() + self.parent_gui.set_checkbox_states() + print("Saved and activated new configuration!") + + def reset(self): + config_manager.reset_to_default() + self.fill_with_current_settings() + + def chancel(self) -> None: + print("Settings dialog was chanceled!") diff --git a/labelCloud/view/viewer.py b/labelCloud/view/viewer.py index f64aff6..76b4658 100644 --- a/labelCloud/view/viewer.py +++ b/labelCloud/view/viewer.py @@ -6,7 +6,7 @@ from PyQt5 import QtOpenGL, QtGui from utils import oglhelper -from control import config_parser +from control.config_manager import config from control.alignmode import AlignMode from control.bbox_controller import BoundingBoxController from control.pcd_manager import PointCloudManger @@ -30,8 +30,6 @@ def __init__(self, parent=None): self.bbox_controller = None # Objects to be drawn - self.draw_floor = config_parser.get_app_settings("SHOW_FLOOR") - self.draw_orientation = config_parser.get_app_settings("SHOW_ORIENTATION") self.crosshair_pos = None self.crosshair_col = (0, 1, 0, 1) self.selected_side_vertices = [] @@ -47,7 +45,8 @@ def set_bbox_controller(self, bbox_controller: BoundingBoxController): # QGLWIDGET METHODS def initializeGL(self): - bg_color = [int(fl_color) for fl_color in config_parser.get_app_settings("BACKGROUND_COLOR")] # floats to ints + bg_color = [int(fl_color) for fl_color in + config.getlist("USER_INTERFACE", "BACKGROUND_COLOR")] # floats to ints self.qglClearColor(QtGui.QColor(*bg_color)) # screen background color GL.glEnable(GL.GL_DEPTH_TEST) # for visualization of depth GL.glEnable(GL.GL_BLEND) # enable transparency @@ -79,7 +78,8 @@ def paintGL(self): GL.glDepthMask(GL.GL_FALSE) # Do not write decoration and preview elements in depth buffer # Draw floor net - if self.draw_floor: + # if self.draw_floor: + if config.getboolean("USER_INTERFACE", "show_floor"): oglhelper.draw_xy_plane(self.pcd_controller.get_pointcloud()) # Draw crosshair/ cursor in 3D world @@ -103,7 +103,7 @@ def paintGL(self): # Draw active bbox if self.bbox_controller.has_active_bbox(): self.bbox_controller.get_active_bbox().draw_bbox(highlighted=True) - if self.draw_orientation: + if config.getboolean("USER_INTERFACE", "show_orientation"): self.bbox_controller.get_active_bbox().draw_orientation() # Draw labeled bboxes