22 #include <nn_detect_common.h>
33 void jevois::dnn::PostProcessorDetectYOLO::onParamChange(postprocessor::anchors
const & JEVOIS_UNUSED_PARAM(param),
34 std::string
const & val)
37 if (val.empty())
return;
40 for (std::string
const & t : tok)
43 if (atok.size() & 1)
LFATAL(
"Odd number of values not allowed in anchor spec [" << t <<
']');
45 for (std::string
const & at : atok) a.emplace_back(std::stof(at));
46 itsAnchors.emplace_back(std::move(a));
57 anchors::freeze(doit);
64 inline float logistic_activate(
float x)
65 {
return 1.0F/(1.0F + expf(-x)); }
70 std::vector<float> & confidences, std::vector<cv::Rect> & boxes,
71 size_t nclass,
float boxThreshold,
float confThreshold,
72 cv::Size
const & bsiz,
int fudge,
size_t const maxbox)
74 if (nclass == 0) nclass = 1;
75 size_t const nouts = outs.size();
76 if (nouts == 0)
LTHROW(
"No output tensors received");
77 if (itsAnchors.size() != nouts)
LTHROW(
"Need " << nouts <<
" sets of anchors");
82 if (itsYoloNum.empty())
84 for (
size_t i = 0; i < nouts; ++i) itsYoloNum.emplace_back(i);
85 std::sort(itsYoloNum.begin(), itsYoloNum.end(),
86 [&outs](
int const & a,
int const & b) { return outs[a].total() > outs[b].total(); });
89 for (
size_t i = 0; i < nouts; ++i)
91 int const yn = itsYoloNum[i];
92 std::vector<float>
const & anc = itsAnchors[yn];
94 for (
size_t a = 0; a < anc.size(); a += 2) vstr +=
jevois::sformat(
"%.2f,%.2f ", anc[a], anc[a+1]);
96 ", anchors=[ " << vstr <<
']');
103 std::vector<std::future<void>> fvec;
105 for (
size_t i = 0; i < nouts; ++i)
107 { yolo_one(outs[i], classIds, confidences, boxes, nclass, itsYoloNum[i], boxThreshold, confThreshold,
108 bsiz, fudge, maxbox, sigmo, scale_xy); }, i));
115 void jevois::dnn::PostProcessorDetectYOLO::yolo_one(cv::Mat
const & out, std::vector<int> & classIds,
116 std::vector<float> & confidences, std::vector<cv::Rect> & boxes,
117 size_t nclass,
int yolonum,
float boxThreshold,
118 float confThreshold, cv::Size
const & bsiz,
int fudge,
119 size_t maxbox,
bool sigmo,
float scale_xy)
121 if (out.type() != CV_32F)
LTHROW(
"Need FLOAT32 data");
122 cv::MatSize
const & msiz = out.size;
123 if (msiz.dims() != 4 || msiz[0] != 1)
134 int constexpr coords = 4;
135 int const bbsize = coords + 1 + nclass;
136 int n = msiz[1] / bbsize;
137 if (msiz[1] % bbsize)
143 n = msiz[3] / bbsize;
145 if (msiz[3] % bbsize)
146 LTHROW(
"Incorrect tensor size: need 1xCxHxW or 1xHxWxC where "
147 "C=num_anchors*(4 coords + 1 box_score + nclass object_scores), got " <<
jevois::dnn::shapestr(out) <<
148 ", nclass=" << nclass <<
", num_anchors=" << itsAnchors[yolonum].size()/2);
151 float const bfac = 1.0F / (8 << yolonum);
152 size_t const total =
h * w * n * bbsize;
153 if (total != out.total())
LTHROW(
"Ooops");
154 std::vector<float>
const & biases = itsAnchors[yolonum];
155 if (
int(biases.size()) != n*2)
156 LTHROW(n <<
" boxes received but only " << biases.size()/2 <<
" boxw,boxh anchors provided");
159 size_t const stride = nchw ?
h * w : 1;
160 size_t const nextloc = nchw ? 1 : n * bbsize;
161 float const * locptr = (
float const *)out.data;
162 size_t const ncs = nclass * stride;
165 for (
int row = 0; row <
h; ++row)
166 for (
int col = 0; col < w; ++col)
169 float const * ptr = locptr;
172 for (
int nn = 0; nn < n; ++nn)
175 float box_score = ptr[coords * stride];
176 if (sigmo) box_score = logistic_activate(box_score);
178 if (box_score > boxThreshold)
181 size_t const class_index = (coords + 1) * stride;
182 size_t maxidx = 0;
float prob = 0.0F;
183 for (
size_t k = 0; k < ncs; k += stride)
184 if (ptr[class_index + k] > prob) { prob = ptr[class_index + k]; maxidx = k; }
185 if (sigmo) prob = logistic_activate(prob);
191 if (prob > confThreshold)
199 float bx = ptr[0 * stride], by = ptr[1 * stride], bw = ptr[2 * stride], bh = ptr[3 * stride];
202 bx = logistic_activate(bx);
203 by = logistic_activate(by);
204 bw = logistic_activate(bw);
205 bh = logistic_activate(bh);
208 b.width = bw * bw * 4.0f * biases[2*nn] * bfac * bsiz.width / w + 0.499F;
209 b.height = bh * bh * 4.0F * biases[2*nn+1] * bfac * bsiz.height /
h + 0.499F;
210 b.x = (bx * scale_xy - 0.5F + col) * bsiz.width / w + 0.499F - b.width / 2;
211 b.y = (by * scale_xy - 0.5F + row) * bsiz.height /
h + 0.499F - b.height / 2;
216 b.width = expf(ptr[2 * stride]) * biases[2*nn] * bfac * bsiz.width / w + 0.499F;
217 b.height = expf(ptr[3 * stride]) * biases[2*nn+1] * bfac * bsiz.height /
h + 0.499F;
218 b.x = (col + logistic_activate(ptr[0 * stride])) * bsiz.width / w + 0.499F - b.width / 2;
219 b.y = (row + logistic_activate(ptr[1 * stride])) * bsiz.height /
h + 0.499F - b.height / 2;
222 std::lock_guard<std::mutex> _(itsOutMtx);
223 boxes.emplace_back(b);
224 classIds.emplace_back(maxidx / stride + fudge);
225 confidences.emplace_back(prob);
226 if (classIds.size() > maxbox)
return;
231 ptr += bbsize * stride;