From 91cbb6ba53147a058e5cc91f5e466f18529abd9d Mon Sep 17 00:00:00 2001 From: Stefano Sabatini Date: Sun, 26 Dec 2010 11:27:05 +0000 Subject: Add dilate libopencv filter. Originally committed as revision 26096 to svn://svn.ffmpeg.org/ffmpeg/trunk --- libavfilter/vf_libopencv.c | 165 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 165 insertions(+) (limited to 'libavfilter/vf_libopencv.c') diff --git a/libavfilter/vf_libopencv.c b/libavfilter/vf_libopencv.c index dce22f7ae6..497d4cab85 100644 --- a/libavfilter/vf_libopencv.c +++ b/libavfilter/vf_libopencv.c @@ -23,8 +23,12 @@ * libopencv wrapper functions */ +/* #define DEBUG */ + #include #include +#include "libavutil/avstring.h" +#include "libavutil/file.h" #include "avfilter.h" static void fill_iplimage_from_picref(IplImage *img, const AVFilterBufferRef *picref, enum PixelFormat pixfmt) @@ -127,6 +131,166 @@ static void smooth_end_frame_filter(AVFilterContext *ctx, IplImage *inimg, IplIm cvSmooth(inimg, outimg, smooth->type, smooth->param1, smooth->param2, smooth->param3, smooth->param4); } +static int read_shape_from_file(int *cols, int *rows, int **values, const char *filename, + void *log_ctx) +{ + uint8_t *buf, *p, *pend; + size_t size; + int ret, i, j, w; + + if ((ret = av_file_map(filename, &buf, &size, 0, log_ctx)) < 0) + return ret; + + /* prescan file to get the number of lines and the maximum width */ + w = 0; + for (i = 0; i < size; i++) { + if (buf[i] == '\n') { + if (*rows == INT_MAX) { + av_log(log_ctx, AV_LOG_ERROR, "Overflow on the number of rows in the file\n"); + return AVERROR_INVALIDDATA; + } + ++(*rows); + *cols = FFMAX(*cols, w); + w = 0; + } else if (w == INT_MAX) { + av_log(log_ctx, AV_LOG_ERROR, "Overflow on the number of columns in the file\n"); + return AVERROR_INVALIDDATA; + } + w++; + } + if (*rows > (FF_INTERNAL_MEM_TYPE_MAX_VALUE / (sizeof(int)) / *cols)) { + av_log(log_ctx, AV_LOG_ERROR, "File with size %dx%d is too big\n", + *rows, *cols); + return AVERROR_INVALIDDATA; + } + if (!(*values = av_mallocz(sizeof(int) * *rows * *cols))) + return AVERROR(ENOMEM); + + /* fill *values */ + p = buf; + pend = buf + size-1; + for (i = 0; i < *rows; i++) { + for (j = 0;; j++) { + if (p > pend || *p == '\n') { + p++; + break; + } else + (*values)[*cols*i + j] = !!isgraph(*(p++)); + } + } + av_file_unmap(buf, size); + +#ifdef DEBUG + { + char *line; + if (!(line = av_malloc(*cols + 1))) + return AVERROR(ENOMEM); + for (i = 0; i < *rows; i++) { + for (j = 0; j < *cols; j++) + line[j] = (*values)[i * *cols + j] ? '@' : ' '; + line[j] = 0; + av_log(log_ctx, AV_LOG_DEBUG, "%3d: %s\n", i, line); + } + av_free(line); + } +#endif + + return 0; +} + +static int parse_iplconvkernel(IplConvKernel **kernel, char *buf, void *log_ctx) +{ + char shape_filename[128] = "", shape_str[32] = "rect"; + int cols = 0, rows = 0, anchor_x = 0, anchor_y = 0, shape = CV_SHAPE_RECT; + int *values = NULL, ret; + + sscanf(buf, "%dx%d+%dx%d/%32[^=]=%127s", &cols, &rows, &anchor_x, &anchor_y, shape_str, shape_filename); + + if (!strcmp(shape_str, "rect" )) shape = CV_SHAPE_RECT; + else if (!strcmp(shape_str, "cross" )) shape = CV_SHAPE_CROSS; + else if (!strcmp(shape_str, "ellipse")) shape = CV_SHAPE_ELLIPSE; + else if (!strcmp(shape_str, "custom" )) { + shape = CV_SHAPE_CUSTOM; + if ((ret = read_shape_from_file(&cols, &rows, &values, shape_filename, log_ctx)) < 0) + return ret; + } else { + av_log(log_ctx, AV_LOG_ERROR, + "Shape unspecified or type '%s' unknown\n.", shape_str); + return AVERROR(EINVAL); + } + + if (rows <= 0 || cols <= 0) { + av_log(log_ctx, AV_LOG_ERROR, + "Invalid non-positive values for shape size %dx%d\n", cols, rows); + return AVERROR(EINVAL); + } + + if (anchor_x < 0 || anchor_y < 0 || anchor_x >= cols || anchor_y >= rows) { + av_log(log_ctx, AV_LOG_ERROR, + "Shape anchor %dx%d is not inside the rectangle with size %dx%d.\n", + anchor_x, anchor_y, cols, rows); + return AVERROR(EINVAL); + } + + *kernel = cvCreateStructuringElementEx(cols, rows, anchor_x, anchor_y, shape, values); + av_freep(&values); + if (!*kernel) + return AVERROR(ENOMEM); + + av_log(log_ctx, AV_LOG_INFO, "Structuring element: w:%d h:%d x:%d y:%d shape:%s\n", + rows, cols, anchor_x, anchor_y, shape_str); + return 0; +} + +typedef struct { + int nb_iterations; + IplConvKernel *kernel; +} DilateContext; + +static av_cold int dilate_init(AVFilterContext *ctx, const char *args, void *opaque) +{ + OCVContext *ocv = ctx->priv; + DilateContext *dilate = ocv->priv; + char default_kernel_str[] = "3x3+0x0/rect"; + char *kernel_str; + const char *buf = args; + int ret; + + dilate->nb_iterations = 1; + + if (args) + kernel_str = av_get_token(&buf, ":"); + if ((ret = parse_iplconvkernel(&dilate->kernel, + *kernel_str ? kernel_str : default_kernel_str, + ctx)) < 0) + return ret; + av_free(kernel_str); + + sscanf(buf, ":%d", &dilate->nb_iterations); + av_log(ctx, AV_LOG_INFO, "iterations_nb:%d\n", dilate->nb_iterations); + if (dilate->nb_iterations <= 0) { + av_log(ctx, AV_LOG_ERROR, "Invalid non-positive value '%d' for nb_iterations\n", + dilate->nb_iterations); + return AVERROR(EINVAL); + } + return 0; +} + +static av_cold void dilate_uninit(AVFilterContext *ctx) +{ + OCVContext *ocv = ctx->priv; + DilateContext *dilate = ocv->priv; + + cvReleaseStructuringElement(&dilate->kernel); +} + +static void dilate_end_frame_filter(AVFilterContext *ctx, IplImage *inimg, IplImage *outimg) +{ + OCVContext *ocv = ctx->priv; + DilateContext *dilate = ocv->priv; + cvDilate(inimg, outimg, dilate->kernel, dilate->nb_iterations); +} + typedef struct { const char *name; size_t priv_size; @@ -136,6 +300,7 @@ typedef struct { } OCVFilterEntry; static OCVFilterEntry ocv_filter_entries[] = { + { "dilate", sizeof(DilateContext), dilate_init, dilate_uninit, dilate_end_frame_filter }, { "smooth", sizeof(SmoothContext), smooth_init, NULL, smooth_end_frame_filter }, }; -- cgit v1.2.3