Browse code

Add dilate libopencv filter.

Originally committed as revision 26096 to svn://svn.ffmpeg.org/ffmpeg/trunk

Stefano Sabatini authored on 2010/12/26 20:27:05
Showing 3 changed files
... ...
@@ -532,6 +532,52 @@ informations:
532 532
 
533 533
 Follows the list of supported libopencv filters.
534 534
 
535
+@subsection dilate
536
+
537
+Dilate an image by using a specific structuring element.
538
+This filter corresponds to the libopencv function @code{cvDilate}.
539
+
540
+It accepts the parameters: @var{struct_el}:@var{nb_iterations}.
541
+
542
+@var{struct_el} represents a structuring element, and has the syntax:
543
+@var{cols}x@var{rows}+@var{anchor_x}x@var{anchor_y}/@var{shape}
544
+
545
+@var{cols} and @var{rows} represent the number of colums and rows of
546
+the structuring element, @var{anchor_x} and @var{anchor_y} the anchor
547
+point, and @var{shape} the shape for the structuring element, and
548
+can be one of the values "rect", "cross", "ellipse", "custom".
549
+
550
+If the value for @var{shape} is "custom", it must be followed by a
551
+string of the form "=@var{filename}". The file with name
552
+@var{filename} is assumed to represent a binary image, with each
553
+printable character corresponding to a bright pixel. When a custom
554
+@var{shape} is used, @var{cols} and @var{rows} are ignored, the number
555
+or columns and rows of the read file are assumed instead.
556
+
557
+The default value for @var{struct_el} is "3x3+0x0/rect".
558
+
559
+@var{nb_iterations} specifies the number of times the transform is
560
+applied to the image, and defaults to 1.
561
+
562
+Follow some example:
563
+@example
564
+# use the default values
565
+ocv=dilate
566
+
567
+# dilate using a structuring element with a 5x5 cross, iterate two times
568
+ocv=dilate=5x5+2x2/cross:2
569
+
570
+# read the shape from the file diamond.shape, iterate two times
571
+# the file diamond.shape may contain a pattern of characters like this:
572
+#   *
573
+#  ***
574
+# *****
575
+#  ***
576
+#   *
577
+# the specified cols and rows are ignored (but not the anchor point coordinates)
578
+ocv=0x0+2x2/custom=diamond.shape:2
579
+@end example
580
+
535 581
 @subsection smooth
536 582
 
537 583
 Smooth the input video.
... ...
@@ -28,7 +28,7 @@
28 28
 
29 29
 #define LIBAVFILTER_VERSION_MAJOR  1
30 30
 #define LIBAVFILTER_VERSION_MINOR 70
31
-#define LIBAVFILTER_VERSION_MICRO  0
31
+#define LIBAVFILTER_VERSION_MICRO  1
32 32
 
33 33
 #define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \
34 34
                                                LIBAVFILTER_VERSION_MINOR, \
... ...
@@ -23,8 +23,12 @@
23 23
  * libopencv wrapper functions
24 24
  */
25 25
 
26
+/* #define DEBUG */
27
+
26 28
 #include <opencv/cv.h>
27 29
 #include <opencv/cxtypes.h>
30
+#include "libavutil/avstring.h"
31
+#include "libavutil/file.h"
28 32
 #include "avfilter.h"
29 33
 
30 34
 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
127 127
     cvSmooth(inimg, outimg, smooth->type, smooth->param1, smooth->param2, smooth->param3, smooth->param4);
128 128
 }
129 129
 
