2 * Copyright (c) 2010 Stefano Sabatini
4 * This file is part of Libav.
6 * Libav is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * Libav is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with Libav; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 * libopencv wrapper functions
28 #include <opencv/cv.h>
29 #include <opencv/cxcore.h>
30 #include "libavutil/avstring.h"
31 #include "libavutil/common.h"
32 #include "libavutil/file.h"
38 static void fill_iplimage_from_picref(IplImage
*img
, const AVFilterBufferRef
*picref
, enum AVPixelFormat pixfmt
)
41 int depth
, channels_nb
;
43 if (pixfmt
== AV_PIX_FMT_GRAY8
) { depth
= IPL_DEPTH_8U
; channels_nb
= 1; }
44 else if (pixfmt
== AV_PIX_FMT_BGRA
) { depth
= IPL_DEPTH_8U
; channels_nb
= 4; }
45 else if (pixfmt
== AV_PIX_FMT_BGR24
) { depth
= IPL_DEPTH_8U
; channels_nb
= 3; }
48 tmpimg
= cvCreateImageHeader((CvSize
){picref
->video
->w
, picref
->video
->h
}, depth
, channels_nb
);
50 img
->imageData
= img
->imageDataOrigin
= picref
->data
[0];
51 img
->dataOrder
= IPL_DATA_ORDER_PIXEL
;
52 img
->origin
= IPL_ORIGIN_TL
;
53 img
->widthStep
= picref
->linesize
[0];
56 static void fill_picref_from_iplimage(AVFilterBufferRef
*picref
, const IplImage
*img
, enum AVPixelFormat pixfmt
)
58 picref
->linesize
[0] = img
->widthStep
;
59 picref
->data
[0] = img
->imageData
;
62 static int query_formats(AVFilterContext
*ctx
)
64 static const enum AVPixelFormat pix_fmts
[] = {
65 AV_PIX_FMT_BGR24
, AV_PIX_FMT_BGRA
, AV_PIX_FMT_GRAY8
, AV_PIX_FMT_NONE
68 ff_set_common_formats(ctx
, ff_make_format_list(pix_fmts
));
74 int (*init
)(AVFilterContext
*ctx
, const char *args
);
75 void (*uninit
)(AVFilterContext
*ctx
);
76 void (*end_frame_filter
)(AVFilterContext
*ctx
, IplImage
*inimg
, IplImage
*outimg
);
83 double param3
, param4
;
86 static av_cold
int smooth_init(AVFilterContext
*ctx
, const char *args
)
88 OCVContext
*ocv
= ctx
->priv
;
89 SmoothContext
*smooth
= ocv
->priv
;
90 char type_str
[128] = "gaussian";
98 sscanf(args
, "%127[^:]:%d:%d:%lf:%lf", type_str
, &smooth
->param1
, &smooth
->param2
, &smooth
->param3
, &smooth
->param4
);
100 if (!strcmp(type_str
, "blur" )) smooth
->type
= CV_BLUR
;
101 else if (!strcmp(type_str
, "blur_no_scale")) smooth
->type
= CV_BLUR_NO_SCALE
;
102 else if (!strcmp(type_str
, "median" )) smooth
->type
= CV_MEDIAN
;
103 else if (!strcmp(type_str
, "gaussian" )) smooth
->type
= CV_GAUSSIAN
;
104 else if (!strcmp(type_str
, "bilateral" )) smooth
->type
= CV_BILATERAL
;
106 av_log(ctx
, AV_LOG_ERROR
, "Smoothing type '%s' unknown.\n", type_str
);
107 return AVERROR(EINVAL
);
110 if (smooth
->param1
< 0 || !(smooth
->param1
%2)) {
111 av_log(ctx
, AV_LOG_ERROR
,
112 "Invalid value '%d' for param1, it has to be a positive odd number\n",
114 return AVERROR(EINVAL
);
116 if ((smooth
->type
== CV_BLUR
|| smooth
->type
== CV_BLUR_NO_SCALE
|| smooth
->type
== CV_GAUSSIAN
) &&
117 (smooth
->param2
< 0 || (smooth
->param2
&& !(smooth
->param2
%2)))) {
118 av_log(ctx
, AV_LOG_ERROR
,
119 "Invalid value '%d' for param2, it has to be zero or a positive odd number\n",
121 return AVERROR(EINVAL
);
124 av_log(ctx
, AV_LOG_VERBOSE
, "type:%s param1:%d param2:%d param3:%f param4:%f\n",
125 type_str
, smooth
->param1
, smooth
->param2
, smooth
->param3
, smooth
->param4
);
129 static void smooth_end_frame_filter(AVFilterContext
*ctx
, IplImage
*inimg
, IplImage
*outimg
)
131 OCVContext
*ocv
= ctx
->priv
;
132 SmoothContext
*smooth
= ocv
->priv
;
133 cvSmooth(inimg
, outimg
, smooth
->type
, smooth
->param1
, smooth
->param2
, smooth
->param3
, smooth
->param4
);
136 static int read_shape_from_file(int *cols
, int *rows
, int **values
, const char *filename
,
139 uint8_t *buf
, *p
, *pend
;
143 if ((ret
= av_file_map(filename
, &buf
, &size
, 0, log_ctx
)) < 0)
146 /* prescan file to get the number of lines and the maximum width */
148 for (i
= 0; i
< size
; i
++) {
149 if (buf
[i
] == '\n') {
150 if (*rows
== INT_MAX
) {
151 av_log(log_ctx
, AV_LOG_ERROR
, "Overflow on the number of rows in the file\n");
152 return AVERROR_INVALIDDATA
;
155 *cols
= FFMAX(*cols
, w
);
157 } else if (w
== INT_MAX
) {
158 av_log(log_ctx
, AV_LOG_ERROR
, "Overflow on the number of columns in the file\n");
159 return AVERROR_INVALIDDATA
;
163 if (*rows
> (SIZE_MAX
/ sizeof(int) / *cols
)) {
164 av_log(log_ctx
, AV_LOG_ERROR
, "File with size %dx%d is too big\n",
166 return AVERROR_INVALIDDATA
;
168 if (!(*values
= av_mallocz(sizeof(int) * *rows
* *cols
)))
169 return AVERROR(ENOMEM
);
174 for (i
= 0; i
< *rows
; i
++) {
176 if (p
> pend
|| *p
== '\n') {
180 (*values
)[*cols
*i
+ j
] = !!isgraph(*(p
++));
183 av_file_unmap(buf
, size
);
188 if (!(line
= av_malloc(*cols
+ 1)))
189 return AVERROR(ENOMEM
);
190 for (i
= 0; i
< *rows
; i
++) {
191 for (j
= 0; j
< *cols
; j
++)
192 line
[j
] = (*values
)[i
* *cols
+ j
] ? '@' : ' ';
194 av_log(log_ctx
, AV_LOG_DEBUG
, "%3d: %s\n", i
, line
);
203 static int parse_iplconvkernel(IplConvKernel
**kernel
, char *buf
, void *log_ctx
)
205 char shape_filename
[128] = "", shape_str
[32] = "rect";
206 int cols
= 0, rows
= 0, anchor_x
= 0, anchor_y
= 0, shape
= CV_SHAPE_RECT
;
207 int *values
= NULL
, ret
;
209 sscanf(buf
, "%dx%d+%dx%d/%32[^=]=%127s", &cols
, &rows
, &anchor_x
, &anchor_y
, shape_str
, shape_filename
);
211 if (!strcmp(shape_str
, "rect" )) shape
= CV_SHAPE_RECT
;
212 else if (!strcmp(shape_str
, "cross" )) shape
= CV_SHAPE_CROSS
;
213 else if (!strcmp(shape_str
, "ellipse")) shape
= CV_SHAPE_ELLIPSE
;
214 else if (!strcmp(shape_str
, "custom" )) {
215 shape
= CV_SHAPE_CUSTOM
;
216 if ((ret
= read_shape_from_file(&cols
, &rows
, &values
, shape_filename
, log_ctx
)) < 0)
219 av_log(log_ctx
, AV_LOG_ERROR
,
220 "Shape unspecified or type '%s' unknown.\n", shape_str
);
221 return AVERROR(EINVAL
);
224 if (rows
<= 0 || cols
<= 0) {
225 av_log(log_ctx
, AV_LOG_ERROR
,
226 "Invalid non-positive values for shape size %dx%d\n", cols
, rows
);
227 return AVERROR(EINVAL
);
230 if (anchor_x
< 0 || anchor_y
< 0 || anchor_x
>= cols
|| anchor_y
>= rows
) {
231 av_log(log_ctx
, AV_LOG_ERROR
,
232 "Shape anchor %dx%d is not inside the rectangle with size %dx%d.\n",
233 anchor_x
, anchor_y
, cols
, rows
);
234 return AVERROR(EINVAL
);
237 *kernel
= cvCreateStructuringElementEx(cols
, rows
, anchor_x
, anchor_y
, shape
, values
);
240 return AVERROR(ENOMEM
);
242 av_log(log_ctx
, AV_LOG_VERBOSE
, "Structuring element: w:%d h:%d x:%d y:%d shape:%s\n",
243 rows
, cols
, anchor_x
, anchor_y
, shape_str
);
249 IplConvKernel
*kernel
;
252 static av_cold
int dilate_init(AVFilterContext
*ctx
, const char *args
)
254 OCVContext
*ocv
= ctx
->priv
;
255 DilateContext
*dilate
= ocv
->priv
;
256 char default_kernel_str
[] = "3x3+0x0/rect";
258 const char *buf
= args
;
261 dilate
->nb_iterations
= 1;
264 kernel_str
= av_get_token(&buf
, ":");
265 if ((ret
= parse_iplconvkernel(&dilate
->kernel
,
266 *kernel_str
? kernel_str
: default_kernel_str
,
271 sscanf(buf
, ":%d", &dilate
->nb_iterations
);
272 av_log(ctx
, AV_LOG_VERBOSE
, "iterations_nb:%d\n", dilate
->nb_iterations
);
273 if (dilate
->nb_iterations
<= 0) {
274 av_log(ctx
, AV_LOG_ERROR
, "Invalid non-positive value '%d' for nb_iterations\n",
275 dilate
->nb_iterations
);
276 return AVERROR(EINVAL
);
281 static av_cold
void dilate_uninit(AVFilterContext
*ctx
)
283 OCVContext
*ocv
= ctx
->priv
;
284 DilateContext
*dilate
= ocv
->priv
;
286 cvReleaseStructuringElement(&dilate
->kernel
);
289 static void dilate_end_frame_filter(AVFilterContext
*ctx
, IplImage
*inimg
, IplImage
*outimg
)
291 OCVContext
*ocv
= ctx
->priv
;
292 DilateContext
*dilate
= ocv
->priv
;
293 cvDilate(inimg
, outimg
, dilate
->kernel
, dilate
->nb_iterations
);
296 static void erode_end_frame_filter(AVFilterContext
*ctx
, IplImage
*inimg
, IplImage
*outimg
)
298 OCVContext
*ocv
= ctx
->priv
;
299 DilateContext
*dilate
= ocv
->priv
;
300 cvErode(inimg
, outimg
, dilate
->kernel
, dilate
->nb_iterations
);
306 int (*init
)(AVFilterContext
*ctx
, const char *args
);
307 void (*uninit
)(AVFilterContext
*ctx
);
308 void (*end_frame_filter
)(AVFilterContext
*ctx
, IplImage
*inimg
, IplImage
*outimg
);
311 static OCVFilterEntry ocv_filter_entries
[] = {
312 { "dilate", sizeof(DilateContext
), dilate_init
, dilate_uninit
, dilate_end_frame_filter
},
313 { "erode", sizeof(DilateContext
), dilate_init
, dilate_uninit
, erode_end_frame_filter
},
314 { "smooth", sizeof(SmoothContext
), smooth_init
, NULL
, smooth_end_frame_filter
},
317 static av_cold
int init(AVFilterContext
*ctx
, const char *args
)
319 OCVContext
*ocv
= ctx
->priv
;
320 char name
[128], priv_args
[1024];
324 sscanf(args
, "%127[^=:]%c%1023s", name
, &c
, priv_args
);
326 for (i
= 0; i
< FF_ARRAY_ELEMS(ocv_filter_entries
); i
++) {
327 OCVFilterEntry
*entry
= &ocv_filter_entries
[i
];
328 if (!strcmp(name
, entry
->name
)) {
329 ocv
->name
= entry
->name
;
330 ocv
->init
= entry
->init
;
331 ocv
->uninit
= entry
->uninit
;
332 ocv
->end_frame_filter
= entry
->end_frame_filter
;
334 if (!(ocv
->priv
= av_mallocz(entry
->priv_size
)))
335 return AVERROR(ENOMEM
);
336 return ocv
->init(ctx
, priv_args
);
340 av_log(ctx
, AV_LOG_ERROR
, "No libopencv filter named '%s'\n", name
);
341 return AVERROR(EINVAL
);
344 static av_cold
void uninit(AVFilterContext
*ctx
)
346 OCVContext
*ocv
= ctx
->priv
;
351 memset(ocv
, 0, sizeof(*ocv
));
354 static int filter_frame(AVFilterLink
*inlink
, AVFilterBufferRef
*in
)
356 AVFilterContext
*ctx
= inlink
->dst
;
357 OCVContext
*ocv
= ctx
->priv
;
358 AVFilterLink
*outlink
= inlink
->dst
->outputs
[0];
359 AVFilterBufferRef
*out
;
360 IplImage inimg
, outimg
;
362 out
= ff_get_video_buffer(outlink
, AV_PERM_WRITE
, outlink
->w
, outlink
->h
);
364 avfilter_unref_bufferp(&in
);
365 return AVERROR(ENOMEM
);
367 avfilter_copy_buffer_ref_props(out
, in
);
369 fill_iplimage_from_picref(&inimg
, in
, inlink
->format
);
370 fill_iplimage_from_picref(&outimg
, out
, inlink
->format
);
371 ocv
->end_frame_filter(ctx
, &inimg
, &outimg
);
372 fill_picref_from_iplimage(out
, &outimg
, inlink
->format
);
374 avfilter_unref_bufferp(&in
);
376 return ff_filter_frame(outlink
, out
);
379 static const AVFilterPad avfilter_vf_ocv_inputs
[] = {
382 .type
= AVMEDIA_TYPE_VIDEO
,
383 .filter_frame
= filter_frame
,
384 .min_perms
= AV_PERM_READ
389 static const AVFilterPad avfilter_vf_ocv_outputs
[] = {
392 .type
= AVMEDIA_TYPE_VIDEO
,
397 AVFilter avfilter_vf_ocv
= {
399 .description
= NULL_IF_CONFIG_SMALL("Apply transform using libopencv."),
401 .priv_size
= sizeof(OCVContext
),
403 .query_formats
= query_formats
,
407 .inputs
= avfilter_vf_ocv_inputs
,
409 .outputs
= avfilter_vf_ocv_outputs
,