Originally committed as revision 26096 to svn://svn.ffmpeg.org/ffmpeg/trunk
| ... | ... |
@@ -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 |
|