JeVois  1.12
JeVois Smart Embedded Machine Vision Toolkit
Share this page:
Module.C
Go to the documentation of this file.
1 // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2 //
3 // JeVois Smart Embedded Machine Vision Toolkit - Copyright (C) 2016 by Laurent Itti, the University of Southern
4 // California (USC), and iLab at USC. See http://iLab.usc.edu and http://jevois.org for information about this project.
5 //
6 // This file is part of the JeVois Smart Embedded Machine Vision Toolkit. This program is free software; you can
7 // redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software
8 // Foundation, version 2. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9 // without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
10 // License for more details. You should have received a copy of the GNU General Public License along with this program;
11 // if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
12 //
13 // Contact information: Laurent Itti - 3641 Watt Way, HNB-07A - Los Angeles, CA 90089-2520 - USA.
14 // Tel: +1 213 740 3527 - itti@pollux.usc.edu - http://iLab.usc.edu - http://jevois.org
15 // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
16 /*! \file */
17 
18 #include <jevois/Core/Module.H>
19 #include <jevois/Core/VideoInput.H>
21 #include <jevois/Core/Engine.H>
25 
26 #include <opencv2/imgproc/imgproc.hpp>
27 
28 #include <cmath>
29 #include <sstream>
30 #include <iomanip>
31 
32 // ####################################################################################################
33 jevois::InputFrame::InputFrame(std::shared_ptr<jevois::VideoInput> const & cam, bool turbo) :
34  itsCamera(cam), itsDidGet(false), itsDidDone(false), itsTurbo(turbo)
35 { }
36 
37 // ####################################################################################################
39 {
40  // If itsCamera is invalidated, we have been moved to another object, so do not do anything here:
41  if (itsCamera.get() == nullptr) return;
42 
43  // If we did not yet get(), just end now, camera will drop this frame:
44  if (itsDidGet == false) return;
45 
46  // If we did get() but not done(), signal done now:
47  if (itsDidDone == false) try { itsCamera->done(itsImage); } catch (...) { }
48 }
49 
50 // ####################################################################################################
51 jevois::RawImage const & jevois::InputFrame::get(bool casync) const
52 {
53  itsCamera->get(itsImage);
54  itsDidGet = true;
55  if (casync && itsTurbo) itsImage.buf->sync();
56  return itsImage;
57 }
58 
59 // ####################################################################################################
61 {
62  itsCamera->done(itsImage);
63  itsDidDone = true;
64 }
65 
66 // ####################################################################################################
67 cv::Mat jevois::InputFrame::getCvGRAY(bool casync) const
68 {
69  jevois::RawImage const & rawimg = get(casync);
70  cv::Mat cvimg = jevois::rawimage::convertToCvGray(rawimg);
71  done();
72  return cvimg;
73 }
74 
75 // ####################################################################################################
76 cv::Mat jevois::InputFrame::getCvBGR(bool casync) const
77 {
78  jevois::RawImage const & rawimg = get(casync);
79  cv::Mat cvimg = jevois::rawimage::convertToCvBGR(rawimg);
80  done();
81  return cvimg;
82 }
83 
84 // ####################################################################################################
85 cv::Mat jevois::InputFrame::getCvRGB(bool casync) const
86 {
87  jevois::RawImage const & rawimg = get(casync);
88  cv::Mat cvimg = jevois::rawimage::convertToCvRGB(rawimg);
89  done();
90  return cvimg;
91 }
92 
93 // ####################################################################################################
94 cv::Mat jevois::InputFrame::getCvRGBA(bool casync) const
95 {
96  jevois::RawImage const & rawimg = get(casync);
97  cv::Mat cvimg = jevois::rawimage::convertToCvRGBA(rawimg);
98  done();
99  return cvimg;
100 }
101 
102 // ####################################################################################################
103 // ####################################################################################################
104 jevois::OutputFrame::OutputFrame(std::shared_ptr<jevois::VideoOutput> const & gad, jevois::RawImage * excimg) :
105  itsGadget(gad), itsDidGet(false), itsDidSend(false), itsImagePtrForException(excimg)
106 { }
107 
108 // ####################################################################################################
110 {
111  // If itsGadget is invalidated, we have been moved to another object, so do not do anything here:
112  if (itsGadget.get() == nullptr) return;
113 
114  // If we did not get(), just end now:
115  if (itsDidGet == false) return;
116 
117  // If Engine gave us a non-zero image pointer for exceptions, and we did get(), pass down the buffer we did get, so
118  // that Engine can write exception text into it, unless it is too late (exception occurred after send()) or too early
119  // (before get()), in which case Engine will get its own buffer:
120  if (itsImagePtrForException)
121  {
122  if (itsDidSend == false) { *itsImagePtrForException = itsImage; }
123  // Engine will be responsible for the final send()
124  }
125  else
126  {
127  // If we did get() but not send(), send now (the image will likely contain garbage):
128  if (itsDidSend == false) try { itsGadget->send(itsImage); } catch (...) { }
129  }
130 }
131 
132 // ####################################################################################################
134 {
135  itsGadget->get(itsImage);
136  itsDidGet = true;
137  return itsImage;
138 }
139 
140 // ####################################################################################################
142 {
143  itsGadget->send(itsImage);
144  itsDidSend = true;
145  if (itsImagePtrForException) itsImagePtrForException->invalidate();
146 }
147 
148 // ####################################################################################################
149 void jevois::OutputFrame::sendCv(cv::Mat const & img, int quality) const
150 {
151  switch(img.type())
152  {
153  case CV_8UC3: sendScaledCvBGR(img, quality); break;
154  case CV_8UC1: sendScaledCvGRAY(img, quality); break;
155  case CV_8UC4: sendScaledCvRGBA(img, quality); break;
156  default: LFATAL("cv::Mat of type " << cvtypestr(img.type()) << " not supported.");
157  }
158 }
159 
160 // ####################################################################################################
161 void jevois::OutputFrame::sendCvGRAY(cv::Mat const & img, int quality) const
162 {
163  jevois::RawImage rawimg = get();
164  jevois::rawimage::convertCvGRAYtoRawImage(img, rawimg, quality);
165  send();
166 }
167 
168 // ####################################################################################################
169 void jevois::OutputFrame::sendCvBGR(cv::Mat const & img, int quality) const
170 {
171  jevois::RawImage rawimg = get();
172  jevois::rawimage::convertCvBGRtoRawImage(img, rawimg, quality);
173  send();
174 }
175 // ####################################################################################################
176 void jevois::OutputFrame::sendCvRGB(cv::Mat const & img, int quality) const
177 {
178  jevois::RawImage rawimg = get();
179  jevois::rawimage::convertCvRGBtoRawImage(img, rawimg, quality);
180  send();
181 }
182 
183 // ####################################################################################################
184 void jevois::OutputFrame::sendCvRGBA(cv::Mat const & img, int quality) const
185 {
186  jevois::RawImage rawimg = get();
187  jevois::rawimage::convertCvRGBAtoRawImage(img, rawimg, quality);
188  send();
189 }
190 
191 // ####################################################################################################
192 void jevois::OutputFrame::sendScaledCvGRAY(cv::Mat const & img, int quality) const
193 {
194  jevois::RawImage rawimg = get();
196  rawimg, quality);
197  send();
198 }
199 
200 // ####################################################################################################
201 void jevois::OutputFrame::sendScaledCvBGR(cv::Mat const & img, int quality) const
202 {
203  jevois::RawImage rawimg = get();
205  rawimg, quality);
206  send();
207 }
208 // ####################################################################################################
209 void jevois::OutputFrame::sendScaledCvRGB(cv::Mat const & img, int quality) const
210 {
211  jevois::RawImage rawimg = get();
213  rawimg, quality);
214  send();
215 }
216 
217 // ####################################################################################################
218 void jevois::OutputFrame::sendScaledCvRGBA(cv::Mat const & img, int quality) const
219 {
220  jevois::RawImage rawimg = get();
222  rawimg, quality);
223  send();
224 }
225 
226 // ####################################################################################################
227 // ####################################################################################################
228 jevois::Module::Module(std::string const & instance) :
229  jevois::Component(instance)
230 { }
231 
232 // ####################################################################################################
234 { }
235 
236 // ####################################################################################################
237 void jevois::Module::process(InputFrame && JEVOIS_UNUSED_PARAM(inframe), OutputFrame && JEVOIS_UNUSED_PARAM(outframe))
238 { LFATAL("Not implemented in this module"); }
239 
240 // ####################################################################################################
241 void jevois::Module::process(InputFrame && JEVOIS_UNUSED_PARAM(inframe))
242 { LFATAL("Not implemented in this module"); }
243 
244 // ####################################################################################################
245 void jevois::Module::sendSerial(std::string const & str)
246 {
247  jevois::Engine * e = dynamic_cast<jevois::Engine *>(itsParent);
248  if (e == nullptr) LFATAL("My parent is not Engine -- CANNOT SEND SERIAL");
249 
250  e->sendSerial(str);
251 }
252 
253 // ####################################################################################################
254 void jevois::Module::parseSerial(std::string const & str,
255  std::shared_ptr<jevois::UserInterface> JEVOIS_UNUSED_PARAM(s))
256 { throw std::runtime_error("Unsupported command [" + str + ']'); }
257 
258 // ####################################################################################################
259 void jevois::Module::supportedCommands(std::ostream & os)
260 { os << "None" << std::endl; }
261 
262 // ####################################################################################################
264 { return engine()->frameNum(); }
265 
266 // ####################################################################################################
267 void jevois::Module::writeCamRegister(unsigned short reg, unsigned short val)
268 { engine()->writeCamRegister(reg, val); }
269 
270 // ####################################################################################################
271 unsigned short jevois::Module::readCamRegister(unsigned short reg)
272 { return engine()->readCamRegister(reg); }
273 
274 // ####################################################################################################
275 void jevois::Module::writeIMUregister(unsigned short reg, unsigned short val)
276 { engine()->writeIMUregister(reg, val); }
277 
278 // ####################################################################################################
279 unsigned short jevois::Module::readIMUregister(unsigned short reg)
280 { return engine()->readIMUregister(reg); }
281 
282 // ####################################################################################################
283 void jevois::Module::writeIMUregisterArray(unsigned short reg, unsigned char const * vals, size_t num)
284 { engine()->writeIMUregisterArray(reg, vals, num); }
285 
286 // ####################################################################################################
287 void jevois::Module::readIMUregisterArray(unsigned short reg, unsigned char * vals, size_t num)
288 { return engine()->readIMUregisterArray(reg, vals, num); }
289 
290 // ####################################################################################################
291 // ####################################################################################################
292 jevois::StdModule::StdModule(std::string const & instance) :
293  jevois::Module(instance)
294 { }
295 
296 // ####################################################################################################
298 { }
299 
300 // ####################################################################################################
301 std::string jevois::StdModule::getStamp() const
302 {
303  std::string ret;
304 
305  switch(serstamp::get())
306  {
307  case jevois::module::SerStamp::None:
308  break;
309 
310  case jevois::module::SerStamp::Frame:
311  ret = std::to_string(frameNum());
312  break;
313 
314  case jevois::module::SerStamp::Time:
315  {
316  std::time_t t = std::time(nullptr); char str[100];
317  std::strftime(str, sizeof(str), "%T", std::localtime(&t));
318  ret = std::string(str);
319  }
320  break;
321 
322  case jevois::module::SerStamp::FrameTime:
323  {
324  std::time_t t = std::time(nullptr); char str[100];
325  std::strftime(str, sizeof(str), "%T", std::localtime(&t));
326  ret = std::to_string(frameNum()) + '/' + std::string(str);
327  }
328  break;
329 
330  case jevois::module::SerStamp::FrameDateTime:
331  {
332  std::time_t t = std::time(nullptr); char str[100];
333  std::strftime(str, sizeof(str), "%F/%T", std::localtime(&t));
334  ret = std::to_string(frameNum()) + '/' + std::string(str);
335  }
336  break;
337  }
338 
339  if (ret.empty() == false) ret += ' ';
340  return ret;
341 }
342 
343 // ####################################################################################################
344 void jevois::StdModule::sendSerialImg1Dx(unsigned int camw, float x, float size, std::string const & id,
345  std::string const & extra)
346 {
347  // Normalize the coordinate and size using the given precision to do rounding:
348  float const eps = std::pow(10.0F, -float(serprec::get()));
349 
350  jevois::coords::imgToStdX(x, camw, eps);
351  float dummy = 0.0F; jevois::coords::imgToStdSize(size, dummy, camw, 100, eps);
352 
353  // Delegate:
354  sendSerialStd1Dx(x, size, id, extra);
355 }
356 
357 // ####################################################################################################
358 void jevois::StdModule::sendSerialStd1Dx(float x, float size, std::string const & id, std::string const & extra)
359 {
360  // Build the message depending on desired style:
361  std::ostringstream oss; oss << std::fixed << std::setprecision(serprec::get());
362 
363  // Prepend frame/date/time as possibly requested by parameter serstamp:
364  oss << getStamp();
365 
366  // Format the message depending on parameter serstyle:
367  switch (serstyle::get())
368  {
369  case jevois::module::SerStyle::Terse:
370  oss << "T1 " << x;
371  break;
372 
373  case jevois::module::SerStyle::Normal:
374  oss << "N1 ";
375  if (id.empty()) oss << "unknown "; else oss << jevois::replaceWhitespace(id) << ' ';
376  oss << x << ' ' << size;
377  break;
378 
379  case jevois::module::SerStyle::Detail:
380  case jevois::module::SerStyle::Fine:
381  oss << "D1 ";
382  if (id.empty()) oss << "unknown "; else oss << jevois::replaceWhitespace(id) << ' ';
383  oss << x - 0.5F * size << ' ' << x + 0.5F * size;
384  if (extra.empty() == false) oss << ' ' << extra;
385  break;
386  }
387 
388  // Send the message:
389  sendSerial(oss.str());
390 }
391 
392 // ####################################################################################################
393 void jevois::StdModule::sendSerialImg1Dy(unsigned int camh, float y, float size, std::string const & id,
394  std::string const & extra)
395 {
396  // Normalize the coordinate and size using the given precision to do rounding:
397  float const eps = std::pow(10.0F, -float(serprec::get()));
398  jevois::coords::imgToStdY(y, camh, eps);
399  float dummy = 0.0F; jevois::coords::imgToStdSize(dummy, size, 100, camh, eps);
400 
401  // Delegate:
402  sendSerialStd1Dy(y, size, id, extra);
403 }
404 
405 // ####################################################################################################
406 void jevois::StdModule::sendSerialStd1Dy(float y, float size, std::string const & id, std::string const & extra)
407 {
408  // Build the message depending on desired style:
409  std::ostringstream oss; oss << std::fixed << std::setprecision(serprec::get());
410 
411  // Prepend frame/date/time as possibly requested by parameter serstamp:
412  oss << getStamp();
413 
414  // Format the message depending on parameter serstyle:
415  switch (serstyle::get())
416  {
417  case jevois::module::SerStyle::Terse:
418  oss << "T1 " << y;
419  break;
420 
421  case jevois::module::SerStyle::Normal:
422  oss << "N1 ";
423  if (id.empty()) oss << "unknown "; else oss << jevois::replaceWhitespace(id) << ' ';
424  oss << y << ' ' << size;
425  break;
426 
427  case jevois::module::SerStyle::Detail:
428  case jevois::module::SerStyle::Fine:
429  oss << "D1 ";
430  if (id.empty()) oss << "unknown "; else oss << jevois::replaceWhitespace(id) << ' ';
431  oss << y - 0.5F * size << ' ' << y + 0.5F * size;
432  if (extra.empty() == false) oss << ' ' << extra;
433  break;
434  }
435 
436  // Send the message:
437  sendSerial(oss.str());
438 }
439 
440 // ####################################################################################################
441 void jevois::StdModule::sendSerialImg2D(unsigned int camw, unsigned int camh, float x, float y, float w, float h,
442  std::string const & id, std::string const & extra)
443 {
444  // Normalize the coordinates and sizes using the given precision to do rounding:
445  float const eps = std::pow(10.0F, -float(serprec::get()));
446 
447  jevois::coords::imgToStd(x, y, camw, camh, eps);
448  jevois::coords::imgToStdSize(w, h, camw, camh, eps);
449 
450  // Delegate:
451  sendSerialStd2D(x, y, w, h, id, extra);
452 }
453 // ####################################################################################################
454 void jevois::StdModule::sendSerialStd2D(float x, float y, float w, float h, std::string const & id,
455  std::string const & extra)
456 {
457  // Build the message depending on desired style:
458  std::ostringstream oss; oss << std::fixed << std::setprecision(serprec::get());
459 
460  // Prepend frame/date/time as possibly requested by parameter serstamp:
461  oss << getStamp();
462 
463  // Format the message depending on parameter serstyle:
464  switch (serstyle::get())
465  {
466  case jevois::module::SerStyle::Terse:
467  oss << "T2 " << x << ' ' << y;
468  break;
469 
470  case jevois::module::SerStyle::Normal:
471  oss << "N2 ";
472  if (id.empty()) oss << "unknown "; else oss << jevois::replaceWhitespace(id) << ' ';
473  oss << x << ' ' << y << ' ' << w << ' ' << h;
474  break;
475 
476  case jevois::module::SerStyle::Detail:
477  oss << "D2 ";
478  if (id.empty()) oss << "unknown "; else oss << jevois::replaceWhitespace(id) << ' ';
479  oss << x - 0.5F * w << ' ' << y - 0.5F * h << ' ';
480  oss << x + 0.5F * w << ' ' << y - 0.5F * h << ' ';
481  oss << x + 0.5F * w << ' ' << y + 0.5F * h << ' ';
482  oss << x + 0.5F * w << ' ' << y - 0.5F * h;
483  if (extra.empty() == false) oss << ' ' << extra;
484  break;
485 
486  case jevois::module::SerStyle::Fine:
487  oss << "F2 ";
488  if (id.empty()) oss << "unknown "; else oss << jevois::replaceWhitespace(id) << ' ';
489  oss << 4 << ' '; // number of vertices
490  oss << x - 0.5F * w << ' ' << y - 0.5F * h << ' ';
491  oss << x + 0.5F * w << ' ' << y - 0.5F * h << ' ';
492  oss << x + 0.5F * w << ' ' << y + 0.5F * h << ' ';
493  oss << x + 0.5F * w << ' ' << y - 0.5F * h;
494  if (extra.empty() == false) oss << ' ' << extra;
495  break;
496  }
497 
498  // Send the message:
499  sendSerial(oss.str());
500 }
501 
502 // ####################################################################################################
503 template <typename T>
504 void jevois::StdModule::sendSerialContour2D(unsigned int camw, unsigned int camh, std::vector<cv::Point_<T> > points,
505  std::string const & id, std::string const & extra)
506 {
507  // Format the message depending on parameter serstyle:
508  switch (serstyle::get())
509  {
510  case jevois::module::SerStyle::Terse:
511  {
512  // Compute center of gravity:
513  float cx = 0.0F, cy = 0.0F;
514  for (cv::Point const & p : points) { cx += p.x; cy += p.y; }
515  if (points.size()) { cx /= points.size(); cy /= points.size(); }
516  sendSerialImg2D(camw, camh, cx, cy, 0.0F, 0.0F, id, extra);
517  }
518  break;
519 
520  case jevois::module::SerStyle::Normal:
521  {
522  // Compute upright bounding rectangle:
523  cv::Rect r = cv::boundingRect(points);
524  sendSerialImg2D(camw, camh, r.x + 0.5F * r.width, r.y + 0.5F * r.height, r.width, r.height, id, extra);
525  }
526  break;
527 
528  case jevois::module::SerStyle::Detail:
529  {
530  // Compute minimal rotated rectangle enclosing the points:
531  cv::RotatedRect r = cv::minAreaRect(points);
532 
533  // Build the message:
534  unsigned int const prec = serprec::get(); float const eps = std::pow(10.0F, -float(prec));
535  std::ostringstream oss; oss << std::fixed << std::setprecision(prec);
536 
537  // Prepend frame/date/time as possibly requested by parameter serstamp:
538  oss << getStamp();
539 
540  // Now the rest of the message:
541  oss << "D2 ";
542  if (id.empty()) oss << "unknown "; else oss << jevois::replaceWhitespace(id) << ' ';
543  cv::Point2f corners[4];
544  r.points(corners);
545 
546  oss << 4; // number of vertices
547 
548  for (int i = 0; i < 4; ++i)
549  {
550  float x = corners[i].x, y = corners[i].y;
551  jevois::coords::imgToStd(x, y, camw, camh, eps);
552  oss << ' ' << x << ' ' << y;
553  }
554  if (extra.empty() == false) oss << ' ' << extra;
555 
556  // Send the message:
557  sendSerial(oss.str());
558  }
559  break;
560 
561  case jevois::module::SerStyle::Fine:
562  {
563  // Build the message:
564  unsigned int const prec = serprec::get(); float const eps = std::pow(10.0F, -float(prec));
565  std::ostringstream oss; oss << std::fixed << std::setprecision(prec);
566 
567  // Prepend frame/date/time as possibly requested by parameter serstamp:
568  oss << getStamp();
569 
570  // Now the rest of the message:
571  oss << "F2 ";
572  if (id.empty()) oss << "unknown "; else oss << jevois::replaceWhitespace(id) << ' ';
573  oss << points.size(); // number of vertices
574 
575  for (cv::Point const & p : points)
576  {
577  float x = p.x, y = p.y;
578  jevois::coords::imgToStd(x, y, camw, camh, eps);
579  oss << ' ' << x << ' ' << y;
580  }
581  if (extra.empty() == false) oss << ' ' << extra;
582 
583  // Send the message:
584  sendSerial(oss.str());
585  }
586  break;
587  }
588 }
589 
590 // Compile in explicit template instantiations:
591 namespace jevois
592 {
593  template
594  void StdModule::sendSerialContour2D(unsigned int camw, unsigned int camh, std::vector<cv::Point_<int> > points,
595  std::string const & id, std::string const & extra);
596  template
597  void StdModule::sendSerialContour2D(unsigned int camw, unsigned int camh, std::vector<cv::Point_<float> > points,
598  std::string const & id, std::string const & extra);
599  template
600  void StdModule::sendSerialContour2D(unsigned int camw, unsigned int camh, std::vector<cv::Point_<double> > points,
601  std::string const & id, std::string const & extra);
602 }
603 
604 // ####################################################################################################
605 void jevois::StdModule::sendSerialStd3D(float x, float y, float z, float w, float h, float d,
606  float q1, float q2, float q3, float q4,
607  std::string const & id, std::string const & extra)
608 {
609  // Build the message depending on desired style:
610  std::ostringstream oss; oss << std::fixed << std::setprecision(serprec::get());
611 
612  // Prepend frame/date/time as possibly requested by parameter serstamp:
613  oss << getStamp();
614 
615  // Format the message depending on parameter serstyle:
616  switch (serstyle::get())
617  {
618  case jevois::module::SerStyle::Terse:
619  oss << "T3 " << x << ' ' << y << ' ' << z;
620  break;
621 
622  case jevois::module::SerStyle::Normal:
623  oss << "N3 ";
624  if (id.empty()) oss << "unknown "; else oss << jevois::replaceWhitespace(id) << ' ';
625  oss << x << ' ' << y << ' ' << z << ' ' << w << ' ' << h << ' ' << d;
626  break;
627 
628  case jevois::module::SerStyle::Detail:
629  oss << "D3 ";
630  if (id.empty()) oss << "unknown "; else oss << jevois::replaceWhitespace(id) << ' ';
631  oss << x << ' ' << y << ' ' << z << ' ' << w << ' ' << h << ' ' << d << ' '
632  << q1 << ' ' << q2 << ' ' << q3 << ' ' << q4;
633  if (extra.empty() == false) oss << ' ' << extra;
634  break;
635 
636  case jevois::module::SerStyle::Fine:
637  oss << "F3 ";
638  if (id.empty()) oss << "unknown "; else oss << jevois::replaceWhitespace(id) << ' ';
639  oss << 8 << ' '; // number of vertices
640  oss << x - 0.5F * w << ' ' << y - 0.5F * h << ' ' << z - 0.5F * d << ' ';
641  oss << x + 0.5F * w << ' ' << y - 0.5F * h << ' ' << z - 0.5F * d << ' ';
642  oss << x + 0.5F * w << ' ' << y + 0.5F * h << ' ' << z - 0.5F * d << ' ';
643  oss << x + 0.5F * w << ' ' << y - 0.5F * h << ' ' << z - 0.5F * d << ' ';
644  oss << x - 0.5F * w << ' ' << y - 0.5F * h << ' ' << z + 0.5F * d << ' ';
645  oss << x + 0.5F * w << ' ' << y - 0.5F * h << ' ' << z + 0.5F * d << ' ';
646  oss << x + 0.5F * w << ' ' << y + 0.5F * h << ' ' << z + 0.5F * d << ' ';
647  oss << x + 0.5F * w << ' ' << y - 0.5F * h << ' ' << z + 0.5F * d << ' ';
648  if (extra.empty() == false) oss << ' ' << extra;
649  break;
650  }
651 
652  // Send the message:
653  sendSerial(oss.str());
654 }
655 
656 // ####################################################################################################
657 void jevois::StdModule::sendSerialStd3D(std::vector<cv::Point3f> points, std::string const & id,
658  std::string const & extra)
659 {
660  // Format the message depending on parameter serstyle:
661  switch (serstyle::get())
662  {
663  case jevois::module::SerStyle::Terse:
664  {
665  // Compute center of gravity:
666  cv::Point3f cg(0.0F, 0.0F, 0.0F);
667  for (cv::Point3f const & p : points) cg += p;
668  if (points.size()) { cg.x /= points.size(); cg.y /= points.size(); cg.z /= points.size(); }
669  sendSerialStd3D(cg.x, cg.y, cg.z, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, id, extra);
670  }
671  break;
672 
673  case jevois::module::SerStyle::Normal:
674  {
675  // Compute upright bounding parallelepiped:
676  cv::Point3f cg(0.0F, 0.0F, 0.0F), pmin(1e30F, 1e30F, 1e30F), pmax(-1e30F, -1e30F, -1e30F);
677  for (cv::Point3f const & p : points)
678  {
679  cg += p;
680  if (p.x < pmin.x) pmin.x = p.x;
681  if (p.y < pmin.y) pmin.y = p.y;
682  if (p.z < pmin.z) pmin.z = p.z;
683  if (p.x > pmax.x) pmax.x = p.x;
684  if (p.y > pmax.y) pmax.y = p.y;
685  if (p.z > pmax.z) pmax.z = p.z;
686  }
687  if (points.size()) { cg.x /= points.size(); cg.y /= points.size(); cg.z /= points.size(); }
688  sendSerialStd3D(cg.x, cg.y, cg.z, pmax.x - pmin.x, pmax.y - pmin.y, pmax.z - pmin.z, 0.0F, 0.0F, 0.0F, 0.0F,
689  id, extra);
690  }
691  break;
692 
693  case jevois::module::SerStyle::Detail:
694  {
695  // Compute upright bounding parallelepiped:
696  cv::Point3f cg(0.0F, 0.0F, 0.0F), pmin(1e30F, 1e30F, 1e30F), pmax(-1e30F, -1e30F, -1e30F);
697  for (cv::Point3f const & p : points)
698  {
699  cg += p;
700  if (p.x < pmin.x) pmin.x = p.x;
701  if (p.y < pmin.y) pmin.y = p.y;
702  if (p.z < pmin.z) pmin.z = p.z;
703  if (p.x > pmax.x) pmax.x = p.x;
704  if (p.y > pmax.y) pmax.y = p.y;
705  if (p.z > pmax.z) pmax.z = p.z;
706  }
707  if (points.size()) { cg.x /= points.size(); cg.y /= points.size(); cg.z /= points.size(); }
708  // FIXME what should we send for the quaternion?
709  sendSerialStd3D(cg.x, cg.y, cg.z, pmax.x - pmin.x, pmax.y - pmin.y, pmax.z - pmin.z, 0.0F, 0.0F, 0.0F, 1.0F,
710  id, extra);
711  }
712  break;
713 
714  case jevois::module::SerStyle::Fine:
715  {
716  // Build the message:
717  unsigned int const prec = serprec::get();
718  std::ostringstream oss; oss << std::fixed << std::setprecision(prec);
719 
720  // Prepend frame/date/time as possibly requested by parameter serstamp:
721  oss << getStamp();
722 
723  // Now the rest of the message:
724  oss << "F3 ";
725  if (id.empty()) oss << "unknown "; else oss << jevois::replaceWhitespace(id) << ' ';
726  oss << points.size(); // number of vertices
727 
728  for (cv::Point3f const & p : points) oss << ' ' << p.x << ' ' << p.y << ' ' << p.z;
729  if (extra.empty() == false) oss << ' ' << extra;
730 
731  // Send the message:
732  sendSerial(oss.str());
733  }
734  break;
735  }
736 }
737 
738 // ####################################################################################################
740 {
742  if (m == jevois::module::SerMark::None || m == jevois::module::SerMark::Stop) return;
743  sendSerial(getStamp() + "MARK START");
744 }
745 
746 // ####################################################################################################
748 {
750  if (m == jevois::module::SerMark::None || m == jevois::module::SerMark::Start) return;
751  sendSerial(getStamp() + "MARK STOP");
752 }
753 
754 // ####################################################################################################
755 void jevois::StdModule::sendSerialObjReco(std::vector<jevois::ObjReco> const & res)
756 {
757  if (res.empty()) return;
758 
759  // Build the message depending on desired style:
760  std::ostringstream oss; oss << std::fixed << std::setprecision(serprec::get());
761 
762  // Prepend frame/date/time as possibly requested by parameter serstamp:
763  oss << getStamp();
764 
765  // Format the message depending on parameter serstyle:
766  switch (serstyle::get())
767  {
768  case jevois::module::SerStyle::Terse:
769  oss << "TO " << jevois::replaceWhitespace(res[0].category);
770  break;
771 
772  case jevois::module::SerStyle::Normal:
773  oss << "NO " << jevois::replaceWhitespace(res[0].category) << ':' << res[0].score;
774  break;
775 
776  case jevois::module::SerStyle::Detail:
777  oss << "DO";
778  for (auto const & r : res) oss << ' ' << jevois::replaceWhitespace(r.category) << ':' << r.score;
779  break;
780 
781  case jevois::module::SerStyle::Fine:
782  oss << "FO";
783  for (auto const & r : res) oss << ' ' << jevois::replaceWhitespace(r.category) << ':' << r.score;
784  break;
785  }
786 
787  // Send the message:
788  sendSerial(oss.str());
789 }
790 
791 // ####################################################################################################
792 void jevois::StdModule::sendSerialObjDetImg2D(unsigned int camw, unsigned int camh, float x, float y, float w, float h,
793  std::vector<ObjReco> const & res)
794 {
795  if (res.empty()) return;
796 
797  std::string best, extra; std::string * ptr = &best;
798  std::string fmt = "%s:%." + std::to_string(serprec::get()) + "f";
799 
800  for (auto const & r : res)
801  {
802  switch (serstyle::get())
803  {
804  case jevois::module::SerStyle::Terse:
805  (*ptr) += jevois::replaceWhitespace(r.category);
806  break;
807 
808  default:
809  (*ptr) += jevois::sformat(fmt.c_str(), jevois::replaceWhitespace(r.category).c_str(), r.score);
810  }
811  if (ptr == &extra) (*ptr) += ' ';
812  ptr = &extra;
813  }
814 
815  // Remove last space:
816  if (extra.empty() == false) extra = extra.substr(0, extra.length() - 1);
817 
818  sendSerialImg2D(camw, camh, x, y, w, h, best, extra);
819 }
820 
cv::Mat convertToCvRGB(RawImage const &src)
Convert RawImage to OpenCV doing color conversion from any RawImage source pixel to OpenCV RGB byte...
Definition: RawImageOps.C:302
cv::Mat convertToCvRGBA(RawImage const &src)
Convert RawImage to OpenCV doing color conversion from any RawImage source pixel to OpenCV RGB-A byte...
Definition: RawImageOps.C:325
void sendSerialContour2D(unsigned int camw, unsigned int camh, std::vector< cv::Point_< T > > points, std::string const &id="", std::string const &extra="")
Send standardized 2D message for polygons in image coordinates.
Definition: Module.C:504
void imgToStdY(float &y, unsigned int const height, float const eps=0.1F)
Transform Y coordinate in-place from camera to standardized, using given image width and height...
Definition: Coordinates.C:43
Data collection mode RAW means that the latest available raw data is returned each time get() is called
Exception-safe wrapper around a raw camera input frame.
Definition: Module.H:57
void imgToStd(float &x, float &y, RawImage const &camimg, float const eps=0.1F)
Transform coordinates in-place from camera to standardized, using a RawImage to establish image size...
Definition: Coordinates.C:22
void writeIMUregisterArray(unsigned short reg, unsigned char const *vals, size_t num)
Write an array of values to the camera&#39;s IMU registers.
Definition: Engine.C:940
cv::Mat convertToCvBGR(RawImage const &src)
Convert RawImage to OpenCV doing color conversion from any RawImage source pixel to OpenCV BGR byte...
Definition: RawImageOps.C:279
unsigned int height
Image height in pixels.
Definition: RawImage.H:146
std::string cvtypestr(unsigned int cvtype)
Convert cv::Mat::type() code to to a string (e.g., CV_8UC1, CV_32SC3, etc)
Definition: Utils.C:52
void sendSerialStd1Dx(float x, float size=0.0F, std::string const &id="", std::string const &extra="")
Send standardized 1D message for a standardized X coordinate.
Definition: Module.C:358
void writeCamRegister(unsigned short reg, unsigned short val)
Write a value of one of the camera&#39;s registers.
Definition: Engine.C:917
cv::Mat getCvRGBA(bool casync=false) const
Shorthand to get the input image as a RGBA cv::Mat and release the raw buffer.
Definition: Module.C:94
std::string sformat(char const *fmt,...) __attribute__((format(__printf__
Create a string using printf style arguments.
Definition: Utils.C:226
void sendScaledCvRGB(cv::Mat const &img, int quality=75) const
Shorthand to send a RGB cv::Mat after converting it to the current output format. ...
Definition: Module.C:209
void sendScaledCvBGR(cv::Mat const &img, int quality=75) const
Shorthand to send a BGR cv::Mat after converting it to the current output format. ...
Definition: Module.C:201
void sendCvRGBA(cv::Mat const &img, int quality=75) const
Shorthand to send a RGBA cv::Mat after converting it to the current output format.
Definition: Module.C:184
std::shared_ptr< VideoBuf > buf
The pixel data buffer.
Definition: RawImage.H:149
void send() const
Send an image out over USB to the host computer.
Definition: Module.C:141
Module(std::string const &instance)
Constructor.
Definition: Module.C:228
void sendCvRGB(cv::Mat const &img, int quality=75) const
Shorthand to send a RGB cv::Mat after converting it to the current output format. ...
Definition: Module.C:176
void sendCv(cv::Mat const &img, int quality=75) const
Shorthand to send a cv::Mat after converting / scaling it to the current output format.
Definition: Module.C:149
RawImage const & get(bool casync=false) const
Get the next captured camera image.
Definition: Module.C:51
void sendCvGRAY(cv::Mat const &img, int quality=75) const
Shorthand to send a GRAY cv::Mat after converting it to the current output format.
Definition: Module.C:161
InputFrame(InputFrame &&other)=default
Move constructor.
virtual void supportedCommands(std::ostream &os)
Human-readable description of this Module&#39;s supported custom commands.
Definition: Module.C:259
unsigned short readCamRegister(unsigned short reg)
Read a value from one of the camera&#39;s registers.
Definition: Module.C:271
void sendSerial(std::string const &str, bool islog=false)
Send a string to all serial ports.
Definition: Engine.C:875
std::string replaceWhitespace(std::string const &str, char rep='_')
Replace white space characters in a string with underscore (default) or another characters.
Definition: Utils.C:172
void sendScaledCvRGBA(cv::Mat const &img, int quality=75) const
Shorthand to send a RGBA cv::Mat after converting it to the current output format.
Definition: Module.C:218
size_t frameNum() const
Get frame number.
Definition: Engine.C:913
void sendCvBGR(cv::Mat const &img, int quality=75) const
Shorthand to send a BGR cv::Mat after converting it to the current output format. ...
Definition: Module.C:169
void writeIMUregister(unsigned short reg, unsigned short val)
Write a value to one of the camera&#39;s IMU registers.
Definition: Engine.C:928
A component of a model hierarchy.
Definition: Component.H:178
virtual void process(InputFrame &&inframe, OutputFrame &&outframe)
Processing function, version that receives a frame from camera and sends a frame out over USB...
StdModule(std::string const &instance)
Constructor.
Definition: Module.C:292
A raw image as coming from a V4L2 Camera and/or being sent out to a USB Gadget.
Definition: RawImage.H:110
void readIMUregisterArray(unsigned short reg, unsigned char *vals, size_t num)
Read an array of values from the camera&#39;s IMU registers.
Definition: Engine.C:946
cv::Mat getCvRGB(bool casync=false) const
Shorthand to get the input image as a RGB cv::Mat and release the raw buffer.
Definition: Module.C:85
void writeCamRegister(unsigned short reg, unsigned short val)
Write a value of one of the camera&#39;s registers.
Definition: Module.C:267
Engine * engine() const
Get a handle to our Engine, or throw if we do not have an Engine as root ancestor.
Definition: Component.C:129
void writeIMUregisterArray(unsigned short reg, unsigned char const *vals, size_t num)
Write an array of values to the camera&#39;s IMU registers.
Definition: Module.C:283
void writeIMUregister(unsigned short reg, unsigned short val)
Write a value to one of the camera&#39;s IMU registers.
Definition: Module.C:275
void sendSerialStd2D(float x, float y, float w=0.0F, float h=0.0F, std::string const &id="", std::string const &extra="")
Send standardized 2D message for standardized coordinates.
Definition: Module.C:454
void sendSerialImg2D(unsigned int camw, unsigned int camh, float x, float y, float w=0.0F, float h=0.0F, std::string const &id="", std::string const &extra="")
Send standardized 2D message for image coordinates.
Definition: Module.C:441
void imgToStdSize(float &w, float &h, unsigned int const width, unsigned int const height, float const eps=0.1F)
Transform size in-place from camera to standardized, using given image width and height.
Definition: Coordinates.C:50
unsigned short readCamRegister(unsigned short reg)
Read a value from one of the camera&#39;s registers.
Definition: Engine.C:922
cv::Mat convertToCvGray(RawImage const &src)
Convert RawImage to OpenCV doing color conversion from any RawImage source pixel to OpenCV gray byte...
Definition: RawImageOps.C:245
void convertCvBGRtoRawImage(cv::Mat const &src, RawImage &dst, int quality)
Convert a BGR cv::Mat to RawImage with already-allocated pixels and pixel type.
Definition: RawImageOps.C:1254
void imgToStdX(float &x, unsigned int const width, float const eps=0.1F)
Transform X coordinate in-place from camera to standardized, using given image width and height...
Definition: Coordinates.C:36
void sendSerialObjReco(std::vector< ObjReco > const &res)
Send a standardized object recognition message.
Definition: Module.C:755
virtual void sendSerial(std::string const &str)
Send a string over the &#39;serout&#39; serial port.
Definition: Module.C:245
void sendSerialImg1Dy(unsigned int camh, float y, float size=0.0F, std::string const &id="", std::string const &extra="")
Send standardized 1D message for an Y image coordinate.
Definition: Module.C:393
cv::Mat getCvGRAY(bool casync=false) const
Shorthand to get the input image as a GRAY cv::Mat and release the raw buffer.
Definition: Module.C:67
unsigned short readIMUregister(unsigned short reg)
Read a value from one of the camera&#39;s IMU registers.
Definition: Engine.C:934
void sendSerialMarkStop()
Send a message MARK STOP to indicate the end of processing.
Definition: Module.C:747
void sendSerialStd3D(float x, float y, float z, float w=0.0F, float h=0.0F, float d=0.0F, float q1=0.0F, float q2=0.0F, float q3=0.0f, float q4=0.0F, std::string const &id="", std::string const &extra="")
Send standardized 3D message.
Definition: Module.C:605
void sendSerialImg1Dx(unsigned int camw, float x, float size=0.0F, std::string const &id="", std::string const &extra="")
Send standardized 1D message for an X image coordinate.
Definition: Module.C:344
#define LFATAL(msg)
Convenience macro for users to print out console or syslog messages, FATAL level. ...
Definition: Log.H:212
virtual ~StdModule()
Virtual destructor for safe inheritance.
Definition: Module.C:297
Prepend standardized serial messages with a frame time
Definition: Module.H:466
void convertCvRGBAtoRawImage(cv::Mat const &src, RawImage &dst, int quality)
Convert an RGBA cv::Mat to RawImage with already-allocated pixels and pixel type. ...
Definition: RawImageOps.C:1323
void readIMUregisterArray(unsigned short reg, unsigned char *vals, size_t num)
Read an array of values from the camera&#39;s IMU registers.
Definition: Module.C:287
JeVois processing engine - gets images from camera sensor, processes them, and sends results over USB...
Definition: Engine.H:265
std::string to_string(T const &val)
Convert from type to string.
Definition: UtilsImpl.H:58
std::string getStamp() const
Get a string with the frame/date/time stamp in it, depending on serstamp parameter.
Definition: Module.C:301
void convertCvGRAYtoRawImage(cv::Mat const &src, RawImage &dst, int quality)
Convert a Gray cv::Mat to RawImage with already-allocated pixels and pixel type.
Definition: RawImageOps.C:1344
virtual void parseSerial(std::string const &str, std::shared_ptr< UserInterface > s)
Receive a string from a serial port which contains a user command.
Definition: Module.C:254
Virtual base class for a vision processing module.
Definition: Module.H:336
void sendScaledCvGRAY(cv::Mat const &img, int quality=75) const
Shorthand to send a GRAY cv::Mat after converting it to the current output format.
Definition: Module.C:192
void sendSerialStd1Dy(float y, float size=0.0F, std::string const &id="", std::string const &extra="")
Send standardized 1D message for a standardized Y coordinate.
Definition: Module.C:406
Exception-safe wrapper around a raw image to be sent over USB.
Definition: Module.H:145
~InputFrame()
Destructor, returns the buffers to the driver as needed.
Definition: Module.C:38
RawImage const & get() const
Get a pre-allocated image so that we can fill the pixel data and later send out over USB using send()...
Definition: Module.C:133
cv::Mat getCvBGR(bool casync=false) const
Shorthand to get the input image as a BGR cv::Mat and release the raw buffer.
Definition: Module.C:76
void done() const
Indicate that user processing is done with the image previously obtained via get() ...
Definition: Module.C:60
void sendSerialMarkStart()
Send a message MARK START to indicate the beginning of processing.
Definition: Module.C:739
cv::Mat rescaleCv(cv::Mat const &img, cv::Size const &newdims)
Rescale an OpenCV image, choosing the right kind of interpolation.
Definition: RawImageOps.C:1608
unsigned short readIMUregister(unsigned short reg)
Read a value from one of the camera&#39;s IMU registers.
Definition: Module.C:279
unsigned int width
Image width in pixels.
Definition: RawImage.H:145
~OutputFrame()
Destructor, returns the buffers to the driver as needed.
Definition: Module.C:109
virtual ~Module()
Virtual destructor for safe inheritance.
Definition: Module.C:233
void convertCvRGBtoRawImage(cv::Mat const &src, RawImage &dst, int quality)
Convert a RGB cv::Mat to RawImage with already-allocated pixels and pixel type.
Definition: RawImageOps.C:1276
void sendSerialObjDetImg2D(unsigned int camw, unsigned int camh, float x, float y, float w, float h, std::vector< ObjReco > const &res)
Send a standardized object detection + recognition message.
Definition: Module.C:792
size_t frameNum() const
Get frame number from the Engine.
Definition: Module.C:263