Skip to content

Commit

Permalink
Merge pull request #52 from ch-sa/ch-sa/refactoring-2022
Browse files Browse the repository at this point in the history
General cleanup
  • Loading branch information
ch-sa authored Jan 9, 2022
2 parents 7dfb1c5 + 6151a91 commit 3693407
Show file tree
Hide file tree
Showing 49 changed files with 243 additions and 237 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
*.qt_for_python
.idea

!labelCloud/resources/examples/exemplary.ply
!labelCloud/resources/examples/exemplary.json
!labelCloud/resources/labelCloud_icon.pcd

# ---------------------------------------------------------------------------- #
# GENERATED #
# ---------------------------------------------------------------------------- #
Expand Down
2 changes: 1 addition & 1 deletion labelCloud/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "0.6.9"
__version__ = "0.6.10"
6 changes: 3 additions & 3 deletions labelCloud/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,18 +46,18 @@ def setup_example_project() -> None:

# Copy example files
shutil.copy(
pkg_resources.resource_filename("labelCloud.ressources", "default_config.ini"),
pkg_resources.resource_filename("labelCloud.resources", "default_config.ini"),
str(cwdir.joinpath("config.ini")),
)
shutil.copy(
pkg_resources.resource_filename(
"labelCloud.ressources.examples", "exemplary.ply"
"labelCloud.resources.examples", "exemplary.ply"
),
str(pcd_folder.joinpath("exemplary.ply")),
)
shutil.copy(
pkg_resources.resource_filename(
"labelCloud.ressources.examples", "exemplary.json"
"labelCloud.resources.examples", "exemplary.json"
),
str(label_folder.joinpath("exemplary.json")),
)
Expand Down
22 changes: 14 additions & 8 deletions labelCloud/control/config_manager.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Load configuration from .ini file."""
import configparser
import os
from typing import List
from pathlib import Path
from typing import List, Union

import pkg_resources

Expand All @@ -12,7 +12,9 @@ class ExtendedConfigParser(configparser.ConfigParser):
Can automatically parse float values besides plain strings.
"""

def getlist(self, section, option, raw=False, vars=None, fallback=None) -> List:
def getlist(
self, section, option, raw=False, vars=None, fallback=None
) -> List[Union[str, float]]:
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(",")]
Expand All @@ -22,25 +24,29 @@ def getlist(self, section, option, raw=False, vars=None, fallback=None) -> List:
return values
return raw_value

def getpath(self, section, option, raw=False, vars=None, fallback=None) -> Path:
"""Get a path from the configuration file."""
return Path(self.get(section, option, raw=raw, vars=vars, fallback=fallback))


