VisionServer  v2.1.1-1-g21dc5465
FRC vision library
visionserver2.h
Go to the documentation of this file.
1#pragma once
2
3#include <string>
4#include <atomic>
5#include <thread>
6#include <chrono>
7#include <initializer_list>
8
9#include <opencv2/opencv.hpp>
10#include <networktables/NetworkTable.h>
11
12#include "cpp-tools/src/types.h"
13
14#include "visioncamera.h"
15
16
17namespace vs2 {
18
19class VisionServer final {
20 struct OutputStream;
21public:
22 inline static const std::shared_ptr<nt::NetworkTable>& ntable() {
23 static std::shared_ptr<nt::NetworkTable> base{nt::NetworkTableInstance::GetDefault().GetTable("Vision Server")};
24 return base;
25 }
26
27 inline static VisionServer& getInstance() {
28 static VisionServer instance;
29 return instance;
30 }
31 inline static void Init() {
35 }
36
37
38 class BasePipe : public cs::CvSource {
39 friend class VisionServer;
40 public:
41 inline static const std::shared_ptr<nt::NetworkTable>& ntable() {
42 static std::shared_ptr<nt::NetworkTable> pipes{VisionServer::ntable()->GetSubTable("Pipelines")};
43 return pipes;
44 }
45
46 inline const std::string& getName() const { return this->name; }
47 inline const std::shared_ptr<nt::NetworkTable>& getTable() const { return this->table; }
48
49 virtual void process(cv::Mat& io_frame) = 0;
50 inline virtual void init() {}
51 inline virtual void close() {}
52
53 protected:
54 inline BasePipe(const char* name) : /* start enable/disable callback for more efficent threading */
55 CvSource(name, cs::VideoMode()), name(name),
56 input(this->name), table(BasePipe::ntable()->GetSubTable(this->name)) {}
57 inline BasePipe(const std::string& name) :
58 CvSource(name, cs::VideoMode()), name(name),
59 input(this->name), table(BasePipe::ntable()->GetSubTable(this->name)) {}
60 inline BasePipe(std::string&& name) :
61 CvSource(name, cs::VideoMode()), name(name),
62 input(this->name), table(BasePipe::ntable()->GetSubTable(this->name)) {}
63 BasePipe() = delete;
64
65
66 void setCamera(const VisionCamera&);
67 void setPipeline(const BasePipe&);
68 void setSource(const cs::VideoSource&);
69 void getFrame(cv::Mat&);
70
71 inline const cv::Mat1f& getSrcMatrix() const { return *this->src_matrix; }
72 inline const cv::Mat1f& getSrcDistort() const { return *this->src_distort; }
73
74 private:
75 std::string name;
76 cs::CvSink input;
77 const cv::Mat_<float>
80 ;
81 const std::shared_ptr<nt::NetworkTable> table;
82
83
84 };
85
86
87 static bool addCamera(VisionCamera&&);
88 static bool addCameras(std::vector<VisionCamera>&&);
89 static bool setCameras(std::vector<VisionCamera>&&);
90 static std::vector<VisionCamera>& getCameras();
91 static size_t numCameras();
92
93 template<class pipeline>
94 static bool addPipeline();
95 static bool addPipeline(BasePipe*);
96 template<class... pipelines>
97 static bool addPipelines();
98 static bool addPipelines(std::vector<BasePipe*>&&);
99 static bool addPipelines(std::initializer_list<BasePipe*>);
100 template<class... pipelines>
101 static bool setPipelines();
102 static bool setPipelines(std::vector<BasePipe*>&&);
103 static bool setPipelines(std::initializer_list<BasePipe*>);
104 static const std::vector<BasePipe*>& getPipelines();
105 static size_t numPipelines();
106
107 static bool addStream();
108 static bool addStream(std::string_view);
109 static bool addStream(std::string_view, int port);
110 static bool addStream(const cs::MjpegServer&);
111 static bool addStream(cs::MjpegServer&&);
112 static bool addStreams(size_t = 2);
113 static bool addStreams(std::initializer_list<std::string_view>);
114 static bool addStreams(std::initializer_list<std::pair<std::string_view, int> >);
115 static bool addStreams(const std::vector<cs::MjpegServer>&);
116 static const std::vector<OutputStream>& getStreams();
117 static size_t numStreams();
118
119 static bool compensate(); // attempts to attach all pipelines to the first available camera, and all outputs to the first available source
120 static bool runRaw(); // run stream index handling for raw inputs (no processing, just camera feeds) - stops when processing is started
121 static bool runRawThread(); // run stream index handling in a separate thread - stops when processing is started
122
123 static bool run(float fps_cap = 30.f); // start multithreaded processing - blocks until stop() is called [in another thread]
124 static bool runSingle(float fps_cap = 30.f); // start singlethreaded processing - blocks until stop() is called [in another thread]
125 static bool runThread(float fps_cap = 30.f); // start multithreaded processing in a separate thread - does not block
126 static bool runSingleThread(float fps_cap = 30.f); // start singlethreaded processing in a separate thread - does not block
127 static bool isRunning();
128 static bool stop(); // stop processing - returns if any instances were actually stopped
129 static inline void stopExit() { stop(); } // a void-returning wrapper for stop() to be used within 'atexit'
130
131
132 template<class pipeline = void, class... pipelines>
133 static size_t pipeExpander(std::vector<std::unique_ptr<BasePipe> >&);
134
135protected:
136 inline static VisionServer& inst() { return getInstance(); }
137
138 static void pipelineRunner(BasePipe*, float fps_cap);
139
140private:
141 VisionServer();
143 VisionServer(const VisionServer&) = delete;
145 void operator=(const VisionServer&) = delete;
146 void operator=(VisionServer&&) = delete;
147
148 std::vector<VisionCamera> cameras;
149 std::vector<BasePipe*> pipelines;
150 std::vector<std::unique_ptr<BasePipe> > heap_allocated;
151 std::vector<OutputStream> streams;
152
153 std::thread head;
154 std::atomic<bool> is_running{false};
155
156
157 struct OutputStream : public cs::MjpegServer {
158 friend class VisionServer;
159 public:
160 inline static const std::shared_ptr<nt::NetworkTable>& ntable() {
161 static std::shared_ptr<nt::NetworkTable> streams{VisionServer::ntable()->GetSubTable("Streams")};
162 return streams;
163 }
164
165 OutputStream(cs::MjpegServer&& s);
166 inline OutputStream(std::string_view n) :
167 OutputStream(frc::CameraServer::AddServer(n)) {}
168 inline OutputStream(std::string_view n, int p) :
169 OutputStream(frc::CameraServer::AddServer(n, p)) {}
170 inline OutputStream(const OutputStream& o) :
171 MjpegServer(o), table(o.table), local_idx(o.local_idx.load()) {}
173 MjpegServer(std::move(o)), table(std::move(o.table)), local_idx(o.local_idx.load()) {}
175
176 void setSourceIdx(int i);
177 inline void setPipelineIdx(uint16_t i) { this->setSourceIdx(i); }
178 inline void setCameraIdx(uint16_t i) { this->setSourceIdx(-(int)i); }
179
180 protected:
181 void syncIdx();
182
183 private:
184 const std::shared_ptr<nt::NetworkTable> table;
185 std::atomic_int local_idx{0};
186
187 };
188
189
190};
191
192
193
194typedef struct VPipeline_S BasePipe; // non-instanced ("singular") VPipeline is just an alias of BasePipe
195
196template<class derived> // CRTP for instance counting -> all derived classes should inherit a passthrough template if they are expected to be extended as well
197class VPipeline : public Instanced<VPipeline<derived> >, public VisionServer::BasePipe {
198 typedef struct VPipeline<derived> This_t;
199protected:
200 VPipeline() = delete;
201 VPipeline(const VPipeline&) = delete;
202 inline VPipeline(const char* name) :
203 Instanced<This_t>(), BasePipe(name + ("/Instance " + std::to_string(this->instance))) {}
204 inline VPipeline(const std::string& name) :
205 Instanced<This_t>(), BasePipe(name + "/Instance " + std::to_string(this->instance)) {}
206 inline VPipeline(std::string&& name) :
207 Instanced<This_t>(), BasePipe(name + "/Instance" + std::to_string(this->instance)) {}
208 inline virtual ~VPipeline() = default;
209
210
211 inline virtual void process(cv::Mat& io_frame) override {}
212
213
214};
215
216template<class... pipelines_t>
217class SequentialPipeline : public VPipeline<SequentialPipeline<pipelines_t...> > {
218 typedef struct SequentialPipeline<pipelines_t...> This_t;
219public:
221 VPipeline<This_t>("SequentialPipeline<" + Construct(this->heap_ptrs) + "> ")
222 {
223 for(size_t i = 0; i < this->heap_ptrs.size(); i++) {
224 this->pipelines.push_back(this->heap_ptrs.at(i).get());
225 }
226 }
227
229 void addPipelines(std::vector<VisionServer::BasePipe*>&&);
230 void addPipelines(std::initializer_list<VisionServer::BasePipe*>);
231
232 virtual void process(cv::Mat& io_frame) override;
233
234protected:
235 static std::string Construct(std::vector<std::unique_ptr<VisionServer::BasePipe> >&);
236
237 std::vector<VisionServer::BasePipe*> pipelines;
238 std::vector<std::unique_ptr<VisionServer::BasePipe> > heap_ptrs;
239
240
241};
243
244
245} // namespace vs2
246
247
248
249
250
251
252
253
254
255
258#include <type_traits>
259#include <sstream>
260
261
262namespace vs2 {
263
264inline std::vector<VisionCamera>& VisionServer::getCameras() { return inst().cameras; }
265inline size_t VisionServer::numCameras() { return inst().cameras.size(); }
266inline const std::vector<VisionServer::BasePipe*>& VisionServer::getPipelines() { return inst().pipelines; }
267inline size_t VisionServer::numPipelines() { return inst().pipelines.size(); }
268inline const std::vector<VisionServer::OutputStream>& VisionServer::getStreams() { return inst().streams; }
269inline size_t VisionServer::numStreams() { return inst().streams.size(); }
270inline bool VisionServer::isRunning() { return inst().is_running; }
271
272template<class pipeline>
274 static_assert(std::is_base_of<VisionServer::BasePipe, pipeline>::value, "Template argument (pipeline) must inherit from BasePipe");
275 static_assert(std::is_default_constructible<pipeline>::value, "Template arguement (pipeline) must be default constructible");
277 VisionServer& _inst = getInstance();
278 _inst.heap_allocated.emplace_back(std::make_unique<pipeline>());
279 _inst.pipelines.push_back(_inst.heap_allocated.back().get());
280 return true;
281 }
282 return false;
283}
284template<class... pipelines_t>
287 VisionServer& _inst = getInstance();
288 _inst.heap_allocated.reserve(_inst.heap_allocated.size() + sizeof...(pipelines_t));
289 _inst.pipelines.reserve(_inst.pipelines.size() + sizeof...(pipelines_t));
290 size_t alloc = VisionServer::pipeExpander<pipelines_t...>(inst().heap_allocated);
291 for(size_t i = alloc; i >= 0; --i) {
292 _inst.pipelines.push_back(_inst.heap_allocated.at(_inst.heap_allocated.size() - i - 1).get());
293 }
294 return true;
295 }
296 return false;
297}
298template<class... pipelines_t>
301 VisionServer& _inst = getInstance();
302 _inst.heap_allocated.clear();
303 _inst.heap_allocated.reserve(sizeof...(pipelines_t));
304 _inst.pipelines.clear();
305 _inst.pipelines.reserve(sizeof...(pipelines_t));
306 VisionServer::pipeExpander<pipelines_t...>(_inst.heap_allocated);
307 for(size_t i = 0; i < _inst.heap_allocated.size(); i++) {
308 _inst.pipelines.push_back(_inst.heap_allocated.at(i).get());
309 }
310 return true;
311 }
312 return false;
313}
314
315template<class pipeline, class... pipelines>
316size_t VisionServer::pipeExpander(std::vector<std::unique_ptr<BasePipe> >& pipes) {
317 if constexpr(!std::is_same<pipeline, void>::value) {
318 static_assert(std::is_base_of<VisionServer::BasePipe, pipeline>::value, "Template argument (pipeline) must inherit from BasePipe");
319 static_assert(std::is_default_constructible<pipeline>::value, "Template arguement (pipeline) must be default constructible");
320
321 pipes.emplace_back(std::make_unique<pipeline>());
322 return 1U + VisionServer::pipeExpander<pipelines...>(pipes);
323 }
324 return 0U;
325}
326
327// template<class derived>
328// void VPipeline<derived>::process(cv::Mat&) {}
329
330template<class... pipelines_t>
331inline std::string SequentialPipeline<pipelines_t...>::Construct(std::vector<std::unique_ptr<VisionServer::BasePipe> >& pipes) {
332 if(VisionServer::pipeExpander<pipelines_t...>(pipes) < 1) {
333 return "void";
334 } else {
335 std::stringstream ret(pipes.at(0)->getName());
336 for(size_t i = 1; i < pipes.size(); i++) {
337 ret << ", " << pipes.at(i)->getName();
338 }
339 return ret.str();
340 }
341
342}
343template<class... pipelines_t>
345 this->pipelines.push_back(p);
346}
347template<class... pipelines_t>
348void SequentialPipeline<pipelines_t...>::addPipelines(std::vector<VisionServer::BasePipe*>&& ps) {
349 this->pipelines.insert(this->pipelines.end(), ps.begin(), ps.end());
350}
351template<class... pipelines_t>
352void SequentialPipeline<pipelines_t...>::addPipelines(std::initializer_list<VisionServer::BasePipe*> ps) {
353 this->pipelines.insert(this->pipelines.end(), ps.begin(), ps.end());
354}
355template<class... pipelines_t>
357 for(size_t i = 0; i < this->pipelines.size(); i++) {
358 this->pipelines.at(i)->process(io_frame);
359 }
360}
361
362} // namespace vs2;
static const cv::Mat_< float > default_matrix
Definition: visioncamera.h:18
static const cv::Mat_< float > default_distort
Definition: visioncamera.h:19
virtual void process(cv::Mat &io_frame) override
void addPipeline(VisionServer::BasePipe *)
void addPipelines(std::vector< VisionServer::BasePipe * > &&)
static std::string Construct(std::vector< std::unique_ptr< VisionServer::BasePipe > > &)
std::vector< std::unique_ptr< VisionServer::BasePipe > > heap_ptrs
std::vector< VisionServer::BasePipe * > pipelines
virtual ~VPipeline()=default
VPipeline(const std::string &name)
virtual void process(cv::Mat &io_frame) override
VPipeline()=delete
VPipeline(const VPipeline &)=delete
VPipeline(std::string &&name)
VPipeline(const char *name)
const cv::Mat1f & getSrcDistort() const
Definition: visionserver2.h:72
const std::string & getName() const
Definition: visionserver2.h:46
BasePipe(const std::string &name)
Definition: visionserver2.h:57
const cv::Mat1f & getSrcMatrix() const
Definition: visionserver2.h:71
const cv::Mat_< float > * src_distort
Definition: visionserver2.h:79
void setSource(const cs::VideoSource &)
BasePipe(const char *name)
Definition: visionserver2.h:54
const std::shared_ptr< nt::NetworkTable > table
Definition: visionserver2.h:81
BasePipe(std::string &&name)
Definition: visionserver2.h:60
const std::shared_ptr< nt::NetworkTable > & getTable() const
Definition: visionserver2.h:47
void setCamera(const VisionCamera &)
virtual void process(cv::Mat &io_frame)=0
void setPipeline(const BasePipe &)
const cv::Mat_< float > * src_matrix
Definition: visionserver2.h:78
static const std::shared_ptr< nt::NetworkTable > & ntable()
Definition: visionserver2.h:41
std::thread head
static bool addStream()
static VisionServer & inst()
static size_t numCameras()
static size_t numPipelines()
static bool addPipeline()
void operator=(VisionServer &&)=delete
static void stopExit()
static const std::vector< BasePipe * > & getPipelines()
static bool setPipelines()
static const std::shared_ptr< nt::NetworkTable > & ntable()
Definition: visionserver2.h:22
static void Init()
Definition: visionserver2.h:31
std::vector< std::unique_ptr< BasePipe > > heap_allocated
static const std::vector< OutputStream > & getStreams()
static size_t numStreams()
void operator=(const VisionServer &)=delete
static bool runSingleThread(float fps_cap=30.f)
VisionServer(const VisionServer &)=delete
static bool addCameras(std::vector< VisionCamera > &&)
static bool run(float fps_cap=30.f)
static size_t pipeExpander(std::vector< std::unique_ptr< BasePipe > > &)
static bool runThread(float fps_cap=30.f)
static bool addStreams(size_t=2)
static bool compensate()
std::vector< VisionCamera > cameras
static bool isRunning()
VisionServer(VisionServer &&)=delete
static void pipelineRunner(BasePipe *, float fps_cap)
static bool runRaw()
static VisionServer & getInstance()
Definition: visionserver2.h:27
static std::vector< VisionCamera > & getCameras()
std::atomic< bool > is_running
static bool addPipelines()
std::vector< BasePipe * > pipelines
static bool addCamera(VisionCamera &&)
static bool runRawThread()
static bool stop()
static bool runSingle(float fps_cap=30.f)
static bool setCameras(std::vector< VisionCamera > &&)
std::vector< OutputStream > streams
Definition: extensions.h:9
struct VPipeline_S BasePipe
SequentialPipeline SeqPipeline
static const std::shared_ptr< nt::NetworkTable > & ntable()
const std::shared_ptr< nt::NetworkTable > table
OutputStream(cs::MjpegServer &&s)
OutputStream(const OutputStream &o)
OutputStream(std::string_view n, int p)
OutputStream(std::string_view n)