摘要
本文主要用於記錄有向距離場的資料
添加了可直接使用的Python实现
添加了部分资料
未完…
最终用Python整了一个脚本方便大家快速CV大法
结果预览
环境
- python3
- openCV
- numpy
1 | # _*_ coding=utf-8 _*_ |
收集的距離場算法與實現
欧几里得距离转换(EDT)算法
*0 前言*
欧几里得距离转换 (Euclidean Distance Transform, EDT) 简单的说即是以最常用的欧几里得距离作为
距离度量,找到每一个前景点到最近的背景点之间的距离。文中提及所有的算法中,均是将二维图片
转为两个一维向量的方式进行。
一些基本定义:
背景点为 0,黑色,为感兴趣点,Voronioi elements,sites;
前景点为 1:白色;
VR: 某一背景点的 VR 指的前景点集合,这些前景点到此背景点的距离比到其他背景点距离都要短。
VS:某一前景点的 VS 指的是背景点的集合,这些背景点到此前景点距离比到其他前景点距离都要短。
1. Saito 的算法:
step1:1-D Transformation
上到下,计算每一行中前景点到本行背景点距离最近的平方,得到中间结果 G;公式如下:
如下图 :
(a) 为原图
(b) 为 同一行的距离平方图, 即 G
step2:2-D Transformation
从左到右,对每一列,对中间结果 G 进行操作,计算本列背景点与本行背景点距离平方和的最小值,得到距离图(Distance Map)H;
如下图(4 即使最近距离的平方).
8SSEDT 算法
Ref : https://github.com/Lisapple/8SSEDT
8點有向按序 歐幾里得距離轉換
有向距離場 (SDF) 是由二值圖像 計算得來, 在每像素上 , 到最近像素的有向距離(可正可負) 有不同值. 前景像素為正距離 , 背景像素為負距離. 下文中, 有向和有符號是統一意思. 有符號更加符合寫程式的觀點.
例:
每像素會擁有一個距離值:
(暗灰色像素為正值 && 負值為亮灰色)
簡單位圖為例
对于 位图 表示為:
1 | [0][0][0] |
限定全部 0 顯示為像素在 (白色) 形狀之外(也叫:背景)且全部 1 在形狀之内 (也叫:前景).
最終結果表示為:
1 | [-2][-1][-1] |
第一個像素 (背景) 為 在一個到前景為 -2 (此時為 有向-平方) 的距離.
最後一個像素 (前景) 為在一個到背景為 1 的距離.
構建初始網格
For each pixel, we need to build a first grid (grid #1) with a distance duet (dx, dy)
like (dx=0, dy=0)
if inside (foreground) and (dx=∞, dy=∞)
if outside (background)
1 | [∞][∞][∞] |
with (0, 0)
represented by 0
and (∞, ∞)
by ∞
.
and a second grid
(grid #2) with inverted distances:
1 | [0][0][0] |
Note: All pixel out of bounds are use the value (∞, ∞)
as:
1 | ∞ ∞ ∞ |
- Computing grids:
To get the distance x
, we look all neighbours (from #1
to #8
) distances:
1 | [#1][#2][#3] |
using relative offset [offset x, offset y]
to x
like so:
1 | [-1,-1][0,-1][1,-1] |
then the final value of x
is
x = min(#0.distance, ..., #7.distance)
using the distance function that compute the magnitude of the distance with offset:
#?.distance = sqrt( (?dx + offset x)^2 + (?dy + offset y)^2 )
This gives:
1 | #1.distance = (∞-1, ∞-1).distance = √(∞^2 + ∞^2) = ∞ |
so
x = min(#0.distance, ..., #7.distance]) = 1
- Updated grid:
1 | [∞][∞][∞] |
Then process the next cell on the right.
Computing method
In total 4 passes are necessary to compute all distances, two sequential passes, for each grid #1 and #2.
Using the initialised grid:
(from left to right, top to bottom)
1 | - - - > |
then (using the same grid)
(from right to left)
1 | < - - - |
then
(from right to left, bottom to top)
1 | < - - - |
then:
(from left to right)
1 | - - - > |
Computing final signed distances
Once the four steps applied on the grid #1 and #2,
we compute the difference of the magnitude of each cell (pixel) #n1
and #n2
of the two grids:
1 | foreach (#n1 of grid #1) and (#n2 of grid #2): |
with #n.distance = sqrt( #n.dx * #n.dx + #n.dy * #n.dy )
.
References
Distance field generator with C++ and SDL codersnotes.com
Valve paper on distance field Improved Alpha-Tested Magnification for Vector Textures and Special Effects
3D有符号距离场原理及实现
Ref: http://www.bimant.com/blog/signed-distance-field-implementation/
Dead Reckoning 算法
Ref : https://segmentfault.com/a/1190000041250697
在Unity的實現
Ref : https://zznewclear13.github.io/posts/calculate-signed-distance-field-using-compute-shader/