[FFmpeg-devel] [PATCH v3 5/5] avfilter/vf_libopencv: add opencv drawbox filter
lance.lmwang at gmail.com
lance.lmwang at gmail.com
Mon May 18 17:22:46 EEST 2020
From: Limin Wang <lance.lmwang at gmail.com>
Signed-off-by: Limin Wang <lance.lmwang at gmail.com>
---
depend on below patchset:
https://patchwork.ffmpeg.org/project/ffmpeg/list/?series=1212
doc/filters.texi | 21 ++++++
libavfilter/vf_libopencv.c | 147 +++++++++++++++++++++++++++++++++++--
2 files changed, 162 insertions(+), 6 deletions(-)
diff --git a/doc/filters.texi b/doc/filters.texi
index e12c667348..cac204fd81 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -14219,6 +14219,27 @@ Display width and height of every faces, face_id is the face index
which is range from [0, nb_faces-1]
@end table
+ at subsection drawbox
+draw all boxes by the detected metadata results of the ocv filter's
+facedetect mode. If no face detection metadata exists, then the filter
+will do nothing.
+
+The filter takes the following parameters:
+ at var{color}|@var{thickness}|@var{line_type}|@var{shift}.
+
+ at var{color} Specify the color of the box to write. For the general syntax of this option,
+check the @ref{color syntax,,"Color" section in the ffmpeg-utils manual,ffmpeg-utils}.
+
+ at var{thickness}
+Set the thickness of the box edge. Default value is @code{1}.
+Negative values, like -1, mean that the function has to draw a filled rectangle.
+
+ at var{line_type}
+Set the line type of the box boundary. Default value is @code{8}.
+
+ at var{shift}
+Set the number of fractional bits in the point coordinates. Default value is @code{0}.
+
@section oscilloscope
2D Video Oscilloscope.
diff --git a/libavfilter/vf_libopencv.c b/libavfilter/vf_libopencv.c
index c70c4dc8b9..2e23222cb4 100644
--- a/libavfilter/vf_libopencv.c
+++ b/libavfilter/vf_libopencv.c
@@ -42,6 +42,7 @@
#include "libavutil/common.h"
#include "libavutil/file.h"
#include "libavutil/opt.h"
+#include "libavutil/parseutils.h"
#include "avfilter.h"
#include "formats.h"
#include "internal.h"
@@ -90,6 +91,7 @@ typedef struct OCVContext {
void (*uninit)(AVFilterContext *ctx);
void (*end_frame_filter)(AVFilterContext *ctx, IplImage *inimg, IplImage *outimg);
void (*postprocess)(AVFilterContext *ctx, AVFrame *out);
+ void (*preprocess)(AVFilterContext *ctx, AVFrame *in);
void *priv;
} OCVContext;
@@ -466,6 +468,127 @@ static void facedetect_postprocess(AVFilterContext *ctx, AVFrame *out)
}
}
+typedef struct DrawboxContext {
+ CvScalar color;
+ int thickness;
+ int line_type;
+ int shift;
+
+ int nb_faces;
+ CvRect *faces[1024];
+} DrawboxContext;
+
+static av_cold int drawbox_init(AVFilterContext *ctx, const char *args)
+{
+ OCVContext *s = ctx->priv;
+ DrawboxContext *drawbox = s->priv;
+ const char *buf = args;
+ int ret;
+ uint8_t rgba[4] = { 255, 0, 0, 255};
+ char color_str[32] = "Red";
+
+ drawbox->thickness = 1;
+ drawbox->line_type = 8;
+ drawbox->shift = 0;
+ if (args) {
+ sscanf(args, "%32[^|]|%d|%d|%d", color_str, &drawbox->thickness, &drawbox->line_type, &drawbox->shift);
+ }
+
+ if (av_parse_color(rgba, color_str, -1, ctx) < 0) {
+ av_log(ctx, AV_LOG_ERROR, "failed to get color \n");
+ return AVERROR(EINVAL);
+ }
+ drawbox->color = cvScalar(rgba[0], rgba[1], rgba[2], rgba[3]);
+
+ av_log(ctx, AV_LOG_TRACE, "rgba: %d:%d:%d:%d, thickness: %d, line_type: %d, shift: %d \n",
+ rgba[0], rgba[1], rgba[2], rgba[3], drawbox->thickness, drawbox->line_type, drawbox->shift);
+
+ return 0;
+}
+
+static void drawbox_preprocess(AVFilterContext *ctx, AVFrame *in)
+{
+ OCVContext *s = ctx->priv;
+ DrawboxContext *drawbox = s->priv;
+ AVDictionaryEntry *ef, *ex, *ey, *ew, *eh;
+ char key2[128];
+ AVDictionary *metadata = in->metadata;
+ int nb_faces = 0;
+
+ ef = av_dict_get(metadata, "lavfi.facedetect.nb_faces", NULL, AV_DICT_MATCH_CASE);
+ if (ef) {
+ nb_faces = strtol(ef->value, NULL, 10);
+ }
+
+ if (nb_faces > 0) {
+ drawbox->nb_faces = nb_faces;
+ for (int i = 0; i < nb_faces && i < sizeof(drawbox->faces); i++ ) {
+ CvRect *tmp;
+
+ tmp = av_realloc(drawbox->faces[i], sizeof(*tmp));
+ if (!tmp)
+ return AVERROR(ENOMEM);
+ drawbox->faces[i] = tmp;
+
+ snprintf(key2, sizeof(key2), "lavfi.facedetect.%d.%s", i, "x");
+ ex = av_dict_get(metadata, key2, NULL, AV_DICT_MATCH_CASE);
+
+ snprintf(key2, sizeof(key2), "lavfi.facedetect.%d.%s", i, "y");
+ ey = av_dict_get(metadata, key2, NULL, AV_DICT_MATCH_CASE);
+
+ snprintf(key2, sizeof(key2), "lavfi.facedetect.%d.%s", i, "w");
+ ew = av_dict_get(metadata, key2, NULL, AV_DICT_MATCH_CASE);
+
+ snprintf(key2, sizeof(key2), "lavfi.facedetect.%d.%s", i, "h");
+ eh = av_dict_get(metadata, key2, NULL, AV_DICT_MATCH_CASE);
+
+ if (ex && ey && ew && eh) {
+ tmp->x = strtol(ex->value, NULL, 10);
+ tmp->y = strtol(ey->value, NULL, 10);
+ tmp->width = strtol(ew->value, NULL, 10);
+ tmp->height = strtol(eh->value, NULL, 10);
+ }
+ }
+ }
+}
+
+static av_cold void drawbox_uninit(AVFilterContext *ctx)
+{
+ OCVContext *s = ctx->priv;
+ DrawboxContext *drawbox = s->priv;
+
+ for (int i = 0; i < drawbox->nb_faces; i++ ) {
+ av_freep(&drawbox->faces[i]);
+ }
+}
+
+static void draw_rectangle(AVFilterContext *ctx, IplImage *img, CvPoint pt1, CvPoint pt2) {
+ OCVContext *s = ctx->priv;
+ DrawboxContext *drawbox = s->priv;
+
+ cvRectangle(img, pt1, pt2, drawbox->color, drawbox->thickness, drawbox->line_type, drawbox->shift);
+}
+
+static void drawbox_end_frame_filter(AVFilterContext *ctx, IplImage *inimg, IplImage *outimg)
+{
+ OCVContext *s = ctx->priv;
+ DrawboxContext *drawbox = s->priv;
+
+ for (int i = 0; i < drawbox->nb_faces; i++ ) {
+ CvPoint pt1, pt2;
+ CvRect *face = drawbox->faces[i];
+
+ if (face) {
+ pt1.x = face->x;
+ pt1.y = face->y;
+ pt2.x = face->x + face->width;
+ pt2.y = face->y + face->height;
+
+ draw_rectangle(ctx, inimg, pt1, pt2);
+ }
+ }
+}
+
typedef struct OCVFilterEntry {
const char *name;
size_t priv_size;
@@ -473,13 +596,15 @@ typedef struct OCVFilterEntry {
void (*uninit)(AVFilterContext *ctx);
void (*end_frame_filter)(AVFilterContext *ctx, IplImage *inimg, IplImage *outimg);
void (*postprocess)(AVFilterContext *ctx, AVFrame *out);
+ void (*preprocess)(AVFilterContext *ctx, AVFrame *in);
} OCVFilterEntry;
static const OCVFilterEntry ocv_filter_entries[] = {
- { "dilate", sizeof(DilateContext), dilate_init, dilate_uninit, dilate_end_frame_filter, NULL },
- { "erode", sizeof(DilateContext), dilate_init, dilate_uninit, erode_end_frame_filter, NULL },
- { "smooth", sizeof(SmoothContext), smooth_init, NULL, smooth_end_frame_filter, NULL },
- { "facedetect", sizeof(FaceDetectContext), facedetect_init, facedetect_uninit, facedetect_end_frame_filter, facedetect_postprocess },
+ { "dilate", sizeof(DilateContext), dilate_init, dilate_uninit, dilate_end_frame_filter, NULL, NULL },
+ { "erode", sizeof(DilateContext), dilate_init, dilate_uninit, erode_end_frame_filter, NULL, NULL},
+ { "smooth", sizeof(SmoothContext), smooth_init, NULL, smooth_end_frame_filter, NULL, NULL},
+ { "facedetect", sizeof(FaceDetectContext), facedetect_init, facedetect_uninit, facedetect_end_frame_filter, NULL, facedetect_postprocess},
+ { "drawbox", sizeof(DrawboxContext), drawbox_init, drawbox_uninit, drawbox_end_frame_filter, drawbox_preprocess, NULL},
};
static av_cold int init(AVFilterContext *ctx)
@@ -498,6 +623,7 @@ static av_cold int init(AVFilterContext *ctx)
s->uninit = entry->uninit;
s->end_frame_filter = entry->end_frame_filter;
s->postprocess = entry->postprocess;
+ s->preprocess = entry->preprocess;
if (!(s->priv = av_mallocz(entry->priv_size)))
return AVERROR(ENOMEM);
@@ -538,12 +664,21 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
out = in;
}
+ if (s->preprocess) {
+ s->preprocess(ctx, in);
+ }
+
fill_iplimage_from_frame(&inimg , in , inlink->format);
if (strcmp(s->name, "facedetect")) {
fill_iplimage_from_frame(&outimg, out, inlink->format);
- s->end_frame_filter(ctx, &inimg, &outimg);
- fill_frame_from_iplimage(out, &outimg, inlink->format);
+ if (strcmp(s->name, "drawbox")) {
+ s->end_frame_filter(ctx, &inimg, &outimg);
+ fill_frame_from_iplimage(out, &outimg, inlink->format);
+ } else {
+ s->end_frame_filter(ctx, &inimg, NULL);
+ fill_frame_from_iplimage(out, &inimg, inlink->format);
+ }
} else {
s->end_frame_filter(ctx, &inimg, NULL);
}
--
2.21.0
More information about the ffmpeg-devel
mailing list