JeVois  1.18
JeVois Smart Embedded Machine Vision Toolkit
Share this page:
GUIhelper.C
Go to the documentation of this file.
1 // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2 //
3 // JeVois Smart Embedded Machine Vision Toolkit - Copyright (C) 2020 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 #ifdef JEVOIS_PRO
19 
20 // for demo
21 #include <math.h>
22 #include <imgui.h>
23 #define IMGUI_DEFINE_MATH_OPERATORS // Access to math operators
24 #include <imgui_internal.h>
25 #include <algorithm> // for tweak demo
26 
27 #include <jevois/GPU/GUIhelper.H>
28 #include <jevois/GPU/GUIconsole.H>
29 #include <jevois/GPU/GPUimage.H>
30 #include <jevois/Core/Module.H>
31 #include <jevois/GPU/GUIeditor.H>
32 #include <jevois/Debug/SysInfo.H>
33 #include <jevois/Util/Utils.H>
34 #include <imgui.h>
35 #include <imgui_internal.h>
36 #include <glm/gtc/matrix_transform.hpp> // glm::translate, glm::rotate, glm::scale, glm::perspective
37 #include <glm/gtx/euler_angles.hpp>
38 #include <fstream>
39 #include <set>
40 
41 #include <dirent.h>
42 #include <sys/stat.h>
43 #include <sys/types.h>
45 
46 // ##############################################################################################################
47 jevois::GUIhelper::GUIhelper(std::string const & instance, bool conslock) :
48  jevois::Component(instance), pixel_perfect_z(0.0f), itsIdle(true), itsConsLock(conslock), itsBackend()
49 {
50  // We defer OpenGL init to startFrame() so that all OpenGL code is in the same thread.
51 
52  // If auto-detecting screen size, get the framebuffer size here so we can use it later:
53  if (winsize::get().width == 0)
54  {
55  // Query the framebuffer if no window size was given:
56  int w = 1920, h = 1080; // defaults in case we fail to read from framebuffer
57  try
58  {
59  std::string const ws = jevois::getFileString("/sys/class/graphics/fb0/virtual_size");
60  std::vector<std::string> const tok = jevois::split(ws, "\\s*[,;x]\\s*");
61  if (tok.size() == 2) { w = std::stoi(tok[0]); h = std::stoi(tok[1]) / 2; } // Reported height is double...
62  LINFO("Detected framebuffer size: " << w << 'x' << h);
63  }
64  catch (...) { } // silently ignore any errors
65 
66  winsize::set(cv::Size(w, h));
67  }
68 
69  itsWindowTitle = "JeVois-Pro v" + std::string(JEVOIS_VERSION_STRING);
70 
71  // Create some config files for the config editor:
72  std::vector<EditorItem> fixedcfg
73  {
74  { JEVOIS_ROOT_PATH "/config/videomappings.cfg", "JeVois videomappings.cfg", EditorSaveAction::RefreshMappings },
75  { JEVOIS_ROOT_PATH "/config/initscript.cfg", "JeVois initscript.cfg", EditorSaveAction::Reboot },
76  { "params.cfg", "Module's params.cfg", EditorSaveAction::Reload },
77  { "script.cfg", "Module's script.cfg", EditorSaveAction::Reload },
78  { JEVOIS_ROOT_PATH "/share/dnn/models.yml",
79  "JeVois models.yml DNN Zoo Root", EditorSaveAction::Reload },
80  { JEVOIS_ROOT_PATH "/share/dnn/opencv.yml",
81  "JeVois opencv.yml DNN Zoo for OpenCV models", EditorSaveAction::Reload },
82  { JEVOIS_ROOT_PATH "/share/dnn/npu.yml",
83  "JeVois npu.yml DNN Zoo for A311D NPU models", EditorSaveAction::Reload },
84  { JEVOIS_ROOT_PATH "/share/dnn/spu.yml",
85  "JeVois spu.yml DNN Zoo for Hailo SPU models", EditorSaveAction::Reload },
86  { JEVOIS_ROOT_PATH "/share/dnn/tpu.yml",
87  "JeVois tpu.yml DNN Zoo for Coral TPU models", EditorSaveAction::Reload },
88  { JEVOIS_ROOT_PATH "/share/dnn/vpu.yml",
89  "JeVois vpu.yml DNN Zoo for Myriad-X VPU models", EditorSaveAction::Reload },
90  };
91 
92  // Create the config editor:
93  itsCfgEditor.reset(new jevois::GUIeditor(this, "cfg", std::move(fixedcfg), JEVOIS_CUSTOM_DNN_PATH, "Custom DNN ",
94  { ".yaml", ".yml" }));
95 
96  // Create some config files for the code editor:
97  std::vector<EditorItem> fixedcode
98  {
99  { "*", "Module's source code", EditorSaveAction::Reload },
100  };
101 
102  // Create the code editor:
103  itsCodeEditor.reset(new jevois::GUIeditor(this, "code", std::move(fixedcode), JEVOIS_PYDNN_PATH, "PyDNN ",
104  { ".py", ".C", ".H", ".cpp", ".hpp", ".c", ".h" }));
105 }
106 
107 // ##############################################################################################################
109 {
110  // In case a DNN get was in progress, wait for it while letting user know:
111  JEVOIS_WAIT_GET_FUTURE(itsDnnGetFut);
112 }
113 
114 // ##############################################################################################################
115 void jevois::GUIhelper::reset(bool modulechanged)
116 {
117  itsEndFrameCalled = true;
118  itsImages.clear();
119  itsImages2.clear();
120  itsLastDrawnImage = nullptr;
121  itsLastDrawnTextLine = -1;
122  itsIdle = true;
123  itsIcon.clear();
124  itsModName.clear();
125  itsModDesc.clear();
126  itsModAuth.clear();
127  itsModLang.clear();
128  itsModDoc.clear();
129 
130  if (modulechanged)
131  {
132  itsCfgEditor->refresh();
133  itsCodeEditor->refresh();
134  }
135 
136  {
137  // Clear old error messages:
138  std::lock_guard<std::mutex> _(itsErrorMtx);
139  itsErrors.clear();
140  }
141 
142  // Get the actual window/screen size:
143  unsigned short w, h;
144  itsBackend.getWindowSize(w, h);
145 
146  if (w == 0) LFATAL("Need to call startFrame() at least once first");
147 
148  float const fov_y = 45.0f;
149 
150  proj = glm::perspective(glm::radians(fov_y), float(w) / float(h), 1.0f, h * 2.0f);
151  const_cast<float &>(pixel_perfect_z) = -float(h) / (2.0 * tan(fov_y * M_PI / 360.0));
152 #ifdef JEVOIS_PLATFORM
153  // On platform, we need to translate a bit to avoid aliasing issues, which are problematic with our YUYV shader:
154  proj = glm::translate(proj, glm::vec3(0.375f, 0.375f, 0.0f));
155 #endif
156  view = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, pixel_perfect_z));
157 
158  // Set the style (on first call):
159  style::set(style::get());
160 }
161 
162 // ##############################################################################################################
163 bool jevois::GUIhelper::startFrame(unsigned short & w, unsigned short & h)
164 {
165  if (itsEndFrameCalled == false) LFATAL("You need to call endFrame() at the end of your process() function");
166 
167  // Get current window size, will be 0x0 if not initialized yet:
168  itsBackend.getWindowSize(w, h);
169 
170  if (w == 0)
171  {
172  // Need to init the display:
173  cv::Size const siz = winsize::get();
174  bool const fs = fullscreen::get();
175  LINFO("OpenGL init " << siz.width << 'x' << siz.height << (fs ? " fullscreen" : ""));
176  itsBackend.init(siz.width, siz.height, fs, scale::get(), itsConsLock);
177  rounding::set(int(rounding::get() * scale::get() + 0.499F));
178 
179  // Get the actual window size and update our param:
180  unsigned short winw, winh; itsBackend.getWindowSize(winw, winh); winsize::set(cv::Size(winw, winh));
181  winsize::freeze();
182  fullscreen::freeze();
183 
184  // Reset the GUI:
185  reset();
186  }
187 
188  // Poll events:
189  bool shouldclose = false; auto const now = std::chrono::steady_clock::now();
190  if (itsBackend.pollEvents(shouldclose)) itsLastEventTime = now;
191 
192  if (shouldclose && allowquit::get())
193  {
194  LINFO("Closing down on user request...");
195  engine()->quit();
196  }
197 
198  // Start the frame on the backend:
199  itsBackend.newFrame();
200 
201  // Check if we have been idle:
202  float const hs = hidesecs::get();
203  if (hs)
204  {
205  std::chrono::duration<float> elapsed = now - itsLastEventTime;
206  itsIdle = (elapsed.count() >= hs);
207  }
208  else itsIdle = false;
209 
210  itsEndFrameCalled = false;
211 
212  return itsIdle;
213 }
214 
215 // ##############################################################################################################
216 void jevois::GUIhelper::onParamChange(jevois::gui::scale const & param, float const & newval)
217 {
218  float oldval = param.get();
219  if (newval == oldval) return;
220 
221  ImGui::GetStyle().ScaleAllSizes(newval / oldval);
222  ImGui::GetIO().FontGlobalScale = newval;
223  ImGui::GetStyle().MouseCursorScale = 2.0f; // do not scale the cursor, otherwise it disappears...
224 
225  // Also scale the window corner rounding, make it no more than 24:
226  if (oldval) rounding::set(std::min(24, int(rounding::get() * newval / oldval + 0.499F)));
227 }
228 
229 // ##############################################################################################################
230 void jevois::GUIhelper::onParamChange(jevois::gui::style const & JEVOIS_UNUSED_PARAM(param),
231  jevois::gui::GuiStyle const & newval)
232 {
233  switch (newval)
234  {
235  case jevois::gui::GuiStyle::Dark:
236  ImGui::StyleColorsDark();
237  itsCfgEditor->SetPalette(TextEditor::GetDarkPalette());
238  itsCodeEditor->SetPalette(TextEditor::GetDarkPalette());
239  break;
240 
241  case jevois::gui::GuiStyle::Light:
242  ImGui::StyleColorsLight();
243  ImGui::GetStyle().Colors[ImGuiCol_WindowBg] = ImVec4(0.94f, 0.94f, 0.94f, 0.92f); // a bit transparent
244  itsCfgEditor->SetPalette(TextEditor::GetLightPalette());
245  itsCodeEditor->SetPalette(TextEditor::GetLightPalette());
246  break;
247 
248  case jevois::gui::GuiStyle::Classic:
249  ImGui::StyleColorsClassic();
250  itsCfgEditor->SetPalette(TextEditor::GetRetroBluePalette());
251  itsCodeEditor->SetPalette(TextEditor::GetRetroBluePalette());
252  break;
253  }
254 }
255 
256 // ##############################################################################################################
257 void jevois::GUIhelper::onParamChange(jevois::gui::rounding const & JEVOIS_UNUSED_PARAM(param), int const & newval)
258 {
259  auto & s = ImGui::GetStyle();
260  s.WindowRounding = newval;
261  s.ChildRounding = newval;
262  s.FrameRounding = newval;
263  s.PopupRounding = newval;
264  s.ScrollbarRounding = newval;
265  s.GrabRounding = newval;
266 }
267 
268 // ##############################################################################################################
270 { return (itsEndFrameCalled == false); }
271 
272 // ##############################################################################################################
273 void jevois::GUIhelper::drawImage(char const * name, jevois::RawImage const & img, int & x, int & y,
274  unsigned short & w, unsigned short & h, bool noalias, bool isoverlay)
275 {
276  // We will use one image per v4l2 buffer:
277  std::string const imgname = name + std::to_string(img.bufindex);
278 
279  // Get the image by name (will create a default-constructed one the first time a new name is used):
280  auto & im = itsImages[imgname];
281 
282  // Set the new pixel data:
283  im.set(img);
284 
285  // Draw it:
286  im.draw(x, y, w, h, noalias, proj * view);
287 
288  // Remember which image was drawn last, used by i2d():
289  if (isoverlay == false)
290  {
291  itsLastDrawnImage = & im;
292  itsUsingScaledImage = false;
293  itsLastDrawnTextLine = -1;
294  }
295 }
296 
297 // ##############################################################################################################
298 void jevois::GUIhelper::drawImage(char const * name, cv::Mat const & img, bool rgb, int & x, int & y,
299  unsigned short & w, unsigned short & h, bool noalias, bool isoverlay)
300 {
301  // Get the image by name (will create a default-constructed one the first time a new name is used):
302  auto & im = itsImages[name];
303 
304  // Set the new pixel data:
305  im.set(img, rgb);
306 
307  // Draw it:
308  im.draw(x, y, w, h, noalias, proj * view);
309 
310  // Remember which image was drawn last, used by i2d():
311  if (isoverlay == false)
312  {
313  itsLastDrawnImage = & im;
314  itsUsingScaledImage = false;
315  itsLastDrawnTextLine = -1;
316  }
317 }
318 
319 // ##############################################################################################################
320 void jevois::GUIhelper::drawInputFrame(char const * name, jevois::InputFrame const & frame, int & x, int & y,
321  unsigned short & w, unsigned short & h, bool noalias, bool casync)
322 {
323  // We will use one image per v4l2 buffer:
324  jevois::RawImage const img = frame.get(casync);
325  std::string const imgname = name + std::to_string(img.bufindex);
326 
327  // Get the image by name (will create a default-constructed one the first time a new name is used):
328  auto & im = itsImages[imgname];
329 
330  // Set the new pixel data using DMABUF acceleration. This will boil down to a no-op unless image size or format has
331  // changed (including the first time we set it):
332  im.set(frame, itsBackend.getDisplay());
333 
334  // Draw it:
335  im.draw(x, y, w, h, noalias, proj * view);
336 
337  // Remember which image was drawn last, used by i2d():
338  itsLastDrawnImage = & im;
339  itsUsingScaledImage = frame.hasScaledImage();
340  itsLastDrawnTextLine = -1;
341  if (itsUsingScaledImage)
342  {
343  jevois::RawImage img2 = frame.get2(casync);
344  itsScaledImageFacX = float(img.width) / float(img2.width);
345  itsScaledImageFacY = float(img.height) / float(img2.height);
346  }
347 }
348 
349 // ##############################################################################################################
350 void jevois::GUIhelper::drawInputFrame2(char const * name, jevois::InputFrame const & frame, int & x, int & y,
351  unsigned short & w, unsigned short & h, bool noalias, bool casync)
352 {
353  // We will use one image per v4l2 buffer:
354  jevois::RawImage const img = frame.get2(casync);
355  std::string const imgname = name + std::to_string(img.bufindex);
356 
357  // Get the image by name (will create a default-constructed one the first time a new name is used):
358  auto & im = itsImages2[imgname];
359 
360  // Set the new pixel data using DMABUF acceleration. This will boil down to a no-op unless image size or format has
361  // changed (including the first time we set it):
362  im.set2(frame, itsBackend.getDisplay());
363 
364  // Draw it:
365  im.draw(x, y, w, h, noalias, proj * view);
366 
367  // Remember which image was drawn last, used by i2d():
368  itsLastDrawnImage = & im;
369  itsUsingScaledImage = false;
370  itsLastDrawnTextLine = -1;
371 }
372 
373 // ##############################################################################################################
374 ImVec2 jevois::GUIhelper::i2d(ImVec2 p, char const * name)
375 {
376  // Find the image:
377  GPUimage * img;
378 
379  if (name == nullptr)
380  {
381  if (itsLastDrawnImage == nullptr) throw std::range_error("You need to call drawImage() or drawInputFrame() first");
382  img = itsLastDrawnImage;
383  if (itsUsingScaledImage) { p.x *= itsScaledImageFacX; p.y *= itsScaledImageFacY; }
384  }
385  else
386  {
387  std::string nstr = name;
388  auto itr = itsImages.find(nstr);
389  if (itr == itsImages.end())
390  {
391  // Add a zero in case we are dealing with a camera frame (drawImage() and drawInputFrame() add suffixes, but all
392  // image buffers are the same size):
393  itr = itsImages.find(nstr + '0');
394  if (itr == itsImages.end()) throw std::range_error("No previously drawn image with name [" + nstr + "] found");
395  }
396  img = & itr->second;
397  }
398 
399  // Delegate:
400  return img->i2d(p);
401 }
402 
403 // ##############################################################################################################
404 ImVec2 jevois::GUIhelper::i2d(float x, float y, char const * name)
405 { return i2d(ImVec2(x, y), name); }
406 
407 // ##############################################################################################################
408 ImVec2 jevois::GUIhelper::i2ds(ImVec2 p, char const * name)
409 {
410  // Find the image:
411  GPUimage * img;
412 
413  if (name == nullptr)
414  {
415  if (itsLastDrawnImage == nullptr) throw std::range_error("You need to call drawImage() or drawInputFrame() first");
416  img = itsLastDrawnImage;
417  if (itsUsingScaledImage) { p.x *= itsScaledImageFacX; p.y *= itsScaledImageFacY; }
418  }
419  else
420  {
421  std::string nstr = name;
422  auto itr = itsImages.find(nstr);
423  if (itr == itsImages.end())
424  {
425  // Add a zero in case we are dealing with a camera frame (drawImage() and drawInputFrame() add suffixes, but all
426  // image buffers are the same size):
427  itr = itsImages.find(nstr + '0');
428  if (itr == itsImages.end()) throw std::range_error("No previously drawn image with name [" + nstr + "] found");
429  }
430  img = & itr->second;
431  }
432 
433  // Delegate:
434  return img->i2ds(p);
435 }
436 
437 // ##############################################################################################################
438 ImVec2 jevois::GUIhelper::i2ds(float x, float y, char const * name)
439 { return i2ds(ImVec2(x, y), name); }
440 
441 // ##############################################################################################################
442 void jevois::GUIhelper::drawLine(float x1, float y1, float x2, float y2, ImU32 col)
443 {
444  ImGui::GetBackgroundDrawList()->AddLine(i2d(x1, y1), i2d(x2, y2), col, linethick::get());
445 }
446 
447 // ##############################################################################################################
448 void jevois::GUIhelper::drawRect(float x1, float y1, float x2, float y2, ImU32 col, bool filled)
449 {
450  auto dlb = ImGui::GetBackgroundDrawList();
451  ImVec2 const tl = i2d(x1, y1);
452  ImVec2 const br = i2d(x2, y2);
453 
454  if (filled) dlb->AddRectFilled(tl, br, applyFillAlpha(col));
455 
456  dlb->AddRect(tl, br, col, 0.0F, ImDrawCornerFlags_All, linethick::get());
457 }
458 
459 // ##############################################################################################################
460 void jevois::GUIhelper::drawPolyInternal(ImVec2 const * pts, size_t npts, ImU32 col, bool filled)
461 {
462  auto dlb = ImGui::GetBackgroundDrawList();
463  float const thick = linethick::get();
464 
465  if (filled) dlb->AddConvexPolyFilled(pts, npts, applyFillAlpha(col));
466 
467  if (npts > 1)
468  {
469  for (size_t i = 0; i < npts - 1; ++i) dlb->AddLine(pts[i], pts[i + 1], col, thick);
470  dlb->AddLine(pts[npts - 1], pts[0], col, thick); // close the polygon
471  }
472 }
473 
474 // ##############################################################################################################
475 void jevois::GUIhelper::drawPoly(std::vector<cv::Point> const & pts, ImU32 col, bool filled)
476 {
477  size_t const npts = pts.size();
478 
479  ImVec2 iv[npts]; int i = 0;
480  for (auto const & p : pts) iv[i++] = i2d(p.x, p.y);
481 
482  drawPolyInternal(iv, npts, col, filled);
483 }
484 
485 // ##############################################################################################################
486 void jevois::GUIhelper::drawPoly(std::vector<cv::Point2f> const & pts, ImU32 col, bool filled)
487 {
488  size_t const npts = pts.size();
489 
490  ImVec2 iv[npts]; int i = 0;
491  for (auto const & p : pts) iv[i++] = i2d(p.x, p.y);
492 
493  drawPolyInternal(iv, npts, col, filled);
494 }
495 
496 // ##############################################################################################################
497 void jevois::GUIhelper::drawCircle(float x, float y, float r, ImU32 col, bool filled)
498 {
499  auto dlb = ImGui::GetBackgroundDrawList();
500 
501  ImVec2 const center = i2d(x, y);
502  float const rad = i2ds(r, 0).x;
503 
504  if (filled) dlb->AddCircleFilled(center, rad, applyFillAlpha(col), 0);
505 
506  dlb->AddCircle(center, rad, col, 0, linethick::get());
507 }
508 
509 // ##############################################################################################################
510 void jevois::GUIhelper::drawText(float x, float y, char const * txt, ImU32 col)
511 {
512  ImGui::GetBackgroundDrawList()->AddText(i2d(x, y), col, txt);
513 }
514 
515 // ##############################################################################################################
516 void jevois::GUIhelper::drawText(float x, float y, std::string const & txt, ImU32 col)
517 {
518  drawText(x, y, txt.c_str(), col);
519 }
520 
521 // ##############################################################################################################
522 ImU32 jevois::GUIhelper::applyFillAlpha(ImU32 col) const
523 {
524  unsigned char alpha = (col & IM_COL32_A_MASK) >> IM_COL32_A_SHIFT;
525  alpha = (unsigned char)(fillalpha::get() * alpha);
526  return (col & ~IM_COL32_A_MASK) | (alpha << IM_COL32_A_SHIFT);
527 }
528 
529 // ##############################################################################################################
530 ImVec2 jevois::GUIhelper::iline(int line, char const * name)
531 {
532  if (line == -1) line = ++itsLastDrawnTextLine; else itsLastDrawnTextLine = line;
533  ImVec2 p = i2d(0, 0, name);
534  p.x += 5.0F;
535  p.y += 5.0F + (ImGui::GetFontSize() + 5.0F) * line;
536  return p;
537 }
538 
539 // ##############################################################################################################
540 void jevois::GUIhelper::itext(char const * txt, ImU32 const & col, int line)
541 {
542  ImU32 const c = (col == IM_COL32_BLACK_TRANS) ? ImU32(overlaycolor::get()) : col;
543  ImGui::GetBackgroundDrawList()->AddText(iline(line), c, txt);
544 }
545 
546 // ##############################################################################################################
547 void jevois::GUIhelper::itext(std::string const & txt, ImU32 const & col, int line)
548 {
549  itext(txt.c_str(), col, line);
550 }
551 
552 // ##############################################################################################################
553 void jevois::GUIhelper::iinfo(jevois::InputFrame const & inframe, std::string const & fpscpu,
554  unsigned short winw, unsigned short winh)
555 {
556  unsigned short ww, wh;
557  if (winw == 0 || winh == 0) itsBackend.getWindowSize(ww, wh); else { ww = winw; wh = winh; }
558 
559  jevois::RawImage const & inimg = inframe.get();
560  std::string cam2str;
561  if (inframe.hasScaledImage())
562  {
563  jevois::RawImage const & inimg2 = inframe.get2();
564  cam2str += jevois::sformat(" + %s:%dx%d", jevois::fccstr(inimg2.fmt).c_str(), inimg2.width, inimg2.height);
565  }
566  std::string const msg = jevois::sformat("%s, Camera: %s:%dx%d%s, Display: RGBA:%dx%d", fpscpu.c_str(),
567  jevois::fccstr(inimg.fmt).c_str(), inimg.width, inimg.height,
568  cam2str.c_str(), ww, wh);
569 
570  ImGui::GetBackgroundDrawList()->AddText(ImVec2(10, wh-10-ImGui::GetFontSize()), overlaycolor::get(), msg.c_str());
571 }
572 
573 // ##############################################################################################################
574 void jevois::GUIhelper::releaseImage(char const * name)
575 {
576  auto itr = itsImages.find(name);
577  if (itr != itsImages.end()) itsImages.erase(itr);
578 }
579 
580 // ##############################################################################################################
581 void jevois::GUIhelper::releaseImage2(char const * name)
582 {
583  auto itr = itsImages2.find(name);
584  if (itr != itsImages2.end()) itsImages2.erase(itr);
585 }
586 
587 // ##############################################################################################################
588 ImVec2 jevois::GUIhelper::d2i(ImVec2 p, char const * name)
589 {
590  // Find the image:
591  GPUimage * img;
592  float fx = 1.0F, fy = 1.0F;
593 
594  if (name == nullptr)
595  {
596  if (itsLastDrawnImage == nullptr) throw std::range_error("You need to call drawImage() or drawInputFrame() first");
597  img = itsLastDrawnImage;
598  if (itsUsingScaledImage) { fx = 1.0F / itsScaledImageFacX; fy = 1.0F / itsScaledImageFacY; }
599  }
600  else
601  {
602  std::string nstr = name;
603  auto itr = itsImages.find(nstr);
604  if (itr == itsImages.end())
605  {
606  // Add a zero in case we are dealing with a camera frame (drawImage() and drawInputFrame() add suffixes, but all
607  // image buffers are the same size):
608  itr = itsImages.find(nstr + '0');
609  if (itr == itsImages.end()) throw std::range_error("No previously drawn image with name [" + nstr + "] found");
610  }
611  img = & itr->second;
612  }
613 
614  // Delegate:
615  ImVec2 ret = img->d2i(p);
616  ret.x *= fx; ret.y *= fy;
617  return ret;
618 }
619 
620 // ##############################################################################################################
621 ImVec2 jevois::GUIhelper::d2i(float x, float y, char const * name)
622 { return d2i(ImVec2(x, y), name); }
623 
624 // ##############################################################################################################
625 ImVec2 jevois::GUIhelper::d2is(ImVec2 p, char const * name)
626 {
627  // Find the image:
628  GPUimage * img;
629  float fx = 1.0F, fy = 1.0F;
630 
631  if (name == nullptr)
632  {
633  if (itsLastDrawnImage == nullptr) throw std::range_error("You need to call drawImage() or drawInputFrame() first");
634  img = itsLastDrawnImage;
635  if (itsUsingScaledImage) { fx = 1.0F / itsScaledImageFacX; fy = 1.0F / itsScaledImageFacY; }
636  }
637  else
638  {
639  std::string nstr = name;
640  auto itr = itsImages.find(nstr);
641  if (itr == itsImages.end())
642  {
643  // Add a zero in case we are dealing with a camera frame (drawImage() and drawInputFrame() add suffixes, but all
644  // image buffers are the same size):
645  itr = itsImages.find(nstr + '0');
646  if (itr == itsImages.end()) throw std::range_error("No previously drawn image with name [" + nstr + "] found");
647  }
648  img = & itr->second;
649  }
650 
651  // Delegate:
652  ImVec2 ret = img->d2is(p);
653  ret.x *= fx; ret.y *= fy;
654  return ret;
655 }
656 
657 // ##############################################################################################################
658 ImVec2 jevois::GUIhelper::d2is(float x, float y, char const * name)
659 { return d2is(ImVec2(x, y), name); }
660 
661 // ##############################################################################################################
663 {
664  // Decide whether to show mouse cursor based on idle state:
665  ImGui::GetIO().MouseDrawCursor = ! itsIdle;
666 
667  // Draw our JeVois GUI on top of everything:
668  if (itsIdle == false) drawJeVoisGUI();
669 
670  // Render everything and swap buffers:
671  itsBackend.render();
672 
673  itsEndFrameCalled = true;
674 }
675 
676 // ##############################################################################################################
678 {
679  if (ImGui::Begin(itsWindowTitle.c_str(), nullptr /* no closing */))//, ImGuiWindowFlags_MenuBar))
680  {
681  //drawMenuBar();
682  drawModuleSelect();
683 
684  //ImGui::Text("Camera + Process + Display: %.2f fps", ImGui::GetIO().Framerate);
685  ImGui::Separator();
686 
687  if (ImGui::BeginTabBar("##tabs", ImGuiTabBarFlags_None))
688  {
689 
690  if (ImGui::BeginTabItem("Info"))
691  {
692  drawInfo();
693  ImGui::EndTabItem();
694  }
695 
696  if (ImGui::BeginTabItem("Parameters"))
697  {
698  drawParameters();
699  ImGui::EndTabItem();
700  }
701 
702  if (ImGui::BeginTabItem("Console"))
703  {
704  drawConsole();
705  ImGui::EndTabItem();
706  }
707 
708  if (ImGui::BeginTabItem("Camera"))
709  {
710  drawCamCtrls();
711  ImGui::EndTabItem();
712  }
713 
714  if (ImGui::BeginTabItem("Config"))
715  {
716  itsCfgEditor->draw();
717  ImGui::EndTabItem();
718  }
719 
720  if (ImGui::BeginTabItem("Code"))
721  {
722  itsCodeEditor->draw();
723  ImGui::EndTabItem();
724  }
725 
726  if (ImGui::BeginTabItem("System"))
727  {
728  drawSystem();
729  ImGui::EndTabItem();
730  }
731 
732  if (ImGui::BeginTabItem("Tweaks"))
733  {
734  drawTweaks();
735  ImGui::EndTabItem();
736  }
737  ImGui::EndTabBar();
738  }
739  ImGui::End();
740  }
741  else ImGui::End(); // do not draw anything if window is collapsed
742 
743  // Show style editor window, imgui demo, etc if user requested it:
744  if (itsShowStyleEditor)
745  {
746  ImGui::Begin("GUI Style Editor", &itsShowStyleEditor);
747  ImGui::ShowStyleEditor();
748  ImGui::End();
749  }
750  if (itsShowAppMetrics) ImGui::ShowMetricsWindow(&itsShowAppMetrics);
751  if (itsShowImGuiDemo) ImGui::ShowDemoWindow(&itsShowImGuiDemo);
752 
753  // Draw an error popup, if any exception was received through reportError():
754  drawErrorPopup();
755 }
756 
757 // ##############################################################################################################
759 {
760  if (ImGui::BeginMenuBar())
761  {
762  if (ImGui::BeginMenu("File"))
763  {
764  if (ImGui::MenuItem("Quit")) engine()->quit();
765 
766  //ShowExampleMenuFile();
767  ImGui::EndMenu();
768  }
769  /*
770  if (ImGui::BeginMenu("Machine Vision Module"))
771  {
772  auto e = engine();
773 
774  // Start with the JeVois-Pro mappings:
775  size_t idx = 0;
776  e->foreachVideoMapping([&idx,&e](jevois::VideoMapping const & m) {
777  if (m.ofmt == JEVOISPRO_FMT_GUI && ImGui::MenuItem(m.str().c_str()))
778  e->requestSetFormat(idx++); else ++idx;
779  });
780  ImGui::Separator();
781 
782  // Then the compatibility JeVois modules:
783  idx = 0;
784  e->foreachVideoMapping([&idx,&e](jevois::VideoMapping const & m) {
785  if (m.ofmt != 0 && m.ofmt != JEVOISPRO_FMT_GUI && ImGui::MenuItem(m.str().c_str()))
786  e->requestSetFormat(idx++); else ++idx;
787  });
788 
789  ImGui::Separator();
790  // Finally the no-USB modules: FIXME - those currently kill the gui since no startFrame() is emitted
791  idx = 0;
792  e->foreachVideoMapping([&idx,&e](jevois::VideoMapping const & m) {
793  if (m.ofmt == 0 && ImGui::MenuItem(m.str().c_str()))
794  e->requestSetFormat(idx++); else ++idx;
795  });
796 
797  ImGui::EndMenu();
798  }
799  */
800  if (ImGui::BeginMenu("Tools"))
801  {
802  ImGui::MenuItem("ImGui Style Editor", NULL, &itsShowStyleEditor);
803  ImGui::MenuItem("ImGui Metrics/Debugger", NULL, &itsShowAppMetrics);
804  ImGui::MenuItem("ImGui Demo/Doc", NULL, &itsShowImGuiDemo);
805 
806  ImGui::EndMenu();
807  }
808 
809  ImGui::EndMenuBar();
810  }
811 }
812 
813 // ##############################################################################################################
815 {
816  static std::map<std::string, size_t> mods;
817  auto e = engine();
818  static std::string currstr;
819 
820  // Refresh the list of modules if needed:
821  ImGui::AlignTextToFramePadding();
822  ImGui::Text("Module:");
823  ImGui::SameLine();
824  ImGui::SetNextItemWidth(6 * ImGui::GetFontSize() + 5);
825  if (ImGui::Combo("##typemachinevisionmodule", &itsVideoMappingListType, "Pro/GUI\0Legacy\0Headless\0\0")
826  || currstr.empty() || itsRefreshVideoMappings)
827  {
828  // Recompute mods for the selected type:
829  itsRefreshVideoMappings = false;
830  mods.clear();
831 
832  switch (itsVideoMappingListType)
833  {
834  case 0:
835  {
836  // JeVois-Pro GUI mappings:
837  size_t idx = 0;
838  e->foreachVideoMapping([&idx](jevois::VideoMapping const & m) {
839  if (m.ofmt == JEVOISPRO_FMT_GUI) mods[m.menustr()] = idx;
840  ++idx;
841  });
842  }
843  break;
844 
845  case 1:
846  {
847  // Legacy JeVois mappings:
848  size_t idx = 0;
849  e->foreachVideoMapping([&idx](jevois::VideoMapping const & m) {
850  if (m.ofmt != 0 && m.ofmt != JEVOISPRO_FMT_GUI) mods[m.menustr()] = idx;
851  ++idx;
852  });
853  }
854  break;
855 
856  case 2:
857  {
858  // Headless modules
859  size_t idx = 0;
860  e->foreachVideoMapping([&idx](jevois::VideoMapping const & m) {
861  if (m.ofmt == 0) mods[m.menustr()] = idx;
862  ++idx;
863  });
864  }
865  break;
866 
867  default: LFATAL("Internal error, itsVideoMappingListType=" << itsVideoMappingListType);
868  }
869 
870  // Refresh our display string:
871  currstr = e->getCurrentVideoMapping().menustr().c_str();
872  }
873 
874  // Draw the module selector and allow selection:
875  ImGui::SameLine();
876 
877  if (ImGui::BeginCombo("##machinevisionmodule", currstr.c_str()))
878  {
879  for (auto const & m : mods)
880  {
881  bool is_selected = false;
882  if (ImGui::Selectable(m.first.c_str(), is_selected))
883  {
884  e->requestSetFormat(m.second);
885  currstr.clear();
886  }
887 
888  }
889  ImGui::EndCombo();
890  }
891 }
892 
893 // ##############################################################################################################
895 {
896  std::shared_ptr<jevois::Module> m = engine()->module();
897  if (m)
898  {
899  // Get the icon and display it:
900  if (itsIcon.loaded() == false)
901  try { itsIcon.load(m->absolutePath("icon.png")); }
902  catch (...)
903  {
905 
906  // Load a default C++ or Python icon:
907  try
908  {
909  if (engine()->getCurrentVideoMapping().ispython) itsIcon.load(JEVOIS_SHARE_PATH "/icons/py.png");
910  else itsIcon.load(JEVOIS_SHARE_PATH "/icons/cpp.png");
911  }
912  catch (...)
913  {
914  // Defaults icons not found, just use a blank:
915  cv::Mat blank(32, 32, CV_8UC4, 0);
916  itsIcon.load(blank);
917  }
918  }
919 
920  if (itsIcon.loaded())
921  {
922  int const siz = ImGui::CalcTextSize(" ").x;
923  itsIcon.draw(ImGui::GetCursorScreenPos(), ImVec2(siz, siz));
924  }
925 
926  // Get the html doc if we have not yet parsed it:
927  if (itsModName.empty())
928  {
929  std::filesystem::path fname = m->absolutePath("modinfo.html");
930  std::ifstream ifs(fname);
931  if (ifs.is_open() == false)
932  itsModAuth = ("Cannot read file: " + fname.string()).c_str();
933  else
934  {
935  int state = 0;
936  for (std::string s; std::getline(ifs, s); )
937  switch (state)
938  {
939  case 0: // Looking for module display name
940  {
941  std::string const str = jevois::extractString(s, "<td class=modinfoname>", "</td>");
942  if (str.empty() == false) { itsModName = str; ++state; }
943  break;
944  }
945 
946  case 1: // Looking for short synopsis
947  {
948  std::string const str = jevois::extractString(s, "<td class=modinfosynopsis>", "</td>");
949  if (str.empty() == false) { itsModDesc = str; ++state; }
950  break;
951  }
952 
953  case 2: // Looking for author info
954  {
955  std::string const str = jevois::extractString(s, "<table class=modinfoauth width=100%>", "</table>");
956  if (str.empty() == false)
957  {
958  itsModAuth = jevois::join(jevois::split(str, "<[^<]*>"), " ").substr(2); // remove HTML tags
959  ++state;
960  }
961  break;
962  }
963 
964  case 3: // Looking for language info
965  {
966  std::string const str = jevois::extractString(s, "<table class=moduledata>", "</table>");
967  if (str.empty() == false)
968  {
969  itsModLang = jevois::join(jevois::split(str, "<[^<]*>"), " "); // remove HTML tags
970  auto tok = jevois::split(itsModLang, "&nbsp;");
971  if (tok.size() >= 3)
972  {
973  if (jevois::stringStartsWith(tok[2], "C++")) itsModLang = "Language: C++";
974  else itsModLang = "Language: Python";
975  }
976  else itsModLang = "Language: Unknown";
977  ++state;
978  }
979  break;
980  }
981 
982  case 4: // Looking for main doc start
983  {
984  std::string const str = jevois::extractString(s, "<td class=modinfodesc>", "");
985  if (str.empty() == false)
986  {
987  std::string str2 = jevois::extractString(str, "<div class=\"textblock\">", "");
988  str2 = jevois::join(jevois::split(str2, "<[^<]*>"), " ");
989  size_t idx = str2.find_first_not_of(" "); if (idx != str2.npos) str2 = str2.substr(idx);
990  itsModDoc.emplace_back(str2);
991  ++state;
992  }
993  break;
994  }
995 
996  case 5: // Extracting main doc until its end marker is encountered
997  {
998  if (s == "</div></td></tr>") ++state;
999  else
1000  {
1001  std::string ss = jevois::join(jevois::split(s, "<[^<]*>"), " ");
1002  std::string prefix;
1003 
1004  if (s.find("/h1>") != s.npos || s.find("/h2>") != s.npos || s.find("/h3>") != s.npos) prefix = "* ";
1005  if (s.find("<li>") != s.npos) prefix = "- ";
1006  ss = prefix + ss;
1007 
1008  // Finally fix multiple spaces:
1009  // https://stackoverflow.com/questions/8362094/replace-multiple-spaces-with-one-space-in-a-string
1010  std::string::iterator new_end =
1011  std::unique(ss.begin(), ss.end(), [](char lhs, char rhs) { return (lhs == rhs) && (lhs == ' '); });
1012  ss.erase(new_end, ss.end());
1013  size_t idx = ss.find_first_not_of(" "); if (idx != ss.npos) ss = ss.substr(idx);
1014  itsModDoc.push_back(ss);
1015  }
1016  }
1017 
1018  default: break;
1019  }
1020  ifs.close();
1021  }
1022  }
1023 
1024  // Display the doc:
1025  ImGui::TextUnformatted((" " + itsModName).c_str());
1026  ImGui::TextUnformatted((" " + itsModDesc).c_str());
1027  ImGui::TextUnformatted((" " + itsModAuth + " " + itsModLang).c_str());
1028  ImGui::TextUnformatted(" ");
1029 
1030  int wrap = ImGui::GetCursorPos().x + ImGui::GetWindowSize().x - ImGui::GetFontSize() * 2.0f;
1031  if (wrap < 200) wrap = 200;
1032  ImGui::PushTextWrapPos(wrap);
1033 
1034  bool show = true;
1035  for (std::string const & s : itsModDoc)
1036  {
1037  // Create collapsible header and get its collapsed status:
1038  if (jevois::stringStartsWith(s, "* "))
1039  show = ImGui::CollapsingHeader(s.c_str() + 2, ImGuiTreeNodeFlags_DefaultOpen);
1040  else if (show)
1041  {
1042  // If header not collapsed, show data:
1043  if (jevois::stringStartsWith(s, "- ")) ImGui::BulletText("%s", s.c_str() + 2);
1044  else ImGui::TextUnformatted(s.c_str());
1045  }
1046  }
1047  ImGui::PopTextWrapPos();
1048  }
1049  else
1050  ImGui::TextUnformatted("No JeVois Module currently loaded.");
1051 }
1052 
1053 // ##############################################################################################################
1054 void jevois::GUIhelper::setparstr(std::string const & descriptor, std::string const & val)
1055 {
1056  try { engine()->setParamStringUnique(descriptor, val); }
1057  catch (...) { reportError(jevois::warnAndIgnoreException()); }
1058  // drawGUI() will call drawErrorPopup() which will show the popup
1059 }
1060 
1061 // ##############################################################################################################
1063 {
1064  static bool show_frozen = true; static bool show_system = false;
1065 
1066  toggleButton("Show Frozen Parameters", &show_frozen);
1067  ImGui::SameLine(ImGui::GetWindowWidth() - ImGui::CalcTextSize("Show System Parameters").x - 30.0f);
1068  toggleButton("Show System Parameters", &show_system);
1069 
1070  jevois::Engine * e = engine();
1071  jevois::Component * c; if (show_system) c = e; else c = e->module().get();
1072 
1073  // Stop here if we want to show module params but we have no module:
1074  if (c == nullptr) { ImGui::TextUnformatted("No module loaded."); return; }
1075 
1076  // Record any ambiguous parameter names, so we can prefix them by component name:
1077  std::set<std::string> pnames, ambig;
1078 
1079  // Get all the parameter summaries:
1080  std::map<std::string /* categ */, std::vector<jevois::ParameterSummary>> psm;
1081  c->foreachParam([this, &psm, &pnames, &ambig](std::string const &, jevois::ParameterBase * p) {
1082  jevois::ParameterSummary psum = p->summary();
1083  if (pnames.insert(psum.name).second == false) ambig.insert(psum.name);
1084  psm[psum.category].push_back(std::move(psum)); } );
1085 
1086  // Stop here if no params to display:
1087  if (psm.empty()) { ImGui::Text("This module has no parameters."); return; }
1088 
1089  // Create a collapsing header for each parameter category:
1090  int widgetnum = 0; // we need a unique ID for each widget
1091  float maxlen = 0.0f;
1092  for (auto const & pp : psm)
1093  {
1094  // Do not even show a header if all params under it are frozen and we do not want to show frozen params:
1095  if (show_frozen == false)
1096  {
1097  bool all_frozen = true;
1098  for (auto const & ps : pp.second) if (ps.frozen == false) { all_frozen = false; break; }
1099  if (all_frozen) continue;
1100  }
1101 
1102  // Show a header for this category:
1103  if (ImGui::CollapsingHeader(pp.first.c_str()))
1104  {
1105  ImGui::Columns(3, "parameters");
1106 
1107  // Create a widget for each param:
1108  for (auto const & ps : pp.second)
1109  {
1110  // Skip if frozen and we do not want to show frozen params:
1111  if (ps.frozen && show_frozen == false) continue;
1112 
1113  // We need a unique ID for each ImGui widget, and we will use no visible widget name:
1114  static char wname[16]; snprintf(wname, 16, "##p%d", widgetnum);
1115  bool reset = true; // will set to false if we do not want a reset button
1116 
1117  // Start with parameter name and a tooltip with its descriptor:
1118  ImGui::AlignTextToFramePadding();
1119  std::string nam = ps.name;
1120  if (ambig.contains(nam))
1121  {
1122  // Here we are only going to disambiguate by the owning component name:
1123  auto tok = jevois::split(ps.descriptor, ":");
1124  if (tok.size() >= 2) nam = tok[tok.size()-2] + ':' + nam;
1125  }
1126 
1127  ImGui::TextUnformatted(nam.c_str());
1128  if (ImGui::IsItemHovered()) ImGui::SetTooltip("%s", ps.descriptor.c_str());
1129  maxlen = std::max(maxlen, ImGui::CalcTextSize(nam.c_str()).x);
1130 
1131  // Add a tooltip:
1132  ImGui::NextColumn();
1133  ImGui::AlignTextToFramePadding();
1134  std::string const & vtype = ps.valuetype;
1135  if (jevois::stringStartsWith(ps.validvalues, "None:"))
1136  helpMarker(ps.description.c_str(), ("Parameter type: " + vtype).c_str());
1137  else
1138  helpMarker(ps.description.c_str(), ("Parameter type: " + vtype).c_str(),
1139  ("Allowed values: " + ps.validvalues).c_str());
1140 
1141  // Now a widget for the parameter:
1142  ImGui::NextColumn();
1143  bool const is_uchar = (vtype == "unsigned char");
1144  bool const is_int = (vtype == "short" || vtype == "int" || vtype == "long int" || vtype == "long long int");
1145  bool const is_uint = (is_uchar || vtype == "unsigned short" || vtype == "unsigned int" ||
1146  vtype == "unsigned long int" || vtype == "unsigned long long int" || vtype == "size_t");
1147  bool const is_real = (vtype == "float" || vtype == "double" || vtype == "long double");
1148 
1149  // Grey out the item if it is disabled:
1150  if (ps.frozen)
1151  {
1152  ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true);
1153  ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.5f);
1154  }
1155 
1156  // ----------------------------------------------------------------------
1157  if (jevois::stringStartsWith(ps.validvalues, "List:["))
1158  {
1159  std::string vals = ps.validvalues.substr(6, ps.validvalues.size() - 7);
1160  auto vv = jevois::split(vals, "\\|");
1161 
1162  if (vv.empty() == false)
1163  {
1164  // Find the index of the current value:
1165  int index = 0; for (auto const & v : vv) if (v == ps.value) break; else ++index;
1166  if (ImGui::Combo(wname, &index,
1167  [](void * vec, int idx, const char ** out_text)
1168  {
1169  auto & ve = *static_cast<std::vector<std::string>*>(vec);
1170  if (idx < 0 || idx >= static_cast<int>(ve.size())) return false;
1171  *out_text = ve.at(idx).c_str();
1172  return true;
1173  },
1174  static_cast<void *>(&vv), vv.size()))
1175  setparstr(ps.descriptor, vv[index]);
1176  }
1177  }
1178  // ----------------------------------------------------------------------
1179  else if (is_uchar || jevois::stringStartsWith(ps.validvalues, "Range:["))
1180  {
1181  if (is_uchar)
1182  {
1183  // For unsigned char, use a slider:
1184  unsigned long val; jevois::paramStringToVal(ps.value, val);
1185  std::string rng = ps.validvalues.substr(7, ps.validvalues.size() - 8);
1186 
1187  // We may or not have a range spec, if not, use 0..255:
1188  if (rng.empty())
1189  {
1190  long mi = 0, ma = 255;
1191  if (ImGui::SliderScalar(wname, ImGuiDataType_U64, &val, &mi, &ma))
1192  setparstr(ps.descriptor, std::to_string(val));
1193  }
1194  else
1195  {
1197  if (ImGui::SliderScalar(wname, ImGuiDataType_U64, &val, &r.min(), &r.max()))
1198  setparstr(ps.descriptor, std::to_string(val));
1199  }
1200  }
1201  else if (is_uint)
1202  {
1203  // For uint that has a range specified, use a slider:
1204  std::string rng = ps.validvalues.substr(7, ps.validvalues.size() - 8);
1206  unsigned long val; jevois::paramStringToVal(ps.value, val);
1207  if (ImGui::SliderScalar(wname, ImGuiDataType_U64, &val, &r.min(), &r.max()))
1208  setparstr(ps.descriptor, std::to_string(val));
1209  }
1210  else if (is_int)
1211  {
1212  // For int that has a range specified, use a slider:
1213  std::string rng = ps.validvalues.substr(7, ps.validvalues.size() - 8);
1215  long val; jevois::paramStringToVal(ps.value, val);
1216  if (ImGui::SliderScalar(wname, ImGuiDataType_S64, &val, &r.min(), &r.max()))
1217  setparstr(ps.descriptor, std::to_string(val));
1218  }
1219  else if (is_real)
1220  {
1221  // For real with a range specified, use a slider:
1222  std::string rng = ps.validvalues.substr(7, ps.validvalues.size() - 8);
1224  double val; jevois::paramStringToVal(ps.value, val);
1225  if (ImGui::SliderScalar(wname, ImGuiDataType_Double, &val, &r.min(), &r.max()))
1226  setparstr(ps.descriptor, std::to_string(val));
1227  }
1228  else
1229  {
1230  // For more complex types, just allow free typing, parameter will do the checking:
1231  char buf[256]; strncpy(buf, ps.value.c_str(), sizeof(buf)-1);
1232  if (ImGui::InputText(wname, buf, sizeof(buf), ImGuiInputTextFlags_EnterReturnsTrue))
1233  setparstr(ps.descriptor, buf);
1234  }
1235  }
1236  // ----------------------------------------------------------------------
1237  else if (vtype == "jevois::Range<unsigned char>")
1238  {
1239  // For a range parameter, use a double drag:
1241  int mi = val.min(), ma = val.max();
1242  if (ImGui::DragIntRange2(wname, &mi, &ma, 0, 0, 255, "Min: %d", "Max: %d"))
1243  setparval(ps.descriptor, jevois::Range<unsigned char>(mi, ma));
1244  }
1245  // ----------------------------------------------------------------------
1246  else if (vtype == "bool")
1247  {
1248  bool val; jevois::paramStringToVal(ps.value, val);
1249  if (ImGui::Checkbox(wname, &val)) setparval(ps.descriptor, val);
1250  }
1251  // ----------------------------------------------------------------------
1252  else if (vtype == "ImColor")
1253  {
1254  ImColor val; jevois::paramStringToVal(ps.value, val);
1255  if (ImGui::ColorEdit4(wname, (float *)&val, ImGuiColorEditFlags_AlphaPreview)) setparval(ps.descriptor, val);
1256  }
1257  // ----------------------------------------------------------------------
1258  else
1259  {
1260  // User will type in some value, parameter will check it:
1261  char buf[256]; strncpy(buf, ps.value.c_str(), sizeof(buf)-1);
1262  if (ImGui::InputText(wname, buf, sizeof(buf), ImGuiInputTextFlags_EnterReturnsTrue))
1263  setparstr(ps.descriptor, buf);
1264  }
1265 
1266  // Possibly add a reset button:
1267  if (reset)
1268  {
1269  static char rname[18]; snprintf(rname, 18, "Reset##%d", widgetnum);
1270  ImGui::SameLine();
1271  if (ImGui::Button(rname)) setparstr(ps.descriptor, ps.defaultvalue);
1272  }
1273 
1274  // Restore any grey out:
1275  if (ps.frozen)
1276  {
1277  ImGui::PopItemFlag();
1278  ImGui::PopStyleVar();
1279  }
1280 
1281  // Ready for next row:
1282  ImGui::NextColumn(); ++widgetnum;
1283  }
1284  ImGui::SetColumnWidth(0, maxlen + 30.0f);
1285  ImGui::SetColumnWidth(1, ImGui::CalcTextSize("(?)").x + 30.0f);
1286  ImGui::SetColumnWidth(2, 1000);
1287 
1288  // Back to single column before the next param categ:
1289  ImGui::Columns(1);
1290  }
1291  }
1292 }
1293 
1294 // ##############################################################################################################
1296 {
1297  jevois::Engine * e = engine();
1298 
1299  // Start with toggle buttons for serlog and serout:
1300  bool slusb = false, slhard = false, schanged = false;
1301  auto sl = e->getParamValUnique<jevois::engine::SerPort>("engine:serlog");
1302  switch (sl)
1303  {
1304  case jevois::engine::SerPort::None: slusb = false; slhard = false; break;
1305  case jevois::engine::SerPort::All: slusb = true; slhard = true; break;
1306  case jevois::engine::SerPort::Hard: slusb = false; slhard = true; break;
1307  case jevois::engine::SerPort::USB: slusb = true; slhard = false; break;
1308  }
1309  ImGui::AlignTextToFramePadding();
1310  ImGui::Text("Log messages:");
1311  ImGui::SameLine(); if (toggleButton("USB##serlogu", &slusb)) schanged = true;
1312  ImGui::SameLine(); if (toggleButton("Hard##serlogh", &slhard)) schanged = true;
1313  ImGui::SameLine(); toggleButton("Cons##serlogc", &itsSerLogEnabled);
1314  ImGui::SameLine(0, 50);
1315 
1316  bool sousb = false, sohard = false;
1317  auto so = e->getParamValUnique<jevois::engine::SerPort>("engine:serout");
1318  switch (so)
1319  {
1320  case jevois::engine::SerPort::None: sousb = false; sohard = false; break;
1321  case jevois::engine::SerPort::All: sousb = true; sohard = true; break;
1322  case jevois::engine::SerPort::Hard: sousb = false; sohard = true; break;
1323  case jevois::engine::SerPort::USB: sousb = true; sohard = false; break;
1324  }
1325  ImGui::Text("Module output:");
1326  ImGui::SameLine(); if (toggleButton("USB##seroutu", &sousb)) schanged = true;
1327  ImGui::SameLine(); if (toggleButton("Hard##serouth", &sohard)) schanged = true;
1328  ImGui::SameLine(); toggleButton("Cons##seroutc", &itsSerOutEnabled);
1329 
1330  if (schanged)
1331  {
1332  if (slusb)
1333  {
1334  if (slhard) e->setParamValUnique("engine:serlog", jevois::engine::SerPort::All);
1335  else e->setParamValUnique("engine:serlog", jevois::engine::SerPort::USB);
1336  }
1337  else
1338  {
1339  if (slhard) e->setParamValUnique("engine:serlog", jevois::engine::SerPort::Hard);
1340  else e->setParamValUnique("engine:serlog", jevois::engine::SerPort::None);
1341  }
1342 
1343  if (sousb)
1344  {
1345  if (sohard) e->setParamValUnique("engine:serout", jevois::engine::SerPort::All);
1346  else e->setParamValUnique("engine:serout", jevois::engine::SerPort::USB);
1347  }
1348  else
1349  {
1350  if (sohard) e->setParamValUnique("engine:serout", jevois::engine::SerPort::Hard);
1351  else e->setParamValUnique("engine:serout", jevois::engine::SerPort::None);
1352  }
1353  }
1354 
1355  // Now a combo for serstyle:
1356  auto m = dynamic_cast<jevois::StdModule *>(e->module().get());
1357  if (m)
1358  {
1359  auto sp = m->getParamValUnique<jevois::module::SerStyle>("serstyle");
1360  int idx = 0; for (auto const & v : jevois::module::SerStyle_Values) if (v == sp) break; else ++idx;
1361 
1362  ImGui::SameLine();
1363  if (ImGui::Combo("serstyle", &idx,
1364  [](void * vec, int idx, const char ** out_text)
1365  {
1366  auto & ve = *static_cast<std::vector<std::string>*>(vec);
1367  if (idx < 0 || idx >= static_cast<int>(ve.size())) return false;
1368  *out_text = ve.at(idx).c_str();
1369  return true;
1370  },
1371  const_cast<void *>(static_cast<void const *>(&jevois::module::SerStyle_Strings)),
1372  jevois::module::SerStyle_Strings.size()))
1373  try { e->setParamValUnique("serstyle", jevois::module::SerStyle_Values[idx]); }
1374  catch (...) { jevois::warnAndIgnoreException(); }
1375  }
1376  ImGui::Separator();
1377 
1378  // Now a console:
1379  auto c = e->getComponent<jevois::GUIconsole>("guiconsole");
1380  if (c) c->draw();
1381 }
1382 
1383 // ##############################################################################################################
1385 { return itsSerLogEnabled; }
1386 
1387 // ##############################################################################################################
1389 { return itsSerOutEnabled; }
1390 
1391 // ##############################################################################################################
1393 {
1394  engine()->drawCameraGUI();
1395 }
1396 
1397 // ##############################################################################################################
1398 int jevois::GUIhelper::modal(std::string const & title, char const * text, int * default_val,
1399  char const * b1txt, char const * b2txt)
1400 {
1401  // Handle optional default_val pointer:
1402  int ret = 0; int * retptr = default_val ? default_val : &ret;
1403 
1404  // Do we want to just return the default value?
1405  if (*retptr == 1 || *retptr == 2) return *retptr;
1406 
1407  // Open the modal if needed, and remember it:
1408  if (itsOpenModals.find(title) == itsOpenModals.end())
1409  {
1410  ImGui::OpenPopup(title.c_str());
1411  itsOpenModals.insert(title);
1412  }
1413 
1414  // Display the modal and get any button clicks:
1415  bool dont_ask_me_next_time = (*retptr == 3);
1416 
1417  if (ImGui::BeginPopupModal(title.c_str(), NULL, ImGuiWindowFlags_AlwaysAutoResize))
1418  {
1419  ImGui::TextUnformatted(text);
1420  ImGui::Separator();
1421  if (default_val)
1422  {
1423  ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
1424  ImGui::Checkbox("Don't ask me next time", &dont_ask_me_next_time);
1425  ImGui::PopStyleVar();
1426  }
1427  if (ImGui::Button(b1txt, ImVec2(120, 0))) ret = 1;
1428  ImGui::SetItemDefaultFocus();
1429  ImGui::SameLine();
1430  if (ImGui::Button(b2txt, ImVec2(120, 0))) ret = 2;
1431  ImGui::EndPopup();
1432  }
1433 
1434  // Close the modal if button clicked:
1435  if (ret == 1 || ret == 2)
1436  {
1437  ImGui::CloseCurrentPopup();
1438  itsOpenModals.erase(title);
1439  if (dont_ask_me_next_time) *retptr = ret; // remember the choice as new default choice
1440  }
1441  else *retptr = dont_ask_me_next_time ? 3 : 0; // propagate checkbox status
1442 
1443  return ret;
1444 }
1445 
1446 // ##############################################################################################################
1447 void jevois::GUIhelper::newModEntry(char const * wname, std::string & str, char const * desc,
1448  char const * hint, char const * hlp)
1449 {
1450  static char buf[256];
1451  ImGui::AlignTextToFramePadding();
1452  ImGui::TextUnformatted(desc);
1453  ImGui::NextColumn();
1454  helpMarker(desc, hlp);
1455  ImGui::NextColumn();
1456  strncpy(buf, str.c_str(), sizeof(buf)-1);
1457  if (ImGui::InputTextWithHint(wname, hint, buf, sizeof(buf))) str = buf;
1458  ImGui::NextColumn();
1459 }
1460 
1461 // ##############################################################################################################
1463 {
1464  float const fontw = ImGui::GetFontSize();
1465 
1466  static int refresh = 1;
1467  static std::string cpu, mem, ver;
1468  static size_t npu, tpu, vpu, spu; static int fan;
1469  if (--refresh == 0)
1470  {
1471  refresh = 60;
1472  cpu = jevois::getSysInfoCPU();
1473  mem = jevois::getSysInfoMem();
1474  ver = jevois::getSysInfoVersion();
1479  fan = jevois::getFanSpeed();
1480  }
1481  ImGui::Text("JeVois-Pro v%s -- %s", JEVOIS_VERSION_STRING, ver.c_str());
1482  ImGui::Text(cpu.c_str());
1483  ImGui::Text(mem.c_str());
1484  ImGui::Text("NPU: %d, TPU: %d, VPU: %d, SPU: %d. Fan: %d%%", npu, tpu, vpu, spu, fan);
1485  ImGui::Separator();
1486 
1487  // #################### Create new module:
1488  drawNewModuleForm();
1489  ImGui::Separator();
1490 
1491  // #################### ping:
1492  static std::string pingstr;
1493  static int showping = 0;
1494  if (ImGui::Button("Ping jevois.usc.edu"))
1495  {
1496  std::string ret = jevois::system("/usr/bin/ping -c 1 -w 2 jevois.usc.edu");
1497  std::vector<std::string> rvec = jevois::split(ret, "\n");
1498  if (rvec.size() < 2) reportError("Unable to ping jevois.usc.edu");
1499  else { pingstr = rvec[1]; showping = 60; }
1500  }
1501  if (showping)
1502  {
1503  ImGui::SameLine();
1504  ImGui::Text(pingstr.c_str());
1505  --showping;
1506  }
1507 
1508  ImGui::Separator();
1509 
1510  // #################### dnnget:
1511  static std::string zip;
1512  static std::string donestr;
1513  static int state = 0;
1514 
1515  ImGuiInputTextFlags flags = ImGuiInputTextFlags_EnterReturnsTrue;
1516  if (state) flags |= ImGuiInputTextFlags_ReadOnly;
1517  ImGui::SetNextItemWidth(fontw * 6.0F);
1518  char buf[5] = { };
1519  if (ImGui::InputText("Load Custom DNN", buf, sizeof(buf), flags)) state = 1;
1520  ImGui::SameLine();
1521 
1522  switch (state)
1523  {
1524  case 0:
1525  ImGui::Text(" ");
1526  break;
1527 
1528  case 1:
1529  {
1530  ImGui::Text("-- Downloading...");
1531  zip = std::string(buf) + ".zip";
1532  itsDnnGetFut =
1534  {
1535  return jevois::system("/usr/bin/curl " JEVOIS_CUSTOM_DNN_URL "/" + zip + " -o "
1536  JEVOIS_CUSTOM_DNN_PATH "/" + zip, true);
1537  });
1538  state = 2;
1539  }
1540  break;
1541 
1542  case 2:
1543  {
1544  if (itsDnnGetFut.valid() == false) { reportError("Unknown error while loading custom DNN"); state = 0; break; }
1545  ImGui::Text("-- Downloading...");
1546  if (itsDnnGetFut.wait_for(std::chrono::microseconds(100)) == std::future_status::ready)
1547  {
1548  itsDnnGetFut.get();
1549 
1550  // Check that the file exists:
1551  std::ifstream ifs(JEVOIS_CUSTOM_DNN_PATH "/" + zip);
1552  if (ifs.is_open() == false)
1553  {
1554  reportError("Failed to download. Check network connectivity and available disk space.");
1555  state = 0;
1556  break;
1557  }
1558  itsDnnGetFut =
1560  {
1561  return jevois::system("/usr/bin/unzip -o " JEVOIS_CUSTOM_DNN_PATH "/" + zip +
1562  " -d " JEVOIS_CUSTOM_DNN_PATH, true);
1563  });
1564  state = 3;
1565  }
1566  }
1567  break;
1568 
1569  case 3:
1570  {
1571  if (itsDnnGetFut.valid() == false) { reportError("Unknown error while unpacking custom DNN"); state = 0; break; }
1572  ImGui::Text("-- Installing...");
1573  if (itsDnnGetFut.wait_for(std::chrono::microseconds(100)) == std::future_status::ready)
1574  {
1575  std::string ret = itsDnnGetFut.get();
1576  std::vector<std::string> rvec = jevois::split(ret, "\n");
1577  if (rvec.size() > 2 && jevois::stringStartsWith(rvec[1], " End-of-central-directory signature not found"))
1578  donestr = "-- Invalid file, check DNN download key.";
1579  else
1580  donestr = "-- Done. Reload model zoo to take effect.";
1581  jevois::system("/bin/rm " JEVOIS_CUSTOM_DNN_PATH "/" + zip, true);
1582  state = 4;
1583  }
1584  }
1585  break;
1586 
1587  case 200:
1588  ImGui::Text(" ");
1589  state = 0;
1590  break;
1591 
1592  default:
1593  ImGui::Text(donestr.c_str());
1594  ++state;
1595  }
1596  ImGui::Separator();
1597 
1598 #ifdef JEVOIS_PLATFORM
1599  // #################### boot mode:
1600  static int bootmode = 0;
1601  ImGui::AlignTextToFramePadding();
1602  ImGui::Text("On boot, start:");
1603  ImGui::SameLine();
1604  if (ImGui::Combo("##onboot", &bootmode, "(no change)\0JeVois-Pro\0Ubuntu Console\0Ubuntu Graphical\0\0"))
1605  {
1606  switch (bootmode)
1607  {
1608  case 0: break;
1609  case 2: jevois::system("systemctl --no-reload set-default multi-user.target"); break;
1610  case 3: jevois::system("systemctl --no-reload set-default graphical.target"); break;
1611  default: jevois::system("systemctl --no-reload set-default jevoispro.target"); break;
1612  }
1613  jevois::system("sync");
1614  }
1615  ImGui::Separator();
1616 #endif
1617 }
1618 
1619 // ##############################################################################################################
1620 namespace
1621 {
1622  unsigned int get_v4l2_fmt(int idx)
1623  {
1624  switch (idx)
1625  {
1626  case 0: return V4L2_PIX_FMT_YUYV;
1627  case 1: return V4L2_PIX_FMT_RGB24;
1628  case 2: return V4L2_PIX_FMT_RGB32;
1629  case 3: return V4L2_PIX_FMT_GREY;
1630  case 4: return V4L2_PIX_FMT_SBGGR16;
1631  default: return 0;
1632  }
1633  }
1634 }
1635 
1636 // ##############################################################################################################
1638 {
1639  float const fontw = ImGui::GetFontSize();
1640 
1641  ImGui::PushStyleColor(ImGuiCol_PopupBg, 0xf0e0ffe0);
1642 
1643  if (ImGui::Button("Create new machine vision module...")) ImGui::OpenPopup("Create new machine vision module");
1644 
1645  ImVec2 const center = ImGui::GetMainViewport()->GetCenter();
1646  ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
1647  ImGui::SetNextWindowContentSize(ImVec2(940, 730));
1648 
1649  if (ImGui::BeginPopupModal("Create new machine vision module", NULL, ImGuiWindowFlags_AlwaysAutoResize))
1650  {
1651  try
1652  {
1653  static std::string name, vendor, synopsis, author, email, website, license;
1654 
1655  ImGui::Text("Fill out the details below:");
1656  ImGui::Separator();
1657 
1658  ImGui::Columns(3, "new module");
1659 
1660  newModEntry("##NewModname", name, "Module Name", "MyModule",
1661  "Required. Must start with an uppercase letter. "
1662  "Will be a folder name under /jevoispro/modules/VendorName");
1663 
1664  newModEntry("##NewModvendor", vendor, "Vendor Name", "MyVendor",
1665  "Required. Must start with an uppercase letter. "
1666  "Will be a folder name under /jevoispro/modules/");
1667 
1668  newModEntry("##NewModsynopsis", synopsis, "Synopsis", "Detect Object of type X",
1669  "Optional. Brief description of what the module does.");
1670 
1671  newModEntry("##NewModauthor", author, "Author Name", "John Smith", "Optional");
1672 
1673  newModEntry("##NewModemail", email, "Author Email", "you@yourcompany.com", "Optional");
1674 
1675  newModEntry("##NewModwebsite", website, "Author Website", "http://yourcompany.com", "Optional");
1676 
1677  newModEntry("##NewModlicense", license, "License", "GPL v3", "Optional");
1678 
1679  // Language:
1680  static int language = 0;
1681  ImGui::AlignTextToFramePadding();
1682  ImGui::TextUnformatted("Module Language");
1683  ImGui::NextColumn();
1684  helpMarker("Module Language", "Machine language to use for your module.");
1685  ImGui::NextColumn();
1686  ImGui::Combo("##NewModlanguage", &language, "Python\0\0"); // FIXME
1687  //ImGui::Combo("##NewModlanguage", &language, "Python\0C++\0\0");
1688  ImGui::NextColumn();
1689 
1690  // Template:
1691  static int templ = 0;
1692  ImGui::AlignTextToFramePadding();
1693  ImGui::TextUnformatted("Module Template");
1694  ImGui::NextColumn();
1695  helpMarker("Module Template", "Type of placeholder code that will be provided to get your module started.");
1696  ImGui::NextColumn();
1697  ImGui::Combo("##NewModtemplate", &templ, "Pro/GUI\0Legacy\0Headless\0\0");
1698  ImGui::NextColumn();
1699 
1700  // Output video mapping:
1701  int oflags = ImGuiInputTextFlags_None;
1702  if (templ != 1)
1703  {
1704  oflags |= ImGuiInputTextFlags_ReadOnly;
1705  ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true);
1706  ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.5f);
1707  }
1708 
1709  static int ofmt = 0;
1710  ImGui::AlignTextToFramePadding();
1711  ImGui::TextUnformatted("Module Output");
1712  ImGui::NextColumn();
1713  helpMarker("Module Output", "Output video format for legacy module.");
1714  ImGui::NextColumn();
1715  ImGui::SetNextItemWidth(fontw * 5.0F);
1716  ImGui::Combo("##NewModofmt", &ofmt, "YUYV\0RGB\0RGBA\0GREY\0BAYER\0\0");
1717  static int ow = 320, oh = 240; static float ofps = 30.0F;
1718  ImGui::SameLine();
1719  ImGui::SetNextItemWidth(fontw * 4.0F);
1720  ImGui::InputInt("##NewModow", &ow, 0, 0, ImGuiInputTextFlags_CharsDecimal | oflags);
1721  ImGui::SameLine();
1722  ImGui::Text("x");
1723  ImGui::SameLine();
1724  ImGui::SetNextItemWidth(fontw * 4.0F);
1725  ImGui::InputInt("##NewModoh", &oh, 0, 0, ImGuiInputTextFlags_CharsDecimal | oflags);
1726  ImGui::SameLine();
1727  ImGui::Text("@");
1728  ImGui::SameLine();
1729  ImGui::SetNextItemWidth(fontw * 4.0F);
1730  ImGui::InputFloat("##NewModofps", &ofps, 0.0F, 0.0F, "%.1f", ImGuiInputTextFlags_CharsDecimal | oflags);
1731  ImGui::SameLine();
1732  ImGui::Text("fps");
1733  ImGui::NextColumn();
1734 
1735  if (templ != 1)
1736  {
1737  ImGui::PopItemFlag();
1738  ImGui::PopStyleVar();
1739  }
1740 
1741  // Camera mode:
1742  static int cmode = 0;
1743  ImGui::AlignTextToFramePadding();
1744  ImGui::TextUnformatted("Camera Mode");
1745  ImGui::NextColumn();
1746  helpMarker("Camera Mode", "Camera sensor configuration for your module.");
1747  ImGui::NextColumn();
1748  ImGui::SetNextItemWidth(fontw * 18.0F);
1749  ImGui::Combo("##NewModcmode", &cmode, "Dual-resolution (Crop+Scale)\0Single-resolution Crop\0"
1750  "Single-resolution Scale\0\0");
1751  ImGui::NextColumn();
1752 
1753  // Camera WDR mode:
1754  static int wdrmode = 0;
1755  ImGui::AlignTextToFramePadding();
1756  ImGui::TextUnformatted("Camera WDR");
1757  ImGui::NextColumn();
1758  helpMarker("Camera WDR", "Camera sensor wide-dynamic-range (WDR) setting for your module. Linear is for no WDR, "
1759  "DOL is for digital overlap (merging short and long exposure frames).");
1760  ImGui::NextColumn();
1761  ImGui::Combo("##NewModwdrmode", &wdrmode, "Linear\0\0"); // FIXME
1762  //ImGui::Combo("##NewModwdrmode", &wdrmode, "Linear\0DOL\0\0");
1763  ImGui::NextColumn();
1764 
1765  // Camera video mapping:
1766  static int cfmt = 0;
1767  ImGui::AlignTextToFramePadding();
1768  ImGui::TextUnformatted("Camera Format");
1769  ImGui::NextColumn();
1770  helpMarker("Camera Format", "Camera video format to use for input to module and for GUI display.");
1771  ImGui::NextColumn();
1772  ImGui::SetNextItemWidth(fontw * 5.0F);
1773  ImGui::Combo("##NewModcfmt", &cfmt, "YUYV\0RGB\0RGBA\0GREY\0BAYER\0\0");
1774  static int cw = 1920, ch = 1080; static float cfps = 30.0F;
1775  ImGui::SameLine();
1776  ImGui::SetNextItemWidth(fontw * 4.0F);
1777  ImGui::InputInt("##NewModcw", &cw, 0, 0, ImGuiInputTextFlags_CharsDecimal);
1778  ImGui::SameLine();
1779  ImGui::Text("x");
1780  ImGui::SameLine();
1781  ImGui::SetNextItemWidth(fontw * 4.0F);
1782  ImGui::InputInt("##NewModch", &ch, 0, 0, ImGuiInputTextFlags_CharsDecimal);
1783  ImGui::SameLine();
1784  ImGui::Text("@");
1785  ImGui::SameLine();
1786  ImGui::SetNextItemWidth(fontw * 4.0F);
1787  ImGui::InputFloat("##NewModcfps", &cfps, 0.0F, 0.0F, "%.1f", ImGuiInputTextFlags_CharsDecimal);
1788  ImGui::SameLine();
1789  ImGui::Text("fps");
1790  ImGui::NextColumn();
1791 
1792  // Camera second frame video mapping:
1793  int c2flags = ImGuiInputTextFlags_None;
1794  if (cmode != 0)
1795  {
1796  oflags |= ImGuiInputTextFlags_ReadOnly;
1797  ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true);
1798  ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.5f);
1799  }
1800 
1801  static int c2fmt = 1;
1802  ImGui::AlignTextToFramePadding();
1803  ImGui::TextUnformatted("Camera Format 2");
1804  ImGui::NextColumn();
1805  helpMarker("Camera Format 2", "Camera video format for the second stream (for processing).");
1806  ImGui::NextColumn();
1807  ImGui::SetNextItemWidth(fontw * 5.0F);
1808  ImGui::Combo("##NewModc2fmt", &c2fmt, "YUYV\0RGB\0RGBA\0GREY\0BAYER\0\0");
1809  static int c2w = 512, c2h = 288;
1810  ImGui::SameLine();
1811  ImGui::SetNextItemWidth(fontw * 4.0F);
1812  ImGui::InputInt("##NewModc2w", &c2w, 0, 0, ImGuiInputTextFlags_CharsDecimal | c2flags);
1813  ImGui::SameLine();
1814  ImGui::Text("x");
1815  ImGui::SameLine();
1816  ImGui::SetNextItemWidth(fontw * 4.0F);
1817  ImGui::InputInt("##NewModc2h", &c2h, 0, 0, ImGuiInputTextFlags_CharsDecimal | c2flags);
1818  ImGui::NextColumn();
1819 
1820  if (cmode != 0)
1821  {
1822  ImGui::PopItemFlag();
1823  ImGui::PopStyleVar();
1824  }
1825 
1826  // Adjust columns:
1827  ImGui::SetColumnWidth(0, fontw * 10.0F);
1828  ImGui::SetColumnWidth(1, ImGui::CalcTextSize("(?)").x + 30.0F);
1829  //ImGui::SetColumnWidth(2, 800.0F);
1830 
1831  ImGui::Columns(1);
1832 
1833 
1834  ImGui::Separator();
1835  ImGui::Separator();
1836 
1837  ImVec2 const button_size(ImGui::GetFontSize() * 7.0f, 0.0f);
1838  if (ImGui::Button("Cancel", button_size))
1839  {
1840  ImGui::CloseCurrentPopup();
1841  ImGui::EndPopup();
1842  ImGui::PopStyleColor();
1843  return;
1844  }
1845 
1846  ImGui::SameLine(0, 530);
1847 
1848  if (ImGui::Button("Create", button_size))
1849  {
1850  // Validate inputs:
1851  if (name.empty()) LFATAL("New Module cannot have an empty name.");
1852  if (name[0]<'A' || name[0]>'Z') LFATAL("New Module name must start with an uppercase letter.");
1853  if (vendor.empty()) LFATAL("New Module cannot have empty vendor name.");
1854  LINFO("New Module data valid...");
1855 
1856  // Let's do it:
1857  mkdir(jevois::sformat("%s/%s", JEVOIS_MODULE_PATH, vendor.c_str()).c_str(), 0777);
1858  std::string const dir = jevois::sformat("%s/%s/%s", JEVOIS_MODULE_PATH, vendor.c_str(), name.c_str());
1859  if (mkdir(dir.c_str(), 0777) == -1)
1860  LFATAL("Error creating directory [" << dir << "] for new module. Maybe that module name already exists "
1861  "or not running as root?");
1862  LINFO("Created new Module directory: " << dir);
1863 
1864  // Create a new video mapping to add to videomappimgs.cfg:
1865  jevois::VideoMapping m { };
1866  switch (templ)
1867  {
1868  case 0: m.ofmt = JEVOISPRO_FMT_GUI; break;
1869  case 1: m.ofmt = get_v4l2_fmt(ofmt); m.ow = ow; m.oh = oh; m.ofps = ofps; break;
1870  case 2: m.ofmt = 0; break;
1871  default: break;
1872  }
1873 
1874  m.cfmt = get_v4l2_fmt(cfmt);
1875  m.cw = cw; m.ch = ch; m.cfps = cfps;
1876 
1877  m.vendor = vendor;
1878  m.modulename = name;
1879 
1880  switch (wdrmode)
1881  {
1882  case 0: m.wdr = jevois::WDRtype::Linear; break;
1883  case 1: m.wdr = jevois::WDRtype::DOL; break;
1884  default: break;
1885  }
1886 
1887  switch (cmode)
1888  {
1889  case 0: m.crop = jevois::CropType::CropScale;
1890  m.c2fmt = get_v4l2_fmt(c2fmt);
1891  m.c2w = c2w; m.c2h = c2h;
1892  break;
1893 
1894  case 1: m.crop = jevois::CropType::Crop; break;
1895  case 2: m.crop = jevois::CropType::Scale; break;
1896  default: break;
1897  }
1898 
1899  m.ispython = (language == 0);
1900 
1901  // Copy the desired code template and cook it:
1902  std::string code;
1903  switch (language)
1904  {
1905  case 0:
1906  {
1907  std::ifstream f(JEVOIS_SHARE_PATH "/templates/PyModule.py");
1908  if (f.is_open() == false) LFATAL("Cannot read " JEVOIS_SHARE_PATH "/templates/PyModule.py");
1909  std::string const str((std::istreambuf_iterator<char>(f)), std::istreambuf_iterator<char>());
1910  code = str;
1911  }
1912  break;
1913 
1914  case 1:
1915  {
1916  LFATAL("C++ template fixme");
1917  }
1918  break;
1919 
1920  default: break;
1921  }
1922 
1923  jevois::replaceStringAll(code, "__MODULE__", name);
1924  jevois::replaceStringAll(code, "__VENDOR__", vendor);
1925  jevois::replaceStringAll(code, "__SYNOPSIS__", synopsis);
1926  jevois::replaceStringAll(code, "__AUTHOR__", author);
1927  jevois::replaceStringAll(code, "__EMAIL__", email);
1928  jevois::replaceStringAll(code, "__WEBSITE__", website);
1929  jevois::replaceStringAll(code, "__LICENSE__", license);
1930  std::ostringstream oss; oss << m;
1931  jevois::replaceStringAll(code, "__VIDEOMAPPING__", oss.str());
1932 
1933  // Write the code:
1934  std::ofstream ofs(m.sopath());
1935  if (ofs.is_open() == false) LFATAL("Cannot write " << m.sopath() << " -- check that you are running as root.");
1936  ofs << code << std::endl;
1937  LINFO("Wrote code template to: " << m.sopath());
1938 
1939  // Add the video mapping:
1940  jevois::system(JEVOIS "-add-videomapping " + oss.str());
1941  LINFO("Added videomapping: " << oss.str());
1942 
1943  engine()->reloadVideoMappings();
1944  size_t idx = 0; size_t foundidx = 12345678;
1945  engine()->foreachVideoMapping([&](VideoMapping const & mm) { if (m.isSameAs(mm)) foundidx = idx; ++idx; });
1946  if (foundidx != 12345678) engine()->requestSetFormat(foundidx);
1947  itsRefreshVideoMappings = true; // Force a refresh of our list of video mappings
1948  /////itsRefreshCfgList = true; // Force a refresh of videomappings.cfg in the config editor
1949  itsVideoMappingListType = templ; // Switch to the mapping list that contains our new module
1950 
1951  // Clear a few things before the next module:
1952  name.clear(); vendor.clear(); synopsis.clear();
1953 
1954  ImGui::CloseCurrentPopup();
1955  }
1956  }
1957  catch (...) { reportAndIgnoreException(); }
1958 
1959  // Make sure we always end the popup, even if we had an exception:
1960  ImGui::EndPopup();
1961  }
1962 
1963  ImGui::PopStyleColor();
1964 }
1965 
1966 // ##############################################################################################################
1967 // imgui opengl demo in 1024 bytes:
1968 using V=ImVec2;using F=float;int h;struct E{V p;F z,w;bool operator<(E&o){return z<o.z;}};E G[999];
1969 #define L(i,x,y,z)for(F i=x;i<y;i+=z)
1970 #define Q(y)sin((y+t)*.03)*(1-sin(t*3)*cos(y/99+t))*9
1971 #define H(p,w)L(k,0,5,1)d->AddCircleFilled(p+V(1,-1)*w*k/8,w*(1-k/5),k<4?0xff000000+k*0x554400:-1);
1972 #define J(b)L(i,0,h,1){E&o=G[int(i)];if(b*o.z>0)H(o.p,(o.z*.3+4)*o.w)}
1973 #define O(b)i=t+1.6+j/99;if(b*sin(i)>0)H(c+v*j+u*(cos(i)*40+Q(j)),30)
1974 void FX(ImDrawList*d,V a,V b,V,ImVec4,F t){F i=sin(t)-.7;V u(cos(i),sin(i)),v(-sin(i),cos(i)),c=(a+b)/2;F l=300;
1975 F w=0;L(z,4,20,1){w+=z;L(yy,-l,l,z*2){F y=yy+fmod(t*z*10,z*2);L(i,-1,2,2)d->AddCircle(c+v*y+u*i*(w+sin((y+t)/25)*w/30),z,0xff000000+0x110e00*int(z*z*z/384),12,z/2);}}
1976 h=0;L(y,-l,l,15)L(b,0,16,1){i=t+b*.2+y/99;G[h++]={c+v*y+u*(cos(i)*60+Q(y)),sinf(i),(b<1||b>14)?2.f:1.5f};}std::sort(G,G+h);
1977  F j=(-2+fmod(t*3,5))*99;J(-1)O(-1)a=c+v*-l;L(y,-l,l,15){b=c+v*y+u*((15-rand())&31)*.1;L(k,0,9,1)d->AddLine(a-v,b,k<8?0x11222200*k:-1,(9-k)*4);a=b;}O(1)J(1)}
1978 
1979 // ##############################################################################################################
1981 {
1982  if (ImGui::Button("Open Style Editor")) itsShowStyleEditor = true;
1983  ImGui::SameLine();
1984  if (ImGui::Button("Open App Metrics")) itsShowAppMetrics = true;
1985  ImGui::SameLine();
1986  if (ImGui::Button("Open ImGui Demo")) itsShowImGuiDemo = true;
1987  ImGui::Separator();
1988 
1989 
1990  float camz = pixel_perfect_z;
1991  float yaw = 0.0f;
1992  float pitch = 0.0f;
1993  float roll = 0.0f;
1994  static float fudgex = 0.375f;
1995  static float fudgey = 0.375f;
1996  static float fudgez = 0.0f;
1997  unsigned short winw, winh; itsBackend.getWindowSize(winw, winh);
1998 
1999  ImGui::SliderFloat("OpenGL Camera z", &camz, -2.0f * winh, -1.0f);
2000  ImGui::SliderAngle("OpenGL yaw", &yaw, -179.0f, 180.0f);
2001  ImGui::SliderAngle("OpenGL pitch", &pitch, -179.0f, 180.0f);
2002  ImGui::SliderAngle("OpenGL roll", &roll, -179.0f, 180.0f);
2003 
2004  ImGui::SliderFloat("fudge x", &fudgex, -1.0f, 1.0f);
2005  ImGui::SliderFloat("fudge y", &fudgey, -1.0f, 1.0f);
2006  ImGui::SliderFloat("fudge z", &fudgez, -1.0f, 1.0f);
2007 
2008  // mess with the projection matrix:
2009  proj = glm::perspective(glm::radians(45.0f), float(winw) / float(winh), 1.0f, winh * 2.0f);
2010  proj = glm::translate(proj, glm::vec3(fudgex, fudgey, fudgez));
2011 
2012  // update our view matrix
2013  view = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, camz));
2014  view *= glm::yawPitchRoll(yaw, pitch, roll);
2015 
2016  // Note: the ortho projection of ImGui is like: glm::ortho(0.0f, 1920.0f, 1080.0f, 0.0f);
2017  /*
2018  glm::mat4 gogo = glm::ortho(0.0f, 1920.0f, 1080.0f, 0.0f);
2019  gogo = glm::translate(gogo, glm::vec3(0.125f, 0.125f, 0.0f));
2020 
2021  for (int i = 0; i < 4; ++i)
2022  for (int j = 0; j < 4; ++j)
2023  printf("gogo[%d][%d] = %f\n", i, j, gogo[i][j]);
2024  */
2025 
2026  //static bool demo = false;
2027  //if (ImGui::Checkbox("OpenGL Demo", &demo))
2028  //{
2029  // from https://github.com/ocornut/imgui/issues/3606
2030  ImGuiIO& io = ImGui::GetIO();
2031  ImGui::Begin("FX", NULL, ImGuiWindowFlags_AlwaysAutoResize);
2032  ImVec2 size(320.0f, 180.0f);
2033  ImGui::InvisibleButton("canvas", size);
2034  ImVec2 p0 = ImGui::GetItemRectMin();
2035  ImVec2 p1 = ImGui::GetItemRectMax();
2036  ImDrawList* draw_list = ImGui::GetWindowDrawList();
2037  draw_list->PushClipRect(p0, p1);
2038 
2039  ImVec4 mouse_data;
2040  mouse_data.x = (io.MousePos.x - p0.x) / size.x;
2041  mouse_data.y = (io.MousePos.y - p0.y) / size.y;
2042  mouse_data.z = io.MouseDownDuration[0];
2043  mouse_data.w = io.MouseDownDuration[1];
2044 
2045  FX(draw_list, p0, p1, size, mouse_data, (float)ImGui::GetTime());
2046  draw_list->PopClipRect();
2047  ImGui::End();
2048  //}
2049 
2050 }
2051 
2052 // ##############################################################################################################
2053 void jevois::GUIhelper::reportError(std::string const & err)
2054 {
2055  auto now = std::chrono::steady_clock::now();
2056 
2057  std::lock_guard<std::mutex> _(itsErrorMtx);
2058 
2059  // Did we already report this error? If so, just update the last received time:
2060  for (auto & e : itsErrors) if (e.err == err) { e.lasttime = now; return; }
2061 
2062  // Too many errors already?
2063  if (itsErrors.size() > 10) { LERROR("Too many errors -- TRUNCATING"); return; }
2064 
2065  // It's a new error, push a new entry into our list:
2066  ErrorData d { err, now, now };
2067  itsErrors.emplace(itsErrors.end(), std::move(d));
2068 
2069  // drawErrorPopup() will clear old entries
2070 }
2071 
2072 // ##############################################################################################################
2074 {
2075  std::lock_guard<std::mutex> _(itsErrorMtx);
2076  itsErrors.clear();
2077 }
2078 
2079 // ##############################################################################################################
2080 void jevois::GUIhelper::reportAndIgnoreException(std::string const & prefix)
2081 {
2082  if (prefix.empty())
2083  {
2084  try { throw; }
2085  catch (std::exception const & e)
2086  { reportError(e.what()); }
2087  catch (boost::python::error_already_set & e)
2088  { reportError("Python error:\n"+jevois::getPythonExceptionString(e)); }
2089  catch (...)
2090  { reportError("Unknown error"); }
2091  }
2092  else
2093  {
2094  try { throw; }
2095  catch (std::exception const & e)
2096  { reportError(prefix + ": " + e.what()); }
2097  catch (boost::python::error_already_set & e)
2098  { reportError(prefix + ": Python error:\n"+jevois::getPythonExceptionString(e)); }
2099  catch (...)
2100  { reportError(prefix + ": Unknown error"); }
2101  }
2102 }
2103 
2104 // ##############################################################################################################
2105 void jevois::GUIhelper::reportAndRethrowException(std::string const & prefix)
2106 {
2107  reportAndIgnoreException(prefix);
2108  throw;
2109 }
2110 
2111 // ##############################################################################################################
2113 {
2114  std::lock_guard<std::mutex> _(itsErrorMtx);
2115  if (itsErrors.empty()) return;
2116 
2117  ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_AlwaysAutoResize |
2118  ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoNav;
2119 
2120  ImGui::SetNextWindowPos(ImVec2(10.0f, 10.0f), ImGuiCond_Always);
2121  ImGui::PushStyleColor(ImGuiCol_WindowBg, 0xc0e0e0ff);
2122 
2123  static bool show = true;
2124 
2125  if (ImGui::Begin("Error detected!", &show, window_flags))
2126  {
2127  ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
2128  ImGui::Text("Error detected!");
2129 
2130  auto itr = itsErrors.begin();
2131  while (itr != itsErrors.end())
2132  {
2133  // Clear the error after a while, unless mouse cursor is on it:
2134  std::chrono::duration<float> d = std::chrono::steady_clock::now() - itr->lasttime;
2135  std::chrono::duration<float> d2 = std::chrono::steady_clock::now() - itr->firsttime;
2136  if (d.count() >= 1.0f && d2.count() >= 10.0f && ImGui::IsWindowHovered() == false)
2137  itr = itsErrors.erase(itr);
2138  else
2139  {
2140  // Show this error:
2141  ImGui::Separator();
2142  ImGui::TextUnformatted(itr->err.c_str());
2143  ++itr;
2144  }
2145  }
2146  ImGui::PopTextWrapPos();
2147 
2148  ImGui::End();
2149  }
2150  ImGui::PopStyleColor();
2151 }
2152 
2153 // ##############################################################################################################
2154 void jevois::GUIhelper::helpMarker(char const * msg, char const * msg2, char const * msg3)
2155 {
2156  //ImGui::TextDisabled("(?)");
2157  ImGui::Text("(?)");
2158  if (ImGui::IsItemHovered())
2159  {
2160  ImGui::BeginTooltip();
2161  ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
2162  ImGui::TextUnformatted(msg);
2163  if (msg2) { ImGui::Separator(); ImGui::TextUnformatted(msg2); }
2164  if (msg3) { ImGui::Separator(); ImGui::TextUnformatted(msg3); }
2165  ImGui::PopTextWrapPos();
2166  ImGui::EndTooltip();
2167  }
2168 }
2169 
2170 // ##############################################################################################################
2171 bool jevois::GUIhelper::toggleButton(char const * name, bool * val)
2172 {
2173  bool changed = false;
2174  if (*val)
2175  {
2176  ImGui::PushID(name);
2177  ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(4.0f/7.0f, 1.0f, 1.0f));
2178  ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(4.0f/7.0f, 1.0f, 1.0f));
2179  ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(4.0f/7.0f, 0.5f, 0.5f));
2180  if (ImGui::Button(name)) { *val = false; changed = true; }
2181  ImGui::PopStyleColor(3);
2182  ImGui::PopID();
2183  }
2184  else if (ImGui::Button(name)) { *val = true; changed = true; }
2185 
2186  return changed;
2187 }
2188 
2189 // ##############################################################################################################
2191 {
2192  unsigned short winw, winh;
2193  startFrame(winw, winh);
2194 
2195  if (itsHeadless.loaded() == false)
2196  try { itsHeadless.load(JEVOIS_SHARE_PATH "/icons/headless.png"); }
2197  catch (...)
2198  {
2200  cv::Mat blank(winh, winw, CV_8UC4, 0);
2201  itsHeadless.load(blank);
2202  }
2203 
2204  if (itsHeadless.loaded()) itsHeadless.draw(ImVec2(0, 0), ImVec2(winw, winh), ImGui::GetBackgroundDrawList());
2205 
2206  endFrame();
2207 }
2208 
2209 #endif // JEVOIS_PRO
jevois::GUIhelper::ErrorData
Definition: GUIhelper.H:383
E
Definition: GUIhelper.C:1968
jevois::module::SerStyle
SerStyle
Definition: Module.H:197
JEVOIS_WAIT_GET_FUTURE
#define JEVOIS_WAIT_GET_FUTURE(f)
Wait for a future to become ready for 5 seconds, get(), warn and ignore exception,...
Definition: Log.H:336
JEVOISPRO_FMT_GUI
#define JEVOISPRO_FMT_GUI
JeVois-Pro zero-copy display of camera input frame (to be used as output mode in VideoMapping)
Definition: Utils.H:31
jevois::GUIhelper::itsCodeEditor
std::shared_ptr< GUIeditor > itsCodeEditor
Definition: GUIhelper.H:446
jevois::GUIhelper::drawImage
void drawImage(char const *name, RawImage const &img, int &x, int &y, unsigned short &w, unsigned short &h, bool noalias=false, bool isoverlay=false)
Draw a RawImage, copying pixel data to an OpenGL texture.
Definition: GUIhelper.C:273
jevois::getFanSpeed
int getFanSpeed()
Get fan speed in percent, only meaningful on JeVois-Pro Platform, all others return 0.
Definition: SysInfo.C:153
jevois::imu::get
Data collection mode RAW means that the latest available raw data is returned each time get() is called
jevois::GUIhelper::drawInputFrame2
void drawInputFrame2(char const *name, InputFrame const &frame, int &x, int &y, unsigned short &w, unsigned short &h, bool noalias=false, bool casync=false)
Draw the second (scaled) input video frame from the camera using zero-copy.
Definition: GUIhelper.C:350
jevois::GUIhelper::drawNewModuleForm
void drawNewModuleForm()
Definition: GUIhelper.C:1637
jevois::paramStringToVal
void paramStringToVal(std::string const &valstring, T &result)
Machine-readable conversion from string to T, for use in jevois::Parameter.
jevois::GUIhelper::reportAndIgnoreException
void reportAndIgnoreException(std::string const &prefix="")
Report current exception in a modal dialog, then ignore it.
Definition: GUIhelper.C:2080
jevois::Range
A generic range class.
Definition: Range.H:80
jevois::GUIhelper::drawMenuBar
void drawMenuBar()
Definition: GUIhelper.C:758
jevois::GUIhelper::drawCircle
void drawCircle(float x, float y, float r, ImU32 col=IM_COL32(128, 255, 128, 255), bool filled=true)
Draw circle over an image.
Definition: GUIhelper.C:497
Module.H
jevois::GUIhelper::startFrame
bool startFrame(unsigned short &w, unsigned short &h)
Start a new rendering frame.
Definition: GUIhelper.C:163
jevois::GUIhelper::modal
int modal(std::string const &title, char const *text, int *default_val=nullptr, char const *b1txt="Ok", char const *b2txt="Cancel")
Helper to draw a modal with 2 choices.
Definition: GUIhelper.C:1398
GPUimage.H
jevois::GUIhelper::itext
void itext(char const *txt, ImU32 const &col=IM_COL32_BLACK_TRANS, int line=-1)
Draw some overlay text on top of an image.
Definition: GUIhelper.C:540
jevois::GUIhelper::onParamChange
void onParamChange(gui::scale const &param, float const &newval) override
jevois::Range::min
const T & min() const
Return the minimum value.
jevois::GUIhelper::drawInfo
void drawInfo()
Definition: GUIhelper.C:894
jevois::sformat
std::string sformat(char const *fmt,...) __attribute__((format(__printf__
Create a string using printf style arguments.
Definition: Utils.C:419
jevois::split
std::vector< std::string > split(std::string const &input, std::string const &regex="\\s+")
Split string into vector of tokens using a regex to specify what to split on; default regex splits by...
Definition: Utils.C:258
jevois::GUIhelper::setparstr
void setparstr(std::string const &descriptor, std::string const &val)
Definition: GUIhelper.C:1054
jevois::GPUimage
Class to hold a GPUtexture, GPUprogram, and other data associated with rendering an image in OpenGL.
Definition: GPUimage.H:38
jevois::getSysInfoMem
std::string getSysInfoMem()
Get memory info.
Definition: SysInfo.C:66
jevois::GUIhelper::headlessDisplay
void headlessDisplay()
Show a message that we are running headless.
Definition: GUIhelper.C:2190
jevois::GUIhelper::drawPolyInternal
void drawPolyInternal(ImVec2 const *pts, size_t npts, ImU32 col, bool filled)
Definition: GUIhelper.C:460
jevois::GUIhelper::endFrame
void endFrame()
Finish current frame and render it.
Definition: GUIhelper.C:662
jevois::Component
A component of a model hierarchy.
Definition: Component.H:181
jevois::GUIhelper::reportAndRethrowException
void reportAndRethrowException(std::string const &prefix="")
Report current exception in a modal dialog, then re-throw it.
Definition: GUIhelper.C:2105
jevois::GUIhelper::releaseImage
void releaseImage(char const *name)
Release an image.
Definition: GUIhelper.C:574
jevois::GUIhelper::drawTweaks
void drawTweaks()
Definition: GUIhelper.C:1980
jevois::GUIhelper::newModEntry
void newModEntry(char const *wname, std::string &str, char const *desc, char const *hint, char const *hlp)
Definition: GUIhelper.C:1447
jevois::GUIhelper::clearErrors
void clearErrors()
Clear all errors currently displayed in the JeVois-Pro GUI.
Definition: GUIhelper.C:2073
jevois::RawImage
A raw image as coming from a V4L2 Camera and/or being sent out to a USB Gadget.
Definition: RawImage.H:110
jevois::GUIhelper::d2i
ImVec2 d2i(ImVec2 p, char const *name=nullptr)
Convert coordinates of a point from on-screen to within a rendered image.
Definition: GUIhelper.C:588
jevois::GUIhelper::helpMarker
void helpMarker(char const *msg, char const *msg2=nullptr, char const *msg3=nullptr)
Display a (?) label and show tooltip when it is hovered.
Definition: GUIhelper.C:2154
jevois::Component::foreachParam
void foreachParam(std::function< void(std::string const &compname, ParameterBase *p)> func, std::string const &cname="")
Run a function on every param we hold.
Definition: Component.C:584
jevois::GUIhelper::i2d
ImVec2 i2d(ImVec2 p, char const *name=nullptr)
Convert coordinates of a point from within a rendered image to on-screen.
Definition: GUIhelper.C:374
jevois::ParameterBase
Base class for Parameter.
Definition: Parameter.H:121
jevois::GUIhelper::drawErrorPopup
void drawErrorPopup()
Definition: GUIhelper.C:2112
jevois::GUIhelper::drawModuleSelect
void drawModuleSelect()
Definition: GUIhelper.C:814
o
#define o
Definition: Font10x20.C:6
jevois::RawImage::bufindex
size_t bufindex
The index of the data buffer in the kernel driver.
Definition: RawImage.H:150
jevois::GUIhelper::drawParameters
void drawParameters()
Definition: GUIhelper.C:1062
jevois::ParameterSummary::category
std::string category
Category of the parameter, as a string.
Definition: Parameter.H:108
LERROR
#define LERROR(msg)
Convenience macro for users to print out console or syslog messages, ERROR level.
Definition: Log.H:211
jevois::GUIhelper::drawRect
void drawRect(float x1, float y1, float x2, float y2, ImU32 col=IM_COL32(128, 255, 128, 255), bool filled=true)
Draw rectangular box over an image.
Definition: GUIhelper.C:448
jevois::GUIhelper::drawCamCtrls
void drawCamCtrls()
Definition: GUIhelper.C:1392
jevois::getFileString
std::string getFileString(char const *fname, int skip=0)
Read one line from a file and return it as a string.
Definition: Utils.C:516
jevois::InputFrame::get
const RawImage & get(bool casync=false) const
Get the next captured camera image.
Definition: InputFrame.C:50
jevois::getSysInfoVersion
std::string getSysInfoVersion()
Get O.S. version info.
Definition: SysInfo.C:74
jevois::RawImage::width
unsigned int width
Image width in pixels.
Definition: RawImage.H:145
Q
#define Q(y)
Definition: GUIhelper.C:1970
jevois::GUIhelper::drawLine
void drawLine(float x1, float y1, float x2, float y2, ImU32 col=IM_COL32(128, 255, 128, 255))
Draw line over an image.
Definition: GUIhelper.C:442
jevois::GUIhelper::seroutEnabled
bool seroutEnabled() const
Tell whether user enabled serout messages to GUI console.
Definition: GUIhelper.C:1388
jevois::GUIeditor
Editor panel for JeVois-Pro GUI.
Definition: GUIeditor.H:46
jevois::GUIhelper::reportError
void reportError(std::string const &err)
Report an error in an overlay window.
Definition: GUIhelper.C:2053
jevois
Definition: Concepts.dox:1
jevois::getNumInstalledNPUs
size_t getNumInstalledNPUs()
Get the number of JeVois-Pro NPUs present on this system.
Definition: SysInfo.C:127
F
float F
Definition: GUIhelper.C:1968
jevois::getSysInfoCPU
std::string getSysInfoCPU()
Get CPU info: frequency, thermal, load.
Definition: SysInfo.C:24
jevois::GUIhelper::drawPoly
void drawPoly(std::vector< cv::Point > const &pts, ImU32 col=IM_COL32(128, 255, 128, 255), bool filled=true)
Draw polygon over an image.
Definition: GUIhelper.C:475
jevois::Component::getParamValUnique
T getParamValUnique(std::string const &paramdescriptor) const
Get a parameter value, simple version assuming only one parameter match.
jevois::system
std::string system(std::string const &cmd, bool errtoo=true)
Execute a command and grab stdout output to a string.
Definition: Utils.C:441
jevois::InputFrame::hasScaledImage
bool hasScaledImage() const
Check whether a second input image scaled by the JeVoisPro Platform ISP is available.
Definition: InputFrame.C:61
GUIconsole.H
J
#define J(b)
Definition: GUIhelper.C:1972
SysInfo.H
jevois::replaceStringAll
size_t replaceStringAll(std::string &str, std::string const &from, std::string const &to)
Replace all instances of 'from' with 'to'.
Definition: Utils.C:332
jevois::GUIhelper::toggleButton
bool toggleButton(char const *name, bool *val)
Helper to draw a toggle button.
Definition: GUIhelper.C:2171
jevois::GUIhelper::reset
void reset(bool modulechanged=true)
Reset to default state, typically called on Module or video format change.
Definition: GUIhelper.C:115
jevois::GUIhelper::frameStarted
bool frameStarted() const
Helper to indicate that startFrame() was called, and thus endFrame() should be called.
Definition: GUIhelper.C:269
jevois::join
std::string join(std::vector< std::string > const &strings, std::string const &delimiter)
Concatenate a vector of tokens into a string.
Definition: Utils.C:268
jevois::getNumInstalledTPUs
size_t getNumInstalledTPUs()
Get the number of Coral TPUs present on this system.
Definition: SysInfo.C:87
jevois::Component::setParamValUnique
void setParamValUnique(std::string const &paramdescriptor, T const &val)
Set a parameter value, simple version assuming only one parameter match.
jevois::extractString
std::string extractString(std::string const &str, std::string const &startsep, std::string const &endsep)
Extract a portion of a string between two delimiters.
Definition: Utils.C:304
jevois::fccstr
std::string fccstr(unsigned int fcc)
Convert a V4L2 four-cc code (V4L2_PIX_FMT_...) to a 4-char string.
Definition: Utils.C:45
jevois::GUIhelper::drawJeVoisGUI
void drawJeVoisGUI()
Definition: GUIhelper.C:677
jevois::GPUimage::i2ds
ImVec2 i2ds(ImVec2 const &p)
Convert a 2D size from within a rendered image to on-screen.
Definition: GPUimage.C:382
jevois::InputFrame::get2
const RawImage & get2(bool casync=false) const
Get the next captured camera image, ISP-scaled second frame.
Definition: InputFrame.C:67
jevois::Engine
JeVois processing engine - gets images from camera sensor, processes them, and sends results over USB...
Definition: Engine.H:381
jevois::GUIhelper::serlogEnabled
bool serlogEnabled() const
Tell whether user enabled serlog messages to GUI console.
Definition: GUIhelper.C:1384
jevois::Manager::getComponent
std::shared_ptr< Comp > getComponent(std::string const &instanceName) const
Get a top-level component by instance name.
jevois::Crop
() Scale() Crop(CropScale)) struct VideoMapping
Simple struct to hold video mapping definitions for the processing Engine.
Definition: VideoMapping.H:43
jevois::GUIhelper::releaseImage2
void releaseImage2(char const *name)
Release an image, second video stream.
Definition: GUIhelper.C:581
jevois::warnAndIgnoreException
std::string warnAndIgnoreException(std::string const &prefix="")
Convenience function to catch an exception, issue some LERROR (depending on type),...
Definition: Log.C:236
jevois::GUIhelper::drawSystem
void drawSystem()
Definition: GUIhelper.C:1462
L
#define L(i, x, y, z)
Definition: GUIhelper.C:1969
LFATAL
#define LFATAL(msg)
Convenience macro for users to print out console or syslog messages, FATAL level.
jevois::getNumInstalledSPUs
size_t getNumInstalledSPUs()
Get the number of Hailo8 SPUs present on this system.
Definition: SysInfo.C:138
jevois::GUIhelper::drawText
void drawText(float x, float y, char const *txt, ImU32 col=IM_COL32(128, 255, 128, 255))
Draw text over an image.
Definition: GUIhelper.C:510
jevois::GUIhelper::GUIhelper
GUIhelper(std::string const &instance, bool conslock=false)
Constructor.
Definition: GUIhelper.C:47
jevois::GUIconsole
Simple console with coloring and completion.
Definition: GUIconsole.H:31
jevois::stringStartsWith
bool stringStartsWith(std::string const &str, std::string const &prefix)
Return true if str starts with prefix (including if both strings are equal)
Definition: Utils.C:282
jevois::ParameterSummary
ParameterSummary provides a summary about a parameter.
Definition: Parameter.H:83
jevois::GUIhelper::drawInputFrame
void drawInputFrame(char const *name, InputFrame const &frame, int &x, int &y, unsigned short &w, unsigned short &h, bool noalias=false, bool casync=false)
Draw the input video frame from the camera using zero-copy.
Definition: GUIhelper.C:320
jevois::GUIhelper::drawConsole
void drawConsole()
Definition: GUIhelper.C:1295
jevois::module::SerStyle_Values
Style for standardized serial messages as defined in SerStyle_Values
Definition: Module.H:199
jevois::getNumInstalledVPUs
size_t getNumInstalledVPUs()
Get the number of Myriad-X VPUs present on this system.
Definition: SysInfo.C:112
jevois::RawImage::height
unsigned int height
Image height in pixels.
Definition: RawImage.H:146
jevois::GUIhelper::iinfo
void iinfo(jevois::InputFrame const &inframe, std::string const &fpscpu, unsigned short winw=0, unsigned short winh=0)
Display processing and video info at bottom of screen.
Definition: GUIhelper.C:553
jevois::GUIhelper::itsWindowTitle
std::string itsWindowTitle
Definition: GUIhelper.H:402
jevois::to_string
std::string to_string(T const &val)
Convert from type to string.
jevois::InputFrame
Exception-safe wrapper around a raw camera input frame.
Definition: InputFrame.H:50
jevois::GUIhelper::d2is
ImVec2 d2is(ImVec2 p, char const *name=nullptr)
Convert a 2D size from on-screen to within a rendered image.
Definition: GUIhelper.C:625
jevois::ParameterBase::summary
virtual const ParameterSummary summary() const =0
Get summary info about this parameter.
jevois::GUIhelper::itsCfgEditor
std::shared_ptr< GUIeditor > itsCfgEditor
Definition: GUIhelper.H:443
jevois::GUIhelper::i2ds
ImVec2 i2ds(ImVec2 p, char const *name=nullptr)
Convert a 2D size from within a rendered image to on-screen.
Definition: GUIhelper.C:408
jevois::RawImage::fmt
unsigned int fmt
Pixel format as a V4L2_PIX_FMT_XXX.
Definition: RawImage.H:147
Utils.H
jevois::Component::absolutePath
std::filesystem::path absolutePath(std::filesystem::path const &path="")
If given path is relative (not starting with /), prepend the Component path to it.
Definition: Component.C:530
jevois::GUIconsole::draw
void draw()
Render into ImGui.
Definition: GUIconsole.C:84
V
ImVec2 V
Definition: GUIhelper.C:1968
GUIeditor.H
jevois::getPythonExceptionString
std::string getPythonExceptionString(boost::python::error_already_set &)
Python exception translation to string so we can print the traceback to our serlog stream.
Definition: PythonException.C:146
jevois::GPUimage::i2d
ImVec2 i2d(ImVec2 const &p)
Convert coordinates of a point from within a rendered image to on-screen.
Definition: GPUimage.C:375
jevois::GUIhelper::iline
ImVec2 iline(int line=-1, char const *name=nullptr)
Get coordinates of the start of a given line of text to be drawn as overlay on top of an image.
Definition: GUIhelper.C:530
PythonException.H
jevois::ParameterSummary::name
std::string name
Plain name of the parameter.
Definition: Parameter.H:90
h
int h
Definition: GUIhelper.C:1968
jevois::Engine::module
std::shared_ptr< Module > module() const
Get a pointer to our current module (may be null)
Definition: Engine.C:1244
jevois::async_little
std::future< std::invoke_result_t< std::decay_t< Function >, std::decay_t< Args >... > > async_little(Function &&f, Args &&... args)
Async execution using a thread pool.
jevois::GUIhelper::applyFillAlpha
ImU32 applyFillAlpha(ImU32 col) const
Definition: GUIhelper.C:522
jevois::StdModule
Base class for a module that supports standardized serial messages.
Definition: Module.H:232
jevois::Range::max
const T & max() const
Return the maximum value.
O
#define O(b)
Definition: GUIhelper.C:1973
jevois::GPUimage::d2i
ImVec2 d2i(ImVec2 const &p)
Convert coordinates of a point from on-screen to within a rendered image.
Definition: GPUimage.C:389
G
E G[999]
Definition: GUIhelper.C:1968
LINFO
#define LINFO(msg)
Convenience macro for users to print out console or syslog messages, INFO level.
Definition: Log.H:194
jevois::GPUimage::d2is
ImVec2 d2is(ImVec2 const &p)
Convert a 2D size from on-screen to within a rendered image.
Definition: GPUimage.C:396
jevois::GUIhelper::~GUIhelper
virtual ~GUIhelper()
Destructor.
Definition: GUIhelper.C:108
GUIhelper.H
FX
void FX(ImDrawList *d, V a, V b, V, ImVec4, F t)
Definition: GUIhelper.C:1974