signed distance field 算法

1649 篇文章 12 订阅
1623 篇文章 23 订阅

将二值图转化成signed distance field后,可以在双线性插值下实现平滑放大。

定义:

到前景的distance field:各点到最近前景点的距离。

到背景的distance field:各点到最近背景景点的距离。

则: signed distance field = 到背景的distance field - 到前景的distance field。

注:最好严格按上面定义计算signed distance field。看到有的博文中说先提取轮廓点,然后计算各点到最近轮廓点的距离,并且如果此点是前景点就将计算出的距离加+号,如果此点是背景点就将计算出的距离加-号。这样确实也得到一个signed distance field,但显然这样计算出来的signed distance field跟严格按照上面定义计算出来的结果是不一样的。

按标准定义计算出signed distance field后,轮廓阈值应取为0.5,即signed distance field中大于等于0.5的像素复原为前景。

实际存储的时候我是求了一下signed distance field中的最大值max和最小值min,然后通过(signedDis-min)/(max-min)将signedDis映射到[0,1],并且将轮廓阈值0.5映射为(0.5-min)/(max-min),即得到了一个取值在[0,1]间的signed distance field,其轮廓阈值为(0.5-min)/(max-min)。

 

生成signed distance field的算法,开始我在这个博文(http://blog.csdn.net/tianwaifeimao/article/details/45078661)中找到一个Saito算法,它利用距离平方在x和y上可分开处理的性质提高了计算效率,虽然没有完全达到线性复杂度,但也比暴力算法快得多。算法的正确性很容易看出来,实现出来实测了一下,也没问题。

后来又在网上找到一个称为8ssedt的算法(见:http://www.codersnotes.com/algorithms/signed-distance-fields),博文中给的论文链接打不开,但给出源代码下载,代码很短能看明白,用的是与最短路径的算法相同的思路,针对问题本身的结构做了很巧妙的优化,达到了线性复杂度。(注:前述Saito算法第一步求各点在本行中的最近前景点时也可以利用8ssedt算法的思路进行优化计算)。

8ssedt算法代码如下(转自:http://www.codersnotes.com/algorithms/signed-distance-fields):

#include "SDL/sdl.h"
#include <math.h>

#define WIDTH  256
#define HEIGHT 256

struct Point
{
	int dx, dy;

	int DistSq() const { return dx*dx + dy*dy; }
};

struct Grid
{
	Point grid[HEIGHT][WIDTH];
};

Point inside = { 0, 0 };
Point empty = { 9999, 9999 };
Grid grid1, grid2;

Point Get( Grid &g, int x, int y )
{
	// OPTIMIZATION: you can skip the edge check code if you make your grid 
	// have a 1-pixel gutter.
	if ( x >= 0 && y >= 0 && x < WIDTH && y < HEIGHT )
		return g.grid[y][x];
	else
		return empty;
}

void Put( Grid &g, int x, int y, const Point &p )
{
	g.grid[y][x] = p;
}

void Compare( Grid &g, Point &p, int x, int y, int offsetx, int offsety )
{
	Point other = Get( g, x+offsetx, y+offsety );
	other.dx += offsetx;
	other.dy += offsety;

	if (other.DistSq() < p.DistSq())
		p = other;
}

void GenerateSDF( Grid &g )
{
	// Pass 0
	for (int y=0;y<HEIGHT;y++)
	{
		for (int x=0;x<WIDTH;x++)
		{
			Point p = Get( g, x, y );
			Compare( g, p, x, y, -1,  0 );
			Compare( g, p, x, y,  0, -1 );
			Compare( g, p, x, y, -1, -1 );
			Compare( g, p, x, y,  1, -1 );
			Put( g, x, y, p );
		}

		for (int x=WIDTH-1;x>=0;x--)
		{
			Point p = Get( g, x, y );
			Compare( g, p, x, y, 1, 0 );
			Put( g, x, y, p );
		}
	}

	// Pass 1
	for (int y=HEIGHT-1;y>=0;y--)
	{
		for (int x=WIDTH-1;x>=0;x--)
		{
			Point p = Get( g, x, y );
			Compare( g, p, x, y,  1,  0 );
			Compare( g, p, x, y,  0,  1 );
			Compare( g, p, x, y, -1,  1 );
			Compare( g, p, x, y,  1,  1 );
			Put( g, x, y, p );
		}

		for (int x=0;x<WIDTH;x++)
		{
			Point p = Get( g, x, y );
			Compare( g, p, x, y, -1, 0 );
			Put( g, x, y, p );
		}
	}
}

int main( int argc, char* args[] )
{
    if ( SDL_Init( SDL_INIT_VIDEO ) == -1 )
        return 1;

    SDL_Surface *screen = SDL_SetVideoMode( WIDTH, HEIGHT, 32, SDL_SWSURFACE );
    if ( !screen )
        return 1;

	// Initialize the grid from the BMP file.
    SDL_Surface *temp = SDL_LoadBMP( "test.bmp" );
	temp = SDL_ConvertSurface( temp, screen->format, SDL_SWSURFACE ); 
	SDL_LockSurface( temp );
	for( int y=0;y<HEIGHT;y++ )
	{
		for ( int x=0;x<WIDTH;x++ )
		{
			Uint8 r,g,b;
			Uint32 *src = ( (Uint32 *)( (Uint8 *)temp->pixels + y*temp->pitch ) ) + x;
			SDL_GetRGB( *src, temp->format, &r, &g, &b );
			
			// Points inside get marked with a dx/dy of zero.
			// Points outside get marked with an infinitely large distance.
			if ( g < 128 )
			{
				Put( grid1, x, y, inside );
				Put( grid2, x, y, empty );
			} else {
				Put( grid2, x, y, inside );
				Put( grid1, x, y, empty );
			}
		}
	}
	SDL_UnlockSurface( temp );

	// Generate the SDF.
	GenerateSDF( grid1 );
	GenerateSDF( grid2 );
	
	// Render out the results.
	SDL_LockSurface( screen );
	for( int y=0;y<HEIGHT;y++ )
	{
		for ( int x=0;x<WIDTH;x++ )
		{
			// Calculate the actual distance from the dx/dy
			int dist1 = (int)( sqrt( (double)Get( grid1, x, y ).DistSq() ) );
			int dist2 = (int)( sqrt( (double)Get( grid2, x, y ).DistSq() ) );
			int dist = dist1 - dist2;

			// Clamp and scale it, just for display purposes.
			int c = dist*3 + 128;
			if ( c < 0 ) c = 0;
			if ( c > 255 ) c = 255;

			Uint32 *dest = ( (Uint32 *)( (Uint8 *)screen->pixels + y*screen->pitch ) ) + x;
			*dest = SDL_MapRGB( screen->format, c, c, c );
		}
	}
	SDL_UnlockSurface( screen );
	SDL_Flip( screen );

	// Wait for a keypress
	SDL_Event event;
	while( true )
	{
		if ( SDL_PollEvent( &event ) ) 
		switch( event.type )
		{
		case SDL_QUIT:
		case SDL_KEYDOWN:
			return true;
		}
	}

	return 0;
}

 

signed distance field 算法

标签:des   算法   class   log   com   http   si   代码   it   

原文:http://www.cnblogs.com/wantnon/p/4947067.html

### 回答1: 签名距离场(Signed Distance Field)是一种用于描述二维或三维空间中物体形状的技术。它通过计算每个像素或顶点到最近物体表面的距离,并将其正负号表示为该像素或顶点的值,从而生成一个包含物体形状信息的图像或数据结构。签名距离场可以用于实现高质量的渲染、碰撞检测、形状变形等应用。 ### 回答2: Signed distance field是一种用于描述2D或3D图形的技术。它可以用来实现许多计算机图形学中的应用,如字体渲染、图形变形、遮挡剪除、违背处理等等。 Signed distance field的主要思想是通过计算每个点到形状(如字形)之间的距离来表示形状。这个距离可以是正数、负数或0,区别在于点与形状的相对位置。如果点在形状内部,距离为负;如果在外部,距离为正;如果在形状上,距离为0。这些距离值被组织成一个网格或纹理,称为signed distance field。 利用signed distance field可以高效地进行图形渲染,实现高质量的字体渲染效果。由于有了距离信息,字体边缘、倾斜等细节均能够得到表现。此外,signed distance field还可以用于形状的物理变形和遮挡剪除处理。在游戏中,它也可以用来处理着色、阴影和碰撞检测。 Signed distance field技术在最近几年被大量应用于2D和3D图形领域中,得到了广泛的关注和研究。它被认为是一个非常有前途的技术,在未来可能会应用于更广泛的领域中。 ### 回答3: Signed Distance Field(SDF,有时称为Distance Field)是一种用于存储和处理图形形状的技术,它被广泛应用于计算机图形学、游戏开发以及工业设计等领域。SDF的主要特点是在图形形状表现中同时提供了距离和方向的信息,这种信息支持一系列的图形操作,例如放缩、旋转和截取等视觉特效。 SDF最初被用于字形渲染,它可以使用比横向向量清晰(sharp)得多的向量控制轮廓;SDF可以被用于对象投影,在三维空间中处理物体形状的透明度;SDF也可以被用于创建特效,在动态创建的形状中保存形状和距离场的注意力值。SDF匹配的方法可以构建出多边形并存储键值对——key-value pairs,该密钥可以用于拾取和过滤。 简而言之,SDF是一种能让你在计算图形边界距离的同时,还能获取专业的视觉效果的推算算法,使用它可以更高效地渲染图形,实现更加复杂的视觉效果。随着技术的进步和应用的广泛,SDF已成为计算机图形学领域中被广泛应用的技术之一。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值