将二值图转化成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,即signed distance field中大于等于0的像素复原为前景。

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

  1. #include "SDL/sdl.h"
  2. #include <math.h>
  3.  
  4. #define WIDTH 256
  5. #define HEIGHT 256
  6.  
  7. struct Point
  8. {
  9. int dx, dy;
  10.  
  11. int DistSq() const { return dx*dx + dy*dy; }
  12. };
  13.  
  14. struct Grid
  15. {
  16. Point grid[HEIGHT][WIDTH];
  17. };
  18.  
  19. Point inside = { 0, 0 };
  20. Point empty = { 9999, 9999 };
  21. Grid grid1, grid2;
  22.  
  23. Point Get( Grid &g, int x, int y )
  24. {
  25. // OPTIMIZATION: you can skip the edge check code if you make your grid
  26. // have a 1-pixel gutter.
  27. if ( x >= 0 && y >= 0 && x < WIDTH && y < HEIGHT )
  28. return g.grid[y][x];
  29. else
  30. return empty;
  31. }
  32.  
  33. void Put( Grid &g, int x, int y, const Point &p )
  34. {
  35. g.grid[y][x] = p;
  36. }
  37.  
  38. void Compare( Grid &g, Point &p, int x, int y, int offsetx, int offsety )
  39. {
  40. Point other = Get( g, x+offsetx, y+offsety );
  41. other.dx += offsetx;
  42. other.dy += offsety;
  43.  
  44. if (other.DistSq() < p.DistSq())
  45. p = other;
  46. }
  47.  
  48. void GenerateSDF( Grid &g )
  49. {
  50. // Pass 0
  51. for (int y=0;y<HEIGHT;y++)
  52. {
  53. for (int x=0;x<WIDTH;x++)
  54. {
  55. Point p = Get( g, x, y );
  56. Compare( g, p, x, y, -1, 0 );
  57. Compare( g, p, x, y, 0, -1 );
  58. Compare( g, p, x, y, -1, -1 );
  59. Compare( g, p, x, y, 1, -1 );
  60. Put( g, x, y, p );
  61. }
  62.  
  63. for (int x=WIDTH-1;x>=0;x--)
  64. {
  65. Point p = Get( g, x, y );
  66. Compare( g, p, x, y, 1, 0 );
  67. Put( g, x, y, p );
  68. }
  69. }
  70.  
  71. // Pass 1
  72. for (int y=HEIGHT-1;y>=0;y--)
  73. {
  74. for (int x=WIDTH-1;x>=0;x--)
  75. {
  76. Point p = Get( g, x, y );
  77. Compare( g, p, x, y, 1, 0 );
  78. Compare( g, p, x, y, 0, 1 );
  79. Compare( g, p, x, y, -1, 1 );
  80. Compare( g, p, x, y, 1, 1 );
  81. Put( g, x, y, p );
  82. }
  83.  
  84. for (int x=0;x<WIDTH;x++)
  85. {
  86. Point p = Get( g, x, y );
  87. Compare( g, p, x, y, -1, 0 );
  88. Put( g, x, y, p );
  89. }
  90. }
  91. }
  92.  
  93. int main( int argc, char* args[] )
  94. {
  95. if ( SDL_Init( SDL_INIT_VIDEO ) == -1 )
  96. return 1;
  97.  
  98. SDL_Surface *screen = SDL_SetVideoMode( WIDTH, HEIGHT, 32, SDL_SWSURFACE );
  99. if ( !screen )
  100. return 1;
  101.  
  102. // Initialize the grid from the BMP file.
  103. SDL_Surface *temp = SDL_LoadBMP( "test.bmp" );
  104. temp = SDL_ConvertSurface( temp, screen->format, SDL_SWSURFACE );
  105. SDL_LockSurface( temp );
  106. for( int y=0;y<HEIGHT;y++ )
  107. {
  108. for ( int x=0;x<WIDTH;x++ )
  109. {
  110. Uint8 r,g,b;
  111. Uint32 *src = ( (Uint32 *)( (Uint8 *)temp->pixels + y*temp->pitch ) ) + x;
  112. SDL_GetRGB( *src, temp->format, &r, &g, &b );
  113.  
  114. // Points inside get marked with a dx/dy of zero.
  115. // Points outside get marked with an infinitely large distance.
  116. if ( g < 128 )
  117. {
  118. Put( grid1, x, y, inside );
  119. Put( grid2, x, y, empty );
  120. } else {
  121. Put( grid2, x, y, inside );
  122. Put( grid1, x, y, empty );
  123. }
  124. }
  125. }
  126. SDL_UnlockSurface( temp );
  127.  
  128. // Generate the SDF.
  129. GenerateSDF( grid1 );
  130. GenerateSDF( grid2 );
  131.  
  132. // Render out the results.
  133. SDL_LockSurface( screen );
  134. for( int y=0;y<HEIGHT;y++ )
  135. {
  136. for ( int x=0;x<WIDTH;x++ )
  137. {
  138. // Calculate the actual distance from the dx/dy
  139. int dist1 = (int)( sqrt( (double)Get( grid1, x, y ).DistSq() ) );
  140. int dist2 = (int)( sqrt( (double)Get( grid2, x, y ).DistSq() ) );
  141. int dist = dist1 - dist2;
  142.  
  143. // Clamp and scale it, just for display purposes.
  144. int c = dist*3 + 128;
  145. if ( c < 0 ) c = 0;
  146. if ( c > 255 ) c = 255;
  147.  
  148. Uint32 *dest = ( (Uint32 *)( (Uint8 *)screen->pixels + y*screen->pitch ) ) + x;
  149. *dest = SDL_MapRGB( screen->format, c, c, c );
  150. }
  151. }
  152. SDL_UnlockSurface( screen );
  153. SDL_Flip( screen );
  154.  
  155. // Wait for a keypress
  156. SDL_Event event;
  157. while( true )
  158. {
  159. if ( SDL_PollEvent( &event ) )
  160. switch( event.type )
  161. {
  162. case SDL_QUIT:
  163. case SDL_KEYDOWN:
  164. return true;
  165. }
  166. }
  167.  
  168. return 0;
  169. }

