JeVois  1.20
JeVois Smart Embedded Machine Vision Toolkit
Share this page:
PreProcessor.C
Go to the documentation of this file.
1 // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2 //
3 // JeVois Smart Embedded Machine Vision Toolkit - Copyright (C) 2021 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 
19 #include <jevois/DNN/Utils.H>
21 #include <jevois/Util/Utils.H>
22 #include <jevois/Core/Engine.H>
24 
25 // ####################################################################################################
26 jevois::dnn::PreProcessor::PreProcessor(std::string const & instance) :
27  jevois::Component(instance), itsPP(new jevois::dnn::PreProcessorForPython(this))
28 { }
29 
30 // ####################################################################################################
32 { }
33 
34 // ####################################################################################################
35 std::vector<cv::Mat> const & jevois::dnn::PreProcessor::blobs() const
36 { return itsBlobs; }
37 
38 // ####################################################################################################
39 cv::Size const & jevois::dnn::PreProcessor::imagesize() const
40 { return itsImageSize; }
41 
42 // ####################################################################################################
43 cv::Size jevois::dnn::PreProcessor::blobsize(size_t num) const
44 {
45  if (num >= itsAttrs.size()) LFATAL("Invalid blob number " << num << ", only have " << itsAttrs.size() << " blobs");
46  return jevois::dnn::attrsize(itsAttrs[num]);
47 }
48 
49 // ####################################################################################################
50 void jevois::dnn::PreProcessor::b2i(float & x, float & y, size_t blobnum)
51 {
52  if (blobnum >= itsCrops.size())
53  LFATAL("Invalid blob number " << blobnum << ", only have " << itsCrops.size() << " crops");
54 
55  cv::Rect const & r = itsCrops[blobnum];
56  b2i(x, y, blobsize(blobnum), (r.x != 0 || r.y != 0));
57 }
58 
59 // ####################################################################################################
60 void jevois::dnn::PreProcessor::b2i(float & x, float & y, cv::Size const & bsiz, bool letterboxed)
61 {
62  if (bsiz.width == 0 || bsiz.height == 0) LFATAL("Cannot handle zero blob width or height");
63 
64  if (letterboxed)
65  {
66  // We did letterbox and crop, so we need to apply scale and offset:
67  float const fac = std::min(itsImageSize.width / float(bsiz.width), itsImageSize.height / float(bsiz.height));
68  float const cropw = fac * bsiz.width + 0.4999F;
69  float const croph = fac * bsiz.height + 0.4999F;
70  x = (itsImageSize.width - cropw) * 0.5F + x * fac;
71  y = (itsImageSize.height - croph) * 0.5F + y * fac;
72  }
73  else
74  {
75  x *= itsImageSize.width / float(bsiz.width);
76  y *= itsImageSize.height / float(bsiz.height);
77  }
78 }
79 
80 // ####################################################################################################
82 {
83  if (num >= itsCrops.size()) LFATAL("Invalid blob number " << num << ", only have " << itsCrops.size() << " blobs");
84  return itsCrops[num];
85 }
86 
87 // ####################################################################################################
88 void jevois::dnn::PreProcessor::getUnscaledCropRect(size_t num, int & tlx, int & tly, int & brx, int & bry)
89 {
90  cv::Rect const & r = getUnscaledCropRect(num);
91  tlx = r.x; tly = r.y; brx = r.x + r.width; bry = r.y + r.height;
92 }
93 
94 // ####################################################################################################
95 void jevois::dnn::PreProcessor::i2b(float & x, float & y, size_t blobnum)
96 {
97  if (blobnum >= itsCrops.size())
98  LFATAL("Invalid blob number " << blobnum << ", only have " << itsCrops.size() << " crops");
99 
100  cv::Rect const & r = itsCrops[blobnum];
101  i2b(x, y, blobsize(blobnum), (r.x != 0 || r.y != 0));
102 }
103 
104 // ####################################################################################################
105 void jevois::dnn::PreProcessor::i2b(float & x, float & y, cv::Size const & bsiz, bool letterboxed)
106 {
107  if (itsImageSize.width == 0 || itsImageSize.height == 0) LFATAL("Cannot handle zero image width or height");
108  if (bsiz.width == 0 || bsiz.height == 0) LFATAL("Cannot handle zero blob width or height");
109 
110  if (letterboxed)
111  {
112  // We did letterbox and crop, so we need to apply scale and offset:
113  float const fac = std::min(itsImageSize.width / float(bsiz.width), itsImageSize.height / float(bsiz.height));
114  float const cropw = fac * bsiz.width + 0.4999F;
115  float const croph = fac * bsiz.height + 0.4999F;
116  x = (x - (itsImageSize.width - cropw) * 0.5F) / fac;
117  y = (y - (itsImageSize.height - croph) * 0.5F) / fac;
118  }
119  else
120  {
121  x *= float(bsiz.width) / itsImageSize.width;
122  y *= float(bsiz.height) / itsImageSize.height;
123  }
124 }
125 
126 // ####################################################################################################
127 std::shared_ptr<jevois::dnn::PreProcessorForPython> jevois::dnn::PreProcessor::getPreProcForPy() const
128 { return itsPP; }
129 
130 // ####################################################################################################
131 std::vector<cv::Mat> jevois::dnn::PreProcessor::process(jevois::RawImage const & img,
132  std::vector<vsi_nn_tensor_attr_t> const & attrs)
133 {
134  // Store input image size and format for future use:
135  itsImageSize.width = img.width; itsImageSize.height = img.height; itsImageFmt = img.fmt;
136  itsCrops.clear(); itsBlobs.clear();
137 
138  if (itsAttrs.empty()) itsAttrs = attrs;
139  if (itsAttrs.empty()) LFATAL("Cannot work with no input tensors");
140 
141  // Do the pre-processing:
142  if (img.fmt == V4L2_PIX_FMT_RGB24)
143  itsBlobs = process(jevois::rawimage::cvImage(img), ! rgb::get(), itsAttrs, itsCrops);
144  else if (img.fmt == V4L2_PIX_FMT_BGR24)
145  itsBlobs = process(jevois::rawimage::cvImage(img), rgb::get(), itsAttrs, itsCrops);
146  else if (rgb::get())
147  itsBlobs = process(jevois::rawimage::convertToCvRGB(img), false, itsAttrs, itsCrops);
148  else
149  itsBlobs = process(jevois::rawimage::convertToCvBGR(img), false, itsAttrs, itsCrops);
150 
151  return itsBlobs;
152 }
153 
154 // ####################################################################################################
156  jevois::OptGUIhelper * helper, bool overlay, bool idle)
157 {
158  // First some info about the input:
159 #ifdef JEVOIS_PRO
160  if (helper && idle == false && ImGui::CollapsingHeader("Pre-Processing", ImGuiTreeNodeFlags_DefaultOpen))
161  {
162  ImGui::BulletText("Input image: %dx%d %s", itsImageSize.width, itsImageSize.height,
163  jevois::fccstr(itsImageFmt).c_str());
164 
165  if (itsImageFmt != V4L2_PIX_FMT_RGB24 && itsImageFmt != V4L2_PIX_FMT_BGR24)
166  {
167  if (rgb::get()) ImGui::BulletText("Convert to RGB");
168  else ImGui::BulletText("Convert to BGR");
169  }
170 
171  // Now a report from the derived class:
172  report(mod, outimg, helper, overlay, idle);
173  }
174 #endif
175 
176  // Now a report from the derived class, when not using a GUI helper:
177  if (helper == nullptr) report(mod, outimg, helper, overlay, idle);
178 
179  // If desired, draw a rectangle around the network input:
180  if (showin::get())
181  {
182 #ifdef JEVOIS_PRO
183  if (helper)
184  for (cv::Rect const & r : itsCrops)
185  ImGui::GetBackgroundDrawList()->AddRect(helper->i2d(r.x, r.y),
186  helper->i2d(r.x + r.width, r.y + r.height), 0x80808080, 0, 0, 5);
187 #endif
188 
189  if (outimg)
190  for (cv::Rect const & r : itsCrops)
191  jevois::rawimage::drawRect(*outimg, r.x, r.y, r.width, r.height, 3, jevois::yuyv::MedGrey);
192  }
193 
194  // Finally some info about the blobs, if detailed info was not requested (detailed info is provided by derived class):
195 #ifdef JEVOIS_PRO
196  if (helper && idle == false && details::get() == false)
197  {
198  int idx = 0;
199  for (cv::Mat const & blob : itsBlobs)
200  {
201  cv::Rect const & r = itsCrops[idx];
202  bool const stretch = (r.x == 0 && r.y == 0);
203 
204  ImGui::BulletText("Crop %d: %dx%d @ %d,%d %s", idx, r.width, r.height, r.x, r.y,
205  stretch ? "" : "(letterbox)");
206  ImGui::BulletText("Blob %d: %s %s", idx, jevois::dnn::shapestr(blob).c_str(),
207  stretch ? "(stretch)" : "(uniform)");
208 
209  ++idx;
210  }
211  }
212 #endif
213 }
jevois::imu::get
Data collection mode RAW means that the latest available raw data is returned each time get() is called
jevois::dnn::PreProcessor::blobsize
cv::Size blobsize(size_t num) const
Access the width and height of a given blob, accounting for NCHW or NHWC.
Definition: PreProcessor.C:43
jevois::dnn::PreProcessor::getUnscaledCropRect
cv::Rect getUnscaledCropRect(size_t blobnum=0)
Get unscaled crop rectangle in image coordinates.
Definition: PreProcessor.C:81
RawImageOps.H
jevois::Component
A component of a model hierarchy.
Definition: Component.H:181
Utils.H
jevois::rawimage::convertToCvRGB
cv::Mat convertToCvRGB(RawImage const &src)
Convert RawImage to OpenCV doing color conversion from any RawImage source pixel to OpenCV RGB byte.
Definition: RawImageOps.C:307
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::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:401
jevois::dnn::PreProcessor::blobs
const std::vector< cv::Mat > & blobs() const
Access the last computed blobs (or empty if process() has not yet been called)
Definition: PreProcessor.C:35
jevois::rawimage::convertToCvBGR
cv::Mat convertToCvBGR(RawImage const &src)
Convert RawImage to OpenCV doing color conversion from any RawImage source pixel to OpenCV BGR byte.
Definition: RawImageOps.C:282
jevois::dnn::PreProcessorForPython
Pre-Processor interface exposed to the python side.
Definition: PythonModule.H:406
jevois::GUIhelper
Helper class to assist modules in creating graphical and GUI elements.
Definition: GUIhelper.H:128
jevois::RawImage::width
unsigned int width
Image width in pixels.
Definition: RawImage.H:145
jevois::dnn::shapestr
std::string shapestr(cv::Mat const &m)
Get a string of the form: "nD AxBxC... TYPE" from an n-dimensional cv::Mat with data type TYPE.
Definition: Utils.C:104
jevois
Definition: Concepts.dox:1
F
float F
Definition: GUIhelper.C:2373
Engine.H
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
LFATAL
#define LFATAL(msg)
Convenience macro for users to print out console or syslog messages, FATAL level.
jevois::dnn::PreProcessor::sendreport
virtual void sendreport(jevois::StdModule *mod, jevois::RawImage *outimg=nullptr, jevois::OptGUIhelper *helper=nullptr, bool overlay=true, bool idle=false)
Report what happened in last process() to console/output video/GUI.
Definition: PreProcessor.C:155
PythonModule.H
jevois::RawImage::height
unsigned int height
Image height in pixels.
Definition: RawImage.H:146
jevois::rawimage::cvImage
cv::Mat cvImage(RawImage const &src)
Create an OpenCV image from the existing RawImage data, sharing the pixel memory rather than copying ...
Definition: RawImageOps.C:31
PreProcessor.H
jevois::dnn::attrsize
cv::Size attrsize(vsi_nn_tensor_attr_t const &attr)
Get a tensor's (width, height) size in cv::Size format, skipping over other dimensions.
Definition: Utils.C:486
jevois::rawimage::drawRect
void drawRect(RawImage &img, int x, int y, unsigned int w, unsigned int h, unsigned int thick, unsigned int col)
Draw a rectangle in a YUYV image.
Definition: RawImageOps.C:607
jevois::RawImage::fmt
unsigned int fmt
Pixel format as a V4L2_PIX_FMT_XXX.
Definition: RawImage.H:147
Utils.H
jevois::dnn::PreProcessor::imagesize
const cv::Size & imagesize() const
Access the last processed image size.
Definition: PreProcessor.C:39
jevois::dnn::PreProcessor::b2i
void b2i(float &x, float &y, size_t blobnum=0)
Convert coordinates from blob back to original image.
Definition: PreProcessor.C:50
jevois::dnn::PreProcessor::process
std::vector< cv::Mat > process(jevois::RawImage const &img, std::vector< vsi_nn_tensor_attr_t > const &attrs)
Extract blobs from input image.
Definition: PreProcessor.C:131
jevois::dnn::PreProcessor::i2b
void i2b(float &x, float &y, size_t blobnum=0)
Convert coordinates from image to blob.
Definition: PreProcessor.C:95
jevois::dnn::PreProcessor::getPreProcForPy
std::shared_ptr< PreProcessorForPython > getPreProcForPy() const
Get a pointer to our python-friendly interface.
Definition: PreProcessor.C:127
jevois::StdModule
Base class for a module that supports standardized serial messages.
Definition: Module.H:232
jevois::dnn::PreProcessor::~PreProcessor
virtual ~PreProcessor()
Destructor.
Definition: PreProcessor.C:31
jevois::dnn::PreProcessor::PreProcessor
PreProcessor(std::string const &instance)
Constructor.
Definition: PreProcessor.C:26