Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in / Register
Toggle navigation
F
ffmpeg.wasm-core
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Linshizhi
ffmpeg.wasm-core
Commits
b17e98de
Commit
b17e98de
authored
May 03, 2014
by
Clément Bœsch
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
avfilter/edgedetect: add a colormix mode.
parent
3f3c3318
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
108 additions
and
18 deletions
+108
-18
filters.texi
doc/filters.texi
+25
-1
vf_edgedetect.c
libavfilter/vf_edgedetect.c
+79
-17
filter-video.mak
tests/fate/filter-video.mak
+3
-0
filter-edgedetect-colormix
tests/ref/fate/filter-edgedetect-colormix
+1
-0
No files found.
doc/filters.texi
View file @
b17e98de
...
@@ -3990,13 +3990,37 @@ by the low threshold.
...
@@ -3990,13 +3990,37 @@ by the low threshold.
Default value for @var{low} is @code{20/255}, and default value for @var{high}
Default value for @var{low} is @code{20/255}, and default value for @var{high}
is @code{50/255}.
is @code{50/255}.
@item mode
Define the drawing mode.
@table @samp
@item wires
Draw white/gray wires on black background.
@item colormix
Mix the colors to create a paint/cartoon effect.
@end table
Default value is @var{wires}.
@end table
@end table
Example:
@subsection Examples
@itemize
@item
Standard edge detection with custom values for the hysteresis thresholding:
@example
@example
edgedetect=low=0.1:high=0.4
edgedetect=low=0.1:high=0.4
@end example
@end example
@item
Painting effect without thresholding:
@example
edgedetect=mode=colormix:high=0
@end example
@end itemize
@section extractplanes
@section extractplanes
Extract color channel components from input video stream into
Extract color channel components from input video stream into
...
...
libavfilter/vf_edgedetect.c
View file @
b17e98de
...
@@ -25,19 +25,32 @@
...
@@ -25,19 +25,32 @@
* @see https://en.wikipedia.org/wiki/Canny_edge_detector
* @see https://en.wikipedia.org/wiki/Canny_edge_detector
*/
*/
#include "libavutil/avassert.h"
#include "libavutil/opt.h"
#include "libavutil/opt.h"
#include "avfilter.h"
#include "avfilter.h"
#include "formats.h"
#include "formats.h"
#include "internal.h"
#include "internal.h"
#include "video.h"
#include "video.h"
typedef
struct
{
enum
FilterMode
{
const
AVClass
*
class
;
MODE_WIRES
,
MODE_COLORMIX
,
NB_MODE
};
struct
plane_info
{
uint8_t
*
tmpbuf
;
uint8_t
*
tmpbuf
;
uint16_t
*
gradients
;
uint16_t
*
gradients
;
char
*
directions
;
char
*
directions
;
};
typedef
struct
{
const
AVClass
*
class
;
struct
plane_info
planes
[
3
];
int
nb_planes
;
double
low
,
high
;
double
low
,
high
;
uint8_t
low_u8
,
high_u8
;
uint8_t
low_u8
,
high_u8
;
enum
FilterMode
mode
;
}
EdgeDetectContext
;
}
EdgeDetectContext
;
#define OFFSET(x) offsetof(EdgeDetectContext, x)
#define OFFSET(x) offsetof(EdgeDetectContext, x)
...
@@ -45,6 +58,9 @@ typedef struct {
...
@@ -45,6 +58,9 @@ typedef struct {
static
const
AVOption
edgedetect_options
[]
=
{
static
const
AVOption
edgedetect_options
[]
=
{
{
"high"
,
"set high threshold"
,
OFFSET
(
high
),
AV_OPT_TYPE_DOUBLE
,
{.
dbl
=
50
/
255
.},
0
,
1
,
FLAGS
},
{
"high"
,
"set high threshold"
,
OFFSET
(
high
),
AV_OPT_TYPE_DOUBLE
,
{.
dbl
=
50
/
255
.},
0
,
1
,
FLAGS
},
{
"low"
,
"set low threshold"
,
OFFSET
(
low
),
AV_OPT_TYPE_DOUBLE
,
{.
dbl
=
20
/
255
.},
0
,
1
,
FLAGS
},
{
"low"
,
"set low threshold"
,
OFFSET
(
low
),
AV_OPT_TYPE_DOUBLE
,
{.
dbl
=
20
/
255
.},
0
,
1
,
FLAGS
},
{
"mode"
,
"set mode"
,
OFFSET
(
mode
),
AV_OPT_TYPE_INT
,
{.
i64
=
MODE_WIRES
},
0
,
NB_MODE
-
1
,
FLAGS
,
"mode"
},
{
"wires"
,
"white/gray wires on black"
,
0
,
AV_OPT_TYPE_CONST
,
{.
i64
=
MODE_WIRES
},
INT_MIN
,
INT_MAX
,
FLAGS
,
"mode"
},
{
"colormix"
,
"mix colors"
,
0
,
AV_OPT_TYPE_CONST
,
{.
i64
=
MODE_COLORMIX
},
INT_MIN
,
INT_MAX
,
FLAGS
,
"mode"
},
{
NULL
}
{
NULL
}
};
};
...
@@ -61,21 +77,37 @@ static av_cold int init(AVFilterContext *ctx)
...
@@ -61,21 +77,37 @@ static av_cold int init(AVFilterContext *ctx)
static
int
query_formats
(
AVFilterContext
*
ctx
)
static
int
query_formats
(
AVFilterContext
*
ctx
)
{
{
const
EdgeDetectContext
*
edgedetect
=
ctx
->
priv
;
if
(
edgedetect
->
mode
==
MODE_WIRES
)
{
/* TODO: reindent */
static
const
enum
AVPixelFormat
pix_fmts
[]
=
{
AV_PIX_FMT_GRAY8
,
AV_PIX_FMT_NONE
};
static
const
enum
AVPixelFormat
pix_fmts
[]
=
{
AV_PIX_FMT_GRAY8
,
AV_PIX_FMT_NONE
};
ff_set_common_formats
(
ctx
,
ff_make_format_list
(
pix_fmts
));
ff_set_common_formats
(
ctx
,
ff_make_format_list
(
pix_fmts
));
}
else
if
(
edgedetect
->
mode
==
MODE_COLORMIX
)
{
static
const
enum
AVPixelFormat
pix_fmts
[]
=
{
AV_PIX_FMT_GBRP
,
AV_PIX_FMT_GRAY8
,
AV_PIX_FMT_NONE
};
ff_set_common_formats
(
ctx
,
ff_make_format_list
(
pix_fmts
));
}
else
{
av_assert0
(
0
);
}
return
0
;
return
0
;
}
}
static
int
config_props
(
AVFilterLink
*
inlink
)
static
int
config_props
(
AVFilterLink
*
inlink
)
{
{
int
p
;
AVFilterContext
*
ctx
=
inlink
->
dst
;
AVFilterContext
*
ctx
=
inlink
->
dst
;
EdgeDetectContext
*
edgedetect
=
ctx
->
priv
;
EdgeDetectContext
*
edgedetect
=
ctx
->
priv
;
edgedetect
->
tmpbuf
=
av_malloc
(
inlink
->
w
*
inlink
->
h
);
edgedetect
->
nb_planes
=
inlink
->
format
==
AV_PIX_FMT_GRAY8
?
1
:
3
;
edgedetect
->
gradients
=
av_calloc
(
inlink
->
w
*
inlink
->
h
,
sizeof
(
*
edgedetect
->
gradients
));
for
(
p
=
0
;
p
<
edgedetect
->
nb_planes
;
p
++
)
{
edgedetect
->
directions
=
av_malloc
(
inlink
->
w
*
inlink
->
h
);
struct
plane_info
*
plane
=
&
edgedetect
->
planes
[
p
];
if
(
!
edgedetect
->
tmpbuf
||
!
edgedetect
->
gradients
||
!
edgedetect
->
directions
)
plane
->
tmpbuf
=
av_malloc
(
inlink
->
w
*
inlink
->
h
);
plane
->
gradients
=
av_calloc
(
inlink
->
w
*
inlink
->
h
,
sizeof
(
*
plane
->
gradients
));
plane
->
directions
=
av_malloc
(
inlink
->
w
*
inlink
->
h
);
if
(
!
plane
->
tmpbuf
||
!
plane
->
gradients
||
!
plane
->
directions
)
return
AVERROR
(
ENOMEM
);
return
AVERROR
(
ENOMEM
);
}
return
0
;
return
0
;
}
}
...
@@ -241,18 +273,29 @@ static void double_threshold(int low, int high, int w, int h,
...
@@ -241,18 +273,29 @@ static void double_threshold(int low, int high, int w, int h,
}
}
}
}
static
void
color_mix
(
int
w
,
int
h
,
uint8_t
*
dst
,
int
dst_linesize
,
const
uint8_t
*
src
,
int
src_linesize
)
{
int
i
,
j
;
for
(
j
=
0
;
j
<
h
;
j
++
)
{
for
(
i
=
0
;
i
<
w
;
i
++
)
dst
[
i
]
=
(
dst
[
i
]
+
src
[
i
])
>>
1
;
dst
+=
dst_linesize
;
src
+=
src_linesize
;
}
}
static
int
filter_frame
(
AVFilterLink
*
inlink
,
AVFrame
*
in
)
static
int
filter_frame
(
AVFilterLink
*
inlink
,
AVFrame
*
in
)
{
{
AVFilterContext
*
ctx
=
inlink
->
dst
;
AVFilterContext
*
ctx
=
inlink
->
dst
;
EdgeDetectContext
*
edgedetect
=
ctx
->
priv
;
EdgeDetectContext
*
edgedetect
=
ctx
->
priv
;
AVFilterLink
*
outlink
=
inlink
->
dst
->
outputs
[
0
];
AVFilterLink
*
outlink
=
inlink
->
dst
->
outputs
[
0
];
uint8_t
*
tmpbuf
=
edgedetect
->
tmpbuf
;
int
p
,
direct
=
0
;
uint16_t
*
gradients
=
edgedetect
->
gradients
;
int8_t
*
directions
=
edgedetect
->
directions
;
int
direct
=
0
;
AVFrame
*
out
;
AVFrame
*
out
;
if
(
av_frame_is_writable
(
in
))
{
if
(
edgedetect
->
mode
!=
MODE_COLORMIX
&&
av_frame_is_writable
(
in
))
{
direct
=
1
;
direct
=
1
;
out
=
in
;
out
=
in
;
}
else
{
}
else
{
...
@@ -264,10 +307,17 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
...
@@ -264,10 +307,17 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
av_frame_copy_props
(
out
,
in
);
av_frame_copy_props
(
out
,
in
);
}
}
for
(
p
=
0
;
p
<
edgedetect
->
nb_planes
;
p
++
)
{
struct
plane_info
*
plane
=
&
edgedetect
->
planes
[
p
];
uint8_t
*
tmpbuf
=
plane
->
tmpbuf
;
uint16_t
*
gradients
=
plane
->
gradients
;
int8_t
*
directions
=
plane
->
directions
;
/* TODO: reindent */
/* gaussian filter to reduce noise */
/* gaussian filter to reduce noise */
gaussian_blur
(
ctx
,
inlink
->
w
,
inlink
->
h
,
gaussian_blur
(
ctx
,
inlink
->
w
,
inlink
->
h
,
tmpbuf
,
inlink
->
w
,
tmpbuf
,
inlink
->
w
,
in
->
data
[
0
],
in
->
linesize
[
0
]);
in
->
data
[
p
],
in
->
linesize
[
p
]);
/* compute the 16-bits gradients and directions for the next step */
/* compute the 16-bits gradients and directions for the next step */
sobel
(
inlink
->
w
,
inlink
->
h
,
sobel
(
inlink
->
w
,
inlink
->
h
,
...
@@ -286,9 +336,16 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
...
@@ -286,9 +336,16 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
/* keep high values, or low values surrounded by high values */
/* keep high values, or low values surrounded by high values */
double_threshold
(
edgedetect
->
low_u8
,
edgedetect
->
high_u8
,
double_threshold
(
edgedetect
->
low_u8
,
edgedetect
->
high_u8
,
inlink
->
w
,
inlink
->
h
,
inlink
->
w
,
inlink
->
h
,
out
->
data
[
0
],
out
->
linesize
[
0
],
out
->
data
[
p
],
out
->
linesize
[
p
],
tmpbuf
,
inlink
->
w
);
tmpbuf
,
inlink
->
w
);
if
(
edgedetect
->
mode
==
MODE_COLORMIX
)
{
color_mix
(
inlink
->
w
,
inlink
->
h
,
out
->
data
[
p
],
out
->
linesize
[
p
],
in
->
data
[
p
],
in
->
linesize
[
p
]);
}
}
if
(
!
direct
)
if
(
!
direct
)
av_frame_free
(
&
in
);
av_frame_free
(
&
in
);
return
ff_filter_frame
(
outlink
,
out
);
return
ff_filter_frame
(
outlink
,
out
);
...
@@ -296,10 +353,15 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
...
@@ -296,10 +353,15 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
static
av_cold
void
uninit
(
AVFilterContext
*
ctx
)
static
av_cold
void
uninit
(
AVFilterContext
*
ctx
)
{
{
int
p
;
EdgeDetectContext
*
edgedetect
=
ctx
->
priv
;
EdgeDetectContext
*
edgedetect
=
ctx
->
priv
;
av_freep
(
&
edgedetect
->
tmpbuf
);
av_freep
(
&
edgedetect
->
gradients
);
for
(
p
=
0
;
p
<
edgedetect
->
nb_planes
;
p
++
)
{
av_freep
(
&
edgedetect
->
directions
);
struct
plane_info
*
plane
=
&
edgedetect
->
planes
[
p
];
av_freep
(
&
plane
->
tmpbuf
);
av_freep
(
&
plane
->
gradients
);
av_freep
(
&
plane
->
directions
);
}
}
}
static
const
AVFilterPad
edgedetect_inputs
[]
=
{
static
const
AVFilterPad
edgedetect_inputs
[]
=
{
...
...
tests/fate/filter-video.mak
View file @
b17e98de
...
@@ -191,6 +191,9 @@ fate-filter-vflip_vflip: CMD = video_filter "vflip,vflip"
...
@@ -191,6 +191,9 @@ fate-filter-vflip_vflip: CMD = video_filter "vflip,vflip"
FATE_FILTER_VSYNTH-$(call ALLYES, FORMAT_FILTER PERMS_FILTER EDGEDETECT_FILTER) += fate-filter-edgedetect
FATE_FILTER_VSYNTH-$(call ALLYES, FORMAT_FILTER PERMS_FILTER EDGEDETECT_FILTER) += fate-filter-edgedetect
fate-filter-edgedetect: CMD = video_filter "format=gray,perms=random,edgedetect"
fate-filter-edgedetect: CMD = video_filter "format=gray,perms=random,edgedetect"
FATE_FILTER_VSYNTH-$(call ALLYES, FORMAT_FILTER PERMS_FILTER EDGEDETECT_FILTER) += fate-filter-edgedetect-colormix
fate-filter-edgedetect-colormix: CMD = video_filter "format=gbrp,perms=random,edgedetect=mode=colormix"
FATE_FILTER_VSYNTH-$(call ALLYES, PERMS_FILTER HUE_FILTER) += fate-filter-hue
FATE_FILTER_VSYNTH-$(call ALLYES, PERMS_FILTER HUE_FILTER) += fate-filter-hue
fate-filter-hue: CMD = video_filter "perms=random,hue=s=sin(2*PI*t)+1"
fate-filter-hue: CMD = video_filter "perms=random,hue=s=sin(2*PI*t)+1"
...
...
tests/ref/fate/filter-edgedetect-colormix
0 → 100644
View file @
b17e98de
edgedetect-colormix c84a2be00652610f968bef8c97d71ef4
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment