|
|
|
@ -154,15 +154,16 @@ static int get_rounded_direction(int gx, int gy) |
|
|
|
|
return DIRECTION_VERTICAL; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void sobel(AVFilterContext *ctx, int w, int h, |
|
|
|
|
uint16_t *dst, int dst_linesize, |
|
|
|
|
const uint8_t *src, int src_linesize) |
|
|
|
|
static void sobel(int w, int h, |
|
|
|
|
uint16_t *dst, int dst_linesize, |
|
|
|
|
int8_t *dir, int dir_linesize, |
|
|
|
|
const uint8_t *src, int src_linesize) |
|
|
|
|
{ |
|
|
|
|
int i, j; |
|
|
|
|
EdgeDetectContext *edgedetect = ctx->priv; |
|
|
|
|
|
|
|
|
|
for (j = 1; j < h - 1; j++) { |
|
|
|
|
dst += dst_linesize; |
|
|
|
|
dir += dir_linesize; |
|
|
|
|
src += src_linesize; |
|
|
|
|
for (i = 1; i < w - 1; i++) { |
|
|
|
|
const int gx = |
|
|
|
@ -175,17 +176,17 @@ static void sobel(AVFilterContext *ctx, int w, int h, |
|
|
|
|
-1*src[-src_linesize + i+1] + 1*src[ src_linesize + i+1]; |
|
|
|
|
|
|
|
|
|
dst[i] = FFABS(gx) + FFABS(gy); |
|
|
|
|
edgedetect->directions[j*w + i] = get_rounded_direction(gx, gy); |
|
|
|
|
dir[i] = get_rounded_direction(gx, gy); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void non_maximum_suppression(AVFilterContext *ctx, int w, int h, |
|
|
|
|
static void non_maximum_suppression(int w, int h, |
|
|
|
|
uint8_t *dst, int dst_linesize, |
|
|
|
|
const int8_t *dir, int dir_linesize, |
|
|
|
|
const uint16_t *src, int src_linesize) |
|
|
|
|
{ |
|
|
|
|
int i, j; |
|
|
|
|
EdgeDetectContext *edgedetect = ctx->priv; |
|
|
|
|
|
|
|
|
|
#define COPY_MAXIMA(ay, ax, by, bx) do { \ |
|
|
|
|
if (src[i] > src[(ay)*src_linesize + i+(ax)] && \
|
|
|
|
@ -195,9 +196,10 @@ static void non_maximum_suppression(AVFilterContext *ctx, int w, int h, |
|
|
|
|
|
|
|
|
|
for (j = 1; j < h - 1; j++) { |
|
|
|
|
dst += dst_linesize; |
|
|
|
|
dir += dir_linesize; |
|
|
|
|
src += src_linesize; |
|
|
|
|
for (i = 1; i < w - 1; i++) { |
|
|
|
|
switch (edgedetect->directions[j*w + i]) { |
|
|
|
|
switch (dir[i]) { |
|
|
|
|
case DIRECTION_45UP: COPY_MAXIMA( 1, -1, -1, 1); break; |
|
|
|
|
case DIRECTION_45DOWN: COPY_MAXIMA(-1, -1, 1, 1); break; |
|
|
|
|
case DIRECTION_HORIZONTAL: COPY_MAXIMA( 0, -1, 0, 1); break; |
|
|
|
@ -207,14 +209,11 @@ static void non_maximum_suppression(AVFilterContext *ctx, int w, int h, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void double_threshold(AVFilterContext *ctx, int w, int h, |
|
|
|
|
static void double_threshold(int low, int high, int w, int h, |
|
|
|
|
uint8_t *dst, int dst_linesize, |
|
|
|
|
const uint8_t *src, int src_linesize) |
|
|
|
|
{ |
|
|
|
|
int i, j; |
|
|
|
|
EdgeDetectContext *edgedetect = ctx->priv; |
|
|
|
|
const int low = edgedetect->low_u8; |
|
|
|
|
const int high = edgedetect->high_u8; |
|
|
|
|
|
|
|
|
|
for (j = 0; j < h; j++) { |
|
|
|
|
for (i = 0; i < w; i++) { |
|
|
|
@ -249,6 +248,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) |
|
|
|
|
AVFilterLink *outlink = inlink->dst->outputs[0]; |
|
|
|
|
uint8_t *tmpbuf = edgedetect->tmpbuf; |
|
|
|
|
uint16_t *gradients = edgedetect->gradients; |
|
|
|
|
int8_t *directions= edgedetect->directions; |
|
|
|
|
int direct = 0; |
|
|
|
|
AVFrame *out; |
|
|
|
|
|
|
|
|
@ -270,19 +270,22 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) |
|
|
|
|
in->data[0], in->linesize[0]); |
|
|
|
|
|
|
|
|
|
/* compute the 16-bits gradients and directions for the next step */ |
|
|
|
|
sobel(ctx, inlink->w, inlink->h, |
|
|
|
|
sobel(inlink->w, inlink->h, |
|
|
|
|
gradients, inlink->w, |
|
|
|
|
directions,inlink->w, |
|
|
|
|
tmpbuf, inlink->w); |
|
|
|
|
|
|
|
|
|
/* non_maximum_suppression() will actually keep & clip what's necessary and
|
|
|
|
|
* ignore the rest, so we need a clean output buffer */ |
|
|
|
|
memset(tmpbuf, 0, inlink->w * inlink->h); |
|
|
|
|
non_maximum_suppression(ctx, inlink->w, inlink->h, |
|
|
|
|
non_maximum_suppression(inlink->w, inlink->h, |
|
|
|
|
tmpbuf, inlink->w, |
|
|
|
|
directions,inlink->w, |
|
|
|
|
gradients, inlink->w); |
|
|
|
|
|
|
|
|
|
/* keep high values, or low values surrounded by high values */ |
|
|
|
|
double_threshold(ctx, inlink->w, inlink->h, |
|
|
|
|
double_threshold(edgedetect->low_u8, edgedetect->high_u8, |
|
|
|
|
inlink->w, inlink->h, |
|
|
|
|
out->data[0], out->linesize[0], |
|
|
|
|
tmpbuf, inlink->w); |
|
|
|
|
|
|
|
|
|