|
|
@@ -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; |
|
|
|
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); |
|
|
|
} |
|
|
|
} |
|
|
|
} 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 */ |