JeVois  1.22
JeVois Smart Embedded Machine Vision Toolkit
Share this page:
Loading...
Searching...
No Matches
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// ####################################################################################################
26jevois::dnn::PreProcessor::PreProcessor(std::string const & instance) :
27 jevois::Component(instance), itsPP(new jevois::dnn::PreProcessorForPython(this))
28{ }
29
30// ####################################################################################################
33
34// ####################################################################################################
35std::vector<cv::Mat> const & jevois::dnn::PreProcessor::blobs() const
36{ return itsBlobs; }
37
38// ####################################################################################################
40{ return itsImageSize; }
41
42// ####################################################################################################
43cv::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// ####################################################################################################
50void 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// ####################################################################################################
60void 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// ####################################################################################################
81void jevois::dnn::PreProcessor::b2is(float & sx, float & sy, size_t blobnum)
82{
83 if (blobnum >= itsCrops.size())
84 LFATAL("Invalid blob number " << blobnum << ", only have " << itsCrops.size() << " crops");
85
86 cv::Rect const & r = itsCrops[blobnum];
87 b2is(sx, sy, blobsize(blobnum), (r.x != 0 || r.y != 0));
88}
89
90// ####################################################################################################
91void jevois::dnn::PreProcessor::b2is(float & sx, float & sy, cv::Size const & bsiz, bool letterboxed)
92{
93 if (bsiz.width == 0 || bsiz.height == 0) LFATAL("Cannot handle zero blob width or height");
94
95 if (letterboxed)
96 {
97 // We did letterbox and crop, so we need to apply scale:
98 float const fac = std::min(itsImageSize.width / float(bsiz.width), itsImageSize.height / float(bsiz.height));
99 sx *= fac;
100 sy *= fac;
101 }
102 else
103 {
104 sx *= itsImageSize.width / float(bsiz.width);
105 sy *= itsImageSize.height / float(bsiz.height);
106 }
107}
108
109// ####################################################################################################
111{
112 if (num >= itsCrops.size()) LFATAL("Invalid blob number " << num << ", only have " << itsCrops.size() << " blobs");
113 return itsCrops[num];
115
116// ####################################################################################################
117void jevois::dnn::PreProcessor::getUnscaledCropRect(size_t num, int & tlx, int & tly, int & brx, int & bry)
118{
119 cv::Rect const & r = getUnscaledCropRect(num);
120 tlx = r.x; tly = r.y; brx = r.x + r.width; bry = r.y + r.height;
121}
122
123// ####################################################################################################
124void jevois::dnn::PreProcessor::i2b(float & x, float & y, size_t blobnum)
125{
126 if (blobnum >= itsCrops.size())
127 LFATAL("Invalid blob number " << blobnum << ", only have " << itsCrops.size() << " crops");
128
129 cv::Rect const & r = itsCrops[blobnum];
130 i2b(x, y, blobsize(blobnum), (r.x != 0 || r.y != 0));
131}
132
133// ####################################################################################################
134void jevois::dnn::PreProcessor::i2b(float & x, float & y, cv::Size const & bsiz, bool letterboxed)
135{
136 if (itsImageSize.width == 0 || itsImageSize.height == 0) LFATAL("Cannot handle zero image width or height");
137 if (bsiz.width == 0 || bsiz.height == 0) LFATAL("Cannot handle zero blob width or height");
138
139 if (letterboxed)
140 {
141 // We did letterbox and crop, so we need to apply scale and offset:
142 float const fac = std::min(itsImageSize.width / float(bsiz.width), itsImageSize.height / float(bsiz.height));
143 float const cropw = fac * bsiz.width + 0.4999F;
144 float const croph = fac * bsiz.height + 0.4999F;
145 x = (x - (itsImageSize.width - cropw) * 0.5F) / fac;
146 y = (y - (itsImageSize.height - croph) * 0.5F) / fac;
147 }
148 else
149 {
150 x *= float(bsiz.width) / itsImageSize.width;
151 y *= float(bsiz.height) / itsImageSize.height;
152 }
153}
154
155// ####################################################################################################
156std::shared_ptr<jevois::dnn::PreProcessorForPython> jevois::dnn::PreProcessor::getPreProcForPy() const
157{ return itsPP; }
158
159// ####################################################################################################
161 std::vector<vsi_nn_tensor_attr_t> const & attrs)
162{
163 // Store input image size and format for future use:
164 itsImageSize.width = img.width; itsImageSize.height = img.height; itsImageFmt = img.fmt;
165 itsCrops.clear(); itsBlobs.clear();
166
167 if (itsAttrs.empty()) itsAttrs = attrs;
168 if (itsAttrs.empty()) LFATAL("Cannot work with no input tensors");
169
170 // Do the pre-processing:
171 if (img.fmt == V4L2_PIX_FMT_RGB24)
172 itsBlobs = process(jevois::rawimage::cvImage(img), ! rgb::get(), itsAttrs, itsCrops);
173 else if (img.fmt == V4L2_PIX_FMT_BGR24)
174 itsBlobs = process(jevois::rawimage::cvImage(img), rgb::get(), itsAttrs, itsCrops);
175 else if (rgb::get())
176 itsBlobs = process(jevois::rawimage::convertToCvRGB(img), false, itsAttrs, itsCrops);
177 else
178 itsBlobs = process(jevois::rawimage::convertToCvBGR(img), false, itsAttrs, itsCrops);
179
180 return itsBlobs;
181}
182
183// ####################################################################################################
185 jevois::OptGUIhelper * helper, bool overlay, bool idle)
186{
187#ifdef JEVOIS_PRO
188 // First some info about the input:
189 if (helper && idle == false && ImGui::CollapsingHeader("Pre-Processing", ImGuiTreeNodeFlags_DefaultOpen))
190 {
191 ImGui::BulletText("Input image: %dx%d %s", itsImageSize.width, itsImageSize.height,
192 jevois::fccstr(itsImageFmt).c_str());
193
194 if (itsImageFmt != V4L2_PIX_FMT_RGB24 && itsImageFmt != V4L2_PIX_FMT_BGR24)
195 {
196 if (rgb::get()) ImGui::BulletText("Convert to RGB");
197 else ImGui::BulletText("Convert to BGR");
198 }
199
200 // Now a report from the derived class:
201 report(mod, outimg, helper, overlay, idle);
202
203 // If desired, draw a rectangle around the network input:
204 if (showin::get())
205 for (cv::Rect const & r : itsCrops)
206 ImGui::GetBackgroundDrawList()->AddRect(helper->i2d(r.x, r.y),
207 helper->i2d(r.x + r.width, r.y + r.height), 0x80808080, 0, 0, 5);
208
209 // Finally some info about the blobs, if detailed info was not requested (detailed info provided by derived class):
210 if (details::get() == false)
211 {
212 int idx = 0;
213 for (cv::Mat const & blob : itsBlobs)
214 {
215 cv::Rect const & r = itsCrops[idx];
216 bool const stretch = (r.x == 0 && r.y == 0);
217
218 ImGui::BulletText("Crop %d: %dx%d @ %d,%d %s", idx, r.width, r.height, r.x, r.y,
219 stretch ? "" : "(letterbox)");
220 ImGui::BulletText("Blob %d: %s %s", idx, jevois::dnn::shapestr(blob).c_str(),
221 stretch ? "(stretch)" : "(uniform)");
222
223 ++idx;
224 }
225 }
226 }
227#else
228 (void)mod; (void)helper; (void)overlay; (void)idle;
229#endif
230
231 // On JeVois-A33, we do not have much room on screen, so write nothing here, the network will write some info about
232 // input tensors; just draw the crop rectangles:
233 if (outimg)
234 {
235 for (cv::Rect const & r : itsCrops)
236 jevois::rawimage::drawRect(*outimg, r.x, r.y, r.width, r.height, 3, jevois::yuyv::MedGrey);
237 }
238}
A component of a model hierarchy.
Definition Component.H:182
Helper class to assist modules in creating graphical and GUI elements.
Definition GUIhelper.H:133
ImVec2 i2d(ImVec2 p, char const *name=nullptr)
Convert coordinates of a point from within a rendered image to on-screen.
Definition GUIhelper.C:400
A raw image as coming from a V4L2 Camera and/or being sent out to a USB Gadget.
Definition RawImage.H:111
unsigned int fmt
Pixel format as a V4L2_PIX_FMT_XXX.
Definition RawImage.H:147
unsigned int width
Image width in pixels.
Definition RawImage.H:145
unsigned int height
Image height in pixels.
Definition RawImage.H:146
Base class for a module that supports standardized serial messages.
Definition Module.H:234
std::shared_ptr< PreProcessorForPython > getPreProcForPy() const
Get a pointer to our python-friendly interface.
cv::Rect getUnscaledCropRect(size_t blobnum=0)
Get unscaled crop rectangle in image coordinates.
PreProcessor(std::string const &instance)
Constructor.
void i2b(float &x, float &y, size_t blobnum=0)
Convert coordinates from image to blob.
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.
std::vector< cv::Mat > process(jevois::RawImage const &img, std::vector< vsi_nn_tensor_attr_t > const &attrs)
Extract blobs from input image.
std::vector< cv::Mat > const & blobs() const
Access the last computed blobs (or empty if process() has not yet been called)
cv::Size const & imagesize() const
Access the last processed image size.
void b2is(float &sx, float &sy, size_t blobnum=0)
Convert box size from blob back to original image.
virtual ~PreProcessor()
Destructor.
void b2i(float &x, float &y, size_t blobnum=0)
Convert coordinates from blob back to original image.
cv::Size blobsize(size_t num) const
Access the width and height of a given blob, accounting for NCHW or NHWC.
#define LFATAL(msg)
Convenience macro for users to print out console or syslog messages, FATAL level.
Definition Log.H:230
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:511
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:109
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
cv::Mat convertToCvRGB(RawImage const &src)
Convert RawImage to OpenCV doing color conversion from any RawImage source pixel to OpenCV RGB byte.
cv::Mat convertToCvBGR(RawImage const &src)
Convert RawImage to OpenCV doing color conversion from any RawImage source pixel to OpenCV BGR byte.
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.
std::string fccstr(unsigned int fcc)
Convert a V4L2 four-cc code (V4L2_PIX_FMT_...) to a 4-char string.
Definition Utils.C:45
unsigned short constexpr MedGrey
YUYV color value.
Definition RawImage.H:57
Main namespace for all JeVois classes and functions.
Definition Concepts.dox:2