28 #include <opencv2/dnn.hpp>
37 classes::freeze(doit);
38 detecttype::freeze(doit);
39 if (itsYOLO) itsYOLO->freeze(doit);
44 std::string
const & val)
46 if (val.empty()) { itsLabels.clear();
return; }
50 dd.back() =
"network"; dd.emplace_back(
"dataroot");
51 std::string
const dataroot = engine()->getParamStringUnique(
jevois::join(dd,
":"));
57 postprocessor::DetectType
const & val)
59 if (val == postprocessor::DetectType::RAWYOLO)
60 itsYOLO = addSubComponent<jevois::dnn::PostProcessorDetectYOLO>(
"yolo");
64 removeSubComponent(
"yolo",
false);
71 if (outs.empty())
LFATAL(
"No outputs received, we need at least one.");
72 cv::Mat
const & out = outs[0]; cv::MatSize
const & msiz = out.size;
76 float const nmsThreshold =
nms::get() * 0.01F;
85 cv::Size
const bsiz = preproc->
blobsize(0);
89 std::vector<int> classIds;
90 std::vector<float> confidences;
91 std::vector<cv::Rect> boxes;
100 case jevois::dnn::postprocessor::DetectType::FasterRCNN:
104 if (outs.size() != 1 || msiz.dims() != 4 || msiz[0] != 1 || msiz[1] != 1 || msiz[3] != 7)
105 LTHROW(
"Expected 1 output blob with shape 1x1xNx7 for N detections with values "
106 "[batchId, classId, confidence, left, top, right, bottom]");
108 float const * data = (
float const *)out.data;
109 for (
size_t i = 0; i < out.total(); i += 7)
111 float confidence = data[i + 2];
112 if (confidence > confThreshold)
114 int left = (int)data[i + 3];
115 int top = (int)data[i + 4];
116 int right = (int)data[i + 5];
117 int bottom = (int)data[i + 6];
118 int width = right - left + 1;
119 int height = bottom - top + 1;
120 classIds.push_back((
int)(data[i + 1]) + fudge);
121 boxes.push_back(cv::Rect(left, top, width, height));
122 confidences.push_back(confidence);
123 if (classIds.size() > maxbox)
break;
130 case jevois::dnn::postprocessor::DetectType::SSD:
134 if (outs.size() != 1 || msiz.dims() != 4 || msiz[0] != 1 || msiz[1] != 1 || msiz[3] != 7)
135 LTHROW(
"Expected 1 output blob with shape 1x1xNx7 for N detections with values "
136 "[batchId, classId, confidence, left, top, right, bottom]");
138 float const * data = (
float const *)out.data;
139 for (
size_t i = 0; i < out.total(); i += 7)
141 float confidence = data[i + 2];
142 if (confidence > confThreshold)
144 int left = (int)(data[i + 3] * bsiz.width);
145 int top = (int)(data[i + 4] * bsiz.height);
146 int right = (int)(data[i + 5] * bsiz.width);
147 int bottom = (int)(data[i + 6] * bsiz.height);
148 int width = right - left + 1;
149 int height = bottom - top + 1;
150 classIds.push_back((
int)(data[i + 1]) + fudge);
151 boxes.push_back(cv::Rect(left, top, width, height));
152 confidences.push_back(confidence);
153 if (classIds.size() > maxbox)
break;
160 case jevois::dnn::postprocessor::DetectType::TPUSSD:
164 if (outs.size() != 4)
165 LTHROW(
"Expected 4 output blobs with shapes 4xN for boxes, N for IDs, N for scores, and 1x1 for count");
166 cv::Mat
const & bboxes = outs[0];
167 cv::Mat
const & ids = outs[1];
168 cv::Mat
const & scores = outs[2];
169 cv::Mat
const & count = outs[3];
170 if (bboxes.total() != 4 * ids.total() || bboxes.total() != 4 * scores.total() || count.total() != 1)
171 LTHROW(
"Expected 4 output blobs with shapes 4xN for boxes, N for IDs, N for scores, and 1x1 for count");
173 size_t num = count.at<
float>(0);
174 if (num > ids.total())
LTHROW(
"Too many detections: " << num <<
" for only " << ids.total() <<
" ids");
175 float const * bb = (
float const *)bboxes.data;
177 for (
size_t i = 0; i < num; ++i)
179 if (scores.at<
float>(i) < confThreshold)
continue;
181 int top = (int)(bb[4 * i] * bsiz.height);
182 int left = (int)(bb[4 * i + 1] * bsiz.width);
183 int bottom = (int)(bb[4 * i + 2] * bsiz.height);
184 int right = (int)(bb[4 * i + 3] * bsiz.width);
185 int width = right - left + 1;
186 int height = bottom - top + 1;
187 classIds.push_back((
int)(ids.at<
float>(i)) + fudge);
188 boxes.push_back(cv::Rect(left, top, width, height));
189 confidences.push_back(scores.at<
float>(i));
190 if (classIds.size() > maxbox)
break;
196 case jevois::dnn::postprocessor::DetectType::YOLO:
198 for (
size_t i = 0; i < outs.size(); ++i)
202 cv::Mat
const & out = outs[i];
203 cv::MatSize
const & ms = out.size;
int const nd = ms.dims();
204 int nbox = -1, ndata = -1;
210 for (
int i = 0; i < nd-2; ++i)
if (ms[i] != 1) nbox = -1;
213 if (nbox < 0 || ndata < 5)
214 LTHROW(
"Expected 1 or more output blobs with shape Nx(5+C) where N is the number of "
215 "detected objects, C is the number of classes, and the first 5 columns are "
216 "[center_x, center_y, width, height, box score]. // "
218 ": need Nx(5+C) or 1xNx(5+C)");
221 int sz2[] = { nbox, ndata };
222 cv::Mat
const out2(2, sz2, out.type(), out.data);
224 float const * data = (
float const *)out2.data;
225 for (
int j = 0; j < nbox; ++j, data += ndata)
227 if (data[4] < boxThreshold)
continue;
229 cv::Mat scores = out2.row(j).colRange(5, ndata);
230 cv::Point classIdPoint;
double confidence;
231 cv::minMaxLoc(scores, 0, &confidence, 0, &classIdPoint);
233 if (confidence < confThreshold)
continue;
236 int centerX, centerY, width, height;
239 centerX = (int)(data[0] * bsiz.width);
240 centerY = (int)(data[1] * bsiz.height);
241 width = (int)(data[2] * bsiz.width);
242 height = (int)(data[3] * bsiz.height);
247 centerX = (int)(data[0]);
248 centerY = (int)(data[1]);
249 width = (int)(data[2]);
250 height = (int)(data[3]);
253 int left = centerX - width / 2;
254 int top = centerY - height / 2;
255 boxes.push_back(cv::Rect(left, top, width, height));
256 classIds.push_back(classIdPoint.x);
257 confidences.push_back((
float)confidence);
258 if (classIds.size() > maxbox)
break;
265 case jevois::dnn::postprocessor::DetectType::RAWYOLO:
267 if (itsYOLO) itsYOLO->yolo(outs, classIds, confidences, boxes, itsLabels.size(), boxThreshold, confThreshold,
268 bsiz, fudge, maxbox);
269 else LFATAL(
"Internal error -- no YOLO subcomponent");
279 catch (std::exception
const & e)
281 std::string err =
"Selected detecttype is " + detecttype::strget() +
" and network produced:\n\n";
283 err +=
"\nFATAL ERROR(s):\n\n";
289 std::vector<int> indices;
290 cv::dnn::NMSBoxes(boxes, confidences, confThreshold, nmsThreshold, indices);
293 for (cv::Rect & b : boxes)
297 cv::Point2f tl = b.tl(); preproc->
b2i(tl.x, tl.y);
298 cv::Point2f br = b.br(); preproc->
b2i(br.x, br.y);
299 b.x = tl.x; b.y = tl.y; b.width = br.x - tl.x; b.height = br.y - tl.y;
303 itsDetections.clear();
304 for (
size_t i = 0; i < indices.size(); ++i)
306 int idx = indices[i];
307 cv::Rect
const & box = boxes[idx];
309 std::vector<jevois::ObjReco> ov;
311 jevois::ObjDetect od { box.x, box.y, box.x + box.width, box.y + box.height, ov };
312 itsDetections.emplace_back(od);
319 bool JEVOIS_UNUSED_PARAM(idle))
323 std::string categ, label;
332 categ =
o.reco[0].category;
337 if (outimg && overlay)
349 helper->
drawRect(
o.tlx,
o.tly,
o.brx,
o.bry, col,
true);
350 helper->
drawText(
o.tlx + 3.0f,
o.tly + 3.0f, label.c_str(), col);