130
+static int read_shape_from_file(int *cols, int *rows, int **values, const char *filename,
131
+                                void *log_ctx)
132
+{
133
+    uint8_t *buf, *p, *pend;
134
+    size_t size;
135
+    int ret, i, j, w;
136
+
137
+    if ((ret = av_file_map(filename, &buf, &size, 0, log_ctx)) < 0)
138
+        return ret;
139
+
140
+    /* prescan file to get the number of lines and the maximum width */
141
+    w = 0;
142
+    for (i = 0; i < size; i++) {
143
+        if (buf[i] == '\n') {
144
+            if (*rows == INT_MAX) {
145
+                av_log(log_ctx, AV_LOG_ERROR, "Overflow on the number of rows in the file\n");
146
+                return AVERROR_INVALIDDATA;
147
+            }
148
+            ++(*rows);
149
+            *cols = FFMAX(*cols, w);
150
+            w = 0;
151
+        } else if (w == INT_MAX) {
152
+            av_log(log_ctx, AV_LOG_ERROR, "Overflow on the number of columns in the file\n");
153
+            return AVERROR_INVALIDDATA;
154
+        }
155
+        w++;
156
+    }
157
+    if (*rows > (FF_INTERNAL_MEM_TYPE_MAX_VALUE / (sizeof(int)) / *cols)) {
158
+        av_log(log_ctx, AV_LOG_ERROR, "File with size %dx%d is too big\n",
159
+               *rows, *cols);
160
+        return AVERROR_INVALIDDATA;
161
+    }
162
+    if (!(*values = av_mallocz(sizeof(int) * *rows * *cols)))
163
+        return AVERROR(ENOMEM);
164
+
165
+    /* fill *values */
166
+    p    = buf;
167
+    pend = buf + size-1;
168
+    for (i = 0; i < *rows; i++) {
169
+        for (j = 0;; j++) {
170
+            if (p > pend || *p == '\n') {
171
+                p++;
172
+                break;
173
+            } else
174
+                (*values)[*cols*i + j] = !!isgraph(*(p++));
175
+        }
176
+    }
177
+    av_file_unmap(buf, size);
178
+
179
+#ifdef DEBUG
180
+    {
181
+        char *line;
182
+        if (!(line = av_malloc(*cols + 1)))
183
+            return AVERROR(ENOMEM);
184
+        for (i = 0; i < *rows; i++) {
185
+            for (j = 0; j < *cols; j++)
186
+                line[j] = (*values)[i * *cols + j] ? '@' : ' ';
187
+            line[j] = 0;
188
+            av_log(log_ctx, AV_LOG_DEBUG, "%3d: %s\n", i, line);
189
+        }
190
+        av_free(line);
191
+    }
192
+#endif
193
+
194
+    return 0;
195
+}
196
+
197
+static int parse_iplconvkernel(IplConvKernel **kernel, char *buf, void *log_ctx)
198
+{
199
+    char shape_filename[128] = "", shape_str[32] = "rect";
200
+    int cols = 0, rows = 0, anchor_x = 0, anchor_y = 0, shape = CV_SHAPE_RECT;
201
+    int *values = NULL, ret;
202
+
203
+    sscanf(buf, "%dx%d+%dx%d/%32[^=]=%127s", &cols, &rows, &anchor_x, &anchor_y, shape_str, shape_filename);
204
+
205
+    if      (!strcmp(shape_str, "rect"   )) shape = CV_SHAPE_RECT;
206
+    else if (!strcmp(shape_str, "cross"  )) shape = CV_SHAPE_CROSS;
207
+    else if (!strcmp(shape_str, "ellipse")) shape = CV_SHAPE_ELLIPSE;
208
+    else if (!strcmp(shape_str, "custom" )) {
209
+        shape = CV_SHAPE_CUSTOM;
210
+        if ((ret = read_shape_from_file(&cols, &rows, &values, shape_filename, log_ctx)) < 0)
211
+            return ret;
212
+    } else {
213
+        av_log(log_ctx, AV_LOG_ERROR,
214
+               "Shape unspecified or type '%s' unknown\n.", shape_str);
215
+        return AVERROR(EINVAL);
216
+    }
217
+
218
+    if (rows <= 0 || cols <= 0) {
219
+        av_log(log_ctx, AV_LOG_ERROR,
220
+               "Invalid non-positive values for shape size %dx%d\n", cols, rows);
221
+        return AVERROR(EINVAL);
222
+    }
223
+
224
+    if (anchor_x < 0 || anchor_y < 0 || anchor_x >= cols || anchor_y >= rows) {
225
+        av_log(log_ctx, AV_LOG_ERROR,
226
+               "Shape anchor %dx%d is not inside the rectangle with size %dx%d.\n",
227
+               anchor_x, anchor_y, cols, rows);
228
+        return AVERROR(EINVAL);
229
+    }
230
+
231
+    *kernel = cvCreateStructuringElementEx(cols, rows, anchor_x, anchor_y, shape, values);
232
+    av_freep(&values);
233
+    if (!*kernel)
234
+        return AVERROR(ENOMEM);
235
+
236
+    av_log(log_ctx, AV_LOG_INFO, "Structuring element: w:%d h:%d x:%d y:%d shape:%s\n",
237
+           rows, cols, anchor_x, anchor_y, shape_str);
238
+    return 0;
239
+}
240
+
241
+typedef struct {
242
+    int nb_iterations;
243
+    IplConvKernel *kernel;
244
+} DilateContext;
245
+
246
+static av_cold int dilate_init(AVFilterContext *ctx, const char *args, void *opaque)
247
+{
248
+    OCVContext *ocv = ctx->priv;
249
+    DilateContext *dilate = ocv->priv;
250
+    char default_kernel_str[] = "3x3+0x0/rect";
251
+    char *kernel_str;
252
+    const char *buf = args;
253
+    int ret;
254
+
255
+    dilate->nb_iterations = 1;
256
+
257
+    if (args)
258
+        kernel_str = av_get_token(&buf, ":");
259
+    if ((ret = parse_iplconvkernel(&dilate->kernel,
260
+                                   *kernel_str ? kernel_str : default_kernel_str,
261
+                                   ctx)) < 0)
262
+        return ret;
263
+    av_free(kernel_str);
264
+
265
+    sscanf(buf, ":%d", &dilate->nb_iterations);
266
+    av_log(ctx, AV_LOG_INFO, "iterations_nb:%d\n", dilate->nb_iterations);
267
+    if (dilate->nb_iterations <= 0) {
268
+        av_log(ctx, AV_LOG_ERROR, "Invalid non-positive value '%d' for nb_iterations\n",
269
+               dilate->nb_iterations);
270
+        return AVERROR(EINVAL);
271
+    }
272
+    return 0;
273
+}
274
+
275
+static av_cold void dilate_uninit(AVFilterContext *ctx)
276
+{
277
+    OCVContext *ocv = ctx->priv;
278
+    DilateContext *dilate = ocv->priv;
279
+
280
+    cvReleaseStructuringElement(&dilate->kernel);
281
+}
282
+
283
+static void dilate_end_frame_filter(AVFilterContext *ctx, IplImage *inimg, IplImage *outimg)
284
+{
285
+    OCVContext *ocv = ctx->priv;
286
+    DilateContext *dilate = ocv->priv;
287
+    cvDilate(inimg, outimg, dilate->kernel, dilate->nb_iterations);
288
+}
289
+
130 290
 typedef struct {
131 291
     const char *name;
132 292
     size_t priv_size;
... ...
@@ -136,6 +300,7 @@ typedef struct {
136 136
 } OCVFilterEntry;
137 137
 
138 138
 static OCVFilterEntry ocv_filter_entries[] = {
139
+    { "dilate", sizeof(DilateContext), dilate_init, dilate_uninit, dilate_end_frame_filter },
139 140
     { "smooth", sizeof(SmoothContext), smooth_init, NULL, smooth_end_frame_filter },
140 141
 };
141 142