forked from minhngoc25a/freetype2
[sdf -> bsdf] Added function to approximate edge distance.
* src/sdf/ftbsdf.c (bsdf_approximate_edge): The function uses the Gustavson's algorithm to approximate the edge from pixel values. * src/sdf/ftbsdf.c (compute_gradient): The function uses Sobel's operator to compute the gradient at a pixel. The is used to detect edge direction.
This commit is contained in:
parent
ffb6890089
commit
fbbec7c64d
|
@ -1,3 +1,15 @@
|
||||||
|
2020-07-29 Anuj Verma <anujv@iitbhilai.ac.in>
|
||||||
|
|
||||||
|
[sdf -> bsdf] Added function to approximate edge distance.
|
||||||
|
|
||||||
|
* src/sdf/ftbsdf.c (bsdf_approximate_edge): The function
|
||||||
|
uses the Gustavson's algorithm to approximate the edge
|
||||||
|
from pixel values.
|
||||||
|
|
||||||
|
* src/sdf/ftbsdf.c (compute_gradient): The function uses
|
||||||
|
Sobel's operator to compute the gradient at a pixel.
|
||||||
|
The is used to detect edge direction.
|
||||||
|
|
||||||
2020-07-28 Anuj Verma <anujv@iitbhilai.ac.in>
|
2020-07-28 Anuj Verma <anujv@iitbhilai.ac.in>
|
||||||
|
|
||||||
* src/sdf/ftbsdf.c (_pass): Use function for repetitive task.
|
* src/sdf/ftbsdf.c (_pass): Use function for repetitive task.
|
||||||
|
|
157
src/sdf/ftbsdf.c
157
src/sdf/ftbsdf.c
|
@ -47,7 +47,8 @@
|
||||||
|
|
||||||
} BSDF_TRaster;
|
} BSDF_TRaster;
|
||||||
|
|
||||||
/* euclidean distance used for euclidean distance transform */
|
/* Euclidean distance used for euclidean distance transform */
|
||||||
|
/* can also be interpreted as edge distance. */
|
||||||
typedef struct ED_
|
typedef struct ED_
|
||||||
{
|
{
|
||||||
FT_16D16 dist; /* distance at `near' */
|
FT_16D16 dist; /* distance at `near' */
|
||||||
|
@ -126,12 +127,15 @@
|
||||||
FT_Int num_neighbour = 0;
|
FT_Int num_neighbour = 0;
|
||||||
|
|
||||||
|
|
||||||
if ( y == 7 && x == 20 )
|
|
||||||
to_check = NULL;
|
|
||||||
|
|
||||||
if ( *s == 0 )
|
if ( *s == 0 )
|
||||||
goto Done;
|
goto Done;
|
||||||
|
|
||||||
|
if ( *s > 0 && *s < 255 )
|
||||||
|
{
|
||||||
|
is_edge = 1;
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
|
|
||||||
/* up */
|
/* up */
|
||||||
CHECK_NEIGHBOR( 0, -1 );
|
CHECK_NEIGHBOR( 0, -1 );
|
||||||
|
|
||||||
|
@ -166,6 +170,122 @@
|
||||||
|
|
||||||
#undef CHECK_NEIGHBOR
|
#undef CHECK_NEIGHBOR
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
*
|
||||||
|
* @Function:
|
||||||
|
* compute_gradient
|
||||||
|
*
|
||||||
|
* @Description:
|
||||||
|
* [TODO]
|
||||||
|
*
|
||||||
|
* @Input:
|
||||||
|
* [TODO]
|
||||||
|
*
|
||||||
|
* @Return:
|
||||||
|
* [TODO]
|
||||||
|
*/
|
||||||
|
static FT_16D16_Vec
|
||||||
|
compute_gradient( ED* current,
|
||||||
|
FT_Int x,
|
||||||
|
FT_Int y,
|
||||||
|
FT_Int w,
|
||||||
|
FT_Int r )
|
||||||
|
{
|
||||||
|
/* [TODO]: Write proper explanation. */
|
||||||
|
FT_16D16_Vec g = { 0, 0 };
|
||||||
|
|
||||||
|
|
||||||
|
if ( x <= 0 || x >= w - 1 ||
|
||||||
|
y <= 0 || y >= r - 1 )
|
||||||
|
return g;
|
||||||
|
|
||||||
|
|
||||||
|
g.x = - current[-w - 1].dist -
|
||||||
|
2 * current[ -1 ].dist -
|
||||||
|
current[ w - 1].dist +
|
||||||
|
current[-w + 1].dist +
|
||||||
|
2 * current[ 1 ].dist +
|
||||||
|
current[ w + 1].dist;
|
||||||
|
|
||||||
|
g.y = - current[-w - 1].dist -
|
||||||
|
2 * current[ -w ].dist -
|
||||||
|
current[-w + 1].dist +
|
||||||
|
current[ w - 1].dist +
|
||||||
|
2 * current[ w ].dist +
|
||||||
|
current[ w + 1].dist;
|
||||||
|
|
||||||
|
FT_Vector_NormLen( &g );
|
||||||
|
g.x = FT_MulFix( g.x, ONE / 2 - current->dist );
|
||||||
|
g.y = FT_MulFix( g.y, ONE / 2 - current->dist );
|
||||||
|
|
||||||
|
return g;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
*
|
||||||
|
* @Function:
|
||||||
|
* bsdf_approximate_edge
|
||||||
|
*
|
||||||
|
* @Description:
|
||||||
|
* [TODO]
|
||||||
|
*
|
||||||
|
* @Input:
|
||||||
|
* [TODO]
|
||||||
|
*
|
||||||
|
* @Return:
|
||||||
|
* [TODO]
|
||||||
|
*/
|
||||||
|
static FT_Error
|
||||||
|
bsdf_approximate_edge( BSDF_Worker* worker )
|
||||||
|
{
|
||||||
|
/* [TODO]: Write proper explanation. */
|
||||||
|
FT_Error error = FT_Err_Ok;
|
||||||
|
FT_Int i, j;
|
||||||
|
FT_Int index;
|
||||||
|
ED* ed;
|
||||||
|
|
||||||
|
|
||||||
|
if ( !worker || !worker->distance_map )
|
||||||
|
{
|
||||||
|
error = FT_THROW( Invalid_Argument );
|
||||||
|
goto Exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
ed = worker->distance_map;
|
||||||
|
|
||||||
|
for ( j = 0; j < worker->rows; j++ )
|
||||||
|
{
|
||||||
|
for ( i = 0; i < worker->width; i++ )
|
||||||
|
{
|
||||||
|
index = j * worker->width + i;
|
||||||
|
|
||||||
|
if ( ed[index].dist != 0 )
|
||||||
|
ed[index].near = compute_gradient( ed + index, i, j,
|
||||||
|
worker->width, worker->rows );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( j = 0; j < worker->rows; j++ )
|
||||||
|
{
|
||||||
|
for ( i = 0; i < worker->width; i++ )
|
||||||
|
{
|
||||||
|
index = j * worker->width + i;
|
||||||
|
|
||||||
|
if ( ed[index].dist == 0 )
|
||||||
|
{
|
||||||
|
ed[index].dist = 200 * ONE;
|
||||||
|
ed[index].near.x = 100 * ONE;
|
||||||
|
ed[index].near.y = 100 * ONE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ed[index].dist = FT_Vector_Length( &ed[index].near );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Exit:
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
*
|
*
|
||||||
* @Function:
|
* @Function:
|
||||||
|
@ -277,7 +397,7 @@
|
||||||
{
|
{
|
||||||
FT_Int t_index = t_j * t_width + t_i;
|
FT_Int t_index = t_j * t_width + t_i;
|
||||||
FT_Int s_index;
|
FT_Int s_index;
|
||||||
FT_Byte pixel_value;
|
FT_Int pixel_value;
|
||||||
|
|
||||||
|
|
||||||
t[t_index] = zero_ed;
|
t[t_index] = zero_ed;
|
||||||
|
@ -290,10 +410,7 @@
|
||||||
if ( s_i < 0 || s_i >= s_width ||
|
if ( s_i < 0 || s_i >= s_width ||
|
||||||
s_j < 0 || s_j >= s_rows )
|
s_j < 0 || s_j >= s_rows )
|
||||||
{
|
{
|
||||||
t[t_index].near.x = FT_INT_MAX;
|
t[t_index].sign = -1;
|
||||||
t[t_index].near.y = FT_INT_MAX;
|
|
||||||
t[t_index].dist = 128 * ONE;
|
|
||||||
t[t_index].sign = -1;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -302,20 +419,19 @@
|
||||||
else
|
else
|
||||||
s_index = s_j * s_width + s_i;
|
s_index = s_j * s_width + s_i;
|
||||||
|
|
||||||
pixel_value = s[s_index];
|
pixel_value = (FT_Int)s[s_index];
|
||||||
|
|
||||||
|
/* clamp the pixel value to [0, 256] */
|
||||||
|
if ( pixel_value == 255 )
|
||||||
|
pixel_value = 256;
|
||||||
|
|
||||||
|
/* only assign values to the edge pixels */
|
||||||
if ( bsdf_is_edge( s + s_index , s_i, s_j, s_width, s_rows ) )
|
if ( bsdf_is_edge( s + s_index , s_i, s_j, s_width, s_rows ) )
|
||||||
{
|
t[t_index].dist = 256 * pixel_value;
|
||||||
t[t_index].dist = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
t[t_index].near.x = FT_INT_MAX;
|
|
||||||
t[t_index].near.y = FT_INT_MAX;
|
|
||||||
t[t_index].dist = 128 * ONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( pixel_value )
|
/* We assume that if the pixel is inside a contour */
|
||||||
|
/* then it's coverage value must be > 127. */
|
||||||
|
if ( pixel_value > 127 )
|
||||||
t[t_index].sign = 1;
|
t[t_index].sign = 1;
|
||||||
else
|
else
|
||||||
t[t_index].sign = -1;
|
t[t_index].sign = -1;
|
||||||
|
@ -765,6 +881,7 @@
|
||||||
worker.params = *sdf_params;
|
worker.params = *sdf_params;
|
||||||
|
|
||||||
FT_CALL( bsdf_init_distance_map( source, &worker ) );
|
FT_CALL( bsdf_init_distance_map( source, &worker ) );
|
||||||
|
FT_CALL( bsdf_approximate_edge( &worker ) );
|
||||||
FT_CALL( edt8( &worker ) );
|
FT_CALL( edt8( &worker ) );
|
||||||
FT_CALL( finalize_sdf( &worker, target ) );
|
FT_CALL( finalize_sdf( &worker, target ) );
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue