From: Limin Wang <lance.lmw...@gmail.com> Signed-off-by: Limin Wang <lance.lmw...@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 +@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: +@var{color}|@var{thickness}|@var{line_type}|@var{shift}. + +@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}. + +@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. + +@var{line_type} +Set the line type of the box boundary. Default value is @code{8}. + +@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 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".