69 if (outs.empty())
LFATAL(
"No outputs received, we need at least one.");
70 cv::Mat
const & out = outs[0]; cv::MatSize
const & msiz = out.size;
72 float const confThreshold = cthresh::get() * 0.01F;
73 float const boxThreshold = dthresh::get() * 0.01F;
74 float const nmsThreshold = nms::get() * 0.01F;
75 bool const sigmo = sigmoid::get();
76 bool const clampbox = boxclamp::get();
77 int const fudge = classoffset::get();
78 bool const smoothmsk = masksmooth::get();
86 cv::Size
const bsiz = preproc->
blobsize(0);
90 std::vector<int> classIds;
91 std::vector<float> confidences;
92 std::vector<cv::Rect> boxes;
93 std::vector<cv::Mat> mask_coeffs;
100 switch(detecttype::get())
103 case jevois::dnn::postprocessor::DetectType::FasterRCNN:
105 if (outs.size() != 1 || msiz.dims() != 4 || msiz[0] != 1 || msiz[1] != 1 || msiz[3] != 7)
106 LTHROW(
"Expected 1 output blob with shape 1x1xNx7 for N detections with values "
107 "[batchId, classId, confidence, left, top, right, bottom]");
109 float const * data = (
float const *)out.data;
110 for (
size_t i = 0; i < out.total(); i += 7)
112 float confidence = data[i + 2];
113 if (confidence > confThreshold)
115 int left = (int)data[i + 3];
116 int top = (int)data[i + 4];
117 int right = (int)data[i + 5];
118 int bottom = (int)data[i + 6];
119 int width = right - left + 1;
120 int height = bottom - top + 1;
121 classIds.push_back((
int)(data[i + 1]) + fudge);
122 boxes.push_back(cv::Rect(left, top, width, height));
123 confidences.push_back(confidence);
130 case jevois::dnn::postprocessor::DetectType::SSD:
132 if (outs.size() != 1 || msiz.dims() != 4 || msiz[0] != 1 || msiz[1] != 1 || msiz[3] != 7)
133 LTHROW(
"Expected 1 output blob with shape 1x1xNx7 for N detections with values "
134 "[batchId, classId, confidence, left, top, right, bottom]");
136 float const * data = (
float const *)out.data;
137 for (
size_t i = 0; i < out.total(); i += 7)
139 float confidence = data[i + 2];
140 if (confidence > confThreshold)
142 int left = (int)(data[i + 3] * bsiz.width);
143 int top = (int)(data[i + 4] * bsiz.height);
144 int right = (int)(data[i + 5] * bsiz.width);
145 int bottom = (int)(data[i + 6] * bsiz.height);
146 int width = right - left + 1;
147 int height = bottom - top + 1;
148 classIds.push_back((
int)(data[i + 1]) + fudge);
149 boxes.push_back(cv::Rect(left, top, width, height));
150 confidences.push_back(confidence);
157 case jevois::dnn::postprocessor::DetectType::TPUSSD:
159 if (outs.size() != 4)
160 LTHROW(
"Expected 4 output blobs with shapes 4xN for boxes, N for IDs, N for scores, and 1x1 for count");
161 cv::Mat
const & bboxes = outs[0];
162 cv::Mat
const & ids = outs[1];
163 cv::Mat
const & scores = outs[2];
164 cv::Mat
const & count = outs[3];
165 if (bboxes.total() != 4 * ids.total() || bboxes.total() != 4 * scores.total() || count.total() != 1)
166 LTHROW(
"Expected 4 output blobs with shapes 4xN for boxes, N for IDs, N for scores, and 1x1 for count");
168 size_t num = count.at<
float>(0);
169 if (num > ids.total())
LTHROW(
"Too many detections: " << num <<
" for only " << ids.total() <<
" ids");
170 float const * bb = (
float const *)bboxes.data;
172 for (
size_t i = 0; i < num; ++i)
174 if (scores.at<
float>(i) < confThreshold)
continue;
176 int top = (int)(bb[4 * i] * bsiz.height);
177 int left = (int)(bb[4 * i + 1] * bsiz.width);
178 int bottom = (int)(bb[4 * i + 2] * bsiz.height);
179 int right = (int)(bb[4 * i + 3] * bsiz.width);
180 int width = right - left + 1;
181 int height = bottom - top + 1;
182 classIds.push_back((
int)(ids.at<
float>(i)) + fudge);
183 boxes.push_back(cv::Rect(left, top, width, height));
184 confidences.push_back(scores.at<
float>(i));
190 case jevois::dnn::postprocessor::DetectType::YOLO:
192 for (
size_t i = 0; i < outs.size(); ++i)
196 cv::Mat
const & out = outs[i];
197 cv::MatSize
const & ms = out.size;
int const nd = ms.dims();
198 int nbox = -1, ndata = -1;
204 for (
int i = 0; i < nd-2; ++i)
if (ms[i] != 1) nbox = -1;
207 if (nbox < 0 || ndata < 5)
208 LTHROW(
"Expected 1 or more output blobs with shape Nx(5+C) where N is the number of "
209 "detected objects, C is the number of classes, and the first 5 columns are "
210 "[center_x, center_y, width, height, box score]. // "
212 ": need Nx(5+C) or 1xNx(5+C)");
215 int sz2[] = { nbox, ndata };
216 cv::Mat
const out2(2, sz2, out.type(), out.data);
218 float const * data = (
float const *)out2.data;
219 for (
int j = 0; j < nbox; ++j, data += ndata)
221 if (data[4] < boxThreshold)
continue;
223 cv::Mat scores = out2.row(j).colRange(5, ndata);
224 cv::Point classIdPoint;
double confidence;
225 cv::minMaxLoc(scores, 0, &confidence, 0, &classIdPoint);
227 if (confidence < confThreshold)
continue;
230 int centerX, centerY, width, height;
233 centerX = (int)(data[0] * bsiz.width);
234 centerY = (int)(data[1] * bsiz.height);
235 width = (int)(data[2] * bsiz.width);
236 height = (int)(data[3] * bsiz.height);
241 centerX = (int)(data[0]);
242 centerY = (int)(data[1]);
243 width = (int)(data[2]);
244 height = (int)(data[3]);
247 int left = centerX - width / 2;
248 int top = centerY - height / 2;
249 boxes.push_back(cv::Rect(left, top, width, height));
250 classIds.push_back(classIdPoint.x);
251 confidences.push_back((
float)confidence);
258 case jevois::dnn::postprocessor::DetectType::YOLOv10:
260 for (
size_t i = 0; i < outs.size(); ++i)
262 cv::Mat
const & out = outs[i];
263 cv::MatSize
const & ms = out.size;
int const nd = ms.dims();
266 LTHROW(
"Expected 1 or more output blobs with shape Nx(4+C) where N is the number of "
267 "detected objects, C is the number of classes, and the first 4 columns are "
268 "[x1, y1, x2, y2]. // "
273 int const nbox = ms[nd-2];
274 int const ndata = ms[nd-1];
275 int sz2[] = { nbox, ndata };
276 cv::Mat
const out2(2, sz2, out.type(), out.data);
279 float const * data = (
float const *)out2.data;
280 for (
int j = 0; j < nbox; ++j, data += ndata)
282 cv::Mat scores = out2.row(j).colRange(4, ndata);
283 cv::Point classIdPoint;
double confidence;
284 cv::minMaxLoc(scores, 0, &confidence, 0, &classIdPoint);
286 if (confidence < confThreshold)
continue;
289 boxes.push_back(cv::Rect(data[0], data[1], data[2]-data[0]+1, data[3]-data[1]+1));
290 classIds.push_back(classIdPoint.x);
291 confidences.push_back((
float)confidence);
298 case jevois::dnn::postprocessor::DetectType::YOLOv10pp:
300 if (outs.size() != 1 || msiz.dims() != 3 || msiz[0] != 1 || msiz[2] != 6)
301 LTHROW(
"Expected 1 output blob with shape 1xNx6 for N detections with values "
302 "[left, top, right, bottom, confidence, classId]");
304 float const * data = (
float const *)out.data;
305 for (
size_t i = 0; i < out.total(); i += 6)
307 float confidence = data[i + 4];
308 if (confidence > confThreshold)
311 int left = (int)data[i + 0];
312 int top = (int)data[i + 1];
313 int right = (int)data[i + 2];
314 int bottom = (int)data[i + 3];
315 int width = right - left + 1;
316 int height = bottom - top + 1;
317 classIds.push_back((
int)(data[i + 5]) + fudge);
318 boxes.push_back(cv::Rect(left, top, width, height));
319 confidences.push_back(confidence);
326 case jevois::dnn::postprocessor::DetectType::RAWYOLO:
328 if (itsYOLO) itsYOLO->yolo(outs, classIds, confidences, boxes, itsLabels.size(), boxThreshold, confThreshold,
329 bsiz, fudge, maxnbox::get(), sigmo);
330 else LFATAL(
"Internal error -- no YOLO subcomponent");
335 case jevois::dnn::postprocessor::DetectType::YOLOX:
337 if ((outs.size() % 3) != 0 || msiz.dims() != 4 || msiz[0] != 1)
338 LTHROW(
"Expected several (usually 3, for 3 strides) sets of 3 blobs: 1xHxWxC (class scores), 1xHxWx4 (boxes), "
339 "1xHxWx1 (objectness scores)");
343 for (
size_t idx = 0; idx < outs.size(); idx += 3)
345 cv::Mat
const & cls = outs[idx]; cv::MatSize
const & cls_siz = cls.size;
346 if (cls_siz.dims() != 4)
LTHROW(
"Output " << idx <<
" is not 4D 1xHxWxC");
347 float const * cls_data = (
float const *)cls.data;
349 cv::Mat
const & bx = outs[idx + 1]; cv::MatSize
const & bx_siz = bx.size;
350 if (bx_siz.dims() != 4 || bx_siz[3] != 4)
LTHROW(
"Output " << idx <<
" is not 1xHxWx4");
351 float const * bx_data = (
float const *)bx.data;
353 cv::Mat
const & obj = outs[idx + 2]; cv::MatSize
const & obj_siz = obj.size;
354 if (obj_siz.dims() != 4 || obj_siz[3] != 1)
LTHROW(
"Output " << idx <<
" is not 1xHxWx1");
355 float const * obj_data = (
float const *)obj.data;
357 for (
int i = 1; i < 3; ++i)
358 if (cls_siz[i] != bx_siz[i] || cls_siz[i] != obj_siz[i])
359 LTHROW(
"Mismatched HxW sizes for outputs " << idx <<
" .. " << idx + 2);
361 size_t const nclass = cls_siz[3];
364 for (
int y = 0; y < cls_siz[1]; ++y)
365 for (
int x = 0; x < cls_siz[2]; ++x)
368 float objectness = obj_data[0];
369 if (objectness >= boxThreshold)
372 size_t best_idx = 0;
float confidence = cls_data[0];
373 for (
size_t i = 1; i < nclass; ++i)
374 if (cls_data[i] > confidence) { confidence = cls_data[i]; best_idx = i; }
376 confidence *= objectness;
378 if (confidence >= confThreshold)
381 float cx = (x + bx_data[0]) * stride;
382 float cy = (y + bx_data[1]) * stride;
383 float width = std::exp(bx_data[2]) * stride;
384 float height = std::exp(bx_data[3]) * stride;
385 float left = cx - 0.5F * width;
386 float top = cy - 0.5F * height;
389 boxes.push_back(cv::Rect(left, top, width, height));
390 classIds.push_back(
int(best_idx) + fudge);
391 confidences.push_back(confidence);
408 case jevois::dnn::postprocessor::DetectType::YOLOv8t:
410 if ((outs.size() % 2) != 0 || msiz.dims() != 4 || msiz[0] != 1)
411 LTHROW(
"Expected several (usually 3, for 3 strides) sets of 2 blobs: 1xHxWx64 (raw boxes) "
412 "and 1xHxWxC (class scores)");
415 int constexpr reg_max = 16;
417 for (
size_t idx = 0; idx < outs.size(); idx += 2)
419 cv::Mat
const & bx = outs[idx]; cv::MatSize
const & bx_siz = bx.size;
420 if (bx_siz.dims() != 4 || bx_siz[3] != 4 * reg_max)
LTHROW(
"Output " << idx <<
" is not 4D 1xHxWx64");
421 float const * bx_data = (
float const *)bx.data;
423 cv::Mat
const & cls = outs[idx + 1]; cv::MatSize
const & cls_siz = cls.size;
424 if (cls_siz.dims() != 4)
LTHROW(
"Output " << idx <<
" is not 4D 1xHxWxC");
425 float const * cls_data = (
float const *)cls.data;
426 size_t const nclass = cls_siz[3];
428 for (
int i = 1; i < 3; ++i)
429 if (cls_siz[i] != bx_siz[i])
LTHROW(
"Mismatched HxW sizes for outputs " << idx <<
" .. " << idx + 1);
432 for (
int y = 0; y < cls_siz[1]; ++y)
433 for (
int x = 0; x < cls_siz[2]; ++x)
436 size_t best_idx = 0;
float confidence = cls_data[0];
437 for (
size_t i = 1; i < nclass; ++i)
438 if (cls_data[i] > confidence) { confidence = cls_data[i]; best_idx = i; }
443 if (confidence >= confThreshold)
449 float xmin = (x + 0.5f -
softmax_dfl(bx_data, dst, reg_max)) * stride;
450 float ymin = (y + 0.5f -
softmax_dfl(bx_data + reg_max, dst, reg_max)) * stride;
451 float xmax = (x + 0.5f +
softmax_dfl(bx_data + 2 * reg_max, dst, reg_max)) * stride;
452 float ymax = (y + 0.5f +
softmax_dfl(bx_data + 3 * reg_max, dst, reg_max)) * stride;
455 boxes.push_back(cv::Rect(xmin, ymin, xmax - xmin, ymax - ymin));
456 classIds.push_back(
int(best_idx) + fudge);
457 confidences.push_back(confidence);
462 bx_data += 4 * reg_max;
472 case jevois::dnn::postprocessor::DetectType::YOLOv8:
474 if ((outs.size() % 2) != 0 || msiz.dims() != 4 || msiz[0] != 1)
475 LTHROW(
"Expected several (usually 3, for 3 strides) sets of 2 blobs: 1x64xHxW (raw boxes) "
476 "and 1xCxHxW (class scores)");
479 int constexpr reg_max = 16;
481 for (
size_t idx = 0; idx < outs.size(); idx += 2)
483 cv::Mat
const & bx = outs[idx]; cv::MatSize
const & bx_siz = bx.size;
484 if (bx_siz.dims() != 4 || bx_siz[1] != 4 * reg_max)
LTHROW(
"Output " << idx <<
" is not 4D 1x64xHxW");
485 float const * bx_data = (
float const *)bx.data;
487 cv::Mat
const & cls = outs[idx + 1]; cv::MatSize
const & cls_siz = cls.size;
488 if (cls_siz.dims() != 4)
LTHROW(
"Output " << idx <<
" is not 4D 1xCxHxW");
489 float const * cls_data = (
float const *)cls.data;
490 size_t const nclass = cls_siz[1];
492 for (
int i = 2; i < 4; ++i)
493 if (cls_siz[i] != bx_siz[i])
LTHROW(
"Mismatched HxW sizes for outputs " << idx <<
" .. " << idx + 1);
495 size_t const step = cls_siz[2] * cls_siz[3];
498 for (
int y = 0; y < cls_siz[2]; ++y)
499 for (
int x = 0; x < cls_siz[3]; ++x)
502 size_t best_idx = 0;
float confidence = cls_data[0];
503 for (
size_t i = 1; i < nclass; ++i)
504 if (cls_data[i * step] > confidence) { confidence = cls_data[i * step]; best_idx = i; }
509 if (confidence >= confThreshold)
515 float xmin = (x + 0.5f -
softmax_dfl(bx_data, dst, reg_max, step)) * stride;
516 float ymin = (y + 0.5f -
softmax_dfl(bx_data + reg_max * step, dst, reg_max, step)) * stride;
517 float xmax = (x + 0.5f +
softmax_dfl(bx_data + 2 * reg_max * step, dst, reg_max, step)) * stride;
518 float ymax = (y + 0.5f +
softmax_dfl(bx_data + 3 * reg_max * step, dst, reg_max, step)) * stride;
521 boxes.push_back(cv::Rect(xmin, ymin, xmax - xmin, ymax - ymin));
522 classIds.push_back(
int(best_idx) + fudge);
523 confidences.push_back(confidence);
538 case jevois::dnn::postprocessor::DetectType::YOLOv8seg:
540 if (outs.size() % 3 != 1 || msiz.dims() != 4 || msiz[0] != 1)
541 LTHROW(
"Expected several (usually 3, for 3 strides) sets of 3 tensors: 1x64xHxW (raw boxes), "
542 "1xCxHxW (class scores), and 1xMxHxW (mask coeffs for M masks); then one 1xMxHxW for M mask prototypes");
545 int constexpr reg_max = 16;
548 cv::MatSize
const & mps = outs.back().size;
549 if (mps.dims() != 4)
LTHROW(
"Mask prototypes not 4D 1xMxHxW");
550 mask_proto = cv::Mat(std::vector<int>{ mps[1], mps[2] * mps[3] }, CV_32F, outs.back().data);
551 int const mask_num = mps[1];
552 mask_proto_h = mps[2];
555 for (
size_t idx = 0; idx < outs.size() - 1; idx += 3)
557 cv::Mat
const & bx = outs[idx]; cv::MatSize
const & bx_siz = bx.size;
558 if (bx_siz.dims() != 4 || bx_siz[1] != 4 * reg_max)
LTHROW(
"Output " << idx <<
" is not 4D 1x64xHxW");
559 float const * bx_data = (
float const *)bx.data;
561 cv::Mat
const & cls = outs[idx + 1]; cv::MatSize
const & cls_siz = cls.size;
562 if (cls_siz.dims() != 4)
LTHROW(
"Output " << idx <<
" is not 4D 1xCxHxW");
563 float const * cls_data = (
float const *)cls.data;
564 size_t const nclass = cls_siz[1];
566 cv::Mat
const & msk = outs[idx + 2]; cv::MatSize
const & msk_siz = msk.size;
567 if (msk_siz.dims() != 4 || msk_siz[1] != mask_num)
LTHROW(
"Output " << idx <<
" is not 4D 1xMxHxW");
568 float const * msk_data = (
float const *)msk.data;
570 for (
int i = 2; i < 4; ++i)
571 if (cls_siz[i] != bx_siz[i] || cls_siz[i] != msk_siz[i])
572 LTHROW(
"Mismatched HxW sizes for outputs " << idx <<
" .. " << idx + 1);
574 size_t const step = cls_siz[2] * cls_siz[3];
577 for (
int y = 0; y < cls_siz[2]; ++y)
578 for (
int x = 0; x < cls_siz[3]; ++x)
581 size_t best_idx = 0;
float confidence = cls_data[0];
582 for (
size_t i = 1; i < nclass; ++i)
583 if (cls_data[i * step] > confidence) { confidence = cls_data[i * step]; best_idx = i; }
588 if (confidence >= confThreshold)
593 float xmin = (x + 0.5f -
softmax_dfl(bx_data, dst, reg_max, step)) * stride;
594 float ymin = (y + 0.5f -
softmax_dfl(bx_data + reg_max * step, dst, reg_max, step)) * stride;
595 float xmax = (x + 0.5f +
softmax_dfl(bx_data + 2 * reg_max * step, dst, reg_max, step)) * stride;
596 float ymax = (y + 0.5f +
softmax_dfl(bx_data + 3 * reg_max * step, dst, reg_max, step)) * stride;
599 boxes.push_back(cv::Rect(xmin, ymin, xmax - xmin, ymax - ymin));
600 classIds.push_back(
int(best_idx) + fudge);
601 confidences.push_back(confidence);
604 cv::Mat coeffs(1, mask_num, CV_32F);
float * cptr = (
float *)coeffs.data;
605 for (
int i = 0; i < mask_num; ++i) *cptr++ = msk_data[i * step];
606 mask_coeffs.emplace_back(coeffs);
610 ++cls_data; ++bx_data; ++msk_data;
620 case jevois::dnn::postprocessor::DetectType::YOLOv8segt:
622 if (outs.size() % 3 != 1 || msiz.dims() != 4 || msiz[0] != 1)
623 LTHROW(
"Expected several (usually 3, for 3 strides) sets of 3 tensors: 1xHxWx64 (raw boxes), "
624 "1xHxWxC (class scores), and 1xHxWxM (mask coeffs for M masks); then one 1xHxWxM for M mask prototypes");
627 int constexpr reg_max = 16;
630 cv::MatSize
const & mps = outs.back().size;
631 if (mps.dims() != 4)
LTHROW(
"Mask prototypes not 4D 1xHxWxM");
632 mask_proto = cv::Mat(std::vector<int>{ mps[1] * mps[2], mps[3] }, CV_32F, outs.back().data);
633 int const mask_num = mps[3];
634 mask_proto_h = mps[1];
637 for (
size_t idx = 0; idx < outs.size() - 1; idx += 3)
639 cv::Mat
const & bx = outs[idx]; cv::MatSize
const & bx_siz = bx.size;
640 if (bx_siz.dims() != 4 || bx_siz[3] != 4 * reg_max)
LTHROW(
"Output " << idx <<
" is not 4D 1xHxWx64");
641 float const * bx_data = (
float const *)bx.data;
643 cv::Mat
const & cls = outs[idx + 1]; cv::MatSize
const & cls_siz = cls.size;
644 if (cls_siz.dims() != 4)
LTHROW(
"Output " << idx <<
" is not 4D 1xHxWxC");
645 float const * cls_data = (
float const *)cls.data;
646 size_t const nclass = cls_siz[3];
648 cv::Mat
const & msk = outs[idx + 2]; cv::MatSize
const & msk_siz = msk.size;
649 if (msk_siz.dims() != 4 || msk_siz[3] != mask_num)
LTHROW(
"Output " << idx <<
" is not 4D 1xHxWxM");
650 float const * msk_data = (
float const *)msk.data;
652 for (
int i = 1; i < 3; ++i)
653 if (cls_siz[i] != bx_siz[i] || cls_siz[i] != msk_siz[i])
654 LTHROW(
"Mismatched HxW sizes for outputs " << idx <<
" .. " << idx + 1);
657 for (
int y = 0; y < cls_siz[1]; ++y)
658 for (
int x = 0; x < cls_siz[2]; ++x)
661 size_t best_idx = 0;
float confidence = cls_data[0];
662 for (
size_t i = 1; i < nclass; ++i)
663 if (cls_data[i] > confidence) { confidence = cls_data[i]; best_idx = i; }
668 if (confidence >= confThreshold)
673 float xmin = (x + 0.5f -
softmax_dfl(bx_data, dst, reg_max)) * stride;
674 float ymin = (y + 0.5f -
softmax_dfl(bx_data + reg_max, dst, reg_max)) * stride;
675 float xmax = (x + 0.5f +
softmax_dfl(bx_data + 2 * reg_max, dst, reg_max)) * stride;
676 float ymax = (y + 0.5f +
softmax_dfl(bx_data + 3 * reg_max, dst, reg_max)) * stride;
679 boxes.push_back(cv::Rect(xmin, ymin, xmax - xmin, ymax - ymin));
680 classIds.push_back(
int(best_idx) + fudge);
681 confidences.push_back(confidence);
684 cv::Mat coeffs(mask_num, 1, CV_32F);
685 std::memcpy(coeffs.data, msk_data, mask_num *
sizeof(
float));
686 mask_coeffs.emplace_back(coeffs);
691 bx_data += 4 * reg_max;
692 msk_data += mask_num;
704 LTHROW(
"Unsupported Post-processor detecttype " <<
int(detecttype::get()));
708 catch (std::exception
const & e)
710 std::string err =
"Selected detecttype is " + detecttype::strget() +
" and network produced:\n\n";
712 err +=
"\nFATAL ERROR(s):\n\n";
718 std::vector<int> indices;
719 if (nmsperclass::get())
720 cv::dnn::NMSBoxesBatched(boxes, confidences, classIds, confThreshold, nmsThreshold, indices, 1.0F, maxnbox::get());
722 cv::dnn::NMSBoxes(boxes, confidences, confThreshold, nmsThreshold, indices, 1.0F, maxnbox::get());
725 itsDetections.clear();
bool namonly = namedonly::get();
726 std::vector<cv::Vec4i> contour_hierarchy;
728 for (
size_t i = 0; i < indices.size(); ++i)
730 int idx = indices[i];
732 if (namonly ==
false || label.empty() ==
false)
734 cv::Rect & b = boxes[idx];
740 std::vector<cv::Point> poly;
741 if (mask_coeffs.empty() ==
false)
745 cv::Mat weighted_mask;
746 if (mask_coeffs[idx].rows == 1) weighted_mask = mask_coeffs[idx] * mask_proto;
747 else weighted_mask = mask_proto * mask_coeffs[idx];
750 weighted_mask = weighted_mask.reshape(0, mask_proto_h);
759 int mask_scale = bsiz.height / mask_proto_h;
762 cv::Mat src = weighted_mask;
763 cv::resize(src, weighted_mask, cv::Size(), mask_scale, mask_scale, cv::INTER_LINEAR);
767 cv::Rect scaled_rect(b.tl() / mask_scale, b.br() / mask_scale);
768 scaled_rect &= cv::Rect(cv::Point(0, 0), weighted_mask.size());
771 cv::Mat roi_mask; cv::threshold(weighted_mask(scaled_rect), roi_mask, 0.5, 255.0, cv::THRESH_BINARY);
772 cv::Mat roi_u8; roi_mask.convertTo(roi_u8, CV_8U);
775 std::vector<std::vector<cv::Point>> polys;
776 cv::findContours(roi_u8, polys, contour_hierarchy, cv::RETR_EXTERNAL,
777 cv::CHAIN_APPROX_SIMPLE, scaled_rect.tl());
780 size_t polyidx = 0;
size_t largest_poly_size = 0;
size_t j = 0;
781 for (
auto const & p : polys)
783 if (p.size() > largest_poly_size) { largest_poly_size = p.size(); polyidx = j; }
788 if (polys.empty() ==
false)
789 for (cv::Point & pt : polys[polyidx])
791 float x = pt.x * mask_scale, y = pt.y * mask_scale;
793 poly.emplace_back(cv::Point(x, y));
798 cv::Point2f tl = b.tl(); preproc->
b2i(tl.x, tl.y);
799 cv::Point2f br = b.br(); preproc->
b2i(br.x, br.y);
800 b.x = tl.x; b.y = tl.y; b.width = br.x - tl.x; b.height = br.y - tl.y;
804 std::vector<jevois::ObjReco> ov;
807 itsDetections.emplace_back(od);