mirror of
https://gitee.com/openharmony/third_party_ffmpeg
synced 2024-11-23 11:19:55 +00:00
avfilter: add sobel and prewitt filter
Signed-off-by: Paul B Mahol <onemda@gmail.com>
This commit is contained in:
parent
b791d0e4e0
commit
afeffd891f
@ -27,6 +27,7 @@ version <next>:
|
||||
- weave filter
|
||||
- gblur filter
|
||||
- avgblur filter
|
||||
- sobel and prewitt filter
|
||||
|
||||
|
||||
version 3.1:
|
||||
|
@ -10860,6 +10860,23 @@ Set medium thresholding (good results, default).
|
||||
@end table
|
||||
@end table
|
||||
|
||||
@section prewitt
|
||||
Apply prewitt operator to input video stream.
|
||||
|
||||
The filter accepts the following option:
|
||||
|
||||
@table @option
|
||||
@item planes
|
||||
Set which planes will be processed, unprocessed planes will be copied.
|
||||
By default value 0xf, all planes will be processed.
|
||||
|
||||
@item scale
|
||||
Set value which will be multiplied with filtered result.
|
||||
|
||||
@item delta
|
||||
Set value which will be added to filtered result.
|
||||
@end table
|
||||
|
||||
@section psnr
|
||||
|
||||
Obtain the average, maximum and minimum PSNR (Peak Signal to Noise
|
||||
@ -12714,6 +12731,23 @@ asendcmd='5.0 astreamselect map 1',astreamselect=inputs=2:map=0
|
||||
@end example
|
||||
@end itemize
|
||||
|
||||
@section sobel
|
||||
Apply sobel operator to input video stream.
|
||||
|
||||
The filter accepts the following option:
|
||||
|
||||
@table @option
|
||||
@item planes
|
||||
Set which planes will be processed, unprocessed planes will be copied.
|
||||
By default value 0xf, all planes will be processed.
|
||||
|
||||
@item scale
|
||||
Set value which will be multiplied with filtered result.
|
||||
|
||||
@item delta
|
||||
Set value which will be added to filtered result.
|
||||
@end table
|
||||
|
||||
@anchor{spp}
|
||||
@section spp
|
||||
|
||||
|
@ -238,6 +238,7 @@ OBJS-$(CONFIG_PHASE_FILTER) += vf_phase.o
|
||||
OBJS-$(CONFIG_PIXDESCTEST_FILTER) += vf_pixdesctest.o
|
||||
OBJS-$(CONFIG_PP_FILTER) += vf_pp.o
|
||||
OBJS-$(CONFIG_PP7_FILTER) += vf_pp7.o
|
||||
OBJS-$(CONFIG_PREWITT_FILTER) += vf_convolution.o
|
||||
OBJS-$(CONFIG_PSNR_FILTER) += vf_psnr.o dualinput.o framesync.o
|
||||
OBJS-$(CONFIG_PULLUP_FILTER) += vf_pullup.o
|
||||
OBJS-$(CONFIG_QP_FILTER) += vf_qp.o
|
||||
@ -270,6 +271,7 @@ OBJS-$(CONFIG_SHUFFLEFRAMES_FILTER) += vf_shuffleframes.o
|
||||
OBJS-$(CONFIG_SHUFFLEPLANES_FILTER) += vf_shuffleplanes.o
|
||||
OBJS-$(CONFIG_SIGNALSTATS_FILTER) += vf_signalstats.o
|
||||
OBJS-$(CONFIG_SMARTBLUR_FILTER) += vf_smartblur.o
|
||||
OBJS-$(CONFIG_SOBEL_FILTER) += vf_convolution.o
|
||||
OBJS-$(CONFIG_SPLIT_FILTER) += split.o
|
||||
OBJS-$(CONFIG_SPP_FILTER) += vf_spp.o
|
||||
OBJS-$(CONFIG_SSIM_FILTER) += vf_ssim.o dualinput.o framesync.o
|
||||
|
@ -254,6 +254,7 @@ void avfilter_register_all(void)
|
||||
REGISTER_FILTER(PIXDESCTEST, pixdesctest, vf);
|
||||
REGISTER_FILTER(PP, pp, vf);
|
||||
REGISTER_FILTER(PP7, pp7, vf);
|
||||
REGISTER_FILTER(PREWITT, prewitt, vf);
|
||||
REGISTER_FILTER(PSNR, psnr, vf);
|
||||
REGISTER_FILTER(PULLUP, pullup, vf);
|
||||
REGISTER_FILTER(QP, qp, vf);
|
||||
@ -286,6 +287,7 @@ void avfilter_register_all(void)
|
||||
REGISTER_FILTER(SHUFFLEPLANES, shuffleplanes, vf);
|
||||
REGISTER_FILTER(SIGNALSTATS, signalstats, vf);
|
||||
REGISTER_FILTER(SMARTBLUR, smartblur, vf);
|
||||
REGISTER_FILTER(SOBEL, sobel, vf);
|
||||
REGISTER_FILTER(SPLIT, split, vf);
|
||||
REGISTER_FILTER(SPP, spp, vf);
|
||||
REGISTER_FILTER(SSIM, ssim, vf);
|
||||
|
@ -30,7 +30,7 @@
|
||||
#include "libavutil/version.h"
|
||||
|
||||
#define LIBAVFILTER_VERSION_MAJOR 6
|
||||
#define LIBAVFILTER_VERSION_MINOR 61
|
||||
#define LIBAVFILTER_VERSION_MINOR 62
|
||||
#define LIBAVFILTER_VERSION_MICRO 100
|
||||
|
||||
#define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \
|
||||
|
@ -34,6 +34,9 @@ typedef struct ConvolutionContext {
|
||||
char *matrix_str[4];
|
||||
float rdiv[4];
|
||||
float bias[4];
|
||||
float scale;
|
||||
float delta;
|
||||
int planes;
|
||||
|
||||
int size[4];
|
||||
int depth;
|
||||
@ -130,6 +133,196 @@ static inline void line_copy16(uint16_t *line, const uint16_t *srcp, int width,
|
||||
}
|
||||
}
|
||||
|
||||
static void filter16_prewitt(ConvolutionContext *s, AVFrame *in, AVFrame *out, int plane)
|
||||
{
|
||||
const uint16_t *src = (const uint16_t *)in->data[plane];
|
||||
uint16_t *dst = (uint16_t *)out->data[plane];
|
||||
const int peak = (1 << s->depth) - 1;
|
||||
const int stride = in->linesize[plane] / 2;
|
||||
const int bstride = s->bstride;
|
||||
const int height = s->planeheight[plane];
|
||||
const int width = s->planewidth[plane];
|
||||
const float scale = s->scale;
|
||||
const float delta = s->delta;
|
||||
uint16_t *p0 = (uint16_t *)s->buffer + 16;
|
||||
uint16_t *p1 = p0 + bstride;
|
||||
uint16_t *p2 = p1 + bstride;
|
||||
uint16_t *orig = p0, *end = p2;
|
||||
int y, x;
|
||||
|
||||
line_copy16(p0, src + stride, width, 1);
|
||||
line_copy16(p1, src, width, 1);
|
||||
|
||||
for (y = 0; y < height; y++) {
|
||||
src += stride * (y < height - 1 ? 1 : -1);
|
||||
line_copy16(p2, src, width, 1);
|
||||
|
||||
for (x = 0; x < width; x++) {
|
||||
int suma = p0[x - 1] * -1 +
|
||||
p0[x] * -1 +
|
||||
p0[x + 1] * -1 +
|
||||
p2[x - 1] * 1 +
|
||||
p2[x] * 1 +
|
||||
p2[x + 1] * 1;
|
||||
int sumb = p0[x - 1] * -1 +
|
||||
p0[x + 1] * 1 +
|
||||
p1[x - 1] * -1 +
|
||||
p1[x + 1] * 1 +
|
||||
p2[x - 1] * -1 +
|
||||
p2[x + 1] * 1;
|
||||
|
||||
dst[x] = av_clip(sqrt(suma*suma + sumb*sumb) * scale + delta, 0, peak);
|
||||
}
|
||||
|
||||
p0 = p1;
|
||||
p1 = p2;
|
||||
p2 = (p2 == end) ? orig: p2 + bstride;
|
||||
dst += out->linesize[plane] / 2;
|
||||
}
|
||||
}
|
||||
|
||||
static void filter16_sobel(ConvolutionContext *s, AVFrame *in, AVFrame *out, int plane)
|
||||
{
|
||||
const uint16_t *src = (const uint16_t *)in->data[plane];
|
||||
uint16_t *dst = (uint16_t *)out->data[plane];
|
||||
const int peak = (1 << s->depth) - 1;
|
||||
const int stride = in->linesize[plane] / 2;
|
||||
const int bstride = s->bstride;
|
||||
const int height = s->planeheight[plane];
|
||||
const int width = s->planewidth[plane];
|
||||
const float scale = s->scale;
|
||||
const float delta = s->delta;
|
||||
uint16_t *p0 = (uint16_t *)s->buffer + 16;
|
||||
uint16_t *p1 = p0 + bstride;
|
||||
uint16_t *p2 = p1 + bstride;
|
||||
uint16_t *orig = p0, *end = p2;
|
||||
int y, x;
|
||||
|
||||
line_copy16(p0, src + stride, width, 1);
|
||||
line_copy16(p1, src, width, 1);
|
||||
|
||||
for (y = 0; y < height; y++) {
|
||||
src += stride * (y < height - 1 ? 1 : -1);
|
||||
line_copy16(p2, src, width, 1);
|
||||
|
||||
for (x = 0; x < width; x++) {
|
||||
int suma = p0[x - 1] * -1 +
|
||||
p0[x] * -2 +
|
||||
p0[x + 1] * -1 +
|
||||
p2[x - 1] * 1 +
|
||||
p2[x] * 2 +
|
||||
p2[x + 1] * 1;
|
||||
int sumb = p0[x - 1] * -1 +
|
||||
p0[x + 1] * 1 +
|
||||
p1[x - 1] * -2 +
|
||||
p1[x + 1] * 2 +
|
||||
p2[x - 1] * -1 +
|
||||
p2[x + 1] * 1;
|
||||
|
||||
dst[x] = av_clip(sqrt(suma*suma + sumb*sumb) * scale + delta, 0, peak);
|
||||
}
|
||||
|
||||
p0 = p1;
|
||||
p1 = p2;
|
||||
p2 = (p2 == end) ? orig: p2 + bstride;
|
||||
dst += out->linesize[plane] / 2;
|
||||
}
|
||||
}
|
||||
|
||||
static void filter_prewitt(ConvolutionContext *s, AVFrame *in, AVFrame *out, int plane)
|
||||
{
|
||||
const uint8_t *src = in->data[plane];
|
||||
uint8_t *dst = out->data[plane];
|
||||
const int stride = in->linesize[plane];
|
||||
const int bstride = s->bstride;
|
||||
const int height = s->planeheight[plane];
|
||||
const int width = s->planewidth[plane];
|
||||
const float scale = s->scale;
|
||||
const float delta = s->delta;
|
||||
uint8_t *p0 = s->buffer + 16;
|
||||
uint8_t *p1 = p0 + bstride;
|
||||
uint8_t *p2 = p1 + bstride;
|
||||
uint8_t *orig = p0, *end = p2;
|
||||
int y, x;
|
||||
|
||||
line_copy8(p0, src + stride, width, 1);
|
||||
line_copy8(p1, src, width, 1);
|
||||
|
||||
for (y = 0; y < height; y++) {
|
||||
src += stride * (y < height - 1 ? 1 : -1);
|
||||
line_copy8(p2, src, width, 1);
|
||||
|
||||
for (x = 0; x < width; x++) {
|
||||
int suma = p0[x - 1] * -1 +
|
||||
p0[x] * -1 +
|
||||
p0[x + 1] * -1 +
|
||||
p2[x - 1] * 1 +
|
||||
p2[x] * 1 +
|
||||
p2[x + 1] * 1;
|
||||
int sumb = p0[x - 1] * -1 +
|
||||
p0[x + 1] * 1 +
|
||||
p1[x - 1] * -1 +
|
||||
p1[x + 1] * 1 +
|
||||
p2[x - 1] * -1 +
|
||||
p2[x + 1] * 1;
|
||||
|
||||
dst[x] = av_clip_uint8(sqrt(suma*suma + sumb*sumb) * scale + delta);
|
||||
}
|
||||
|
||||
p0 = p1;
|
||||
p1 = p2;
|
||||
p2 = (p2 == end) ? orig: p2 + bstride;
|
||||
dst += out->linesize[plane];
|
||||
}
|
||||
}
|
||||
|
||||
static void filter_sobel(ConvolutionContext *s, AVFrame *in, AVFrame *out, int plane)
|
||||
{
|
||||
const uint8_t *src = in->data[plane];
|
||||
uint8_t *dst = out->data[plane];
|
||||
const int stride = in->linesize[plane];
|
||||
const int bstride = s->bstride;
|
||||
const int height = s->planeheight[plane];
|
||||
const int width = s->planewidth[plane];
|
||||
const float scale = s->scale;
|
||||
const float delta = s->delta;
|
||||
uint8_t *p0 = s->buffer + 16;
|
||||
uint8_t *p1 = p0 + bstride;
|
||||
uint8_t *p2 = p1 + bstride;
|
||||
uint8_t *orig = p0, *end = p2;
|
||||
int y, x;
|
||||
|
||||
line_copy8(p0, src + stride, width, 1);
|
||||
line_copy8(p1, src, width, 1);
|
||||
|
||||
for (y = 0; y < height; y++) {
|
||||
src += stride * (y < height - 1 ? 1 : -1);
|
||||
line_copy8(p2, src, width, 1);
|
||||
|
||||
for (x = 0; x < width; x++) {
|
||||
int suma = p0[x - 1] * -1 +
|
||||
p0[x] * -2 +
|
||||
p0[x + 1] * -1 +
|
||||
p2[x - 1] * 1 +
|
||||
p2[x] * 2 +
|
||||
p2[x + 1] * 1;
|
||||
int sumb = p0[x - 1] * -1 +
|
||||
p0[x + 1] * 1 +
|
||||
p1[x - 1] * -2 +
|
||||
p1[x + 1] * 2 +
|
||||
p2[x - 1] * -1 +
|
||||
p2[x + 1] * 1;
|
||||
|
||||
dst[x] = av_clip_uint8(sqrt(suma*suma + sumb*sumb) * scale + delta);
|
||||
}
|
||||
|
||||
p0 = p1;
|
||||
p1 = p2;
|
||||
p2 = (p2 == end) ? orig: p2 + bstride;
|
||||
dst += out->linesize[plane];
|
||||
}
|
||||
}
|
||||
|
||||
static void filter16_3x3(ConvolutionContext *s, AVFrame *in, AVFrame *out, int plane)
|
||||
{
|
||||
const uint16_t *src = (const uint16_t *)in->data[plane];
|
||||
@ -338,7 +531,8 @@ static void filter_5x5(ConvolutionContext *s, AVFrame *in, AVFrame *out, int pla
|
||||
|
||||
static int config_input(AVFilterLink *inlink)
|
||||
{
|
||||
ConvolutionContext *s = inlink->dst->priv;
|
||||
AVFilterContext *ctx = inlink->dst;
|
||||
ConvolutionContext *s = ctx->priv;
|
||||
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
|
||||
int ret, p;
|
||||
|
||||
@ -356,13 +550,23 @@ static int config_input(AVFilterLink *inlink)
|
||||
if (!s->buffer)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
if (s->depth > 8) {
|
||||
for (p = 0; p < s->nb_planes; p++) {
|
||||
if (s->size[p] == 3)
|
||||
s->filter[p] = filter16_3x3;
|
||||
else if (s->size[p] == 5)
|
||||
s->filter[p] = filter16_5x5;
|
||||
if (!strcmp(ctx->filter->name, "convolution")) {
|
||||
if (s->depth > 8) {
|
||||
for (p = 0; p < s->nb_planes; p++) {
|
||||
if (s->size[p] == 3)
|
||||
s->filter[p] = filter16_3x3;
|
||||
else if (s->size[p] == 5)
|
||||
s->filter[p] = filter16_5x5;
|
||||
}
|
||||
}
|
||||
} else if (!strcmp(ctx->filter->name, "prewitt")) {
|
||||
if (s->depth > 8)
|
||||
for (p = 0; p < s->nb_planes; p++)
|
||||
s->filter[p] = filter16_prewitt;
|
||||
} else if (!strcmp(ctx->filter->name, "sobel")) {
|
||||
if (s->depth > 8)
|
||||
for (p = 0; p < s->nb_planes; p++)
|
||||
s->filter[p] = filter16_sobel;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -403,34 +607,50 @@ static av_cold int init(AVFilterContext *ctx)
|
||||
ConvolutionContext *s = ctx->priv;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
int *matrix = (int *)s->matrix[i];
|
||||
char *p, *arg, *saveptr = NULL;
|
||||
if (!strcmp(ctx->filter->name, "convolution")) {
|
||||
for (i = 0; i < 4; i++) {
|
||||
int *matrix = (int *)s->matrix[i];
|
||||
char *p, *arg, *saveptr = NULL;
|
||||
|
||||
p = s->matrix_str[i];
|
||||
while (s->matrix_length[i] < 25) {
|
||||
if (!(arg = av_strtok(p, " ", &saveptr)))
|
||||
break;
|
||||
p = s->matrix_str[i];
|
||||
while (s->matrix_length[i] < 25) {
|
||||
if (!(arg = av_strtok(p, " ", &saveptr)))
|
||||
break;
|
||||
|
||||
p = NULL;
|
||||
sscanf(arg, "%d", &matrix[s->matrix_length[i]]);
|
||||
s->matrix_length[i]++;
|
||||
p = NULL;
|
||||
sscanf(arg, "%d", &matrix[s->matrix_length[i]]);
|
||||
s->matrix_length[i]++;
|
||||
}
|
||||
|
||||
if (s->matrix_length[i] == 9) {
|
||||
s->size[i] = 3;
|
||||
if (!memcmp(matrix, same3x3, sizeof(same3x3)))
|
||||
s->copy[i] = 1;
|
||||
else
|
||||
s->filter[i] = filter_3x3;
|
||||
} else if (s->matrix_length[i] == 25) {
|
||||
s->size[i] = 5;
|
||||
if (!memcmp(matrix, same5x5, sizeof(same5x5)))
|
||||
s->copy[i] = 1;
|
||||
else
|
||||
s->filter[i] = filter_5x5;
|
||||
} else {
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
}
|
||||
|
||||
if (s->matrix_length[i] == 9) {
|
||||
s->size[i] = 3;
|
||||
if (!memcmp(matrix, same3x3, sizeof(same3x3)))
|
||||
s->copy[i] = 1;
|
||||
} else if (!strcmp(ctx->filter->name, "prewitt")) {
|
||||
for (i = 0; i < 4; i++) {
|
||||
if ((1 << i) & s->planes)
|
||||
s->filter[i] = filter_prewitt;
|
||||
else
|
||||
s->filter[i] = filter_3x3;
|
||||
} else if (s->matrix_length[i] == 25) {
|
||||
s->size[i] = 5;
|
||||
if (!memcmp(matrix, same5x5, sizeof(same5x5)))
|
||||
s->copy[i] = 1;
|
||||
}
|
||||
} else if (!strcmp(ctx->filter->name, "sobel")) {
|
||||
for (i = 0; i < 4; i++) {
|
||||
if ((1 << i) & s->planes)
|
||||
s->filter[i] = filter_sobel;
|
||||
else
|
||||
s->filter[i] = filter_5x5;
|
||||
} else {
|
||||
return AVERROR(EINVAL);
|
||||
s->copy[i] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -462,6 +682,8 @@ static const AVFilterPad convolution_outputs[] = {
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
#if CONFIG_CONVOLUTION_FILTER
|
||||
|
||||
AVFilter ff_vf_convolution = {
|
||||
.name = "convolution",
|
||||
.description = NULL_IF_CONFIG_SMALL("Apply convolution filter."),
|
||||
@ -474,3 +696,57 @@ AVFilter ff_vf_convolution = {
|
||||
.outputs = convolution_outputs,
|
||||
.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
|
||||
};
|
||||
|
||||
#endif /* CONFIG_CONVOLUTION_FILTER */
|
||||
|
||||
#if CONFIG_PREWITT_FILTER
|
||||
|
||||
static const AVOption prewitt_options[] = {
|
||||
{ "planes", "set planes to filter", OFFSET(planes), AV_OPT_TYPE_INT, {.i64=15}, 0, 15, FLAGS},
|
||||
{ "scale", "set scale", OFFSET(scale), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, 0.0, 65535, FLAGS},
|
||||
{ "delta", "set delta", OFFSET(delta), AV_OPT_TYPE_FLOAT, {.dbl=0}, -65535, 65535, FLAGS},
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
AVFILTER_DEFINE_CLASS(prewitt);
|
||||
|
||||
AVFilter ff_vf_prewitt = {
|
||||
.name = "prewitt",
|
||||
.description = NULL_IF_CONFIG_SMALL("Apply prewitt operator."),
|
||||
.priv_size = sizeof(ConvolutionContext),
|
||||
.priv_class = &prewitt_class,
|
||||
.init = init,
|
||||
.uninit = uninit,
|
||||
.query_formats = query_formats,
|
||||
.inputs = convolution_inputs,
|
||||
.outputs = convolution_outputs,
|
||||
.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
|
||||
};
|
||||
|
||||
#endif /* CONFIG_PREWITT_FILTER */
|
||||
|
||||
#if CONFIG_SOBEL_FILTER
|
||||
|
||||
static const AVOption sobel_options[] = {
|
||||
{ "planes", "set planes to filter", OFFSET(planes), AV_OPT_TYPE_INT, {.i64=15}, 0, 15, FLAGS},
|
||||
{ "scale", "set scale", OFFSET(scale), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, 0.0, 65535, FLAGS},
|
||||
{ "delta", "set delta", OFFSET(delta), AV_OPT_TYPE_FLOAT, {.dbl=0}, -65535, 65535, FLAGS},
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
AVFILTER_DEFINE_CLASS(sobel);
|
||||
|
||||
AVFilter ff_vf_sobel = {
|
||||
.name = "sobel",
|
||||
.description = NULL_IF_CONFIG_SMALL("Apply sobel operator."),
|
||||
.priv_size = sizeof(ConvolutionContext),
|
||||
.priv_class = &sobel_class,
|
||||
.init = init,
|
||||
.uninit = uninit,
|
||||
.query_formats = query_formats,
|
||||
.inputs = convolution_inputs,
|
||||
.outputs = convolution_outputs,
|
||||
.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
|
||||
};
|
||||
|
||||
#endif /* CONFIG_SOBEL_FILTER */
|
||||
|
Loading…
Reference in New Issue
Block a user