64#define OFFSET(x) offsetof(DnnDetectContext, dnnctx.x)
65#define OFFSET2(x) offsetof(DnnDetectContext, x)
66#define FLAGS AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM
69#if (CONFIG_LIBTENSORFLOW == 1)
72#if (CONFIG_LIBOPENVINO == 1)
75#if (CONFIG_LIBONNXRUNTIME == 1)
81 {
"ssd",
"output shape [1, 1, N, 7]", 0,
AV_OPT_TYPE_CONST, { .i64 =
DDMT_SSD }, 0, 0,
FLAGS, .unit =
"model_type" },
82 {
"yolo",
"output shape [1, N*Cx*Cy*DetectionBox]", 0,
AV_OPT_TYPE_CONST, { .i64 =
DDMT_YOLOV1V2 }, 0, 0,
FLAGS, .unit =
"model_type" },
83 {
"yolov3",
"outputs shape [1, N*D, Cx, Cy]", 0,
AV_OPT_TYPE_CONST, { .i64 =
DDMT_YOLOV3 }, 0, 0,
FLAGS, .unit =
"model_type" },
84 {
"yolov4",
"outputs shape [1, N*D, Cx, Cy]", 0,
AV_OPT_TYPE_CONST, { .i64 =
DDMT_YOLOV4 }, 0, 0,
FLAGS, .unit =
"model_type" },
95 return 1.f / (1.f +
exp(-x));
106 for (
int i = 0;
i < nb_classes;
i++) {
107 if (label_data[
i * cell_size] > max_prob) {
108 max_prob = label_data[
i * cell_size];
135 double scaled = conf * 10000.0;
138 if (scaled > INT_MAX)
146 double x1,
double y1,
int frame_w,
int frame_h)
148 double lo_x = -1.0 * frame_w, hi_x = 2.0 * frame_w;
149 double lo_y = -1.0 * frame_h, hi_y = 2.0 * frame_h;
170 double x1_min = bbox1->
x, y1_min = bbox1->
y;
171 double x1_max = (
double)bbox1->
x + bbox1->
w, y1_max = (
double)bbox1->
y + bbox1->
h;
172 double x2_min = bbox2->
x, y2_min = bbox2->
y;
173 double x2_max = (
double)bbox2->
x + bbox2->
w, y2_max = (
double)bbox2->
y + bbox2->
h;
174 double overlapping_width =
FFMIN(x1_max, x2_max) -
FFMAX(x1_min, x2_min);
175 double overlapping_height =
FFMIN(y1_max, y2_max) -
FFMAX(y1_min, y2_min);
176 double intersection_area =
177 (overlapping_width < 0 || overlapping_height < 0) ? 0 : overlapping_height * overlapping_width;
180 double union_area =
area1 +
area2 - intersection_area;
182 if (
area1 <= 0 ||
area2 <= 0 || union_area <= 0)
184 return (
float)(intersection_area / union_area);
191 float conf_threshold =
ctx->confidence;
192 int detection_boxes, box_size;
193 int cell_w = 0, cell_h = 0, scale_w = 0, scale_h = 0;
194 int nb_classes =
ctx->nb_classes;
202 if (output[output_index].dims[0] != 1) {
204 "YOLO output batch dimension must be 1, got %d\n",
205 output[output_index].dims[0]);
210 cell_w =
ctx->cell_w;
211 cell_h =
ctx->cell_h;
215 if (output[output_index].dims[2] != output[output_index].dims[3] &&
216 output[output_index].dims[2] == output[output_index].dims[1]) {
218 cell_w = output[output_index].
dims[2];
219 cell_h = output[output_index].
dims[1];
221 cell_w = output[output_index].
dims[3];
222 cell_h = output[output_index].
dims[2];
224 scale_w =
ctx->scale_width;
225 scale_h =
ctx->scale_height;
227 switch (
ctx->model_type) {
230 post_process_raw_data =
linear;
233 post_process_raw_data =
sigmoid;
237 if (cell_h <= 0 || cell_w <= 0) {
242 if (nb_classes <= 0) {
247 if (output[output_index].dims[1] <= 0 || output[output_index].dims[2] <= 0 ||
248 output[output_index].dims[3] <= 0) {
253 size_t box_size_sz = (size_t)nb_classes + 5;
254 size_t cell_area, elems_per_box,
tmp, total_elems, detection_boxes_sz;
256 if (
av_size_mult((
size_t)cell_w, (
size_t)cell_h, &cell_area) < 0 ||
257 av_size_mult(box_size_sz, cell_area, &elems_per_box) < 0 ||
258 elems_per_box == 0 || elems_per_box > INT_MAX) {
264 (
size_t)output[output_index].dims[2], &
tmp) < 0 ||
265 av_size_mult(
tmp, (
size_t)output[output_index].dims[3], &total_elems) < 0 ||
266 total_elems > INT_MAX) {
271 if (total_elems % elems_per_box) {
276 detection_boxes_sz = total_elems / elems_per_box;
277 if (detection_boxes_sz == 0 || detection_boxes_sz > INT_MAX) {
282 box_size = (int)box_size_sz;
283 detection_boxes = (int)detection_boxes_sz;
285 anchors_needed = (
int64_t)detection_boxes * 2;
286 if (anchors_needed < 0 || *anchor_used < 0 ||
287 *anchor_used + anchors_needed >
ctx->nb_anchor) {
289 "anchors array (%d floats) is too small for %d detection box(es) "
290 "in output %d (needs %"PRId64
" floats starting at offset %"PRId64
")\n",
291 ctx->nb_anchor, detection_boxes, output_index, anchors_needed, *anchor_used);
294 anchors =
ctx->anchors + *anchor_used;
295 *anchor_used += anchors_needed;
297 for (
int box_id = 0; box_id < detection_boxes; box_id++) {
298 for (
int cx = 0; cx < cell_w; cx++)
299 for (
int cy = 0; cy < cell_h; cy++) {
300 float x, y,
w,
h, conf;
301 float *detection_boxes_data;
306 ((cy * cell_w + cx) * detection_boxes + box_id) * box_size;
307 conf = post_process_raw_data(detection_boxes_data[4]);
309 detection_boxes_data =
output_data + box_id * box_size * cell_w * cell_h;
310 conf = post_process_raw_data(
311 detection_boxes_data[cy * cell_w + cx + 4 * cell_w * cell_h]);
315 x = post_process_raw_data(detection_boxes_data[0]);
316 y = post_process_raw_data(detection_boxes_data[1]);
317 w = detection_boxes_data[2];
318 h = detection_boxes_data[3];
320 conf = conf * post_process_raw_data(detection_boxes_data[label_id + 5]);
322 x = post_process_raw_data(detection_boxes_data[cy * cell_w + cx]);
323 y = post_process_raw_data(detection_boxes_data[cy * cell_w + cx + cell_w * cell_h]);
324 w = detection_boxes_data[cy * cell_w + cx + 2 * cell_w * cell_h];
325 h = detection_boxes_data[cy * cell_w + cx + 3 * cell_w * cell_h];
327 detection_boxes_data + cy * cell_w + cx + 5 * cell_w * cell_h);
328 conf = conf * post_process_raw_data(
329 detection_boxes_data[cy * cell_w + cx + (label_id + 5) * cell_w * cell_h]);
331 if (!
isfinite(conf) || conf < conf_threshold) {
339 double w_px =
exp((
double)
w) * anchors[box_id * 2] *
frame->width / scale_w;
340 double h_px =
exp((
double)
h) * anchors[box_id * 2 + 1] *
frame->height / scale_h;
341 double x_px = (cx + (
double)x) / cell_w *
frame->width - w_px / 2;
342 double y_px = (cy + (
double)y) / cell_h *
frame->height - h_px / 2;
348 if (
ctx->labels && label_id < ctx->label_count) {
367 float conf_threshold =
ctx->confidence;
405 memcpy(bbox, candidate_bbox,
sizeof(*bbox));
431 for (
int i = 0;
i < nb_outputs;
i++) {
446 float conf_threshold =
ctx->confidence;
447 int proposal_count = 0;
449 int detect_output_idx = 0;
450 int label_output_idx = -1;
451 float *detections =
NULL, *labels =
NULL;
455 int scale_w =
ctx->scale_width;
456 int scale_h =
ctx->scale_height;
457 size_t detect_elems, needed_elems;
459 if (nb_outputs == 1 && output->
dims[3] == 7) {
460 detect_output_idx = 0;
461 proposal_count = output->
dims[2];
462 detect_size = output->
dims[3];
463 detections = output->
data;
464 }
else if (nb_outputs == 2 && output[0].dims[3] == 5) {
465 detect_output_idx = 0;
466 proposal_count = output[0].
dims[2];
467 detect_size = output[0].
dims[3];
468 detections = output[0].
data;
469 labels = output[1].
data;
470 label_output_idx = 1;
471 }
else if (nb_outputs == 2 && output[1].dims[3] == 5) {
472 detect_output_idx = 1;
473 proposal_count = output[1].
dims[2];
474 detect_size = output[1].
dims[3];
475 detections = output[1].
data;
476 labels = output[0].
data;
477 label_output_idx = 0;
483 if (proposal_count < 0) {
488 if (proposal_count == 0)
491 if (
av_size_mult((
size_t)proposal_count, (
size_t)detect_size,
492 &needed_elems) < 0) {
496 if (needed_elems > INT_MAX) {
498 "detection tensor has %zu elements, more than the supported maximum\n",
503 if (
av_size_mult((
size_t)output[detect_output_idx].dims[0],
504 (
size_t)output[detect_output_idx].dims[1], &detect_elems) < 0 ||
505 av_size_mult(detect_elems, (
size_t)output[detect_output_idx].dims[2], &detect_elems) < 0 ||
506 av_size_mult(detect_elems, (
size_t)output[detect_output_idx].dims[3], &detect_elems) < 0) {
510 if (detect_elems != needed_elems) {
512 "detection tensor has %zu elements, expected %zu\n",
513 detect_elems, needed_elems);
517 if (label_output_idx >= 0) {
519 if (
av_size_mult((
size_t)output[label_output_idx].dims[0],
520 (
size_t)output[label_output_idx].dims[1], &label_count) < 0 ||
521 av_size_mult(label_count, (
size_t)output[label_output_idx].dims[2], &label_count) < 0 ||
522 av_size_mult(label_count, (
size_t)output[label_output_idx].dims[3], &label_count) < 0) {
526 if (label_count < (
size_t)proposal_count) {
528 "labels tensor has %zu element(s), too small for %d proposal(s)\n",
529 label_count, proposal_count);
534 for (
int i = 0;
i < proposal_count; ++
i) {
537 conf = detections[
i * detect_size + 2];
539 conf = detections[
i * detect_size + 4];
540 if (!
isfinite(conf) || conf < conf_threshold) {
546 if (nb_bboxes == 0) {
559 for (
int i = 0;
i < proposal_count; ++
i) {
561 float conf, x0, y0, x1, y1;
562 double x0_px, y0_px, x1_px, y1_px;
564 if (nb_outputs == 1) {
566 conf = detections[
i * detect_size + 2];
567 x0 = detections[
i * detect_size + 3];
568 y0 = detections[
i * detect_size + 4];
569 x1 = detections[
i * detect_size + 5];
570 y1 = detections[
i * detect_size + 6];
573 x0 = detections[
i * detect_size] / scale_w;
574 y0 = detections[
i * detect_size + 1] / scale_h;
575 x1 = detections[
i * detect_size + 2] / scale_w;
576 y1 = detections[
i * detect_size + 3] / scale_h;
577 conf = detections[
i * detect_size + 4];
580 if (!
isfinite(conf) || conf < conf_threshold) {
597 if (
ctx->labels && label_id >= 0 && label_id < ctx->label_count) {
604 if (nb_bboxes == 0) {
624 switch (
ctx->model_type) {
649 float conf_threshold =
ctx->confidence;
650 float *conf, *position, *label_id, x0, y0, x1, y1;
656 proposal_count = *(
float *)(output[0].
data);
657 conf = output[1].
data;
658 position = output[3].
data;
659 label_id = output[2].
data;
667 for (
int i = 0;
i < proposal_count; ++
i) {
668 if (conf[
i] < conf_threshold)
673 if (nb_bboxes == 0) {
686 for (
int i = 0;
i < proposal_count; ++
i) {
688 y0 = position[
i * 4];
689 x0 = position[
i * 4 + 1];
690 y1 = position[
i * 4 + 2];
691 x1 = position[
i * 4 + 3];
695 if (conf[
i] < conf_threshold) {
699 bbox->
x = (int)(x0 *
frame->width);
700 bbox->
w = (int)(x1 *
frame->width) - bbox->
x;
701 bbox->
y = (int)(y0 *
frame->height);
702 bbox->
h = (int)(y1 *
frame->height) - bbox->
y;
708 if (
ctx->labels && label_id_i >= 0 && label_id_i < ctx->label_count) {
715 if (nb_bboxes == 0) {
741 for (
int i = 0;
i <
ctx->label_count;
i++) {
744 ctx->label_count = 0;
760 while (!feof(file)) {
763 if (!fgets(buf, 256, file)) {
767 line_len = strlen(buf);
769 int i = line_len - 1;
770 if (buf[
i] ==
'\n' || buf[
i] ==
'\r' || buf[
i] ==
' ') {
808 switch(backend_type) {
810 if (output_nb != 4) {
812 but get %d instead\n", output_nb);
836 if (using_yolo && !
ctx->anchors) {
848 if (!
ctx->bboxes_fifo)
852 if (
ctx->labels_filename) {
891 *out_pts = in_frame->
pts +
pts;
960 if (
ctx->bboxes_fifo) {
976 int ret, width_idx, height_idx;
985 ctx->scale_width = model_input.
dims[width_idx] == -1 ? inlink->
w :
986 model_input.
dims[width_idx];
987 ctx->scale_height = model_input.
dims[height_idx] == -1 ? inlink->
h :
988 model_input.
dims[height_idx];
1002 .p.name =
"dnn_detect",
1004 .p.priv_class = &dnn_detect_class,
static int config_input(AVFilterLink *inlink)
const FFFilter ff_vf_dnn_detect
static AVFormatContext * ctx
int ff_inlink_acknowledge_status(AVFilterLink *link, int *rstatus, int64_t *rpts)
Test and acknowledge the change of status on the link.
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
int ff_inlink_consume_frame(AVFilterLink *link, AVFrame **rframe)
Take a frame from the link's FIFO and update the link's stats.
#define i(width, name, range_min, range_max)
common internal and external API header
AVDetectionBBoxHeader * av_detection_bbox_create_side_data(AVFrame *frame, uint32_t nb_bboxes)
Allocates memory for AVDetectionBBoxHeader, plus an array of nb_bboxes AVDetectionBBox,...
#define AV_DETECTION_BBOX_LABEL_NAME_MAX_SIZE
static av_always_inline AVDetectionBBox * av_get_detection_bbox(const AVDetectionBBoxHeader *header, unsigned int idx)
int ff_dnn_set_detect_post_proc(DnnContext *ctx, DetectPostProc post_proc)
void ff_dnn_uninit(DnnContext *ctx)
DNNAsyncStatusType ff_dnn_get_result(DnnContext *ctx, AVFrame **in_frame, AVFrame **out_frame)
int ff_dnn_execute_model(DnnContext *ctx, AVFrame *in_frame, AVFrame *out_frame)
int ff_dnn_init(DnnContext *ctx, DNNFunctionType func_type, AVFilterContext *filter_ctx)
int ff_dnn_get_input(DnnContext *ctx, DNNData *input)
int ff_dnn_flush(DnnContext *ctx)
int ff_dnn_filter_init_child_class(AVFilterContext *filter)
common functions for the dnn based filters
#define AVFILTER_DNN_DEFINE_CLASS(fname, backend_mask)
static int dnn_get_height_idx_by_layout(DNNLayout layout)
static int dnn_get_width_idx_by_layout(DNNLayout layout)
int(* init)(AVBSFContext *ctx)
@ AV_OPT_TYPE_CONST
Special option type for declaring named constants.
@ AV_OPT_TYPE_FLAG_ARRAY
May be combined with another regular option type to declare an array option.
@ AV_OPT_TYPE_INT
Underlying C type is int.
@ AV_OPT_TYPE_FLOAT
Underlying C type is float.
@ AV_OPT_TYPE_STRING
Underlying C type is a uint8_t* that is either NULL or points to a C string allocated with the av_mal...
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
#define AVERROR_EOF
End of file.
AVFifo * av_fifo_alloc2(size_t nb_elems, size_t elem_size, unsigned int flags)
Allocate and initialize an AVFifo with a given element size.
void av_fifo_freep2(AVFifo **f)
Free an AVFifo and reset pointer to NULL.
#define AV_FIFO_FLAG_AUTO_GROW
Automatically resize the FIFO on writes, so that the data fits.
size_t av_fifo_can_read(const AVFifo *f)
int av_fifo_peek(const AVFifo *f, void *buf, size_t nb_elems, size_t offset)
Read data from a FIFO without modifying FIFO state.
int av_fifo_write(AVFifo *f, const void *buf, size_t nb_elems)
Write data into a FIFO.
int av_fifo_read(AVFifo *f, void *buf, size_t nb_elems)
Read data from a FIFO.
AVFrameSideData * av_frame_get_side_data(const AVFrame *frame, enum AVFrameSideDataType type)
@ AV_FRAME_DATA_DETECTION_BBOXES
Bounding boxes for object detection and classification, as described by AVDetectionBBoxHeader.
#define AV_LOG_VERBOSE
Detailed information.
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
static AVRational av_make_q(int num, int den)
Create an AVRational.
static int av_cmp_q(AVRational a, AVRational b)
Compare two rationals.
int av_dynarray_add_nofree(void *tab_ptr, int *nb_ptr, void *elem)
Add an element to a dynamic array.
int av_size_mult(size_t a, size_t b, size_t *r)
Multiply two size_t values checking for overflow.
size_t av_strlcpy(char *dst, const char *src, size_t size)
Copy the string src to dst, but no more than size - 1 bytes, and null-terminate dst.
static int linear(InterplayACMContext *s, unsigned ind, unsigned col)
static av_cold void uninit(AVBitStreamFilterContext *ctx)
static int output_data(MLPDecodeContext *m, unsigned int substr, AVFrame *frame, int *got_frame_ptr)
Write the audio data into the output buffer.
#define FILTER_INPUTS(array)
#define FILTER_OUTPUTS(array)
#define FF_FILTER_FORWARD_WANTED(outlink, inlink)
Forward the frame_wanted_out flag from an output link to an input link.
#define FILTER_PIXFMTS_ARRAY(array)
static void ff_outlink_set_status(AVFilterLink *link, int status, int64_t pts)
Set the status field of a link from the source filter.
#define FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink)
Forward the status on an output link to an input link.
FILE * avpriv_fopen_utf8(const char *path, const char *mode)
Open a file using a UTF-8 filename.
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
void avpriv_report_missing_feature(void *avc, const char *msg,...) av_printf_format(2
Log a generic warning message about a missing feature.
static enum AVPixelFormat pix_fmts[]
Memory handling functions.
#define AV_PIX_FMT_GRAYF32
AVPixelFormat
Pixel format.
@ AV_PIX_FMT_NV12
planar YUV 4:2:0, 12bpp, 1 plane for Y and 1 plane for the UV components, which are interleaved (firs...
@ AV_PIX_FMT_RGB24
packed RGB 8:8:8, 24bpp, RGBRGB...
@ AV_PIX_FMT_YUV420P
planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
@ AV_PIX_FMT_YUV422P
planar YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples)
@ AV_PIX_FMT_GRAY8
Y , 8bpp.
@ AV_PIX_FMT_YUV410P
planar YUV 4:1:0, 9bpp, (1 Cr & Cb sample per 4x4 Y samples)
@ AV_PIX_FMT_YUV411P
planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples)
@ AV_PIX_FMT_YUV444P
planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples)
@ AV_PIX_FMT_BGR24
packed RGB 8:8:8, 24bpp, BGRBGR...
static const uint8_t header[24]
static av_cold int preinit(AVBitStreamFilterContext *ctx)
Describe the class of an AVClass context structure.
char detect_label[AV_DETECTION_BBOX_LABEL_NAME_MAX_SIZE]
Detect result with confidence.
int x
Distance in pixels from the left/top edge of the frame, together with width and height,...
AVRational detect_confidence
void * priv
private data for use by the filter
A link between two filters.
int w
agreed upon image width
int h
agreed upon image height
AVFilterContext * src
source filter
AVFilterContext * dst
dest filter
A filter pad used for either input or output.
Structure to hold side data for an AVFrame.
This structure describes decoded (raw) audio or video data.
int64_t pts
Presentation timestamp in time_base units (time when frame should be shown to user).
May be set as default_val for AV_OPT_TYPE_FLAG_ARRAY options.
DNNBackendType backend_type
DNNDetectionModelType model_type
int av_usleep(unsigned usec)
Sleep for a period of time.
static FilteringContext * filter_ctx
static const AVFilterPad dnn_detect_inputs[]
static int read_detect_label_file(AVFilterContext *context)
static float sigmoid(float x)
static const AVOption dnn_detect_options[]
static float dnn_detect_IOU(AVDetectionBBox *bbox1, AVDetectionBBox *bbox2)
static int dnn_detect_flush_frame(AVFilterLink *outlink, int64_t pts, int64_t *out_pts)
static int config_input(AVFilterLink *inlink)
static int dnn_detect_parse_yolo_output(AVFrame *frame, DNNData *output, int output_index, AVFilterContext *filter_ctx, int64_t *anchor_used)
static int check_output_nb(DnnDetectContext *ctx, DNNBackendType backend_type, int output_nb)
static const AVOptionArrayDef anchor_array_def
static int dnn_detect_confidence_num(double conf)
static int dnn_detect_float_to_coord(double v)
static float linear(float x)
static av_cold int dnn_detect_init(AVFilterContext *context)
static int dnn_detect_post_proc_anchored(AVFrame *frame, DNNData *output, int nb_outputs, AVFilterContext *filter_ctx)
static void dnn_detect_set_bbox_edges(AVDetectionBBox *bbox, double x0, double y0, double x1, double y1, int frame_w, int frame_h)
static void free_detect_labels(DnnDetectContext *ctx)
static int dnn_detect_fill_side_data(AVFrame *frame, AVFilterContext *filter_ctx)
static av_cold void dnn_detect_uninit(AVFilterContext *context)
static int dnn_detect_activate(AVFilterContext *filter_ctx)
static int dnn_detect_get_label_id(int nb_classes, int cell_size, float *label_data)
static int dnn_detect_post_proc_ssd(AVFrame *frame, DNNData *output, int nb_outputs, AVFilterContext *filter_ctx)
static int dnn_detect_post_proc_yolo(AVFrame *frame, DNNData *output, AVFilterContext *filter_ctx)
static int dnn_detect_post_proc_tf(AVFrame *frame, DNNData *output, AVFilterContext *filter_ctx)
static int dnn_detect_label_id_from_float(float f)
static int dnn_detect_post_proc(AVFrame *frame, DNNData *output, uint32_t nb, AVFilterContext *filter_ctx)
static int dnn_detect_post_proc_yolov3(AVFrame *frame, DNNData *output, AVFilterContext *filter_ctx, int nb_outputs)
const AVFilterPad ff_video_default_filterpad[1]
An AVFilterPad array whose only entry has name "default" and is of type AVMEDIA_TYPE_VIDEO.