ReUseX  0.0.5
3D Point Cloud Processing for Building Reuse
Loading...
Searching...
No Matches
label_semantics.hpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2025 Povl Filip Sonne-Frederiksen
2//
3// SPDX-License-Identifier: GPL-3.0-or-later
4
5#pragma once
6
7#include <cstdint>
8#include <stdexcept>
9#include <string>
10
11#include <opencv2/core.hpp>
12
29
30namespace reusex::core {
31
34inline constexpr uint32_t kUnlabeled = 0;
35
38inline constexpr int kBackgroundApi = -1;
39
43inline constexpr uint16_t kMaxStorableLabel = 65534;
44
46inline constexpr bool is_valid_label(uint32_t label) noexcept {
47 return label != kUnlabeled;
48}
49
56inline size_t label_to_index(uint32_t label) {
57 if (!is_valid_label(label))
58 throw std::out_of_range(
59 "label_to_index: label 0 is unlabeled and has no index");
60 return static_cast<size_t>(label) - 1;
61}
62
63// ── Scalar conversions ────────────────────────────────────────────────────
64
73inline uint32_t api_to_point_label(int api_label) {
74 if (api_label == kBackgroundApi)
75 return kUnlabeled;
76 if (api_label < 0)
77 throw std::out_of_range("api_to_point_label: negative label " +
78 std::to_string(api_label) +
79 " is not the background sentinel (-1)");
80 return static_cast<uint32_t>(api_label);
81}
82
85inline int point_label_to_api(uint32_t point_label) {
86 if (point_label == kUnlabeled)
87 return kBackgroundApi;
88 return static_cast<int>(point_label);
89}
90
96inline uint16_t api_to_storage(int api_label) {
97 if (api_label < kBackgroundApi)
98 throw std::out_of_range("api_to_storage: label " +
99 std::to_string(api_label) + " is below -1");
100 if (api_label > static_cast<int>(kMaxStorableLabel))
101 throw std::out_of_range(
102 "api_to_storage: label " + std::to_string(api_label) +
103 " exceeds maximum storable label " +
104 std::to_string(static_cast<int>(kMaxStorableLabel)) +
105 " (would wrap CV_16U storage)");
106 return static_cast<uint16_t>(api_label + 1);
107}
108
111inline int storage_to_api(uint16_t storage_value) {
112 return static_cast<int>(storage_value) - 1;
113}
114
115// ── Whole-cv::Mat converters ──────────────────────────────────────────────
116
122inline cv::Mat storage_mat_to_api(const cv::Mat &storage) {
123 if (storage.empty())
124 return cv::Mat();
125 if (storage.type() != CV_16UC1)
126 throw std::invalid_argument(
127 "storage_mat_to_api: expected CV_16UC1 storage image");
128 cv::Mat api;
129 storage.convertTo(api, CV_32S);
130 api -= 1;
131 return api;
132}
133
140inline cv::Mat api_mat_to_storage(const cv::Mat &api) {
141 if (api.empty())
142 throw std::invalid_argument("api_mat_to_storage: empty label image");
143 if (api.type() != CV_32SC1)
144 throw std::invalid_argument(
145 "api_mat_to_storage: expected CV_32SC1 API image");
146
147 double min_val = 0.0;
148 double max_val = 0.0;
149 cv::minMaxLoc(api, &min_val, &max_val);
150 if (min_val < static_cast<double>(kBackgroundApi))
151 throw std::out_of_range("api_mat_to_storage: label " +
152 std::to_string(static_cast<int>(min_val)) +
153 " is below -1");
154 if (max_val > static_cast<double>(kMaxStorableLabel))
155 throw std::out_of_range(
156 "api_mat_to_storage: label " +
157 std::to_string(static_cast<int>(max_val)) +
158 " exceeds maximum storable label " +
159 std::to_string(static_cast<int>(kMaxStorableLabel)) +
160 " (would wrap CV_16U storage)");
161
162 cv::Mat offset = api + 1;
163 cv::Mat storage;
164 offset.convertTo(storage, CV_16U);
165 return storage;
166}
167
168} // namespace reusex::core
constexpr uint16_t kMaxStorableLabel
Largest label that can be stored in the CV_16U PNG layer.
size_t label_to_index(uint32_t label)
Convert a point label to a zero-based vector index, replacing the error-prone bare label - 1 idiom us...
uint16_t api_to_storage(int api_label)
API label (CV_32S, -1 = background) → storage value (CV_16U, 0 = bg, label + 1).
int storage_to_api(uint16_t storage_value)
Storage value (CV_16U, 0 = bg, label + 1) → API label (CV_32S, -1 = background).
cv::Mat storage_mat_to_api(const cv::Mat &storage)
Convert a storage label image (CV_16U, 0 = bg) to an API label image (CV_32S, -1 = background) by sub...
constexpr int kBackgroundApi
ProjectDB segmentation API convention: -1 marks background/unlabeled in the CV_32S label images retur...
cv::Mat api_mat_to_storage(const cv::Mat &api)
Convert an API label image (CV_32S, -1 = background) to a storage label image (CV_16U,...
uint32_t api_to_point_label(int api_label)
API (CV_32S, -1 = background) → point label (uint32_t, 0 = unlabeled).
constexpr uint32_t kUnlabeled
Point-cloud convention: 0 means "unlabeled" in every CloudL (labels, planes, rooms,...
int point_label_to_api(uint32_t point_label)
Point label (uint32_t, 0 = unlabeled) → API (CV_32S, -1 = background).
constexpr bool is_valid_label(uint32_t label) noexcept