22#include <nn_detect_common.h>
33void jevois::dnn::PostProcessorDetectYOLO::onParamChange(postprocessor::anchors
const &, std::string
const & val)
36 if (val.empty())
return;
39 for (std::string
const & t : tok)
42 if (atok.size() & 1)
LFATAL(
"Odd number of values not allowed in anchor spec [" << t <<
']');
44 for (std::string
const & at : atok) a.emplace_back(std::stof(at));
45 itsAnchors.emplace_back(std::move(a));
56 anchors::freeze(doit);
61 std::vector<float> & confidences, std::vector<cv::Rect> & boxes,
62 size_t nclass,
float boxThreshold,
float confThreshold,
63 cv::Size
const & bsiz,
int fudge,
size_t const maxbox,
bool sigmo)
65 if (nclass == 0) nclass = 1;
66 size_t const nouts = outs.size();
67 if (nouts == 0)
LTHROW(
"No output tensors received");
68 if (itsAnchors.size() != nouts)
LTHROW(
"Need " << nouts <<
" sets of anchors");
73 if (itsYoloNum.empty())
75 for (
size_t i = 0; i < nouts; ++i) itsYoloNum.emplace_back(i);
76 std::sort(itsYoloNum.begin(), itsYoloNum.end(),
77 [&outs](
int const & a,
int const & b) { return outs[a].total() > outs[b].total(); });
80 for (
size_t i = 0; i < nouts; ++i)
82 int const yn = itsYoloNum[i];
83 std::vector<float>
const & anc = itsAnchors[yn];
85 for (
size_t a = 0; a < anc.size(); a += 2) vstr +=
jevois::sformat(
"%.2f,%.2f ", anc[a], anc[a+1]);
87 ", anchors=[ " << vstr <<
']');
92 float scale_xy = scalexy::get();
93 std::vector<std::future<void>> fvec;
95 for (
size_t i = 0; i < nouts; ++i)
97 { yolo_one(outs[i], classIds, confidences, boxes, nclass, itsYoloNum[i], boxThreshold, confThreshold,
98 bsiz, fudge, maxbox, sigmo, scale_xy); }, i));
105void jevois::dnn::PostProcessorDetectYOLO::yolo_one(cv::Mat
const & out, std::vector<int> & classIds,
106 std::vector<float> & confidences, std::vector<cv::Rect> & boxes,
107 size_t nclass,
int yolonum,
float boxThreshold,
108 float confThreshold, cv::Size
const & bsiz,
int fudge,
109 size_t maxbox,
bool sigmo,
float scale_xy)
111 if (out.type() != CV_32F)
LTHROW(
"Need FLOAT32 data");
112 cv::MatSize
const & msiz = out.size;
113 if (msiz.dims() != 4 || msiz[0] != 1)
124 int constexpr coords = 4;
125 int const bbsize = coords + 1 + nclass;
126 int n = msiz[1] / bbsize;
127 if (msiz[1] % bbsize)
133 n = msiz[3] / bbsize;
135 if (msiz[3] % bbsize)
136 LTHROW(
"Incorrect tensor size: need 1xCxHxW or 1xHxWxC where "
137 "C=num_anchors*(4 coords + 1 box_score + nclass object_scores), got " <<
jevois::dnn::shapestr(out) <<
138 ", nclass=" << nclass <<
", num_anchors=" << itsAnchors[yolonum].size()/2);
141 float const bfac = 1.0F / (8 << yolonum);
142 size_t const total =
h * w * n * bbsize;
143 if (total != out.total())
LTHROW(
"Ooops");
144 std::vector<float>
const & biases = itsAnchors[yolonum];
145 if (
int(biases.size()) != n*2)
146 LTHROW(n <<
" boxes received but only " << biases.size()/2 <<
" boxw,boxh anchors provided");
149 size_t const stride = nchw ?
h * w : 1;
150 size_t const nextloc = nchw ? 1 : n * bbsize;
151 float const * locptr = (
float const *)out.data;
152 size_t const ncs = nclass * stride;
155 for (
int row = 0; row <
h; ++row)
156 for (
int col = 0; col < w; ++col)
159 float const * ptr = locptr;
162 for (
int nn = 0; nn < n; ++nn)
165 float box_score = ptr[coords * stride];
168 if (box_score > boxThreshold)
171 size_t const class_index = (coords + 1) * stride;
172 size_t maxidx = 0;
float prob = 0.0F;
173 for (
size_t k = 0; k < ncs; k += stride)
174 if (ptr[class_index + k] > prob) { prob = ptr[class_index + k]; maxidx = k; }
181 if (prob > confThreshold)
189 float bx = ptr[0 * stride], by = ptr[1 * stride], bw = ptr[2 * stride], bh = ptr[3 * stride];
198 b.width = bw * bw * 4.0f * biases[2*nn] * bfac * bsiz.width / w + 0.499F;
199 b.height = bh * bh * 4.0F * biases[2*nn+1] * bfac * bsiz.height /
h + 0.499F;
200 b.x = (bx * scale_xy - 0.5F + col) * bsiz.width / w + 0.499F - b.width / 2;
201 b.y = (by * scale_xy - 0.5F + row) * bsiz.height /
h + 0.499F - b.height / 2;
206 b.width = expf(ptr[2 * stride]) * biases[2*nn] * bfac * bsiz.width / w + 0.499F;
207 b.height = expf(ptr[3 * stride]) * biases[2*nn+1] * bfac * bsiz.height /
h + 0.499F;
212 std::lock_guard<std::mutex> _(itsOutMtx);
213 boxes.emplace_back(b);
214 classIds.emplace_back(maxidx / stride + fudge);
215 confidences.emplace_back(prob);
216 if (classIds.size() > maxbox)
return;
221 ptr += bbsize * stride;
virtual ~PostProcessorDetectYOLO()
Destructor.
void yolo(std::vector< cv::Mat > const &outs, std::vector< int > &classIds, std::vector< float > &confidences, std::vector< cv::Rect > &boxes, size_t nclass, float boxThreshold, float confThreshold, cv::Size const &bsiz, int fudge, size_t const maxbox, bool sigmo)
Generic raw YOLO processing.
void freeze(bool doit)
Freeze/unfreeze parameters that users should not change while running.
#define LFATAL(msg)
Convenience macro for users to print out console or syslog messages, FATAL level.
#define LINFO(msg)
Convenience macro for users to print out console or syslog messages, INFO level.
float sigmoid(float x)
Compute sigmoid using fastexp.
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.
std::vector< T > joinall(std::vector< std::future< T > > &fvec, bool multiline=true)
Collect results from several async threads that are all returning a T result.
std::future< std::invoke_result_t< std::decay_t< Function >, std::decay_t< Args >... > > async(Function &&f, Args &&... args)
Async execution using a thread pool.
std::string sformat(char const *fmt,...) __attribute__((format(__printf__
Create a string using printf style arguments.
std::vector< std::string > split(std::string const &input, std::string const ®ex="\\s+")
Split string into vector of tokens using a regex to specify what to split on; default regex splits by...