[sdf -> bsdf] Add explanation of the approximation.

* src/sdf/ftbsdf.c (compute_gradient => compute_edge_distance):
  Renamed to make sense of what the function does.
  Also, added the explanation of the algorithm used
  and a high level view of how it works.

* src/sdf/ftbsdf.c (compare_neighbor): Fix a bug related
  to value approximation before calling `FT_Vector_Length'.
This commit is contained in:
Anuj Verma 2020-07-31 17:43:33 +05:30 committed by anujverma
parent dcdcc65201
commit 62b38d2b85
2 changed files with 72 additions and 13 deletions

View File

@ -1,3 +1,15 @@
2020-07-31 Anuj Verma <anujv@iitbhilai.ac.in>
[sdf -> bsdf] Add explanation of the approximation.
* src/sdf/ftbsdf.c (compute_gradient => compute_edge_distance):
Renamed to make sense of what the function does.
Also, added the explanation of the algorithm used
and a high level view of how it works.
* src/sdf/ftbsdf.c (compare_neighbor): Fix a bug related
to value approximation before calling `FT_Vector_Length'.
2020-07-30 Anuj Verma <anujv@iitbhilai.ac.in> 2020-07-30 Anuj Verma <anujv@iitbhilai.ac.in>
* src/sdf/ftsdfcommon.h (*): Fix line endings. * src/sdf/ftsdfcommon.h (*): Fix line endings.

View File

@ -154,7 +154,7 @@
/************************************************************************** /**************************************************************************
* *
* @Function: * @Function:
* compute_gradient * compute_edge_distance
* *
* @Description: * @Description:
* [TODO] * [TODO]
@ -166,13 +166,46 @@
* [TODO] * [TODO]
*/ */
static FT_16D16_Vec static FT_16D16_Vec
compute_gradient( ED* current, compute_edge_distance( ED* current,
FT_Int x, FT_Int x,
FT_Int y, FT_Int y,
FT_Int w, FT_Int w,
FT_Int r ) FT_Int r )
{ {
/* [TODO]: Write proper explanation. */ /* This is the function which is based on the paper presented */
/* by Stefan Gustavson and Robin Strand which is used to app- */
/* roximate edge distance from anti-aliased bitmaps. */
/* */
/* The algorithm is as follows: */
/* */
/* * In anti-aliased images, the pixel's alpha value is the */
/* coverage of the pixel by the outline. For example if the */
/* alpha value is 0.5f then we can assume the the outline */
/* passes through the center of the pixel. */
/* */
/* * So, we can use that alpha value to approximate the real */
/* distance of the pixel to edge pretty accurately. A real */
/* simple approximation is ( 0.5f - alpha ), assuming that */
/* the outline is parallel to the x or y axis. But in this */
/* algorithm that is pretty accurate the edge distance. */
/* */
/* * The only remaining piece of information that we cannot */
/* approximate directly from the alpha is the direction of */
/* the edge. That is where we use the Sobel's operator to */
/* compute the gradient of the pixel. The gradient give us */
/* a pretty good approximation of the edge direction. */
/* We use a 3x3 kernel filter to compute the gradient. */
/* */
/* * After the above two steps we have both the direction and */
/* the distance to the edge which is used to generate the */
/* Signed Distance Field. */
/* */
/* References: */
/* * Anti-Aliased Euclidean Distance Transform: */
/* http://weber.itn.liu.se/~stegu/aadist/edtaa_preprint.pdf */
/* * Sobel Operator: */
/* https://en.wikipedia.org/wiki/Sobel_operator */
/* */
FT_16D16_Vec g = { 0, 0 }; FT_16D16_Vec g = { 0, 0 };
FT_16D16 dist; FT_16D16 dist;
FT_16D16 a1, temp; FT_16D16 a1, temp;
@ -184,7 +217,18 @@
return g; return g;
/* compute the gradient */ /* Compute the gradient using the Sobel operator. */
/* In this case we use the following 3x3 filters: */
/* */
/* For x: | -1 0 -1 | */
/* | -root(2) 0 root(2) | */
/* | -1 0 1 | */
/* */
/* For y: | -1 -root(2) -1 | */
/* | 0 0 0 | */
/* | 1 root(2) 1 | */
/* */
/* [Note]: 92681 is nothing but root(2) in 16.16 */
g.x = - current[-w - 1].dist - g.x = - current[-w - 1].dist -
FT_MulFix( current[-1].dist, 92681 ) - FT_MulFix( current[-1].dist, 92681 ) -
current[ w - 1].dist + current[ w - 1].dist +
@ -260,7 +304,6 @@
static FT_Error static FT_Error
bsdf_approximate_edge( BSDF_Worker* worker ) bsdf_approximate_edge( BSDF_Worker* worker )
{ {
/* [TODO]: Write proper explanation. */
FT_Error error = FT_Err_Ok; FT_Error error = FT_Err_Ok;
FT_Int i, j; FT_Int i, j;
FT_Int index; FT_Int index;
@ -282,7 +325,8 @@
index = j * worker->width + i; index = j * worker->width + i;
if ( ed[index].dist != 0 ) if ( ed[index].dist != 0 )
ed[index].near = compute_gradient( ed + index, i, j, /* approximate the edge distance */
ed[index].near = compute_edge_distance( ed + index, i, j,
worker->width, worker->rows ); worker->width, worker->rows );
} }
} }
@ -294,6 +338,8 @@
{ {
index = j * worker->width + i; index = j * worker->width + i;
/* Assign the values, for bacground pixel assign */
/* values vert far away. */
if ( ed[index].dist == 0 ) if ( ed[index].dist == 0 )
{ {
ed[index].dist = 200 * ONE; ed[index].dist = 200 * ONE;
@ -449,7 +495,7 @@
pixel_value = 256; pixel_value = 256;
/* only assign values to the edge pixels */ /* only assign values to the edge pixels */
if ( bsdf_is_edge( s + s_index , s_i, s_j, s_width, s_rows ) ) if ( pixel_value )
t[t_index].dist = 256 * pixel_value; t[t_index].dist = 256 * pixel_value;
/* We assume that if the pixel is inside a contour */ /* We assume that if the pixel is inside a contour */
@ -510,8 +556,9 @@
/* Of course this will be eliminated while using */ /* Of course this will be eliminated while using */
/* squared distances. */ /* squared distances. */
/* approximate the distance */ /* Approximate the distance, use 1 to avoid */
dist = to_check->dist + ( FT_ABS( x_offset ) + FT_ABS( y_offset ) ) * ONE; /* precision errors. */
dist = to_check->dist + ONE;
if ( dist < current->dist ) if ( dist < current->dist )
{ {