signed distance field 算法的更多相关文章

  1. Signed Distance Field Shadow in Unity

    0x00 前言 最近读到了一个今年GDC上很棒的分享,是Sebastian Aaltonen带来的利用Ray-tracing实现一些有趣的效果的分享. 其中有一段他介绍到了对Signed Distan ...

  2. Signed Distance Field Technique

    [Distance Field Technique] 一种小纹理高清放大的技术. A distance field is generated from a high resolution image, ...

  3. distance field(占坑

    signed distance field https://kosmonautblog.wordpress.com/2017/05/09/signed-distance-field-rendering ...

  4. 扒一扒编辑距离(Levenshtein Distance)算法

    最近由于工作需要,接触了编辑距离(Levenshtein Distance)算法.赶脚很有意思.最初百度了一些文章,但讲的都不是很好,读起来感觉似懂非懂.最后还是用google找到了一些资料才慢慢理解 ...

  5. Levenshtein distance 编辑距离算法

    这几天再看 virtrual-dom,关于两个列表的对比,讲到了 Levenshtein distance 距离,周末抽空做一下总结. Levenshtein Distance 介绍 在信息理论和计算 ...

  6. Lucene的FuzzyQuery中用到的Levenshtein Distance(LD)算法

    2019独角兽企业重金招聘Python工程师标准>>> Lucene的FuzzyQuery中用到的Levenshtein Distance(LD)算法 博客分类: java 搜索引擎 ...

  7. hdu 4712 Hamming Distance ( 随机算法混过了 )

    Hamming Distance Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others) ...

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

    编辑距离即从一个字符串变换到另一个字符串所需要的最少变化操作步骤(以字符为单位,如son到sun,s不用变,将o->s,n不用变,故操作步骤为1). 为了得到编辑距离,我们画一张二维表来理解,以 ...

  9. Levenshtein Distance + LCS 算法计算两个字符串的相似度

    //LD最短编辑路径算法 public static int LevenshteinDistance(string source, string target) { int cell = source ...

随机推荐

  1. 如何获取php错误

    今天把项目放在测试服务器,但是出现一个问题,用的TP5框架,我把入口文件放在了根目录,访问的时候报错了,框架引导文件引入不了,也不报错,就是说访问不了. 所以就用了一段代码把错误获取出来了,代码如下: ...

  2. 美国风投行业50年数据揭示的10条VC投资秘密法则

    美国风投行业50年数据揭示的10条VC投资秘密法则 来源:金融女王(微信号:FintechQ) 作者:Hatim Tyabji & Vijay Sathe 本文编译自以下外媒文章:  http ...

  3. Enyim Memached 客户端 执行GET 总是返回NULL

    排查: 1. ping 远程Linux 服务器 正常 2.11211 端口正常 3. ps aux | grep memcached 显示正常 4. 使用另外一个客户端 memcachedClient ...

  4. CF(D. Fibonacci Sums)dp计数

    题目链接:http://codeforces.com/contest/126/problem/D 题意:一个数能够有多种由互不同样的斐波那契数组成的情况: 解法:dp,easy证明:每一个数通过贪心能 ...

  5. windows 服务器不能使用剪贴板解决办法

    您可以在系统资源中先结束rdpclip.exe进程,然后重新打开c:\windows\system32\rdpclip.exe即可

  6. Servlet拦截静态图片的解决方案

    一.现象 建立一个使用Freemarker的Web Project程序. Product.ftl中的代码为: <!DOCTYPE html PUBLIC "-//W3C//DTDHTM ...

  7. 【云计算】k8s相关资料

    参考资料: How to get started, and achieve tasks, using Kubernetes:http://kubernetes.io/docs/getting-star ...

  8. dbus启动失败:Couldn't connect to system bus: Unable to autolaunch a dbus-daemon without a $DISPLAY for X11

    在没有开启x窗口的shell下启动dbus相关程序时会如上错误,详细原因如下: This is not considered to be a bug. Auto-launching D-Bus ses ...

  9. 安卓新闻client笔记积累

    做一个项目,假设有第三方的框架的话.就会简单非常多.如今看的这个新闻client就用到了很多框架,还有非常多知识点,放在这里,记录下来. (1)Android Volley 之自己定义Request ...

  10. static 关键字 静态属性与方法 -> :: self $this 区别 可见性的关键字区别

    1.声明类属性或方法为静态,就可以不实例化类而直接访问.静态属性不能通过一个类已实例化的对象来访问(但静态方法可以). 2.由于静态方法不需要通过对象即可调用,所以伪变量 $this 在静态方法中不可 ...