JeVois  1.10
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 {
265  jevois::Engine * e = dynamic_cast<jevois::Engine *>(itsParent);
266  if (e == nullptr) LFATAL("My parent is not Engine -- CANNOT GET FRAME NUMBER");
267 
268  return e->frameNum();
269 }
270 
271 // ####################################################################################################
272 void jevois::Module::writeCamRegister(unsigned short reg, unsigned short val)
273 {
274  jevois::Engine * e = dynamic_cast<jevois::Engine *>(itsParent);
275  if (e == nullptr) LFATAL("My parent is not Engine -- CANNOT COMPLETE OPERATION");
276  e->writeCamRegister(reg, val);
277 }
278 // ####################################################################################################
279 unsigned short jevois::Module::readCamRegister(unsigned short reg)
280 {
281  jevois::Engine * e = dynamic_cast<jevois::Engine *>(itsParent);
282  if (e == nullptr) LFATAL("My parent is not Engine -- CANNOT COMPLETE OPERATION");
283  return e->readCamRegister(reg);
284 }
285 
286 // ####################################################################################################
287 void jevois::Module::writeIMUregister(unsigned short reg, unsigned short val)
288 {
289  jevois::Engine * e = dynamic_cast<jevois::Engine *>(itsParent);
290  if (e == nullptr) LFATAL("My parent is not Engine -- CANNOT COMPLETE OPERATION");
291  e->writeIMUregister(reg, val);
292 }
293 
294 // ####################################################################################################
295 unsigned short jevois::Module::readIMUregister(unsigned short reg)
296 {
297  jevois::Engine * e = dynamic_cast<jevois::Engine *>(itsParent);
298  if (e == nullptr) LFATAL("My parent is not Engine -- CANNOT COMPLETE OPERATION");
299  return e->readIMUregister(reg);
300 }
301 
302 // ####################################################################################################
303 // ####################################################################################################
304 jevois::StdModule::StdModule(std::string const & instance) :
305  jevois::Module(instance)
306 { }
307 
308 // ####################################################################################################
310 { }
311 
312 // ####################################################################################################
313 std::string jevois::StdModule::getStamp() const
314 {
315  std::string ret;
316 
317  switch(serstamp::get())
318  {
319  case jevois::module::SerStamp::None:
320  break;
321 
322  case jevois::module::SerStamp::Frame:
323  ret = std::to_string(frameNum());
324  break;
325 
326  case jevois::module::SerStamp::Time:
327  {
328  std::time_t t = std::time(nullptr); char str[100];
329  std::strftime(str, sizeof(str), "%T", std::localtime(&t));
330  ret = std::string(str);
331  }
332  break;
333 
334  case jevois::module::SerStamp::FrameTime:
335  {
336  std::time_t t = std::time(nullptr); char str[100];
337  std::strftime(str, sizeof(str), "%T", std::localtime(&t));
338  ret = std::to_string(frameNum()) + '/' + std::string(str);
339  }
340  break;
341 
342  case jevois::module::SerStamp::FrameDateTime:
343  {
344  std::time_t t = std::time(nullptr); char str[100];
345  std::strftime(str, sizeof(str), "%F/%T", std::localtime(&t));
346  ret = std::to_string(frameNum()) + '/' + std::string(str);
347  }
348  break;
349  }
350 
351  if (ret.empty() == false) ret += ' ';
352  return ret;
353 }
354 
355 // ####################################################################################################
356 void jevois::StdModule::sendSerialImg1Dx(unsigned int camw, float x, float size, std::string const & id,
357  std::string const & extra)
358 {
359  // Normalize the coordinate and size using the given precision to do rounding:
360  float const eps = std::pow(10.0F, -float(serprec::get()));
361 
362  jevois::coords::imgToStdX(x, camw, eps);
363  float dummy = 0.0F; jevois::coords::imgToStdSize(size, dummy, camw, 100, eps);
364 
365  // Delegate:
366  sendSerialStd1Dx(x, size, id, extra);
367 }
368 
369 // ####################################################################################################
370 void jevois::StdModule::sendSerialStd1Dx(float x, float size, std::string const & id, std::string const & extra)
371 {
372  // Build the message depending on desired style:
373  std::ostringstream oss; oss << std::fixed << std::setprecision(serprec::get());
374 
375  // Prepend frame/date/time as possibly requested by parameter serstamp:
376  oss << getStamp();
377 
378  // Format the message depending on parameter serstyle:
379  switch (serstyle::get())
380  {
381  case jevois::module::SerStyle::Terse:
382  oss << "T1 " << x;
383  break;
384 
385  case jevois::module::SerStyle::Normal:
386  oss << "N1 ";
387  if (id.empty()) oss << "unknown "; else oss << jevois::replaceWhitespace(id) << ' ';
388  oss << x << ' ' << size;
389  break;
390 
391  case jevois::module::SerStyle::Detail:
392  case jevois::module::SerStyle::Fine:
393  oss << "D1 ";
394  if (id.empty()) oss << "unknown "; else oss << jevois::replaceWhitespace(id) << ' ';
395  oss << x - 0.5F * size << ' ' << x + 0.5F * size;
396  if (extra.empty() == false) oss << ' ' << extra;
397  break;
398  }
399 
400  // Send the message:
401  sendSerial(oss.str());
402 }
403 
404 // ####################################################################################################
405 void jevois::StdModule::sendSerialImg1Dy(unsigned int camh, float y, float size, std::string const & id,
406  std::string const & extra)
407 {
408  // Normalize the coordinate and size using the given precision to do rounding:
409  float const eps = std::pow(10.0F, -float(serprec::get()));
410  jevois::coords::imgToStdY(y, camh, eps);
411  float dummy = 0.0F; jevois::coords::imgToStdSize(dummy, size, 100, camh, eps);
412 
413  // Delegate:
414  sendSerialStd1Dy(y, size, id, extra);
415 }
416 
417 // ####################################################################################################
418 void jevois::StdModule::sendSerialStd1Dy(float y, float size, std::string const & id, std::string const & extra)
419 {
420  // Build the message depending on desired style:
421  std::ostringstream oss; oss << std::fixed << std::setprecision(serprec::get());
422 
423  // Prepend frame/date/time as possibly requested by parameter serstamp:
424  oss << getStamp();
425 
426  // Format the message depending on parameter serstyle:
427  switch (serstyle::get())
428  {
429  case jevois::module::SerStyle::Terse:
430  oss << "T1 " << y;
431  break;
432 
433  case jevois::module::SerStyle::Normal:
434  oss << "N1 ";
435  if (id.empty()) oss << "unknown "; else oss << jevois::replaceWhitespace(id) << ' ';
436  oss << y << ' ' << size;
437  break;
438 
439  case jevois::module::SerStyle::Detail:
440  case jevois::module::SerStyle::Fine:
441  oss << "D1 ";
442  if (id.empty()) oss << "unknown "; else oss << jevois::replaceWhitespace(id) << ' ';
443  oss << y - 0.5F * size << ' ' << y + 0.5F * size;
444  if (extra.empty() == false) oss << ' ' << extra;
445  break;
446  }
447 
448  // Send the message:
449  sendSerial(oss.str());
450 }
451 
452 // ####################################################################################################
453 void jevois::StdModule::sendSerialImg2D(unsigned int camw, unsigned int camh, float x, float y, float w, float h,
454  std::string const & id, std::string const & extra)
455 {
456  // Normalize the coordinates and sizes using the given precision to do rounding:
457  float const eps = std::pow(10.0F, -float(serprec::get()));
458 
459  jevois::coords::imgToStd(x, y, camw, camh, eps);
460  jevois::coords::imgToStdSize(w, h, camw, camh, eps);
461 
462  // Delegate:
463  sendSerialStd2D(x, y, w, h, id, extra);
464 }
465 // ####################################################################################################
466 void jevois::StdModule::sendSerialStd2D(float x, float y, float w, float h, std::string const & id,
467  std::string const & extra)
468 {
469  // Build the message depending on desired style:
470  std::ostringstream oss; oss << std::fixed << std::setprecision(serprec::get());
471 
472  // Prepend frame/date/time as possibly requested by parameter serstamp:
473  oss << getStamp();
474 
475  // Format the message depending on parameter serstyle:
476  switch (serstyle::get())
477  {
478  case jevois::module::SerStyle::Terse:
479  oss << "T2 " << x << ' ' << y;
480  break;
481 
482  case jevois::module::SerStyle::Normal:
483  oss << "N2 ";
484  if (id.empty()) oss << "unknown "; else oss << jevois::replaceWhitespace(id) << ' ';
485  oss << x << ' ' << y << ' ' << w << ' ' << h;
486  break;
487 
488  case jevois::module::SerStyle::Detail:
489  oss << "D2 ";
490  if (id.empty()) oss << "unknown "; else oss << jevois::replaceWhitespace(id) << ' ';
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  oss << x + 0.5F * w << ' ' << y - 0.5F * h;
495  if (extra.empty() == false) oss << ' ' << extra;
496  break;
497 
498  case jevois::module::SerStyle::Fine:
499  oss << "F2 ";
500  if (id.empty()) oss << "unknown "; else oss << jevois::replaceWhitespace(id) << ' ';
501  oss << 4 << ' '; // number of vertices
502  oss << x - 0.5F * w << ' ' << y - 0.5F * h << ' ';
503  oss << x + 0.5F * w << ' ' << y - 0.5F * h << ' ';
504  oss << x + 0.5F * w << ' ' << y + 0.5F * h << ' ';
505  oss << x + 0.5F * w << ' ' << y - 0.5F * h;
506  if (extra.empty() == false) oss << ' ' << extra;
507  break;
508  }
509 
510  // Send the message:
511  sendSerial(oss.str());
512 }
513 
514 // ####################################################################################################
515 template <typename T>
516 void jevois::StdModule::sendSerialContour2D(unsigned int camw, unsigned int camh, std::vector<cv::Point_<T> > points,
517  std::string const & id, std::string const & extra)
518 {
519  // Format the message depending on parameter serstyle:
520  switch (serstyle::get())
521  {
522  case jevois::module::SerStyle::Terse:
523  {
524  // Compute center of gravity:
525  float cx = 0.0F, cy = 0.0F;
526  for (cv::Point const & p : points) { cx += p.x; cy += p.y; }
527  if (points.size()) { cx /= points.size(); cy /= points.size(); }
528  sendSerialImg2D(camw, camh, cx, cy, 0.0F, 0.0F, id, extra);
529  }
530  break;
531 
532  case jevois::module::SerStyle::Normal:
533  {
534  // Compute upright bounding rectangle:
535  cv::Rect r = cv::boundingRect(points);
536  sendSerialImg2D(camw, camh, r.x + 0.5F * r.width, r.y + 0.5F * r.height, r.width, r.height, id, extra);
537  }
538  break;
539 
540  case jevois::module::SerStyle::Detail:
541  {
542  // Compute minimal rotated rectangle enclosing the points:
543  cv::RotatedRect r = cv::minAreaRect(points);
544 
545  // Build the message:
546  unsigned int const prec = serprec::get(); float const eps = std::pow(10.0F, -float(prec));
547  std::ostringstream oss; oss << std::fixed << std::setprecision(prec);
548 
549  // Prepend frame/date/time as possibly requested by parameter serstamp:
550  oss << getStamp();
551 
552  // Now the rest of the message:
553  oss << "D2 ";
554  if (id.empty()) oss << "unknown "; else oss << jevois::replaceWhitespace(id) << ' ';
555  cv::Point2f corners[4];
556  r.points(corners);
557 
558  oss << 4; // number of vertices
559 
560  for (int i = 0; i < 4; ++i)
561  {
562  float x = corners[i].x, y = corners[i].y;
563  jevois::coords::imgToStd(x, y, camw, camh, eps);
564  oss << ' ' << x << ' ' << y;
565  }
566  if (extra.empty() == false) oss << ' ' << extra;
567 
568  // Send the message:
569  sendSerial(oss.str());
570  }
571  break;
572 
573  case jevois::module::SerStyle::Fine:
574  {
575  // Build the message:
576  unsigned int const prec = serprec::get(); float const eps = std::pow(10.0F, -float(prec));
577  std::ostringstream oss; oss << std::fixed << std::setprecision(prec);
578 
579  // Prepend frame/date/time as possibly requested by parameter serstamp:
580  oss << getStamp();
581 
582  // Now the rest of the message:
583  oss << "F2 ";
584  if (id.empty()) oss << "unknown "; else oss << jevois::replaceWhitespace(id) << ' ';
585  oss << points.size(); // number of vertices
586 
587  for (cv::Point const & p : points)
588  {
589  float x = p.x, y = p.y;
590  jevois::coords::imgToStd(x, y, camw, camh, eps);
591  oss << ' ' << x << ' ' << y;
592  }
593  if (extra.empty() == false) oss << ' ' << extra;
594 
595  // Send the message:
596  sendSerial(oss.str());
597  }
598  break;
599  }
600 }
601 
602 // Compile in explicit template instantiations:
603 namespace jevois
604 {
605  template
606  void StdModule::sendSerialContour2D(unsigned int camw, unsigned int camh, std::vector<cv::Point_<int> > points,
607  std::string const & id, std::string const & extra);
608  template
609  void StdModule::sendSerialContour2D(unsigned int camw, unsigned int camh, std::vector<cv::Point_<float> > points,
610  std::string const & id, std::string const & extra);
611  template
612  void StdModule::sendSerialContour2D(unsigned int camw, unsigned int camh, std::vector<cv::Point_<double> > points,
613  std::string const & id, std::string const & extra);
614 }
615 
616 // ####################################################################################################
617 void jevois::StdModule::sendSerialStd3D(float x, float y, float z, float w, float h, float d,
618  float q1, float q2, float q3, float q4,
619  std::string const & id, std::string const & extra)
620 {
621  // Build the message depending on desired style:
622  std::ostringstream oss; oss << std::fixed << std::setprecision(serprec::get());
623 
624  // Prepend frame/date/time as possibly requested by parameter serstamp:
625  oss << getStamp();
626 
627  // Format the message depending on parameter serstyle:
628  switch (serstyle::get())
629  {
630  case jevois::module::SerStyle::Terse:
631  oss << "T3 " << x << ' ' << y << ' ' << z;
632  break;
633 
634  case jevois::module::SerStyle::Normal:
635  oss << "N3 ";
636  if (id.empty()) oss << "unknown "; else oss << jevois::replaceWhitespace(id) << ' ';
637  oss << x << ' ' << y << ' ' << z << ' ' << w << ' ' << h << ' ' << d;
638  break;
639 
640  case jevois::module::SerStyle::Detail:
641  oss << "D3 ";
642  if (id.empty()) oss << "unknown "; else oss << jevois::replaceWhitespace(id) << ' ';
643  oss << x << ' ' << y << ' ' << z << ' ' << w << ' ' << h << ' ' << d << ' '
644  << q1 << ' ' << q2 << ' ' << q3 << ' ' << q4;
645  if (extra.empty() == false) oss << ' ' << extra;
646  break;
647 
648  case jevois::module::SerStyle::Fine:
649  oss << "F3 ";
650  if (id.empty()) oss << "unknown "; else oss << jevois::replaceWhitespace(id) << ' ';
651  oss << 8 << ' '; // number of vertices
652  oss << x - 0.5F * w << ' ' << y - 0.5F * h << ' ' << z - 0.5F * d << ' ';
653  oss << x + 0.5F * w << ' ' << y - 0.5F * h << ' ' << z - 0.5F * d << ' ';
654  oss << x + 0.5F * w << ' ' << y + 0.5F * h << ' ' << z - 0.5F * d << ' ';
655  oss << x + 0.5F * w << ' ' << y - 0.5F * h << ' ' << z - 0.5F * d << ' ';
656  oss << x - 0.5F * w << ' ' << y - 0.5F * h << ' ' << z + 0.5F * d << ' ';
657  oss << x + 0.5F * w << ' ' << y - 0.5F * h << ' ' << z + 0.5F * d << ' ';
658  oss << x + 0.5F * w << ' ' << y + 0.5F * h << ' ' << z + 0.5F * d << ' ';
659  oss << x + 0.5F * w << ' ' << y - 0.5F * h << ' ' << z + 0.5F * d << ' ';
660  if (extra.empty() == false) oss << ' ' << extra;
661  break;
662  }
663 
664  // Send the message:
665  sendSerial(oss.str());
666 }
667 
668 // ####################################################################################################
669 void jevois::StdModule::sendSerialStd3D(std::vector<cv::Point3f> points, std::string const & id,
670  std::string const & extra)
671 {
672  // Format the message depending on parameter serstyle:
673  switch (serstyle::get())
674  {
675  case jevois::module::SerStyle::Terse:
676  {
677  // Compute center of gravity:
678  cv::Point3f cg(0.0F, 0.0F, 0.0F);
679  for (cv::Point3f const & p : points) cg += p;
680  if (points.size()) { cg.x /= points.size(); cg.y /= points.size(); cg.z /= points.size(); }
681  sendSerialStd3D(cg.x, cg.y, cg.z, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, id, extra);
682  }
683  break;
684 
685  case jevois::module::SerStyle::Normal:
686  {
687  // Compute upright bounding parallelepiped:
688  cv::Point3f cg(0.0F, 0.0F, 0.0F), pmin(1e30F, 1e30F, 1e30F), pmax(-1e30F, -1e30F, -1e30F);
689  for (cv::Point3f const & p : points)
690  {
691  cg += p;
692  if (p.x < pmin.x) pmin.x = p.x;
693  if (p.y < pmin.y) pmin.y = p.y;
694  if (p.z < pmin.z) pmin.z = p.z;
695  if (p.x > pmax.x) pmax.x = p.x;
696  if (p.y > pmax.y) pmax.y = p.y;
697  if (p.z > pmax.z) pmax.z = p.z;
698  }
699  if (points.size()) { cg.x /= points.size(); cg.y /= points.size(); cg.z /= points.size(); }
700  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,
701  id, extra);
702  }
703  break;
704 
705  case jevois::module::SerStyle::Detail:
706  {
707  // Compute upright bounding parallelepiped:
708  cv::Point3f cg(0.0F, 0.0F, 0.0F), pmin(1e30F, 1e30F, 1e30F), pmax(-1e30F, -1e30F, -1e30F);
709  for (cv::Point3f const & p : points)
710  {
711  cg += p;
712  if (p.x < pmin.x) pmin.x = p.x;
713  if (p.y < pmin.y) pmin.y = p.y;
714  if (p.z < pmin.z) pmin.z = p.z;
715  if (p.x > pmax.x) pmax.x = p.x;
716  if (p.y > pmax.y) pmax.y = p.y;
717  if (p.z > pmax.z) pmax.z = p.z;
718  }
719  if (points.size()) { cg.x /= points.size(); cg.y /= points.size(); cg.z /= points.size(); }
720  // FIXME what should we send for the quaternion?
721  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,
722  id, extra);
723  }
724  break;
725 
726  case jevois::module::SerStyle::Fine:
727  {
728  // Build the message:
729  unsigned int const prec = serprec::get();
730  std::ostringstream oss; oss << std::fixed << std::setprecision(prec);
731 
732  // Prepend frame/date/time as possibly requested by parameter serstamp:
733  oss << getStamp();
734 
735  // Now the rest of the message:
736  oss << "F3 ";
737  if (id.empty()) oss << "unknown "; else oss << jevois::replaceWhitespace(id) << ' ';
738  oss << points.size(); // number of vertices
739 
740  for (cv::Point3f const & p : points) oss << ' ' << p.x << ' ' << p.y << ' ' << p.z;
741  if (extra.empty() == false) oss << ' ' << extra;
742 
743  // Send the message:
744  sendSerial(oss.str());
745  }
746  break;
747  }
748 }
749 
750 // ####################################################################################################
752 {
753  jevois::module::SerMark const m = sermark::get();
754  if (m == jevois::module::SerMark::None || m == jevois::module::SerMark::Stop) return;
755  sendSerial(getStamp() + "MARK START");
756 }
757 
758 // ####################################################################################################
760 {
761  jevois::module::SerMark const m = sermark::get();
762  if (m == jevois::module::SerMark::None || m == jevois::module::SerMark::Start) return;
763  sendSerial(getStamp() + "MARK STOP");
764 }
765 
766 // ####################################################################################################
767 void jevois::StdModule::sendSerialObjReco(std::vector<jevois::ObjReco> const & res)
768 {
769  if (res.empty()) return;
770 
771  // Build the message depending on desired style:
772  std::ostringstream oss; oss << std::fixed << std::setprecision(serprec::get());
773 
774  // Prepend frame/date/time as possibly requested by parameter serstamp:
775  oss << getStamp();
776 
777  // Format the message depending on parameter serstyle:
778  switch (serstyle::get())
779  {
780  case jevois::module::SerStyle::Terse:
781  oss << "TO " << jevois::replaceWhitespace(res[0].category);
782  break;
783 
784  case jevois::module::SerStyle::Normal:
785  oss << "NO " << jevois::replaceWhitespace(res[0].category) << ':' << res[0].score;
786  break;
787 
788  case jevois::module::SerStyle::Detail:
789  oss << "DO";
790  for (auto const & r : res) oss << ' ' << jevois::replaceWhitespace(r.category) << ':' << r.score;
791  break;
792 
793  case jevois::module::SerStyle::Fine:
794  oss << "FO";
795  for (auto const & r : res) oss << ' ' << jevois::replaceWhitespace(r.category) << ':' << r.score;
796  break;
797  }
798 
799  // Send the message:
800  sendSerial(oss.str());
801 }
802 
803 // ####################################################################################################
804 void jevois::StdModule::sendSerialObjDetImg2D(unsigned int camw, unsigned int camh, float x, float y, float w, float h,
805  std::vector<ObjReco> const & res)
806 {
807  if (res.empty()) return;
808 
809  std::string best, extra; std::string * ptr = &best;
810  std::string fmt = "%s:%." + std::to_string(serprec::get()) + "f";
811 
812  for (auto const & r : res)
813  {
814  switch (serstyle::get())
815  {
816  case jevois::module::SerStyle::Terse:
817  (*ptr) += jevois::replaceWhitespace(r.category);
818  break;
819 
820  default:
821  (*ptr) += jevois::sformat(fmt.c_str(), jevois::replaceWhitespace(r.category).c_str(), r.score);
822  }
823  if (ptr == &extra) (*ptr) += ' ';
824  ptr = &extra;
825  }
826 
827  // Remove last space:
828  if (extra.empty() == false) extra = extra.substr(0, extra.length() - 1);
829 
830  sendSerialImg2D(camw, camh, x, y, w, h, best, extra);
831 }
832 
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:516
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
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
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:370
void writeCamRegister(unsigned short reg, unsigned short val)
Write a value of one of the camera&#39;s registers.
Definition: Engine.C:915
void send(RawImage const &img) override
Send an image out over USB to the host computer.
Definition: Gadget.C:856
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
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:279
void sendSerial(std::string const &str, bool islog=false)
Send a string to all serial ports.
Definition: Engine.C:873
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:911
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:926
A component of a model hierarchy.
Definition: Component.H:177
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:304
A raw image as coming from a V4L2 Camera and/or being sent out to a USB Gadget.
Definition: RawImage.H:110
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:272
virtual void done(RawImage &img)=0
Indicate that user processing is done with an image previously obtained via get() ...
void writeIMUregister(unsigned short reg, unsigned short val)
Write a value to one of the camera&#39;s IMU registers.
Definition: Module.C:287
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:466
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:453
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:920
virtual void get(RawImage &img)=0
Get the next captured buffer.
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:767
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:405
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:932
void sendSerialMarkStop()
Send a message MARK STOP to indicate the end of processing.
Definition: Module.C:759
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:617
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:356
#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:309
Prepend standardized serial messages with a frame time
Definition: Module.H:454
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
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:313
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:418
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:751
cv::Mat rescaleCv(cv::Mat const &img, cv::Size const &newdims)
Rescale an OpenCV image, choosing the right kind of interpolation.
Definition: RawImageOps.C:1596
unsigned short readIMUregister(unsigned short reg)
Read a value from one of the camera&#39;s IMU registers.
Definition: Module.C:295
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:804
size_t frameNum() const
Get frame number from the Engine.
Definition: Module.C:263