class ConfigManager(object):
PATH_TO_CONFIG = "config.ini" # TODO: Handle!
PATH_TO_DEFAULT_CONFIG = pkg_resources.resource_filename(
"labelCloud.ressources", "default_config.ini"
PATH_TO_CONFIG = Path.cwd().joinpath("config.ini")
PATH_TO_DEFAULT_CONFIG = Path(
pkg_resources.resource_filename("labelCloud.resources", "default_config.ini")
)

def __init__(self) -> None:
self.config = ExtendedConfigParser(comment_prefixes="/", allow_no_value=True)
self.read_from_file()

def read_from_file(self) -> None:
if os.path.isfile(ConfigManager.PATH_TO_CONFIG):
if ConfigManager.PATH_TO_CONFIG.is_file():
self.config.read(ConfigManager.PATH_TO_CONFIG)
else:
self.config.read(ConfigManager.PATH_TO_DEFAULT_CONFIG)

def write_into_file(self) -> None:
with open(ConfigManager.PATH_TO_CONFIG, "w") as configfile:
with ConfigManager.PATH_TO_CONFIG.open("w") as configfile:
self.config.write(configfile, space_around_delimiters=True)

def reset_to_default(self) -> None:
Expand Down
25 changes: 12 additions & 13 deletions labelCloud/control/label_manager.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import ntpath
import os
from pathlib import Path
from typing import List

from ..label_formats import BaseLabelFormat, CentroidFormat, KittiFormat, VerticesFormat
from ..model.bbox import BBox
from .config_manager import config


def get_label_strategy(export_format: str, label_folder: str) -> "BaseLabelFormat":
def get_label_strategy(export_format: str, label_folder: Path) -> "BaseLabelFormat":
if export_format == "vertices":
return VerticesFormat(label_folder, LabelManager.EXPORT_PRECISION)
elif export_format == "centroid_rel":
Expand Down Expand Up @@ -45,17 +44,19 @@ class LabelManager(object):
EXPORT_PRECISION = config.getint("LABEL", "export_precision")

def __init__(
self, strategy: str = STD_LABEL_FORMAT, path_to_label_folder: str = None
self, strategy: str = STD_LABEL_FORMAT, path_to_label_folder: Path = 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)
self.label_folder = path_to_label_folder or config.getpath(
"FILE", "label_folder"
)
if not self.label_folder.is_dir():
self.label_folder.mkdir(parents=True)

self.label_strategy = get_label_strategy(strategy, self.label_folder)

def import_labels(self, pcd_name: str) -> List[BBox]:
def import_labels(self, pcd_path: Path) -> List[BBox]:
try:
return self.label_strategy.import_labels(os.path.splitext(pcd_name)[0])
return self.label_strategy.import_labels(pcd_path)
except KeyError as key_error:
print("Found a key error with %s in the dictionary." % key_error)
print(
Expand All @@ -69,7 +70,5 @@ def import_labels(self, pcd_name: str) -> List[BBox]:
)
return []

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)
def export_labels(self, pcd_path: Path, bboxes: List[BBox]) -> None:
self.label_strategy.export_labels(bboxes, pcd_path)
84 changes: 36 additions & 48 deletions labelCloud/control/pcd_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@
Module to manage the point clouds (loading, navigation, floor alignment).
Sets the point cloud and original point cloud path. Initiate the writing to the virtual object buffer.
"""
import ntpath
import os
from dataclasses import dataclass
from pathlib import Path
from shutil import copyfile
from typing import TYPE_CHECKING, List, Optional, Tuple

Expand All @@ -29,7 +28,7 @@ class Perspective(object):

def color_pointcloud(points, z_min, z_max) -> np.ndarray:
palette = np.loadtxt(
pkg_resources.resource_filename("labelCloud.ressources", "rocket-palette.txt")
pkg_resources.resource_filename("labelCloud.resources", "rocket-palette.txt")
)
palette_len = len(palette) - 1

Expand All @@ -48,8 +47,8 @@ class PointCloudManger(object):

def __init__(self) -> None:
# Point cloud management
self.pcd_folder = config.get("FILE", "pointcloud_folder")
self.pcds = []
self.pcd_folder = config.getpath("FILE", "pointcloud_folder")
self.pcds: List[Path] = []
self.current_id = -1

self.current_o3d_pcd = None
Expand All @@ -61,12 +60,21 @@ def __init__(self) -> None:
self.collected_object_classes = set()
self.saved_perspective: Perspective = None

@property
def pcd_path(self) -> Path:
return self.pcds[self.current_id]

@property
def pcd_name(self) -> Optional[str]:
if self.current_id >= 0:
return self.pcd_path.name

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):
if self.pcd_folder.is_dir():
self.pcds = []
for file in sorted(os.listdir(self.pcd_folder), key=str.casefold):
if file.endswith(tuple(PointCloudManger.PCD_EXTENSIONS)):
for file in sorted(self.pcd_folder.iterdir()):
if file.suffix in PointCloudManger.PCD_EXTENSIONS:
self.pcds.append(file)
else:
print(f"Point cloud path {self.pcd_folder} is not a valid directory.")
Expand All @@ -85,7 +93,7 @@ def read_pointcloud_folder(self) -> None:
)
self.pointcloud = self.load_pointcloud(
pkg_resources.resource_filename(
"labelCloud.ressources", "labelCloud_icon.pcd"
"labelCloud.resources", "labelCloud_icon.pcd"
)
)
self.update_pcd_infos(pointcloud_label=" – (select folder!)")
Expand All @@ -101,7 +109,7 @@ def get_next_pcd(self) -> None:
print("Loading next point cloud...")
if self.pcds_left():
self.current_id += 1
self.pointcloud = self.load_pointcloud(self.get_current_path())
self.pointcloud = self.load_pointcloud(self.pcd_path)
self.update_pcd_infos()
else:
print("No point clouds left!")
Expand All @@ -110,27 +118,13 @@ def get_prev_pcd(self) -> None:
print("Loading previous point cloud...")
if self.current_id > 0:
self.current_id -= 1
self.pointcloud = self.load_pointcloud(self.get_current_path())
self.pointcloud = self.load_pointcloud(self.pcd_path)
self.update_pcd_infos()
else:
raise Exception("No point cloud left for loading!")

def get_pointcloud(self) -> PointCloud:
return self.pointcloud

def get_current_name(self) -> str:
if self.current_id >= 0:
return self.pcds[self.current_id]

def get_current_details(self) -> Tuple[str, int, int]:
if self.current_id >= 0:
return self.get_current_name(), self.current_id + 1, len(self.pcds)

def get_current_path(self) -> str:
return os.path.join(self.pcd_folder, self.pcds[self.current_id])

def get_labels_from_file(self) -> List[BBox]:
bboxes = self.label_manager.import_labels(self.get_current_name())
bboxes = self.label_manager.import_labels(self.pcd_path)
print("Loaded %s bboxes!" % len(bboxes))
return bboxes

Expand All @@ -141,7 +135,7 @@ def set_view(self, view: "GUI") -> None:

def save_labels_into_file(self, bboxes: List[BBox]) -> None:
if self.pcds:
self.label_manager.export_labels(self.get_current_path(), bboxes)
self.label_manager.export_labels(self.pcd_path, bboxes)
self.collected_object_classes.update(
{bbox.get_classname() for bbox in bboxes}
)
Expand All @@ -162,26 +156,22 @@ def save_current_perspective(self, active: bool = True) -> None:
print("Reset saved perspective.")

# MANIPULATOR
def load_pointcloud(self, path_to_pointcloud: str) -> PointCloud:
print("=" * 20, "Loading", ntpath.basename(path_to_pointcloud), "=" * 20)
def load_pointcloud(self, path_to_pointcloud: Path) -> PointCloud:
print("=" * 20, "Loading", path_to_pointcloud.name, "=" * 20)

if config.getboolean("USER_INTERFACE", "keep_perspective"):
self.save_current_perspective()

if (
os.path.splitext(path_to_pointcloud)[1] == ".bin"
): # Loading binary pcds with numpy
if path_to_pointcloud.suffix == ".bin": # Loading binary pcds with numpy
bin_pcd = np.fromfile(path_to_pointcloud, dtype=np.float32)
points = bin_pcd.reshape((-1, 4))[
:, 0:3
] # Reshape and drop reflection values
self.current_o3d_pcd = o3d.geometry.PointCloud(
o3d.utility.Vector3dVector(points)
)
else:
self.current_o3d_pcd = o3d.io.read_point_cloud(
path_to_pointcloud
) # Load point cloud with open3d
else: # Load point cloud with open3d
self.current_o3d_pcd = o3d.io.read_point_cloud(str(path_to_pointcloud))

tmp_pcd = PointCloud(path_to_pointcloud)
tmp_pcd.points = np.asarray(self.current_o3d_pcd.points).astype(
Expand Down Expand Up @@ -271,15 +261,13 @@ def rotate_pointcloud(
self, axis: List[float], angle: float, rotation_point: List[float]
) -> None:
# Save current, original point cloud in ORIGINALS_FOLDER
originals_path = os.path.join(
self.pcd_folder, PointCloudManger.ORIGINALS_FOLDER
)
if not os.path.exists(originals_path):
os.mkdir(originals_path)
originals_path = self.pcd_folder.joinpath(PointCloudManger.ORIGINALS_FOLDER)
originals_path.mkdir(parents=True, exist_ok=True)
copyfile(
self.get_current_path(),
os.path.join(originals_path, self.get_current_name()),
str(self.pcd_path),
str(originals_path.joinpath(self.pcd_name)),
)

# Rotate and translate point cloud
rotation_matrix = o3d.geometry.get_rotation_matrix_from_axis_angle(
np.multiply(axis, angle)
Expand All @@ -298,11 +286,11 @@ def rotate_pointcloud(
center=(0, 0, 0),
)

save_path = self.get_current_path()
if os.path.splitext(save_path)[1] == ".bin":
save_path = save_path[:-4] + ".pcd"
save_path = self.pcd_path
if save_path.suffix == ".bin": # save .bin point clouds as .pcd
save_path = save_path.parent.joinpath(save_path.stem + ".pcd")

o3d.io.write_point_cloud(save_path, self.current_o3d_pcd)
o3d.io.write_point_cloud(str(save_path), self.current_o3d_pcd)
self.pointcloud = self.load_pointcloud(save_path)

# HELPER
Expand All @@ -323,7 +311,7 @@ def get_perspective(self) -> Tuple[float, float, float]:
# UPDATE GUI

def update_pcd_infos(self, pointcloud_label: str = None) -> None:
self.view.set_pcd_label(pointcloud_label or self.get_current_name())
self.view.set_pcd_label(pointcloud_label or self.pcd_name)
self.view.update_progress(self.current_id)

if self.current_id <= 0:
Expand Down
Loading

0 comments on commit 3693407

Please sign in to comment.