diff --git a/config.ini b/config.ini
index a063f5e..8929a92 100644
--- a/config.ini
+++ b/config.ini
@@ -55,5 +55,4 @@ viewing_precision = 2
near_plane = 0.1
far_plane = 300
; keep last perspective between point clouds
-keep_perspective = False
-
+keep_perspective = False
\ No newline at end of file
diff --git a/labelCloud/control/alignmode.py b/labelCloud/control/alignmode.py
index ef3583a..2129180 100644
--- a/labelCloud/control/alignmode.py
+++ b/labelCloud/control/alignmode.py
@@ -3,22 +3,22 @@
three points on the plane that serves as the ground. Then the old point cloud will be
saved up and the aligned current will overwrite the old.
"""
-from typing import Union, TYPE_CHECKING
+from typing import TYPE_CHECKING, Union
import numpy as np
-
import utils.oglhelper as ogl
+
from .pcd_manager import PointCloudManger
if TYPE_CHECKING:
from view.gui import GUI
-class AlignMode:
- def __init__(self, pcd_manager: PointCloudManger):
+class AlignMode(object):
+ def __init__(self, pcd_manager: PointCloudManger) -> None:
self.pcd_manager = pcd_manager
self.view: Union[GUI, None] = None
- self.activated = False
+ self.is_active = False
self.point_color = (1, 1, 0, 1)
self.area_color = (1, 1, 0, 0.6)
self.plane1 = None
@@ -28,40 +28,37 @@ def __init__(self, pcd_manager: PointCloudManger):
self.tmp_p2 = None
self.tmp_p3 = None
- def set_view(self, view: "GUI"):
+ def set_view(self, view: "GUI") -> None:
self.view = view
self.view.glWidget.align_mode = self
- def is_active(self):
- return self.activated
-
- def change_activation(self, force=None):
+ def change_activation(self, force=None) -> None:
if force is not None:
- self.activated = force
- elif self.activated:
- self.activated = False
+ self.is_active = force
+ elif self.is_active:
+ self.is_active = False
self.reset()
else:
- self.activated = True
+ self.is_active = True
- if self.activated:
+ if self.is_active:
self.view.update_status(
"Select three points on the plane that should be the floor.",
"alignment",
)
- self.view.action_alignpcd.setChecked(self.activated)
+ self.view.action_alignpcd.setChecked(self.is_active)
self.view.activate_draw_modes(
- not self.activated
+ not self.is_active
) # Prevent bbox drawing while aligning
- print("Alignmode was changed to %s!" % self.activated)
+ print(f"Alignmode was changed to {self.is_active}!")
- def reset(self, points_only: bool = False):
+ def reset(self, points_only: bool = False) -> None:
self.plane1, self.plane2, self.plane3 = (None, None, None)
self.tmp_p2, self.tmp_p3 = (None, None)
if not points_only:
self.change_activation(force=False)
- def register_point(self, new_point):
+ def register_point(self, new_point) -> None:
if self.plane1 is None:
self.plane1 = new_point
elif not self.plane2:
@@ -75,13 +72,13 @@ def register_point(self, new_point):
else:
print("Cannot register point.")
- def register_tmp_point(self, new_tmp_point):
+ def register_tmp_point(self, new_tmp_point) -> None:
if self.plane1 and (not self.plane2):
self.tmp_p2 = new_tmp_point
elif self.plane2 and (not self.plane3):
self.tmp_p3 = new_tmp_point
- def draw_preview(self):
+ def draw_preview(self) -> None:
if not self.plane3:
if self.plane1:
ogl.draw_points([self.plane1], color=self.point_color)
@@ -104,7 +101,6 @@ def draw_preview(self):
)
elif self.plane1 and self.plane2 and self.plane3:
-
ogl.draw_points(
[self.plane1, self.plane2, self.plane3], color=self.point_color
)
@@ -112,7 +108,7 @@ def draw_preview(self):
[self.plane1, self.plane2, self.plane3], color=self.area_color
)
- def calculate_angles(self):
+ def calculate_angles(self) -> None:
# Calculate plane normal with self.plane1 as origin
plane_normal = np.cross(
np.subtract(self.plane2, self.plane1), np.subtract(self.plane3, self.plane1)
diff --git a/labelCloud/control/bbox_controller.py b/labelCloud/control/bbox_controller.py
index bc29a12..2ccf395 100644
--- a/labelCloud/control/bbox_controller.py
+++ b/labelCloud/control/bbox_controller.py
@@ -4,13 +4,12 @@
Bounding Box Management: adding, selecting updating, deleting bboxes;
Possible Active Bounding Box Manipulations: rotation, translation, scaling
"""
-from typing import TYPE_CHECKING, Union, List
+from typing import TYPE_CHECKING, List, Optional, Union
import numpy as np
-
-
-from utils import oglhelper
from model.bbox import BBox
+from utils import oglhelper
+
from .config_manager import config
if TYPE_CHECKING:
@@ -46,41 +45,41 @@ def wrapper(*args, **kwargs):
return wrapper
-class BoundingBoxController:
+class BoundingBoxController(object):
STD_SCALING = config.getfloat("LABEL", "std_scaling")
- def __init__(self):
+ def __init__(self) -> None:
self.view = None
self.bboxes = []
self.active_bbox_id = -1 # -1 means zero bboxes
self.pcdc = None
# GETTERS
- def has_active_bbox(self):
+ def has_active_bbox(self) -> bool:
return 0 <= self.active_bbox_id < self.get_no_of_bboxes()
- def get_active_bbox(self) -> Union[BBox, None]:
+ def get_active_bbox(self) -> Optional[BBox]:
if self.has_active_bbox():
return self.bboxes[self.active_bbox_id]
else:
return None
- def get_bboxes(self):
+ def get_bboxes(self) -> List[BBox]:
return self.bboxes
- def get_no_of_bboxes(self):
+ def get_no_of_bboxes(self) -> int:
return len(self.bboxes)
@has_active_bbox_decorator
- def get_classname(self):
+ def get_classname(self) -> str:
return self.get_active_bbox().get_classname()
# SETTERS
- def set_view(self, view: "GUI"):
+ def set_view(self, view: "GUI") -> None:
self.view = view
- def add_bbox(self, bbox: BBox):
+ def add_bbox(self, bbox: BBox) -> None:
if isinstance(bbox, BBox):
self.bboxes.append(bbox)
self.set_active_bbox(self.bboxes.index(bbox))
@@ -88,12 +87,12 @@ def add_bbox(self, bbox: BBox):
"Bounding Box added, it can now be corrected.", mode="correction"
)
- def update_bbox(self, bbox_id: int, bbox: BBox):
+ def update_bbox(self, bbox_id: int, bbox: BBox) -> None:
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: int):
+ def delete_bbox(self, bbox_id: int) -> None:
if 0 <= bbox_id < len(self.bboxes):
del self.bboxes[bbox_id]
if bbox_id == self.active_bbox_id:
@@ -101,11 +100,11 @@ def delete_bbox(self, bbox_id: int):
else:
self.update_label_list()
- def delete_current_bbox(self):
+ def delete_current_bbox(self) -> None:
selected_item_id = self.view.label_list.currentRow()
self.delete_bbox(selected_item_id)
- def set_active_bbox(self, bbox_id: int):
+ def set_active_bbox(self, bbox_id: int) -> None:
if 0 <= bbox_id < len(self.bboxes):
self.active_bbox_id = bbox_id
self.update_all()
@@ -116,31 +115,31 @@ def set_active_bbox(self, bbox_id: int):
self.deselect_bbox()
@has_active_bbox_decorator
- def set_classname(self, new_class: str):
+ def set_classname(self, new_class: str) -> None:
self.get_active_bbox().set_classname(new_class)
self.update_label_list()
@has_active_bbox_decorator
- def set_center(self, cx: float, cy: float, cz: float):
+ def set_center(self, cx: float, cy: float, cz: float) -> None:
self.get_active_bbox().center = (cx, cy, cz)
- def set_bboxes(self, bboxes: List[BBox]):
+ def set_bboxes(self, bboxes: List[BBox]) -> None:
self.bboxes = bboxes
self.deselect_bbox()
self.update_label_list()
- def reset(self):
+ def reset(self) -> None:
self.deselect_bbox()
self.set_bboxes([])
- def deselect_bbox(self):
+ def deselect_bbox(self) -> None:
self.active_bbox_id = -1
self.update_all()
self.view.update_status("", mode="navigation")
# MANIPULATORS
@has_active_bbox_decorator
- def update_position(self, axis: str, value: float):
+ def update_position(self, axis: str, value: float) -> None:
if axis == "pos_x":
self.get_active_bbox().set_x_translation(value)
elif axis == "pos_y":
@@ -151,7 +150,7 @@ def update_position(self, axis: str, value: float):
raise Exception("Wrong axis describtion.")
@has_active_bbox_decorator
- def update_dimension(self, dimension: str, value: float):
+ def update_dimension(self, dimension: str, value: float) -> None:
if dimension == "length":
self.get_active_bbox().set_length(value)
elif dimension == "width":
@@ -162,7 +161,7 @@ def update_dimension(self, dimension: str, value: float):
raise Exception("Wrong dimension describtion.")
@has_active_bbox_decorator
- def update_rotation(self, axis: str, value: float):
+ def update_rotation(self, axis: str, value: float) -> None:
if axis == "rot_x":
self.get_active_bbox().set_x_rotation(value)
elif axis == "rot_y":
@@ -174,7 +173,7 @@ def update_rotation(self, axis: str, value: float):
@only_zrotation_decorator
@has_active_bbox_decorator
- def rotate_around_x(self, dangle: float = None, clockwise: bool = False):
+ def rotate_around_x(self, dangle: float = None, clockwise: bool = False) -> None:
dangle = dangle or config.getfloat("LABEL", "std_rotation")
if clockwise:
dangle *= -1
@@ -184,7 +183,7 @@ def rotate_around_x(self, dangle: float = None, clockwise: bool = False):
@only_zrotation_decorator
@has_active_bbox_decorator
- def rotate_around_y(self, dangle: float = None, clockwise: bool = False):
+ def rotate_around_y(self, dangle: float = None, clockwise: bool = False) -> None:
dangle = dangle or config.getfloat("LABEL", "std_rotation")
if clockwise:
dangle *= -1
@@ -195,7 +194,7 @@ def rotate_around_y(self, dangle: float = None, clockwise: bool = False):
@has_active_bbox_decorator
def rotate_around_z(
self, dangle: float = None, clockwise: bool = False, absolute: bool = False
- ):
+ ) -> None:
dangle = dangle or config.getfloat("LABEL", "std_rotation")
if clockwise:
dangle *= -1
@@ -210,7 +209,7 @@ def rotate_around_z(
@has_active_bbox_decorator
def rotate_with_mouse(
self, x_angle: float, y_angle: float
- ): # TODO: Make more intuitive
+ ) -> None: # TODO: Make more intuitive
# Get bbox perspective
pcd_z_rotation = self.pcdc.get_pointcloud().rot_z
bbox_z_rotation = self.get_active_bbox().get_z_rotation()
@@ -224,7 +223,7 @@ def rotate_with_mouse(
self.rotate_around_z(x_angle)
@has_active_bbox_decorator
- def translate_along_x(self, distance: float = None, left: bool = False):
+ def translate_along_x(self, distance: float = None, left: bool = False) -> None:
distance = distance or config.getfloat("LABEL", "std_translation")
if left:
distance *= -1
@@ -237,7 +236,7 @@ def translate_along_x(self, distance: float = None, left: bool = False):
)
@has_active_bbox_decorator
- def translate_along_y(self, distance: float = None, forward: bool = False):
+ def translate_along_y(self, distance: float = None, forward: bool = False) -> None:
distance = distance or config.getfloat("LABEL", "std_translation")
if forward:
distance *= -1
@@ -250,7 +249,7 @@ def translate_along_y(self, distance: float = None, forward: bool = False):
)
@has_active_bbox_decorator
- def translate_along_z(self, distance: float = None, down: bool = False):
+ def translate_along_z(self, distance: float = None, down: bool = False) -> None:
distance = distance or config.getfloat("LABEL", "std_translation")
if down:
distance *= -1
diff --git a/labelCloud/control/config_manager.py b/labelCloud/control/config_manager.py
index 70d23ca..721cb36 100644
--- a/labelCloud/control/config_manager.py
+++ b/labelCloud/control/config_manager.py
@@ -1,7 +1,5 @@
"""Load configuration from .ini file."""
import configparser
-
-
import os
from typing import List
@@ -27,21 +25,21 @@ class ConfigManager(object):
PATH_TO_CONFIG = "config.ini"
PATH_TO_DEFAULT_CONFIG = "ressources/default_config.ini"
- def __init__(self):
+ def __init__(self) -> None:
self.config = ExtendedConfigParser(comment_prefixes="/", allow_no_value=True)
self.read_from_file()
- def read_from_file(self):
+ def read_from_file(self) -> None:
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):
+ def write_into_file(self) -> None:
with open(ConfigManager.PATH_TO_CONFIG, "w") as configfile:
self.config.write(configfile, space_around_delimiters=True)
- def reset_to_default(self):
+ def reset_to_default(self) -> None:
self.config.read(ConfigManager.PATH_TO_DEFAULT_CONFIG)
def get_file_settings(self, key: str) -> str:
diff --git a/labelCloud/control/controller.py b/labelCloud/control/controller.py
index bf209b7..1b94ae0 100644
--- a/labelCloud/control/controller.py
+++ b/labelCloud/control/controller.py
@@ -1,11 +1,10 @@
from typing import Union
-from PyQt5 import QtGui, QtCore
-
-
+from PyQt5 import QtCore, QtGui
from utils import oglhelper
from model.bbox import BBox
from view.gui import GUI
+
from .alignmode import AlignMode
from .bbox_controller import BoundingBoxController
from .drawing_manager import DrawingManager
@@ -15,7 +14,7 @@
class Controller:
MOVEMENT_THRESHOLD = 0.1
- def __init__(self):
+ def __init__(self) -> None:
"""Initializes all controllers and managers."""
self.view: Union["GUI", None] = None
self.pcd_manager = PointCloudManger()
@@ -35,7 +34,7 @@ def __init__(self):
self.side_mode = False
self.selected_side = None
- def startup(self, view: "GUI"):
+ def startup(self, view: "GUI") -> None:
"""Sets the view in all controllers and dependent modules; Loads labels from file."""
self.view = view
self.bbox_controller.set_view(self.view)
@@ -49,14 +48,14 @@ def startup(self, view: "GUI"):
self.pcd_manager.read_pointcloud_folder()
self.next_pcd(save=False)
- def loop_gui(self):
+ def loop_gui(self) -> None:
"""Function collection called during each event loop iteration."""
self.set_crosshair()
self.set_selected_side()
self.view.glWidget.updateGL()
# POINT CLOUD METHODS
- def next_pcd(self, save: bool = True):
+ def next_pcd(self, save: bool = True) -> None:
if save:
self.save()
if self.pcd_manager.pcds_left():
@@ -67,7 +66,7 @@ def next_pcd(self, save: bool = True):
self.view.update_progress(len(self.pcd_manager.pcds))
self.view.button_next_pcd.setEnabled(False)
- def prev_pcd(self):
+ def prev_pcd(self) -> None:
self.save()
if self.pcd_manager.current_id > 0:
self.pcd_manager.get_prev_pcd()
@@ -75,18 +74,18 @@ def prev_pcd(self):
self.bbox_controller.set_bboxes(self.pcd_manager.get_labels_from_file())
# CONTROL METHODS
- def save(self):
+ def save(self) -> None:
"""Saves all bounding boxes in the label file."""
self.pcd_manager.save_labels_into_file(self.bbox_controller.get_bboxes())
- def reset(self):
+ def reset(self) -> None:
"""Resets the controllers and bounding boxes from the current screen."""
self.bbox_controller.reset()
self.drawing_mode.reset()
self.align_mode.reset()
# CORRECTION METHODS
- def set_crosshair(self):
+ def set_crosshair(self) -> None:
"""Sets the crosshair position in the glWidget to the current cursor position."""
if self.curr_cursor_pos:
self.view.glWidget.crosshair_col = [0, 1, 0]
@@ -95,7 +94,7 @@ def set_crosshair(self):
self.curr_cursor_pos.y(),
)
- def set_selected_side(self):
+ def set_selected_side(self) -> None:
"""Sets the currently hovered bounding box side in the glWidget."""
if (
(not self.side_mode)
@@ -124,7 +123,7 @@ def set_selected_side(self):
self.view.glWidget.selected_side_vertices = []
# EVENT PROCESSING
- def mouse_clicked(self, a0: QtGui.QMouseEvent):
+ def mouse_clicked(self, a0: QtGui.QMouseEvent) -> None:
"""Triggers actions when the user clicks the mouse."""
self.last_cursor_pos = a0.pos()
@@ -135,7 +134,7 @@ def mouse_clicked(self, a0: QtGui.QMouseEvent):
):
self.drawing_mode.register_point(a0.x(), a0.y(), correction=True)
- elif self.align_mode.is_active() and (not self.ctrl_pressed):
+ elif self.align_mode.is_active and (not self.ctrl_pressed):
self.align_mode.register_point(
self.view.glWidget.get_world_coords(a0.x(), a0.y(), correction=False)
)
@@ -143,11 +142,11 @@ def mouse_clicked(self, a0: QtGui.QMouseEvent):
elif self.selected_side:
self.side_mode = True
- def mouse_double_clicked(self, a0: QtGui.QMouseEvent):
+ def mouse_double_clicked(self, a0: QtGui.QMouseEvent) -> None:
"""Triggers actions when the user double clicks the mouse."""
self.bbox_controller.select_bbox_by_ray(a0.x(), a0.y())
- def mouse_move_event(self, a0: QtGui.QMouseEvent):
+ def mouse_move_event(self, a0: QtGui.QMouseEvent) -> None:
"""Triggers actions when the user moves the mouse."""
self.curr_cursor_pos = a0.pos() # Updates the current mouse cursor position
@@ -157,7 +156,7 @@ def mouse_move_event(self, a0: QtGui.QMouseEvent):
a0.x(), a0.y(), correction=True, is_temporary=True
)
- elif self.align_mode.is_active() and (not self.ctrl_pressed):
+ elif self.align_mode.is_active and (not self.ctrl_pressed):
self.align_mode.register_tmp_point(
self.view.glWidget.get_world_coords(a0.x(), a0.y(), correction=False)
)
@@ -171,7 +170,7 @@ def mouse_move_event(self, a0: QtGui.QMouseEvent):
if (
self.ctrl_pressed
and (not self.drawing_mode.is_active())
- and (not self.align_mode.is_active())
+ and (not self.align_mode.is_active)
):
if a0.buttons() & QtCore.Qt.LeftButton: # bbox rotation
self.bbox_controller.rotate_with_mouse(-dx, -dy)
@@ -196,9 +195,8 @@ def mouse_move_event(self, a0: QtGui.QMouseEvent):
self.scroll_mode = False
self.last_cursor_pos = a0.pos()
- def mouse_scroll_event(self, a0: QtGui.QWheelEvent):
+ def mouse_scroll_event(self, a0: QtGui.QWheelEvent) -> None:
"""Triggers actions when the user scrolls the mouse wheel."""
-
if self.selected_side:
self.side_mode = True
@@ -212,9 +210,8 @@ def mouse_scroll_event(self, a0: QtGui.QWheelEvent):
self.pcd_manager.zoom_into(a0.angleDelta().y())
self.scroll_mode = True
- def key_press_event(self, a0: QtGui.QKeyEvent):
+ def key_press_event(self, a0: QtGui.QKeyEvent) -> None:
"""Triggers actions when the user presses a key."""
-
# Reset position to intial value
if a0.key() == QtCore.Qt.Key_Control:
self.ctrl_pressed = True
@@ -235,7 +232,7 @@ def key_press_event(self, a0: QtGui.QKeyEvent):
if self.drawing_mode.is_active():
self.drawing_mode.reset()
print("Resetted drawn points!")
- elif self.align_mode.is_active():
+ elif self.align_mode.is_active:
self.align_mode.reset()
print("Resetted selected points!")
@@ -277,7 +274,7 @@ def key_press_event(self, a0: QtGui.QKeyEvent):
# move down
self.bbox_controller.translate_along_z(down=True)
- def key_release_event(self, a0: QtGui.QKeyEvent):
+ def key_release_event(self, a0: QtGui.QKeyEvent) -> None:
"""Triggers actions when the user releases a key."""
if a0.key() == QtCore.Qt.Key_Control:
self.ctrl_pressed = False
diff --git a/labelCloud/control/drawing_manager.py b/labelCloud/control/drawing_manager.py
index ccbddb9..a68e1c7 100644
--- a/labelCloud/control/drawing_manager.py
+++ b/labelCloud/control/drawing_manager.py
@@ -1,43 +1,31 @@
-from abc import ABCMeta, abstractmethod, ABC
-from typing import Union, List, TYPE_CHECKING
+from typing import TYPE_CHECKING, Union
-import numpy as np
-
-import utils.math3d as math3d
-import utils.oglhelper as ogl
-from model.bbox import BBox
from .bbox_controller import BoundingBoxController
-from .config_manager import config
+from .drawing_strategies import IDrawingStrategy
if TYPE_CHECKING:
from view.gui import GUI
-class DrawingManager:
- def __init__(self, bbox_controller: BoundingBoxController):
+class DrawingManager(object):
+ def __init__(self, bbox_controller: BoundingBoxController) -> None:
self.bbox_controller = bbox_controller
self.view: Union["GUI", None] = None
self.drawing_strategy: Union[IDrawingStrategy, None] = None
- def set_view(self, view: "GUI"):
+ def set_view(self, view: "GUI") -> None:
self.view = view
self.view.glWidget.drawing_mode = self
def is_active(self) -> bool:
return isinstance(self.drawing_strategy, IDrawingStrategy)
- def is_mode(self, mode: str = None) -> bool:
- if self.is_active():
- return self.drawing_strategy.__class__.__name__ == mode
- else:
- return False
-
def has_preview(self) -> bool:
if self.is_active():
return self.drawing_strategy.__class__.PREVIEW
- def set_drawing_strategy(self, strategy: str) -> None:
- if self.is_active() and self.is_mode(strategy):
+ def set_drawing_strategy(self, strategy: IDrawingStrategy) -> None:
+ if self.is_active() and self.drawing_strategy == strategy:
self.reset()
print("Deactivated drawing!")
else:
@@ -45,32 +33,12 @@ def set_drawing_strategy(self, strategy: str) -> None:
self.reset()
print("Resetted previous active drawing mode!")
- if strategy == "PickingStrategy":
- self.drawing_strategy = PickingStrategy(self.view)
- self.view.update_status(
- "Please pick the location for the bounding box front center.",
- mode="drawing",
- )
- elif strategy == "RectangleStrategy":
- self.drawing_strategy = RectangleStrategy(self.view)
- self.view.update_status(
- "Please select a corner for the 2D bounding box.", mode="drawing"
- )
- elif strategy == "SpanStrategy":
- self.drawing_strategy = SpanStrategy(self.view)
- self.view.update_status(
- "Begin by selecting a vertex of the bounding box.", mode="drawing"
- )
+ self.drawing_strategy = strategy
def register_point(
self, x, y, correction: bool = False, is_temporary: bool = False
) -> None:
- if self.is_mode("RectangleStrategy"):
- world_point = self.view.glWidget.get_world_coords(x, y, z=0)
- else:
- world_point = self.view.glWidget.get_world_coords(
- x, y, correction=correction
- )
+ world_point = self.view.glWidget.get_world_coords(x, y, correction=correction)
if is_temporary:
self.drawing_strategy.register_tmp_point(world_point)
else:
@@ -85,291 +53,8 @@ def register_point(
def draw_preview(self) -> None:
self.drawing_strategy.draw_preview()
- def reset(self, points_only: bool = False):
+ def reset(self, points_only: bool = False) -> None:
if self.is_active():
self.drawing_strategy.reset()
if not points_only:
self.drawing_strategy = None
-
-
-class IDrawingStrategy:
- __metaclass__ = ABCMeta
- POINTS_NEEDED: int
- PREVIEW: bool = False
-
- def __init__(self, view: "GUI"):
- self.view = view
- self.points_registered = 0
- self.point_1 = None
-
- def is_bbox_finished(self) -> bool:
- return self.points_registered >= self.__class__.POINTS_NEEDED
-
- @abstractmethod
- def register_point(self, new_point: List[float]) -> None:
- raise NotImplementedError
-
- def register_tmp_point(self, new_tmp_point: List[float]) -> None:
- pass
-
- def register_scrolling(self, distance: float) -> None:
- pass
-
- @abstractmethod
- def get_bbox(self) -> BBox:
- raise NotImplementedError
-
- def draw_preview(self) -> None:
- pass
-
- def reset(self) -> None:
- self.points_registered = 0
- self.point_1 = None
-
-
-class PickingStrategy(IDrawingStrategy, ABC):
- POINTS_NEEDED = 1
- PREVIEW = True
-
- def __init__(self, view: "GUI"):
- super().__init__(view)
- print("Enabled drawing mode.")
- self.tmp_p1 = None
- self.bbox_z_rotation = 0
-
- def register_point(self, new_point: List[float]) -> None:
- self.point_1 = new_point
- print("registered point " + str(self.point_1))
- self.points_registered += 1
-
- def register_tmp_point(self, new_tmp_point: List[float]) -> None:
- self.tmp_p1 = new_tmp_point
-
- def register_scrolling(self, distance: float) -> None:
- self.bbox_z_rotation += distance // 30
-
- def draw_preview(self) -> None: # TODO: Refactor
- if 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: # 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
-
- def reset(self) -> None:
- super().reset()
- self.tmp_p1 = None
- self.view.button_activate_picking.setChecked(False)
-
-
-class SpanStrategy(IDrawingStrategy, ABC):
- POINTS_NEEDED = 4
- PREVIEW = True
- CORRECTION = False # Increases dimensions after drawing
-
- def __init__(self, view: "GUI"):
- super().__init__(view)
- print("Enabled spanning mode.")
- self.preview_color = (1, 1, 0, 1)
- self.point_2 = None # second edge
- self.point_3 = None # width
- self.point_4 = None # height
- self.tmp_p2 = None # tmp points for preview
- self.tmp_p3 = None
- self.tmp_p4 = None
- self.p1_w = None # p1 + dir_vector
- self.p2_w = None # p2 + dir_vector
- self.dir_vector = None # p1 + dir_vector
-
- def reset(self) -> None:
- super().reset()
- self.point_2, self.point_3, self.point_4 = (None, None, None)
- self.tmp_p2, self.tmp_p3, self.tmp_p4, self.p1_w, self.p2_w = (
- None,
- None,
- None,
- None,
- None,
- )
- self.view.button_activate_spanning.setChecked(False)
-
- def register_point(self, new_point: List[float]) -> None:
- if self.point_1 is None:
- self.point_1 = new_point
- self.view.update_status(
- "Select a point representing the length of the bounding box."
- )
- elif not self.point_2:
- self.point_2 = new_point
- self.view.update_status(
- "Select any point for the depth of the bounding box."
- )
- elif not self.point_3:
- self.point_3 = new_point
- self.view.update_status(
- "Select any point for the height of the bounding box."
- )
- elif not self.point_4:
- self.point_4 = new_point
- else:
- print("Cannot register point.")
- self.points_registered += 1
-
- def register_tmp_point(self, new_tmp_point: List[float]) -> None:
- if self.point_1 and (not self.point_2):
- self.tmp_p2 = new_tmp_point
- elif self.point_2 and (not self.point_3):
- self.tmp_p3 = new_tmp_point
- elif self.point_3:
- self.tmp_p4 = new_tmp_point
-
- def get_bbox(self) -> BBox:
- length = math3d.vector_length(np.subtract(self.point_1, self.point_2))
- width = math3d.vector_length(self.dir_vector)
- height = self.point_4[2] - self.point_1[2] # can also be negative
-
- line_center = np.add(self.point_1, self.point_2) / 2
- area_center = np.add(line_center * 2, self.dir_vector) / 2
- center = np.add(area_center, [0, 0, height / 2])
-
- # Calculating z-rotation
- len_vec_2d = np.subtract(self.point_1, self.point_2)
- z_angle = np.arctan(len_vec_2d[1] / len_vec_2d[0])
-
- if SpanStrategy.CORRECTION:
- length *= 1.1
- width *= 1.1
- height *= 1.1
-
- bbox = BBox(*center, length=length, width=width, height=abs(height))
- bbox.set_z_rotation(math3d.radians_to_degrees(z_angle))
-
- 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))
- return bbox
-
- def draw_preview(self) -> None:
- if not self.tmp_p4:
- if self.point_1:
- ogl.draw_points([self.point_1], color=self.preview_color)
-
- if self.point_1 and (self.point_2 or self.tmp_p2):
- if self.point_2:
- self.tmp_p2 = self.point_2
- ogl.draw_points([self.tmp_p2], color=(1, 1, 0, 1))
- ogl.draw_lines([self.point_1, self.tmp_p2], color=self.preview_color)
-
- if self.point_1 and self.point_2 and (self.tmp_p3 or self.point_3):
- if self.point_3:
- self.tmp_p3 = self.point_3
- # Get x-y-aligned vector from line to point with intersection
- self.dir_vector, intersection = math3d.get_line_perpendicular(
- self.point_1, self.point_2, self.tmp_p3
- )
- # Calculate projected vertices
- self.p1_w = np.add(self.point_1, self.dir_vector)
- self.p2_w = np.add(self.point_2, self.dir_vector)
- ogl.draw_points([self.p1_w, self.p2_w], color=self.preview_color)
- ogl.draw_rectangles(
- [self.point_1, self.point_2, self.p2_w, self.p1_w],
- color=(1, 1, 0, 0.5),
- )
-
- elif (
- self.point_1
- and self.point_2
- and self.point_3
- and self.tmp_p4
- and (not self.point_4)
- ):
- height1 = self.tmp_p4[2] - self.point_1[2]
- p1_t = np.add(self.point_1, [0, 0, height1])
- p2_t = np.add(self.point_2, [0, 0, height1])
- p1_wt = np.add(self.p1_w, [0, 0, height1])
- p2_wt = np.add(self.p2_w, [0, 0, height1])
-
- ogl.draw_cuboid(
- [
- self.p1_w,
- self.point_1,
- self.point_2,
- self.p2_w,
- p1_wt,
- p1_t,
- p2_t,
- p2_wt,
- ],
- color=(1, 1, 0, 0.5),
- draw_vertices=True,
- vertex_color=self.preview_color,
- )
-
-
-class RectangleStrategy(IDrawingStrategy, ABC):
- POINTS_NEEDED = 3
- PREVIEW = True
-
- def __init__(self, view: "GUI"):
- super().__init__(view)
- self.point_2 = None
- self.tmp_p2 = None
-
- def register_point(self, new_point: List[float]):
- if self.point_1 is None:
- self.point_1 = new_point
- self.view.update_status("Select the opposing point of the 2D bounding box.")
- elif not self.point_2:
- self.point_2 = new_point
- else:
- print("Cannot register point.")
- self.points_registered += 1
-
- def register_tmp_point(self, new_tmp_point: List[float]):
- if self.point_1 and (not self.point_2):
- self.tmp_p2 = new_tmp_point
-
- def get_bbox(self):
- # self.view.controller.pcd_manager.
- pass
-
- def draw_preview(self):
- if self.point_1:
- ogl.draw_points([self.point_1])
- if self.point_2 or self.tmp_p2:
- if self.point_2:
- self.tmp_p2 = self.point_2
- bottom_left = [self.point_1[0], self.tmp_p2[1], self.point_1[2]]
- top_right = [self.tmp_p2[0], self.point_1[1], self.tmp_p2[2]]
-
- ogl.draw_rectangles([self.point_1, bottom_left, self.tmp_p2, top_right])
-
- def reset(self) -> None:
- super().reset()
- self.point_2, self.tmp_p2 = (None, None)
- self.view.button_activate_drag.setChecked(False)
diff --git a/labelCloud/control/drawing_strategies.py b/labelCloud/control/drawing_strategies.py
new file mode 100644
index 0000000..4065ef3
--- /dev/null
+++ b/labelCloud/control/drawing_strategies.py
@@ -0,0 +1,260 @@
+from abc import ABC, ABCMeta, abstractmethod
+from typing import TYPE_CHECKING, List
+
+import numpy as np
+import utils.math3d as math3d
+import utils.oglhelper as ogl
+from model.bbox import BBox
+
+from .config_manager import config
+
+if TYPE_CHECKING:
+ from view.gui import GUI
+
+import numpy as np
+
+
+class IDrawingStrategy:
+ __metaclass__ = ABCMeta
+ POINTS_NEEDED: int
+ PREVIEW: bool = False
+
+ def __init__(self, view: "GUI") -> None:
+ self.view = view
+ self.points_registered = 0
+ self.point_1 = None
+
+ def is_bbox_finished(self) -> bool:
+ return self.points_registered >= self.__class__.POINTS_NEEDED
+
+ @abstractmethod
+ def register_point(self, new_point: List[float]) -> None:
+ raise NotImplementedError
+
+ def register_tmp_point(self, new_tmp_point: List[float]) -> None:
+ pass
+
+ def register_scrolling(self, distance: float) -> None:
+ pass
+
+ @abstractmethod
+ def get_bbox(self) -> BBox:
+ raise NotImplementedError
+
+ def draw_preview(self) -> None:
+ pass
+
+ def reset(self) -> None:
+ self.points_registered = 0
+ self.point_1 = None
+
+
+class PickingStrategy(IDrawingStrategy, ABC):
+ POINTS_NEEDED = 1
+ PREVIEW = True
+
+ def __init__(self, view: "GUI") -> None:
+ super().__init__(view)
+ print("Enabled drawing mode.")
+ self.view.update_status(
+ "Please pick the location for the bounding box front center.",
+ mode="drawing",
+ )
+ self.tmp_p1 = None
+ self.bbox_z_rotation = 0
+
+ def register_point(self, new_point: List[float]) -> None:
+ self.point_1 = new_point
+ print("registered point " + str(self.point_1))
+ self.points_registered += 1
+
+ def register_tmp_point(self, new_tmp_point: List[float]) -> None:
+ self.tmp_p1 = new_tmp_point
+
+ def register_scrolling(self, distance: float) -> None:
+ self.bbox_z_rotation += distance // 30
+
+ def draw_preview(self) -> None: # TODO: Refactor
+ if 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: # 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
+
+ def reset(self) -> None:
+ super().reset()
+ self.tmp_p1 = None
+ self.view.button_activate_picking.setChecked(False)
+
+
+class SpanStrategy(IDrawingStrategy, ABC):
+ POINTS_NEEDED = 4
+ PREVIEW = True
+ CORRECTION = False # Increases dimensions after drawing
+
+ def __init__(self, view: "GUI") -> None:
+ super().__init__(view)
+ print("Enabled spanning mode.")
+ self.view.update_status(
+ "Begin by selecting a vertex of the bounding box.", mode="drawing"
+ )
+ self.preview_color = (1, 1, 0, 1)
+ self.point_2 = None # second edge
+ self.point_3 = None # width
+ self.point_4 = None # height
+ self.tmp_p2 = None # tmp points for preview
+ self.tmp_p3 = None
+ self.tmp_p4 = None
+ self.p1_w = None # p1 + dir_vector
+ self.p2_w = None # p2 + dir_vector
+ self.dir_vector = None # p1 + dir_vector
+
+ def reset(self) -> None:
+ super().reset()
+ self.point_2, self.point_3, self.point_4 = (None, None, None)
+ self.tmp_p2, self.tmp_p3, self.tmp_p4, self.p1_w, self.p2_w = (
+ None,
+ None,
+ None,
+ None,
+ None,
+ )
+ self.view.button_activate_spanning.setChecked(False)
+
+ def register_point(self, new_point: List[float]) -> None:
+ if self.point_1 is None:
+ self.point_1 = new_point
+ self.view.update_status(
+ "Select a point representing the length of the bounding box."
+ )
+ elif not self.point_2:
+ self.point_2 = new_point
+ self.view.update_status(
+ "Select any point for the depth of the bounding box."
+ )
+ elif not self.point_3:
+ self.point_3 = new_point
+ self.view.update_status(
+ "Select any point for the height of the bounding box."
+ )
+ elif not self.point_4:
+ self.point_4 = new_point
+ else:
+ print("Cannot register point.")
+ self.points_registered += 1
+
+ def register_tmp_point(self, new_tmp_point: List[float]) -> None:
+ if self.point_1 and (not self.point_2):
+ self.tmp_p2 = new_tmp_point
+ elif self.point_2 and (not self.point_3):
+ self.tmp_p3 = new_tmp_point
+ elif self.point_3:
+ self.tmp_p4 = new_tmp_point
+
+ def get_bbox(self) -> BBox:
+ length = math3d.vector_length(np.subtract(self.point_1, self.point_2))
+ width = math3d.vector_length(self.dir_vector)
+ height = self.point_4[2] - self.point_1[2] # can also be negative
+
+ line_center = np.add(self.point_1, self.point_2) / 2
+ area_center = np.add(line_center * 2, self.dir_vector) / 2
+ center = np.add(area_center, [0, 0, height / 2])
+
+ # Calculating z-rotation
+ len_vec_2d = np.subtract(self.point_1, self.point_2)
+ z_angle = np.arctan(len_vec_2d[1] / len_vec_2d[0])
+
+ if SpanStrategy.CORRECTION:
+ length *= 1.1
+ width *= 1.1
+ height *= 1.1
+
+ bbox = BBox(*center, length=length, width=width, height=abs(height))
+ bbox.set_z_rotation(math3d.radians_to_degrees(z_angle))
+
+ 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))
+ return bbox
+
+ def draw_preview(self) -> None:
+ if not self.tmp_p4:
+ if self.point_1:
+ ogl.draw_points([self.point_1], color=self.preview_color)
+
+ if self.point_1 and (self.point_2 or self.tmp_p2):
+ if self.point_2:
+ self.tmp_p2 = self.point_2
+ ogl.draw_points([self.tmp_p2], color=(1, 1, 0, 1))
+ ogl.draw_lines([self.point_1, self.tmp_p2], color=self.preview_color)
+
+ if self.point_1 and self.point_2 and (self.tmp_p3 or self.point_3):
+ if self.point_3:
+ self.tmp_p3 = self.point_3
+ # Get x-y-aligned vector from line to point with intersection
+ self.dir_vector, intersection = math3d.get_line_perpendicular(
+ self.point_1, self.point_2, self.tmp_p3
+ )
+ # Calculate projected vertices
+ self.p1_w = np.add(self.point_1, self.dir_vector)
+ self.p2_w = np.add(self.point_2, self.dir_vector)
+ ogl.draw_points([self.p1_w, self.p2_w], color=self.preview_color)
+ ogl.draw_rectangles(
+ [self.point_1, self.point_2, self.p2_w, self.p1_w],
+ color=(1, 1, 0, 0.5),
+ )
+
+ elif (
+ self.point_1
+ and self.point_2
+ and self.point_3
+ and self.tmp_p4
+ and (not self.point_4)
+ ):
+ height1 = self.tmp_p4[2] - self.point_1[2]
+ p1_t = np.add(self.point_1, [0, 0, height1])
+ p2_t = np.add(self.point_2, [0, 0, height1])
+ p1_wt = np.add(self.p1_w, [0, 0, height1])
+ p2_wt = np.add(self.p2_w, [0, 0, height1])
+
+ ogl.draw_cuboid(
+ [
+ self.p1_w,
+ self.point_1,
+ self.point_2,
+ self.p2_w,
+ p1_wt,
+ p1_t,
+ p2_t,
+ p2_wt,
+ ],
+ color=(1, 1, 0, 0.5),
+ draw_vertices=True,
+ vertex_color=self.preview_color,
+ )
diff --git a/labelCloud/control/label_manager.py b/labelCloud/control/label_manager.py
index 10fa592..fa0afeb 100644
--- a/labelCloud/control/label_manager.py
+++ b/labelCloud/control/label_manager.py
@@ -1,13 +1,13 @@
import json
import ntpath
import os
-from abc import ABCMeta, abstractmethod, ABC
+from abc import ABC, ABCMeta, abstractmethod
from typing import List
import numpy as np
-
from model.bbox import BBox
from utils import math3d
+
from .config_manager import config
@@ -25,7 +25,7 @@ def get_label_strategy(export_format: str, label_folder: str) -> "IFormattingInt
return CentroidFormat(label_folder, relative_rotation=False)
-class LabelManager:
+class LabelManager(object):
LABEL_FORMATS = [
"vertices",
"centroid_rel",
@@ -37,7 +37,7 @@ class LabelManager:
def __init__(
self, strategy: str = STD_LABEL_FORMAT, path_to_label_folder: str = None
- ):
+ ) -> None:
self.label_folder = path_to_label_folder or config.get("FILE", "label_folder")
if not os.path.isdir(self.label_folder):
os.mkdir(self.label_folder)
@@ -60,7 +60,7 @@ def import_labels(self, pcd_name: str) -> List[BBox]:
)
return []
- def export_labels(self, pcd_path: str, bboxes: List[BBox]):
+ def export_labels(self, pcd_path: str, bboxes: List[BBox]) -> None:
pcd_name = ntpath.basename(pcd_path)
pcd_folder = os.path.dirname(pcd_path)
self.label_strategy.export_labels(bboxes, pcd_name, pcd_folder, pcd_path)
@@ -71,7 +71,7 @@ def export_labels(self, pcd_path: str, bboxes: List[BBox]):
#
-def save_to_label_file(path_to_file, data):
+def save_to_label_file(path_to_file, data) -> None:
if os.path.isfile(path_to_file):
print("File %s already exists, replacing file ..." % path_to_file)
if os.path.splitext(path_to_file)[1] == ".json":
@@ -82,7 +82,7 @@ def save_to_label_file(path_to_file, data):
write_file.write(data)
-def round_dec(x, decimal_places: int = LabelManager.EXPORT_PRECISION):
+def round_dec(x, decimal_places: int = LabelManager.EXPORT_PRECISION) -> List[float]:
return np.round(x, decimal_places).tolist()
@@ -110,10 +110,10 @@ def rel2abs_rotation(rel_rotation: float) -> float:
return abs_rotation
-class IFormattingInterface:
+class IFormattingInterface(object):
__metaclass__ = ABCMeta
- def __init__(self, label_folder, relative_rotation=False):
+ def __init__(self, label_folder, relative_rotation=False) -> None:
self.label_folder = label_folder
print("Set export strategy to %s." % self.__class__.__name__)
self.relative_rotation = relative_rotation
@@ -127,19 +127,19 @@ def __init__(self, label_folder, relative_rotation=False):
print("Saving rotations absolutely to positve x-axis in degrees (0..360°).")
@abstractmethod
- def import_labels(self, pcd_name_stripped):
+ def import_labels(self, pcd_name_stripped) -> List[BBox]:
raise NotImplementedError
@abstractmethod
- def export_labels(self, bboxes, pcd_name, pcd_folder, pcd_path):
+ def export_labels(self, bboxes, pcd_name, pcd_folder, pcd_path) -> None:
raise NotImplementedError
- def update_label_folder(self, new_label_folder):
+ def update_label_folder(self, new_label_folder) -> None:
self.label_folder = new_label_folder
class VerticesFormat(IFormattingInterface, ABC):
- def import_labels(self, pcd_name_stripped):
+ def import_labels(self, pcd_name_stripped) -> List[BBox]:
labels = []
path_to_label = os.path.join(self.label_folder, pcd_name_stripped + ".json")
@@ -170,7 +170,7 @@ def import_labels(self, pcd_name_stripped):
print("Imported %s labels from %s." % (len(data["objects"]), path_to_label))
return labels
- def export_labels(self, bboxes, pcd_name, pcd_folder, pcd_path):
+ def export_labels(self, bboxes, pcd_name, pcd_folder, pcd_path) -> None:
data = dict()
# Header
data["folder"] = pcd_folder
@@ -198,7 +198,7 @@ def export_labels(self, bboxes, pcd_name, pcd_folder, pcd_path):
class CentroidFormat(IFormattingInterface, ABC):
- def import_labels(self, pcd_name_stripped):
+ def import_labels(self, pcd_name_stripped) -> List[BBox]:
labels = []
path_to_label = os.path.join(self.label_folder, pcd_name_stripped + ".json")
if os.path.isfile(path_to_label):
@@ -218,7 +218,7 @@ def import_labels(self, pcd_name_stripped):
def export_labels(
self, bboxes: List[BBox], pcd_name: str, pcd_folder: str, pcd_path: str
- ):
+ ) -> None:
data = dict()
# Header
data["folder"] = pcd_folder
@@ -262,7 +262,7 @@ def export_labels(
class KittiFormat(IFormattingInterface, ABC):
- def import_labels(self, pcd_name_stripped):
+ def import_labels(self, pcd_name_stripped) -> List[BBox]:
labels = []
path_to_label = os.path.join(self.label_folder, pcd_name_stripped + ".txt")
if os.path.isfile(path_to_label):
@@ -282,7 +282,7 @@ def import_labels(self, pcd_name_stripped):
def export_labels(
self, bboxes: List[BBox], pcd_name: str, pcd_folder: str, pcd_path: str
- ):
+ ) -> None:
data = str()
# Labels
diff --git a/labelCloud/control/pcd_manager.py b/labelCloud/control/pcd_manager.py
index c7a43e5..cdeabb1 100644
--- a/labelCloud/control/pcd_manager.py
+++ b/labelCloud/control/pcd_manager.py
@@ -4,30 +4,29 @@
"""
import ntpath
import os
+from dataclasses import dataclass
from shutil import copyfile
-from typing import List, Tuple, TYPE_CHECKING, Optional
+from typing import TYPE_CHECKING, List, Optional, Tuple
import numpy as np
import open3d as o3d
-
from model.bbox import BBox
from model.point_cloud import PointCloud
+
from .config_manager import config
from .label_manager import LabelManager
-from dataclasses import dataclass
-
if TYPE_CHECKING:
from view.gui import GUI
@dataclass
-class Perspective:
+class Perspective(object):
zoom: float
rotation: Tuple[float, float, float]
-def color_pointcloud(points, z_min, z_max):
+def color_pointcloud(points, z_min, z_max) -> np.ndarray:
palette = np.loadtxt("labelCloud/ressources/rocket-palette.txt")
palette_len = len(palette) - 1
@@ -37,14 +36,14 @@ def color_pointcloud(points, z_min, z_max):
return colors
-class PointCloudManger:
+class PointCloudManger(object):
PCD_EXTENSIONS = [".pcd", ".ply", ".pts", ".xyz", ".xyzn", ".xyzrgb", ".bin"]
ORIGINALS_FOLDER = "original_pointclouds"
TRANSLATION_FACTOR = config.getfloat("POINTCLOUD", "STD_TRANSLATION")
ZOOM_FACTOR = config.getfloat("POINTCLOUD", "STD_ZOOM")
COLORIZE = config.getboolean("POINTCLOUD", "COLORLESS_COLORIZE")
- def __init__(self):
+ def __init__(self) -> None:
# Point cloud management
self.pcd_folder = config.get("FILE", "pointcloud_folder")
self.pcds = []
@@ -59,7 +58,7 @@ def __init__(self):
self.collected_object_classes = set()
self.saved_perspective: Perspective = None
- def read_pointcloud_folder(self):
+ def read_pointcloud_folder(self) -> None:
"""Checks point cloud folder and sets self.pcds to all valid point cloud file names."""
if os.path.isdir(self.pcd_folder):
self.pcds = []
@@ -93,7 +92,7 @@ def read_pointcloud_folder(self):
def pcds_left(self) -> bool:
return self.current_id + 1 < len(self.pcds)
- def get_next_pcd(self):
+ def get_next_pcd(self) -> None:
print("Loading next point cloud...")
if self.pcds_left():
self.current_id += 1
@@ -102,7 +101,7 @@ def get_next_pcd(self):
else:
print("No point clouds left!")
- def get_prev_pcd(self):
+ def get_prev_pcd(self) -> None:
print("Loading previous point cloud...")
if self.current_id > 0:
self.current_id -= 1
@@ -111,7 +110,7 @@ def get_prev_pcd(self):
else:
raise Exception("No point cloud left for loading!")
- def get_pointcloud(self):
+ def get_pointcloud(self) -> PointCloud:
return self.pointcloud
def get_current_name(self) -> str:
@@ -125,7 +124,7 @@ def get_current_details(self) -> Tuple[str, int, int]:
def get_current_path(self) -> str:
return os.path.join(self.pcd_folder, self.pcds[self.current_id])
- def get_labels_from_file(self):
+ def get_labels_from_file(self) -> List[BBox]:
bboxes = self.label_manager.import_labels(self.get_current_name())
print("Loaded %s bboxes!" % len(bboxes))
return bboxes
@@ -135,7 +134,7 @@ def set_view(self, view: "GUI") -> None:
self.view = view
self.view.glWidget.set_pointcloud_controller(self)
- def save_labels_into_file(self, bboxes: List[BBox]):
+ def save_labels_into_file(self, bboxes: List[BBox]) -> None:
if self.pcds:
self.label_manager.export_labels(self.get_current_path(), bboxes)
self.collected_object_classes.update(
@@ -222,41 +221,41 @@ def load_pointcloud(self, path_to_pointcloud: str) -> PointCloud:
print("=" * 65)
return tmp_pcd
- def rotate_around_x(self, dangle):
+ def rotate_around_x(self, dangle) -> None:
self.pointcloud.set_rot_x(self.pointcloud.rot_x - dangle)
- def rotate_around_y(self, dangle):
+ def rotate_around_y(self, dangle) -> None:
self.pointcloud.set_rot_y(self.pointcloud.rot_y - dangle)
- def rotate_around_z(self, dangle):
+ def rotate_around_z(self, dangle) -> None:
self.pointcloud.set_rot_z(self.pointcloud.rot_z - dangle)
- def translate_along_x(self, distance):
+ def translate_along_x(self, distance) -> None:
self.pointcloud.set_trans_x(
self.pointcloud.trans_x - distance * PointCloudManger.TRANSLATION_FACTOR
)
- def translate_along_y(self, distance):
+ def translate_along_y(self, distance) -> None:
self.pointcloud.set_trans_y(
self.pointcloud.trans_y + distance * PointCloudManger.TRANSLATION_FACTOR
)
- def translate_along_z(self, distance):
+ def translate_along_z(self, distance) -> None:
self.pointcloud.set_trans_z(
self.pointcloud.trans_z - distance * PointCloudManger.TRANSLATION_FACTOR
)
- def zoom_into(self, distance):
+ def zoom_into(self, distance) -> None:
zoom_distance = distance * PointCloudManger.ZOOM_FACTOR
self.pointcloud.set_trans_z(self.pointcloud.trans_z + zoom_distance)
- def reset_translation(self):
+ def reset_translation(self) -> None:
self.pointcloud.reset_translation()
- def reset_rotation(self):
+ def reset_rotation(self) -> None:
self.pointcloud.rot_x, self.pointcloud.rot_y, self.pointcloud.rot_z = (0, 0, 0)
- def reset_transformations(self):
+ def reset_transformations(self) -> None:
self.reset_translation()
self.reset_rotation()
@@ -300,7 +299,7 @@ def rotate_pointcloud(
# HELPER
- def get_perspective(self):
+ def get_perspective(self) -> Tuple[float, float, float]:
x_rotation = self.pointcloud.rot_x
z_rotation = self.pointcloud.rot_z
@@ -315,7 +314,7 @@ def get_perspective(self):
# UPDATE GUI
- def update_pcd_infos(self, pointcloud_label: str = None):
+ def update_pcd_infos(self, pointcloud_label: str = None) -> None:
self.view.set_pcd_label(pointcloud_label or self.get_current_name())
self.view.update_progress(self.current_id)
diff --git a/labelCloud/model/bbox.py b/labelCloud/model/bbox.py
index a027b4a..c664d11 100644
--- a/labelCloud/model/bbox.py
+++ b/labelCloud/model/bbox.py
@@ -1,14 +1,12 @@
-from typing import Tuple, List
+from typing import List, Tuple
-import OpenGL.GL as GL
import numpy as np
-
+import OpenGL.GL as GL
from control.config_manager import config
-from utils import math3d
-from utils import oglhelper
+from utils import math3d, oglhelper
-class BBox:
+class BBox(object):
# order in which the bounding box edges are drawn
BBOX_EDGES = [
(0, 1),
@@ -44,7 +42,7 @@ def __init__(
length: float = None,
width: float = None,
height: float = None,
- ):
+ ) -> None:
self.center = cx, cy, cz
self.length = length or config.getfloat("LABEL", "STD_BOUNDINGBOX_LENGTH")
self.width = width or config.getfloat("LABEL", "STD_BOUNDINGBOX_WIDTH")
@@ -98,29 +96,29 @@ def get_volume(self) -> float:
# SETTERS
- def set_classname(self, classname):
+ def set_classname(self, classname) -> None:
if classname:
self.classname = classname
- def set_length(self, length):
+ def set_length(self, length) -> None:
if length > 0:
self.length = length
else:
print("New length is too small.")
- def set_width(self, width):
+ def set_width(self, width) -> None:
if width > 0:
self.width = width
else:
print("New width is too small.")
- def set_height(self, height):
+ def set_height(self, height) -> None:
if height > 0:
self.height = height
else:
print("New height is too small.")
- def set_dimensions(self, length, width, height):
+ def set_dimensions(self, length, width, height) -> None:
if (length > 0) and (width > 0) and (height > 0):
self.length = length
self.width = width
@@ -128,13 +126,13 @@ def set_dimensions(self, length, width, height):
else:
print("New dimensions are too small.")
- def set_x_rotation(self, angle):
+ def set_x_rotation(self, angle) -> None:
self.x_rotation = angle % 360
- def set_y_rotation(self, angle):
+ def set_y_rotation(self, angle) -> None:
self.y_rotation = angle % 360
- def set_z_rotation(self, angle):
+ def set_z_rotation(self, angle) -> None:
self.z_rotation = angle % 360
def set_rotations(self, x_angle, y_angle, z_angle):
@@ -142,17 +140,17 @@ def set_rotations(self, x_angle, y_angle, z_angle):
self.y_rotation = y_angle
self.z_rotation = z_angle
- def set_x_translation(self, x_translation):
+ def set_x_translation(self, x_translation) -> None:
self.center = (x_translation, *self.center[1:])
- def set_y_translation(self, y_translation):
+ def set_y_translation(self, y_translation) -> None:
self.center = (self.center[0], y_translation, self.center[2])
- def set_z_translation(self, z_translation):
+ def set_z_translation(self, z_translation) -> None:
self.center = (*self.center[:2], z_translation)
# Updates the dimension of the BBox (important after scaling!)
- def set_axis_aligned_verticies(self):
+ def set_axis_aligned_verticies(self) -> None:
self.verticies = np.array(
[
[-self.length / 2, -self.width / 2, -self.height / 2],
@@ -167,7 +165,7 @@ def set_axis_aligned_verticies(self):
)
# Draw the BBox using verticies
- def draw_bbox(self, highlighted=False):
+ def draw_bbox(self, highlighted=False) -> None:
self.set_axis_aligned_verticies()
GL.glPushMatrix()
@@ -184,7 +182,7 @@ def draw_bbox(self, highlighted=False):
oglhelper.draw_lines(drawing_sequence, color=bbox_color)
GL.glPopMatrix()
- def draw_orientation(self, crossed_side: bool = True):
+ def draw_orientation(self, crossed_side: bool = True) -> None:
# Get object coordinates for arrow
arrow_length = self.length * 0.4
bp2 = [arrow_length, 0, 0]
@@ -227,11 +225,11 @@ def draw_orientation(self, crossed_side: bool = True):
# MANIPULATORS
# Translate bbox by cx, cy, cz
- def translate_bbox(self, dx, dy, dz):
+ def translate_bbox(self, dx, dy, dz) -> None:
self.center = math3d.translate_point(list(self.center), dx, dy, dz)
# Translate bbox away from extension by half distance
- def translate_side(self, p_id_s, p_id_o, distance):
+ def translate_side(self, p_id_s, p_id_o, distance) -> None:
direction = np.subtract(
self.get_vertices()[p_id_s], self.get_vertices()[p_id_o]
)
@@ -239,7 +237,7 @@ def translate_side(self, p_id_s, p_id_o, distance):
self.center = math3d.translate_point(self.center, *translation_vector)
# Extend bbox side by distance
- def change_side(self, side, distance): # ToDo: Move to controller?
+ def change_side(self, side, distance) -> None: # ToDo: Move to controller?
if side == "right" and self.length + distance > BBox.MIN_DIMENSION:
self.length += distance
self.translate_side(3, 0, distance) # TODO: Make dependend from side list
diff --git a/labelCloud/model/point_cloud.py b/labelCloud/model/point_cloud.py
index 7c60bb3..1c6262c 100644
--- a/labelCloud/model/point_cloud.py
+++ b/labelCloud/model/point_cloud.py
@@ -1,8 +1,8 @@
import ctypes
+from typing import List, Tuple
import numpy as np
import OpenGL.GL as GL
-
from control.config_manager import config
# Get size of float (4 bytes) for VBOs
@@ -10,7 +10,7 @@
# Creates an array buffer in a VBO
-def create_buffer(attributes):
+def create_buffer(attributes) -> GL.glGenBuffers:
bufferdata = (ctypes.c_float * len(attributes))(*attributes) # float buffer
buffersize = len(attributes) * SIZE_OF_FLOAT # buffer size in bytes
@@ -21,8 +21,8 @@ def create_buffer(attributes):
return vbo
-class PointCloud:
- def __init__(self, path):
+class PointCloud(object):
+ def __init__(self, path) -> None:
self.path_to_pointcloud = path
self.points = None
self.colors = None
@@ -42,59 +42,59 @@ def __init__(self, path):
self.trans_z = 0.0
# GETTERS AND SETTERS
- def get_no_of_points(self):
+ def get_no_of_points(self) -> int:
return len(self.points)
- def get_no_of_colors(self):
+ def get_no_of_colors(self) -> int:
return len(self.colors)
- def get_rotations(self):
+ def get_rotations(self) -> List[float]:
return [self.rot_x, self.rot_y, self.rot_z]
- def get_translations(self):
+ def get_translations(self) -> List[float]:
return [self.trans_x, self.trans_y, self.trans_z]
- def get_mins_maxs(self):
+ def get_mins_maxs(self) -> Tuple[float, float]:
return self.pcd_mins, self.pcd_maxs
- def get_min_max_height(self):
+ def get_min_max_height(self) -> Tuple[float, float]:
return self.pcd_mins[2], self.pcd_maxs[2]
- def set_mins_maxs(self):
+ def set_mins_maxs(self) -> None:
self.pcd_mins = np.amin(self.points, axis=0)
self.pcd_maxs = np.amax(self.points, axis=0)
- def set_rot_x(self, angle):
+ def set_rot_x(self, angle) -> None:
self.rot_x = angle % 360
- def set_rot_y(self, angle):
+ def set_rot_y(self, angle) -> None:
self.rot_y = angle % 360
- def set_rot_z(self, angle):
+ def set_rot_z(self, angle) -> None:
self.rot_z = angle % 360
- def set_rotations(self, x: float, y: float, z: float):
+ def set_rotations(self, x: float, y: float, z: float) -> None:
self.rot_x = x % 360
self.rot_y = y % 360
self.rot_z = z % 360
- def set_trans_x(self, val):
+ def set_trans_x(self, val) -> None:
self.trans_x = val
- def set_trans_y(self, val):
+ def set_trans_y(self, val) -> None:
self.trans_y = val
- def set_trans_z(self, val):
+ def set_trans_z(self, val) -> None:
self.trans_z = val
- def set_translations(self, x: float, y: float, z: float):
+ def set_translations(self, x: float, y: float, z: float) -> None:
self.trans_x = x
self.trans_y = y
self.trans_z = z
# MANIPULATORS
- def transform_data(self):
+ def transform_data(self) -> np.ndarray:
if self.colorless:
attributes = self.points
else:
@@ -103,11 +103,11 @@ def transform_data(self):
return attributes.flatten() # flatten to single list
- def write_vbo(self):
+ def write_vbo(self) -> None:
v_array = self.transform_data()
self.vbo = create_buffer(v_array)
- def draw_pointcloud(self):
+ def draw_pointcloud(self) -> None:
GL.glTranslate(
self.trans_x, self.trans_y, self.trans_z
) # third, pcd translation
@@ -153,10 +153,10 @@ def draw_pointcloud(self):
GL.glDisableClientState(GL.GL_COLOR_ARRAY)
GL.glBindBuffer(GL.GL_ARRAY_BUFFER, 0)
- def reset_translation(self):
+ def reset_translation(self) -> None:
self.trans_x, self.trans_y, self.trans_z = self.init_translation
- def print_details(self):
+ def print_details(self) -> None:
print("Point Cloud Center:\t\t%s" % np.round(self.center, 2))
print("Point Cloud Minimums:\t%s" % np.round(self.pcd_mins, 2))
print("Point Cloud Maximums:\t%s" % np.round(self.pcd_maxs, 2))
diff --git a/labelCloud/ressources/interface.ui b/labelCloud/ressources/interface.ui
index cb5203a..133a3ba 100644
--- a/labelCloud/ressources/interface.ui
+++ b/labelCloud/ressources/interface.ui
@@ -715,25 +715,6 @@ QListWidget#label_list::item:selected {
- -
-
-
- true
-
-
- Drag Bounding Box
-
-
-
- 20
- 20
-
-
-
- true
-
-
-
-
@@ -1668,7 +1649,6 @@ QListWidget#label_list::item:selected {
button_bbox_decr
dial_bbox_zrotation
button_pick_bbox
- button_drag_bbox
button_span_bbox
button_save_label
current_class_lineedit
diff --git a/labelCloud/utils/math3d.py b/labelCloud/utils/math3d.py
index e3d9c66..e7131cf 100644
--- a/labelCloud/utils/math3d.py
+++ b/labelCloud/utils/math3d.py
@@ -1,5 +1,5 @@
import math
-from typing import List, Tuple
+from typing import List, Optional, Tuple
import numpy as np
@@ -146,7 +146,7 @@ def vertices2rotations(
def get_line_perpendicular(
line_start: List[float], line_end: List[float], point: List[float]
-):
+) -> Tuple[tuple, tuple]:
"""Get line perpendicular to point parallel to x-y-plane
Returns:
@@ -170,7 +170,7 @@ def get_line_perpendicular(
# Calculates intersection between vector (p0, p1) and plane (p_co, p_no)
def get_line_plane_intersection(
p0: List[float], p1: List[float], p_co: List[float], p_no: List[float], epsilon=1e-6
-):
+) -> Optional[np.ndarray]:
"""Calculate the intersection between a point and a plane.
:param p0: Point on the line
diff --git a/labelCloud/utils/oglhelper.py b/labelCloud/utils/oglhelper.py
index de4d2db..c7835f9 100644
--- a/labelCloud/utils/oglhelper.py
+++ b/labelCloud/utils/oglhelper.py
@@ -1,12 +1,12 @@
from typing import List, Tuple, Union
-import OpenGL.GL as GL
import numpy as np
+import OpenGL.GL as GL
+from model.bbox import BBox
+from model.point_cloud import PointCloud
from OpenGL import GLU
from utils import math3d
-from model.bbox import BBox
-from model.point_cloud import PointCloud
Color4f = Tuple[float, float, float, float] # type alias for type hinting
PointList = List[List[float]]
diff --git a/labelCloud/view/gui.py b/labelCloud/view/gui.py
index b177c7d..4fcd220 100644
--- a/labelCloud/view/gui.py
+++ b/labelCloud/view/gui.py
@@ -1,11 +1,12 @@
import os
from typing import TYPE_CHECKING, List, Set
-from PyQt5 import QtWidgets, uic, QtCore, QtGui
+from control.config_manager import config
+from control.drawing_strategies import PickingStrategy, SpanStrategy
+from PyQt5 import QtCore, QtGui, QtWidgets, uic
from PyQt5.QtCore import QEvent, Qt
-from PyQt5.QtWidgets import QCompleter, QFileDialog, QActionGroup, QAction, QMessageBox
+from PyQt5.QtWidgets import QAction, QActionGroup, QCompleter, QFileDialog, QMessageBox
-from control.config_manager import config
from .settings_dialog import SettingsDialog
from .viewer import GLWidget
@@ -38,7 +39,7 @@ def set_zrotation_only(state: bool) -> None:
class GUI(QtWidgets.QMainWindow):
- def __init__(self, control: "Controller"):
+ def __init__(self, control: "Controller") -> None:
super(GUI, self).__init__()
print(os.getcwd())
uic.loadUi("labelCloud/ressources/interface.ui", self)
@@ -122,10 +123,6 @@ def __init__(self, control: "Controller"):
self.button_activate_picking = self.findChild(
QtWidgets.QPushButton, "button_pick_bbox"
)
- self.button_activate_drag = self.findChild(
- QtWidgets.QPushButton, "button_drag_bbox"
- ) # ToDo Remove?
- self.button_activate_drag.setVisible(False)
self.button_activate_spanning = self.findChild(
QtWidgets.QPushButton, "button_span_bbox"
)
@@ -191,7 +188,7 @@ def __init__(self, control: "Controller"):
self.timer.start()
# Event connectors
- def connect_events(self):
+ def connect_events(self) -> None:
# POINTCLOUD CONTROL
self.button_next_pcd.clicked.connect(
lambda: self.controller.next_pcd(save=True)
@@ -244,14 +241,13 @@ def connect_events(self):
# LABEL CONTROL
self.button_activate_picking.clicked.connect(
- lambda: self.controller.drawing_mode.set_drawing_strategy("PickingStrategy")
+ lambda: self.controller.drawing_mode.set_drawing_strategy(
+ PickingStrategy(self)
+ )
)
self.button_activate_spanning.clicked.connect(
- lambda: self.controller.drawing_mode.set_drawing_strategy("SpanStrategy")
- )
- self.button_activate_drag.clicked.connect(
lambda: self.controller.drawing_mode.set_drawing_strategy(
- "RectangleStrategy"
+ SpanStrategy(self)
)
)
self.button_save_labels.clicked.connect(self.controller.save)
@@ -307,7 +303,7 @@ def connect_events(self):
)
self.action_change_settings.triggered.connect(self.show_settings_dialog)
- def set_checkbox_states(self):
+ def set_checkbox_states(self) -> None:
self.action_showfloor.setChecked(
config.getboolean("USER_INTERFACE", "show_floor")
)
@@ -319,7 +315,7 @@ def set_checkbox_states(self):
)
# Collect, filter and forward events to viewer
- def eventFilter(self, event_object, event):
+ def eventFilter(self, event_object, event) -> bool:
# Keyboard Events
# if (event.type() == QEvent.KeyPress) and (not self.line_edited_activated()):
if (event.type() == QEvent.KeyPress) and (
@@ -361,11 +357,13 @@ def closeEvent(self, a0: QtGui.QCloseEvent) -> None:
self.timer.stop()
a0.accept()
- def show_settings_dialog(self):
+ def show_settings_dialog(self) -> None:
dialog = SettingsDialog(self)
dialog.exec()
- def show_no_pointcloud_dialog(self, pcd_folder: str, pcd_extensions: List[str]):
+ def show_no_pointcloud_dialog(
+ self, pcd_folder: str, pcd_extensions: List[str]
+ ) -> None:
msg = QMessageBox(self)
msg.setIcon(QMessageBox.Warning)
msg.setText(
@@ -389,10 +387,10 @@ def init_progress(self, min_value, max_value):
self.progressbar_pcd.setMinimum(min_value)
self.progressbar_pcd.setMaximum(max_value)
- def update_progress(self, value):
+ def update_progress(self, value) -> None:
self.progressbar_pcd.setValue(value)
- def update_curr_class_edit(self, force: str = None):
+ def update_curr_class_edit(self, force: str = None) -> None:
if force is not None:
self.curr_class_edit.setText(force)
else:
@@ -400,14 +398,14 @@ def update_curr_class_edit(self, force: str = None):
self.controller.bbox_controller.get_active_bbox().get_classname()
)
- def update_label_completer(self, classnames=None):
+ def update_label_completer(self, classnames=None) -> 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):
+ def update_bbox_stats(self, bbox) -> None:
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], viewing_precision)))
@@ -430,7 +428,7 @@ def update_bbox_stats(self, bbox):
self.volume_label.setText(str(round(bbox.get_volume(), viewing_precision)))
- def update_bbox_parameter(self, parameter: str):
+ def update_bbox_parameter(self, parameter: str) -> None:
str_value = None
self.setFocus() # Changes the focus from QLineEdit to the window
@@ -466,18 +464,17 @@ def update_bbox_parameter(self, parameter: str):
self.controller.bbox_controller.update_rotation(parameter, float(str_value))
return True
- def save_new_length(self):
+ def save_new_length(self) -> None:
new_length = self.length_edit.text()
self.controller.bbox_controller.get_active_bbox().length = float(new_length)
print(f"New length for bounding box submitted → {new_length}.")
# Enables, disables the draw mode
- def activate_draw_modes(self, state: bool):
+ def activate_draw_modes(self, state: bool) -> None:
self.button_activate_picking.setEnabled(state)
- self.button_activate_drag.setEnabled(state)
self.button_activate_spanning.setEnabled(state)
- def update_status(self, message: str, mode: str = None):
+ def update_status(self, message: str, mode: str = None) -> None:
self.tmp_status.setText(message)
if mode:
self.update_mode_status(mode)
@@ -488,7 +485,7 @@ def line_edited_activated(self) -> bool:
return True
return False
- def update_mode_status(self, mode: str):
+ def update_mode_status(self, mode: str) -> None:
self.action_alignpcd.setEnabled(True)
if mode == "drawing":
text = "Drawing Mode"
@@ -501,7 +498,7 @@ def update_mode_status(self, mode: str):
text = "Navigation Mode"
self.mode_status.setText(text)
- def change_pointcloud_folder(self):
+ def change_pointcloud_folder(self) -> None:
path_to_folder = QFileDialog.getExistingDirectory(
self,
"Change Point Cloud Folder",
@@ -515,7 +512,7 @@ def change_pointcloud_folder(self):
self.controller.pcd_manager.get_next_pcd()
print("Changed point cloud folder to %s!" % path_to_folder)
- def change_label_folder(self):
+ def change_label_folder(self) -> None:
path_to_folder = QFileDialog.getExistingDirectory(
self, "Change Label Folder", directory=config.get("FILE", "label_folder")
)
@@ -528,7 +525,7 @@ def change_label_folder(self):
)
print("Changed label folder to %s!" % path_to_folder)
- def update_default_object_class_menu(self, new_classes: Set[str] = None):
+ def update_default_object_class_menu(self, new_classes: Set[str] = None) -> None:
object_classes = set(config.getlist("LABEL", "object_classes"))
object_classes.update(new_classes or [])
existing_classes = {
@@ -544,6 +541,6 @@ def update_default_object_class_menu(self, new_classes: Set[str] = None):
self.menu_setdefaultclass.addActions(self.actiongroup_defaultclass.actions())
- def change_default_object_class(self, action: QAction):
+ def change_default_object_class(self, action: QAction) -> None:
config.set("LABEL", "std_object_class", action.text())
print(f"Changed default object class to {action.text()}.")
diff --git a/labelCloud/view/settings_dialog.py b/labelCloud/view/settings_dialog.py
index 1661ac3..a567ab1 100644
--- a/labelCloud/view/settings_dialog.py
+++ b/labelCloud/view/settings_dialog.py
@@ -1,12 +1,11 @@
-from PyQt5 import uic
-from PyQt5.QtWidgets import QDialog
-
from control.config_manager import config, config_manager
from control.label_manager import LabelManager
+from PyQt5 import uic
+from PyQt5.QtWidgets import QDialog
class SettingsDialog(QDialog):
- def __init__(self, parent=None):
+ def __init__(self, parent=None) -> None:
super().__init__(parent)
self.parent_gui = parent
uic.loadUi("labelCloud/ressources/settings_interface.ui", self)
@@ -16,7 +15,7 @@ def __init__(self, parent=None):
self.buttonBox.rejected.connect(self.chancel)
self.reset_button.clicked.connect(self.reset)
- def fill_with_current_settings(self):
+ def fill_with_current_settings(self) -> None:
# File
self.lineEdit_pointcloudfolder.setText(config.get("FILE", "pointcloud_folder"))
self.lineEdit_labelfolder.setText(config.get("FILE", "label_folder"))
@@ -163,7 +162,7 @@ def save(self) -> None:
)
print("Saved and activated new configuration!")
- def reset(self):
+ def reset(self) -> None:
config_manager.reset_to_default()
self.fill_with_current_settings()
diff --git a/labelCloud/view/viewer.py b/labelCloud/view/viewer.py
index eeff31c..46977d6 100644
--- a/labelCloud/view/viewer.py
+++ b/labelCloud/view/viewer.py
@@ -1,16 +1,15 @@
-from typing import Union
+from typing import Tuple, Union
import numpy as np
import OpenGL.GL as GL
-from OpenGL import GLU
-from PyQt5 import QtOpenGL, QtGui
-
-from utils import oglhelper
-from control.config_manager import config
from control.alignmode import AlignMode
from control.bbox_controller import BoundingBoxController
-from control.pcd_manager import PointCloudManger
+from control.config_manager import config
from control.drawing_manager import DrawingManager
+from control.pcd_manager import PointCloudManger
+from OpenGL import GLU
+from PyQt5 import QtGui, QtOpenGL
+from utils import oglhelper
# Main widget for presenting the point cloud
@@ -18,7 +17,7 @@ class GLWidget(QtOpenGL.QGLWidget):
NEAR_PLANE = config.getfloat("USER_INTERFACE", "near_plane")
FAR_PLANE = config.getfloat("USER_INTERFACE", "far_plane")
- def __init__(self, parent=None):
+ def __init__(self, parent=None) -> None:
self.parent = parent
QtOpenGL.QGLWidget.__init__(self, parent)
self.setMouseTracking(
@@ -44,15 +43,15 @@ def __init__(self, parent=None):
self.drawing_mode: Union[DrawingManager, None] = None
self.align_mode: Union[AlignMode, None] = None
- def set_pointcloud_controller(self, pcd_manager: PointCloudManger):
+ def set_pointcloud_controller(self, pcd_manager: PointCloudManger) -> None:
self.pcd_manager = pcd_manager
- def set_bbox_controller(self, bbox_controller: BoundingBoxController):
+ def set_bbox_controller(self, bbox_controller: BoundingBoxController) -> None:
self.bbox_controller = bbox_controller
# QGLWIDGET METHODS
- def initializeGL(self):
+ def initializeGL(self) -> None:
bg_color = [
int(fl_color)
for fl_color in config.getlist("USER_INTERFACE", "BACKGROUND_COLOR")
@@ -66,7 +65,7 @@ def initializeGL(self):
# Must be written again, due to buffer clearing
self.pcd_manager.get_pointcloud().write_vbo()
- def resizeGL(self, width, height):
+ def resizeGL(self, width, height) -> None:
print("Resized widget.")
GL.glViewport(0, 0, width, height)
GL.glMatrixMode(GL.GL_PROJECTION)
@@ -76,7 +75,7 @@ def resizeGL(self, width, height):
GLU.gluPerspective(45.0, aspect, GLWidget.NEAR_PLANE, GLWidget.FAR_PLANE)
GL.glMatrixMode(GL.GL_MODELVIEW)
- def paintGL(self):
+ def paintGL(self) -> None:
GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT)
GL.glPushMatrix() # push the current matrix to the current stack
@@ -102,7 +101,7 @@ def paintGL(self):
self.drawing_mode.draw_preview()
if self.align_mode is not None:
- if self.align_mode.is_active():
+ if self.align_mode.is_active:
self.align_mode.draw_preview()
# Highlight selected side with filled rectangle
@@ -126,7 +125,7 @@ def paintGL(self):
# Translates the 2D cursor position from screen plane into 3D world space coordinates
def get_world_coords(
self, x: int, y: int, z: float = None, correction: bool = False
- ):
+ ) -> Tuple[float, float, float]:
x *= self.DEVICE_PIXEL_RATIO # For fixing mac retina bug
y *= self.DEVICE_PIXEL_RATIO
@@ -159,7 +158,7 @@ def get_world_coords(
# Creates a circular mask with radius around center
-def circular_mask(arr_length, center, radius):
+def circular_mask(arr_length, center, radius) -> np.ndarray:
dx = np.arange(arr_length)
return (dx[np.newaxis, :] - center) ** 2 + (
dx[:, np.newaxis] - center
@@ -167,7 +166,7 @@ def circular_mask(arr_length, center, radius):
# Returns the minimum (closest) depth for a specified radius around the center
-def depth_min(depths, center, r=4):
+def depth_min(depths, center, r=4) -> float:
selected_depths = depths[circular_mask(len(depths), center, r)]
filtered_depths = selected_depths[(0 < selected_depths) & (selected_depths < 1)]
if 0 in depths: # Check if cursor is at widget border
@@ -179,7 +178,7 @@ def depth_min(depths, center, r=4):
# Returns the mean depth for a specified radius around the center
-def depth_smoothing(depths, center, r=15):
+def depth_smoothing(depths, center, r=15) -> float:
selected_depths = depths[circular_mask(len(depths), center, r)]
if 0 in depths: # Check if cursor is at widget border
return 1