ReUseX  0.0.5
3D Point Cloud Processing for Building Reuse
Loading...
Searching...
No Matches
BackendFactory.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#include "reusex/core/logging.hpp"
7#include "reusex/vision/IMLBackend.hpp"
8
9#ifdef REUSEX_USE_LIBTORCH
10#include "reusex/vision/libtorch/Backend.hpp"
11#endif
12
13#ifdef REUSEX_USE_TENSORRT
14#include "reusex/vision/tensor_rt/Backend.hpp"
15#endif
16
17#ifdef REUSEX_USE_ONNX
18#include "reusex/vision/onnx/Backend.hpp"
19#endif
20
21#ifdef REUSEX_USE_OPENVINO
22#include "reusex/vision/openvino/Backend.hpp"
23#endif
24
25#include <fmt/std.h>
26
27#include <algorithm>
28#include <cctype>
29#include <filesystem>
30
31namespace reusex::vision {
41
43 public:
44 /* Detects the model type from the model path.
45 *
46 * Inspects the path stem and, for directories, contained file names.
47 * Detection is case-insensitive:
48 * - name containing "sam3.1"/"sam3p1" -> Model::sam3p1
49 * - "sam3" or "sam2" in the name -> Model::sam3
50 * - directory with vision-encoder + tracker engines -> Model::sam3p1
51 * - directory containing "vision-encoder.*" -> Model::sam3
52 * - otherwise -> Model::yolo
53 *
54 * @param model_path: The file or directory path of the model.
55 * @return The detected model type.
56 */
57 static Model detect_model(const std::filesystem::path &model_path) {
58 auto to_lower = [](std::string s) {
59 std::transform(s.begin(), s.end(), s.begin(),
60 [](unsigned char c) { return std::tolower(c); });
61 return s;
62 };
63
64 // Check directory/file name itself. A "sam3.1"/"sam3p1" name shortcut
65 // selects the video tracker; check it BEFORE the plain sam3/sam2 shortcut.
66 // Use filename() not stem(): a directory named "sam3.1-video" has stem()
67 // == "sam3" (".1-video" parsed as an extension), which would mis-route it
68 // to the plain sam3 path and skip the tracker.
69 auto name = to_lower(model_path.filename().string());
70 if (name.find("sam3.1") != std::string::npos ||
71 name.find("sam3p1") != std::string::npos) {
72 reusex::info("Detected SAM3.1 model from path name: {}", model_path);
73 return Model::sam3p1;
74 }
75 if (name.find("sam3") != std::string::npos ||
76 name.find("sam2") != std::string::npos) {
77 reusex::info("Detected SAM3 model from path name: {}", model_path);
78 return Model::sam3;
79 }
80
81 // For directories, inspect contained filenames. SAM 3.1 additionally ships
82 // the tracker engines; require vision-encoder + memory-encoder +
83 // memory-attention and return sam3p1 BEFORE the plain-sam3 return.
84 if (std::filesystem::is_directory(model_path)) {
85 bool has_vision = false, has_mem_encoder = false,
86 has_mem_attention = false;
87 for (const auto &entry :
88 std::filesystem::directory_iterator(model_path)) {
89 auto stem = to_lower(entry.path().stem().string());
90 if (stem.find("vision-encoder") != std::string::npos)
91 has_vision = true;
92 if (stem.find("tracker-memory-encoder") != std::string::npos)
93 has_mem_encoder = true;
94 if (stem.find("tracker-memory-attention") != std::string::npos)
95 has_mem_attention = true;
96 }
97 if (has_vision && has_mem_encoder && has_mem_attention) {
99 "Detected SAM3.1 video model (tracker engines present): {}",
100 model_path);
101 return Model::sam3p1;
102 }
103 if (has_vision) {
104 reusex::info("Detected SAM3 model from sub-model files: {}",
105 model_path);
106 return Model::sam3;
107 }
108 }
109
110 reusex::info("Defaulting to YOLO model type for path: {}", model_path);
111 return Model::yolo;
112 }
113
114 /* Detects the appropriate backend based on the model path.
115 * @param model_path: The file or directory path of the model.
116 * @return The detected backend type.
117 */
118 static Backend detect_backend(const std::filesystem::path &model_path) {
119 using namespace std::filesystem;
120
121 if (is_regular_file(model_path))
122 return detect_backend_from_file(model_path);
123
124 if (is_directory(model_path))
125 for (const auto &entry : directory_iterator(model_path))
126 if (entry.is_regular_file())
127 if (auto backend = detect_backend_from_file(entry.path());
128 backend != Backend::unknown)
129 return backend;
130
131 return Backend::unknown;
132 }
133
134 /* Creates an instance of the specified backend type.
135 * @param type: The backend type to create.
136 * @return A unique pointer to the created backend instance.
137 * @throws std::runtime_error if the backend type is not implemented or
138 * unsupported.
139 */
140 static std::unique_ptr<IMLBackend> create(Backend type) {
141 switch (type) {
142 case Backend::opencv:
143 reusex::error("OpenCV backend is not implemented yet.");
144 throw std::runtime_error("OpenCV backend not implemented");
145
147#ifdef REUSEX_USE_TENSORRT
148 return std::make_unique<reusex::vision::tensor_rt::TensorRTBackend>();
149#else
150 reusex::error("TensorRT backend not compiled in this build. "
151 "Rebuild with -DML_BACKENDS=TensorRT or AUTO.");
152 throw std::runtime_error("TensorRT backend not available");
153#endif
154
156#ifdef REUSEX_USE_LIBTORCH
157 return std::make_unique<reusex::vision::libtorch::LibTorchBackend>();
158#else
159 reusex::error("LibTorch backend not compiled in this build. "
160 "Rebuild with -DML_BACKENDS=LibTorch or AUTO.");
161 throw std::runtime_error("LibTorch backend not available");
162#endif
163
164 case Backend::dnn:
165 reusex::error("DNN backend is not implemented yet.");
166 throw std::runtime_error("DNN backend not implemented");
167
169#ifdef REUSEX_USE_ONNX
170 return std::make_unique<reusex::vision::onnx::ONNXBackend>();
171#else
172 reusex::error("ONNX Runtime backend is not implemented yet.");
173 throw std::runtime_error("ONNX Runtime backend not implemented");
174#endif
175
177#ifdef REUSEX_USE_OPENVINO
178 return std::make_unique<reusex::vision::openvino::OpenVINOBackend>();
179#else
180 reusex::error("OpenVINO backend is not implemented yet.");
181 throw std::runtime_error("OpenVINO backend not implemented");
182#endif
183
184 default:
185 reusex::error("Unsupported backend type: {}", static_cast<int>(type));
186 throw std::runtime_error("Unsupported backend");
187 }
188 }
189
190 private:
191 /* Helper function to detect backend type from a single file based on its
192 * extension.
193 * @param file_path: The path of the file to analyze.
194 * @return The detected backend type or unknown if the extension is not
195 * recognized.
196 */
197 static Backend
198 detect_backend_from_file(const std::filesystem::path &file_path) {
199 auto ext = file_path.extension();
200
201 if (ext.empty()) {
202 reusex::warn("File {} has no extension. Unable to detect backend.",
203 file_path);
204 return Backend::unknown;
205 }
206
207 else if (ext == ".engine") {
208 reusex::info("Detected TensorRT engine file: {}", file_path);
209#ifndef REUSEX_USE_TENSORRT
210 reusex::warn("TensorRT detected but not compiled in this build. Backend "
211 "unavailable.");
212#endif
213 return Backend::tensor_rt;
214 } else if (ext == ".pt" || ext == ".pth" || ext == ".torchscript") {
215 reusex::info("Detected PyTorch model file: {}", file_path);
216#ifndef REUSEX_USE_LIBTORCH
217 reusex::warn("LibTorch detected but not compiled in this build. Backend "
218 "unavailable.");
219#endif
220 return Backend::libtorch;
221 } else if (ext == ".onnx") {
222 reusex::info("Detected ONNX model file: {}", file_path);
223#ifndef REUSEX_USE_ONNX
224 reusex::warn("ONNX Runtime detected but not compiled in this build. "
225 "Backend unavailable.");
226#endif
228 } else if (ext == ".xml" || ext == ".bin") {
229 reusex::info("Detected OpenVINO model files: {}", file_path);
230#ifndef REUSEX_USE_OPENVINO
231 reusex::warn("OpenVINO detected but not compiled in this build. Backend "
232 "unavailable.");
233#endif
234 return Backend::openvino;
235 }
236
237 reusex::warn("Unknown model file extension: {}. Unable to detect backend; "
238 "returning Backend::unknown.",
239 ext);
240 return Backend::unknown;
241 }
242};
243} // namespace reusex::vision
static Model detect_model(const std::filesystem::path &model_path)
static Backend detect_backend(const std::filesystem::path &model_path)
static std::unique_ptr< IMLBackend > create(Backend type)
void warn(fmt::format_string< Args... > format, Args &&...args)
Definition logging.hpp:93
void error(fmt::format_string< Args... > format, Args &&...args)
Definition logging.hpp:100
void info(fmt::format_string< Args... > format, Args &&...args)
Definition logging.hpp:86