signed distance field 算法

将二值图转化成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;
}
时间: 2024-10-15 01:57:23

signed distance field 算法的相关文章

Signed Distance Field Shadow in Unity

0x00 前言 最近读到了一个今年GDC上很棒的分享,是Sebastian Aaltonen带来的利用Ray-tracing实现一些有趣的效果的分享. 其中有一段他介绍到了对Signed Distance Field Shadow的改进,主要体现在消除SDF阴影的一些artifact上. 第一次看到Signed Distance Field Shadow是在大神Inigo Quilez的博客上,较传统的阴影实现方式,例如shadow map,视觉效果要好很多.可以看到下图中物体的阴影随着距离由近

Distance Field Technique

[Distance Field Technique] 一种小纹理高清放大的技术. 参考:<Improved Alpha-Tested Magnification for Vector Textures and Special Effects>.pdf 原文地址:https://www.cnblogs.com/tekkaman/p/9053053.html

Levenshtein distance 编辑距离算法

这几天再看 virtrual-dom,关于两个列表的对比,讲到了 Levenshtein distance 距离,周末抽空做一下总结. Levenshtein Distance 介绍 在信息理论和计算机科学中,Levenshtein 距离是用于测量两个序列之间的差异量(即编辑距离)的度量.两个字符串之间的 Levenshtein 距离定义为将一个字符串转换为另一个字符串所需的最小编辑数,允许的编辑操作是单个字符的插入,删除或替换. 例子 ‘kitten’和’sitten’之间的 Levensht

计算两组标签相似度算法——levenshtein distance 编辑距离算法

标签在数据分析中起到很重要的作用,给用户打标签,给商品打标签,给新闻打标签,好的标签可以为我们后期分析数据时提供很大的便利.有时我们需要计算两个对象之间标签的相似度.目前学习的算法是levenshtein distance 编辑距离算法. 代码示例: //标签相似度 public static double levenshtein(String s1, String s2) { System.out.println("levenshtein str1:"+s1+" str2:

Levenshtein Distance (编辑距离) 算法详解

编辑距离即从一个字符串变换到另一个字符串所需要的最少变化操作步骤(以字符为单位,如son到sun,s不用变,将o->s,n不用变,故操作步骤为1). 为了得到编辑距离,我们画一张二维表来理解,以beauty和batyu为例: 图示如1单元格位置即是两个单词的第一个字符[b]比较得到的值,其值由它上方的值(1).它左方的值(1)和.它左上角的值(0)来决定.当单元格所在的行和列所对应的字符(如3对应的是a和b)相等时,它左上角的值+0,否则加1(如在1处,[b]=[b]故左上角的值加0即0+0=0

运行带distance field的Hiero

从http://libgdx.badlogicgames.com/releases/下载zip包并解压,切换到解压后的目录,执行: java -cp gdx.jar;gdx-natives.jar;gdx-backend-lwjgl.jar;gdx-backend-lwjgl-natives.jar;extensions\gdx-tools\gdx-tools.jar com.badlogic.gdx.tools.hiero.Hiero

distance font rendering

使用bitmap font 时有一个缺陷就是在字体缩放时, 会显示出明显的锯齿. 所以, 通常会为某种字体创建诸如 small ,normal ,big 等不同大小的字体以应对不同的缩放区间. 这样会造成巨大的内存开销.  value 的论文 http://www.valvesoftware.com/publications/2007/SIGGRAPH2007_AlphaTestedMagnification.pdf 中提到一种 scale friendly 的方法, 实现的结果如下. 实现方法

三维重建技术概述

基于视觉的三维重建,指的是通过摄像机获取场景物体的数据图像,并对此图像进行分析处理,再结合计算机视觉知识推导出现实环境中物体的三维信息. 1. 相关概念 (1)彩色图像与深度图像 彩色图像也叫作RGB图像,R.G.B三个分量对应于红.绿.蓝三个通道的颜色,它们的叠加组成了图像像素的不同灰度级.RGB颜色空间是构成多彩现实世界的基础.深度图像又被称为距离图像,与灰度图像中像素点存储亮度值不同,其像素点存储的是该点到相机的距离,即深度值.图2-1表示深度图像与灰度图像之间的关系. 图2-1 深度图像

Computer Graphics Research Software

Helping you avoid re-inventing the wheel since 2009! Last updated December 5, 2012.Try searching this page for keywords like 'segmentation' or 'PLY'.If you would like to contribute links, please e-mail them to [email protected]. Papers & Archives Gra