27#include <opencv2/dnn.hpp>
37 classes::freeze(doit);
38 detecttypeobb::freeze(doit);
44 if (val.empty()) { itsLabels.clear();
return; }
50 postprocessor::DetectTypeOBB
const & val)
59 if (outs.empty())
LFATAL(
"No outputs received, we need at least one.");
60 cv::Mat
const & out = outs[0]; cv::MatSize
const & msiz = out.size;
62 float const confThreshold = cthresh::get() * 0.01F;
64 float const nmsThreshold = nms::get() * 0.01F;
65 bool const sigmo = sigmoid::get();
66 int const fudge = classoffset::get();
78 std::vector<int> classIds;
79 std::vector<float> confidences;
80 std::vector<cv::RotatedRect> boxes;
85 switch(detecttypeobb::get())
88 case jevois::dnn::postprocessor::DetectTypeOBB::YOLOv8:
92 if ((outs.size() % 3) != 0 || msiz.dims() != 4 || msiz[0] != 1)
93 LTHROW(
"Expected several (usually 3, for 3 strides) sets of 2 blobs: 1x64xHxW (raw boxes), "
94 "1xCxHxW (class scores), and 1x1xHxW (box angles)");
97 int constexpr reg_max = 16;
99 for (
size_t idx = 0; idx < outs.size(); idx += 3)
101 cv::Mat
const & bx = outs[idx]; cv::MatSize
const & bx_siz = bx.size;
102 if (bx_siz.dims() != 4 || bx_siz[1] != 4 * reg_max)
LTHROW(
"Output " << idx <<
" is not 4D 1x64xHxW");
103 float const * bx_data = (
float const *)bx.data;
105 cv::Mat
const & cls = outs[idx + 1]; cv::MatSize
const & cls_siz = cls.size;
106 if (cls_siz.dims() != 4)
LTHROW(
"Output " << idx <<
" is not 4D 1xCxHxW");
107 float const * cls_data = (
float const *)cls.data;
108 size_t const nclass = cls_siz[1];
110 cv::Mat
const & ang = outs[idx + 2]; cv::MatSize
const & ang_siz = ang.size;
111 if (cls_siz.dims() != 4 || ang_siz[1] != 1)
LTHROW(
"Output " << idx <<
" is not 4D 1x1xHxW");
112 float const * ang_data = (
float const *)ang.data;
114 for (
int i = 2; i < 4; ++i)
115 if (cls_siz[i] != bx_siz[i])
LTHROW(
"Mismatched HxW sizes for outputs " << idx <<
" .. " << idx + 1);
117 size_t const step = cls_siz[2] * cls_siz[3];
120 for (
int y = 0; y < cls_siz[2]; ++y)
121 for (
int x = 0; x < cls_siz[3]; ++x)
124 size_t best_idx = 0;
float confidence = cls_data[0];
125 for (
size_t i = 1; i < nclass; ++i)
126 if (cls_data[i * step] > confidence) { confidence = cls_data[i * step]; best_idx = i; }
131 if (confidence >= confThreshold)
141 if (angle >= 0.5F * M_PI && angle <= 0.75F * M_PI) angle -= M_PI;
143 float const cosa = std::cos(angle);
144 float const sina = std::sin(angle);
148 float const ltx =
softmax_dfl(bx_data, dst, reg_max, step);
149 float const lty =
softmax_dfl(bx_data + reg_max * step, dst, reg_max, step);
150 float const rbx =
softmax_dfl(bx_data + 2 * reg_max * step, dst, reg_max, step);
151 float const rby =
softmax_dfl(bx_data + 3 * reg_max * step, dst, reg_max, step);
153 float const xf = 0.5F * (rbx - ltx);
154 float const yf = 0.5F * (rby - lty);
156 float const cx = (x + 0.5F + xf * cosa - yf * sina) * stride;
157 float const cy = (y + 0.5F + xf * sina + yf * cosa) * stride;
158 float const width = (ltx + rbx) * stride;
159 float const height = (lty + rby) * stride;
162 boxes.push_back(cv::RotatedRect(cv::Point2f(cx, cy), cv::Size2f(width, height), angle * 180.0F / M_PI));
163 classIds.push_back(
int(best_idx) + fudge);
164 confidences.push_back(confidence);
168 ++cls_data; ++bx_data; ++ang_data;
180 LTHROW(
"Unsupported Post-processor detecttype " <<
int(detecttypeobb::get()));
184 catch (std::exception
const & e)
186 std::string err =
"Selected detecttypeobb is " + detecttypeobb::strget() +
" and network produced:\n\n";
188 err +=
"\nFATAL ERROR(s):\n\n";
194 std::vector<int> indices;
199 cv::dnn::NMSBoxes(boxes, confidences, confThreshold, nmsThreshold, indices, 1.0F, maxnbox::get());
202 for (cv::RotatedRect & b : boxes)
204 preproc->
b2i(b.center.x, b.center.y);
205 preproc->
b2is(b.size.width, b.size.height);
209 itsDetections.clear();
bool namonly = namedonly::get();
210 for (
size_t i = 0; i < indices.size(); ++i)
212 int idx = indices[i];
213 cv::RotatedRect
const & box = boxes[idx];
215 if (namonly ==
false || label.empty() ==
false)
218 std::vector<jevois::ObjReco> ov;
221 itsDetections.emplace_back(od);
231 bool const serreport = serialreport::get();
235 std::string categ, label;
244 categ =
o.reco[0].category;
249 if (outimg && overlay)
251 std::vector<cv::Point2f> pts;
o.rect.points(pts);
252 for (
size_t i = 1; i < pts.size(); ++i)
265 std::vector<cv::Point2f> corners;
o.rect.points(corners);
266 helper->
drawPoly(corners, col,
true);
267 helper->
drawText(corners[1].x + 3.0f, corners[1].y + 3.0f, label.c_str(), col);
280{
return itsDetections; }
#define JEVOIS_SHARE_PATH
Base path for shared files (e.g., neural network weights, etc)
Helper class to assist modules in creating graphical and GUI elements.
void drawText(float x, float y, char const *txt, ImU32 col=IM_COL32(128, 255, 128, 255))
Draw text over an image.
void drawPoly(std::vector< cv::Point > const &pts, ImU32 col=IM_COL32(128, 255, 128, 255), bool filled=true)
Draw polygon over an image.
A raw image as coming from a V4L2 Camera and/or being sent out to a USB Gadget.
Base class for a module that supports standardized serial messages.
void sendSerialObjDetImg2D(unsigned int camw, unsigned int camh, float x, float y, float w, float h, std::vector< ObjReco > const &res)
Send a standardized object detection + recognition message.
void report(jevois::StdModule *mod, jevois::RawImage *outimg=nullptr, jevois::OptGUIhelper *helper=nullptr, bool overlay=true, bool idle=false) override
Report what happened in last process() to console/output video/GUI.
std::vector< ObjDetectOBB > const & latestDetectionsOBB() const
Get the latest detections, use with caution, not thread-safe.
void onParamChange(postprocessor::detecttypeobb const ¶m, postprocessor::DetectTypeOBB const &val) override
void freeze(bool doit) override
Freeze/unfreeze parameters that users should not change while running.
virtual ~PostProcessorDetectOBB()
Destructor.
void process(std::vector< cv::Mat > const &outs, PreProcessor *preproc) override
Process outputs and draw/send some results.
Pre-Processor for neural network pipeline.
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.
void b2i(float &x, float &y, size_t blobnum=0)
Convert coordinates from blob back to original image.
#define LFATAL(msg)
Convenience macro for users to print out console or syslog messages, FATAL level.
std::string getLabel(std::map< int, std::string > const &labels, int id, bool namedonly=false)
Get a label from an id.
std::map< int, std::string > readLabelsFile(std::string const &fname)
Read a label file.
float sigmoid(float x)
Compute sigmoid using fastexp.
float softmax_dfl(float const *src, float *dst, size_t const n, size_t const stride=1)
Compute softmax and return DFL distance.
int stringToRGBA(std::string const &label, unsigned char alpha=128)
Compute a color from a label name.
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.
void writeText(RawImage &img, std::string const &txt, int x, int y, unsigned int col, Font font=Font6x10)
Write some text in an image.
void drawLine(RawImage &img, int x1, int y1, int x2, int y2, unsigned int thick, unsigned int col)
Draw a line in a YUYV image.
std::string sformat(char const *fmt,...) __attribute__((format(__printf__
Create a string using printf style arguments.
std::filesystem::path absolutePath(std::filesystem::path const &root, std::filesystem::path const &path)
Compute an absolute path from two paths.
unsigned short constexpr LightGreen
YUYV color value.
A trivial struct to store object detection results, for oriented bounding boxes (OBB)
A trivial struct to store object recognition results.