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
-
-
@@ -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