1. 摘要

自从 Horn 在 20 世纪 70 年代初开发出第一种从阴影中恢复形状 (SfS) 技术以来,出现了许多不同的方法。在本文中,复述了1994年蔡博士的论文 Shape from shading using a linear approximation,对表面法线(分量p和分量q)使用有限差分法进行离散近似,然后线性化深度反射函数 Z(x,y)。并将该算法在示例图像上进行了测试,成功重建三维(Tsai et al., 1994),并对试验结果进行简单分析。

  1. 简介

Shape-from-Shading (从阴影中恢复形状)是一种经典的三维重建技术。它利用单目图像(或多目图像)中的图像强度信息,结合光照方向与传感器(例如照相机)方向对目标表面三维信息进行估计,不需要立体像对。SfS技术主要的估计算法分为四种:最小化方法、传播方法、局部方法和线性方法(Zhang et al., 1998)。本篇内容参考著名的Tsai & Shah线性化方法,在朗伯表面实现三维重建。包括公式推导与python代码实现。

  1. 前置知识

3.1 朗伯模型

朗伯模型是一种最经典也是最简单的反射模型。朗伯模型假设从粗糙表面反射的光的强度仅取决于表面法线和光源方向,如图Fig. 1。因此,朗伯表面在所有方向上都同样明亮。

Fig. 1. 朗伯模型示意图

反射是通过对表面的单位法向量 和一个归一化的光照方向矢量 进行点积来计算的, 如Eq.(1)所示。

(1)

3.2 复合函数求导

(2)

3.3 一元函数泰勒展开

(3)

3.4 雅克比迭代法

雅克比迭代法是一种求解线性方程组的方法,可以在不断迭代后准确的求解线性方程组的仅此解。在此就不过多赘述,但可以简单地理解为不断将估算值输入进线性方程组中,得到的解再次输入线性方程组中,每次得到的解将更接近线性方程组的精确解。

  1. 假设

我们SfS算法本质上是一种对表面深度的估算,所以我们很难在不进行任何理想化考虑的情况下进行准确的三维重建。因此,为了减少未知数同时也为了简化计算,我们将进行如下假设:

  1. 朗伯模型

  1. 平行光源

  1. 暂不考虑地形相互遮挡

  1. 重构的形状产生与输入图像相同的亮度

也就是说,在朗伯表面的每一个微元,都由相同方位的光源进行照射,并且产生的阴影不会由更远处的地形产生遮挡。以上四条假设也是本篇所介绍的SfS方法的核心之一。

  1. 使用线性近似实现Shape-from-Shading

5.1 参数设置

: 位于图像 处的像素强度值

: 朗伯反射强度值

: 表面法线在X方向的偏导数

: 表面法线在Y方向的偏导数

: 光照方位角

: 光照入射角

: 光照向量在X方向的分量

: 光照向量在Y方向的分量

5.2 Shape-from-Shading

5.2.1 计算表面梯度

我们使用最简单的梯度计算方法,也就是某像素在X方向的上的梯度由它和它左边的像素进行计算,在Y方向上的梯度由它和它上边的像素进行计算,如Eq.(4)和Eq.(5)。因此,用这种方法计算得到的梯度图在斜向45°上拥有较好地效果,也导致整体SfS在斜向45°方向上有较好地重建效果。

(4)

(5)

5.2.2 计算反射强度

根据假设4,我们可以直接令初始图像强度 = 反射强度, 也就是Eq.(6)

(6)

将计算表面梯度的公式Eq.(4)和Eq.(5)代入朗伯反射模型公式Eq.(1)中,得到公式Eq.(7)

(7)

令:

(8)

将Eq.(7)代入Eq.(8),并进行泰勒一阶展开得到Eq.(9)

(9)

其中,是在第次迭代中恢复的三维表面。令并进行移项,将移动到等号左边,得到Eq.(10)

(10)

其中,

(11)

这里涉及到复合函数求导与分式求导,具体知识可参考同济大学《高等数学》。经过以上计算,我们得到了最终的参数关系:

最后,将初始三维设置为0,也就是,这样就是可以在一个水平的表面逐渐恢复三维信息了。

  1. Python实现

"""References: "Ping-Sing, T., & Shah, M. (1994). Shape from shading using linear approximation.""Ruo, Z., Ping-Sing, T., Cryer, J. E., & Shah, M. (1999). Shape-from-shading: a survey"
"""
from PIL import Image
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D# Path of the image.
img_path = "mozart.jpg"# Read image as an array.
E = Image.open(img_path) # Define the light source orientation.
tilt  = ...
slant = ...tilt  = np.deg2rad(tilt)
slant = np.deg2rad(slant)# Define the surface normal.
p = np.zeros_like(E)
q = np.zeros_like(E)# Define the baseline surface.
Z = np.zeros_like(E)# Define the surface derivatives in x and y directions.
Z_x = np.zeros_like(E)
Z_y = np.zeros_like(E)# Define the maximum number of iterations.
maxIter = 200# Calculate the normalized illumination direction
ix = np.cos(tilt) * np.tan(slant)
iy = np.sin(tilt) * np.tan(slant)# Get the image size
(h, w) = np.shape(E)# Jacobi Iteration
for i in range(maxIter):# Using the illumination direction and the currently estimate# surface normals, compute the corresponding reflectance map.# refer to Eq.(7) .R = (np.cos(slant) + p * np.cos(tilt)*np.sin(slant)+ q * np.sin(tilt) * np.sin(slant)) / np.sqrt(1 + p**2 + q**2)# At each iteration, make sure that the reflectance map is positive at# each pixel, set negative values to 0.R = np.maximum(0, R)# Compute our function f which is the deviation of the computed# reflectance map from the original image. Refer to Eq.(8)f = E - R# Compute the derivative of f with respect to our surface Z, refer to Eq.(11)df_dZ =(p+q) * (ix*p + iy*q + 1) / (np.sqrt((1 + p**2 + q**2)**3)*np.sqrt(1 + ix**2 + iy**2))-(ix+iy)/(np.sqrt(1 + p**2 + q**2)*np.sqrt(1 + ix**2 + iy**2))# Update the surface, refer to (10), and please avoid dividing by zeroZ = Z - f/(df_dZ + np.finfo(np.float32).eps)# Compute the surface derivatives with respect to x and y.Z_x[1:h,:] = Z[0:h-1,:]Z_y[:,1:w] = Z[:,0:w-1]# Using the updated surface, compute new surface normals, refer to Eq.(4) and Eq.(5)p = Z - Z_xq = Z - Z_y# Show the result
fig  = plt.figure()
ax3  = plt.axes(projection = '3d')
xx   = np.arange(0, h, 1)
yy   = np.arange(0, w, 1)
X, Y = np.meshgrid(xx, yy)
ax3.plot_surface(X, Y, Z, rstride = 4, cstride = 4, cmap = 'Greys_r')
plt.show()
  1. 结果与拓展讨论

我们使用的图像是经典的计算机视觉示例图像Mozart,如图Fig.2。

Fig. 2. 所使用的输入图像"mozart.jpg"

经过200次迭代,所建立的三维模型如图Fig.3所示。

Fig. 3. 在不同角度下观察三维重建结果

可以看到,人物的鼻子是凹陷的,明显有悖于我们的常识。其原因是因为原始图像中人物的鼻子两侧有阴影,类似的阴影也可以被认为是鼻子对光线造成的遮挡,违背了我们的假设4,,并且鼻子部分的像素值与脸颊部分的像素值相近,而我们的算法是完全依照像素值进行计算,无法分辨实际真实情况,这也使此算法和朗伯模型的弊端。为此我们可以在设置时,也就是代码line33,将设置为一个已有的DEM数据。这种方法已经应用在相当多的领域,当然,在我们本次的实验中,此方法也很难纠正上述问题。

参考文献

Ping-Sing, T., & Shah, M. (1994). Shape from shading using linear approximation. Image and vision computing, 12(8), 487-498. https://doi.org/10.1016/0262-8856(94)90002-7

Ruo, Z., Ping-Sing, T., Cryer, J. E., & Shah, M. (1999). Shape-from-shading: a survey. IEEE transactions on pattern analysis and machine intelligence, 21(8), 690-706. https://doi.org/10.1109/34.784284

Shape-from-Shading 经典算法之Tsai Shah法相关推荐

  1. 经典算法之希尔排序法(Java实现)

    活动地址:21天学习挑战赛 目录 一.算法 1.算法概述 2.基本思想 3.算法步骤 4.算法特点 二.算法实践 1.Java代码 2.执行结果 三.复杂度分析 1.时间复杂度 2.空间复杂度 一.算 ...

  2. 经典算法之折半插入排序法

    活动地址:21天学习挑战赛 文章目录 一.算法 1.算法概述 2.算法步骤 二.算法实践 1.Java代码 2.执行结果 三.复杂度分析 1.时间复杂度 2.空间复杂度 一.算法 1.算法概述 直接插 ...

  3. 经典算法之二分查找法(俗称基本二分搜索法)

    经典算法之二分查找法(俗称二分搜索法) 文章目录 经典算法之二分查找法(俗称二分搜索法) 前言 一.什么是二分查找法? 二.代码实现 总结 前言 就算法而言,我们主要学习的是数学+思维+逻辑+数据结构 ...

  4. 经典算法之直接插入排序法

    活动地址:21天学习挑战赛 文章目录 一.插入排序的基本思想 二.直接插入排序法 1.算法步骤 2.排序过程 3.算法实现 4.复杂度分析 三.每日一练 解题思路 解题代码 一.插入排序的基本思想 每 ...

  5. 经典算法之顺序查找法

    活动地址:CSDN21天学习挑战赛 前言 已经进入八月份了,暑假也正式进入倒计时.本人前段时间在学习前端中移动端部分的微信小程序开发知识,也算勉勉强强能入门(因为没有前端三件套的基础,前端居然是从小程 ...

  6. 经典算法之折半查找法

    活动地址:21天学习挑战赛 目录 一. 算法 概述 算法过程 二.代码实践 三.复杂度分析 时间复杂度 空间复杂度 四.优缺点分析 优点 缺点 一. 算法 概述 折半查找( Binary Search ...

  7. 3D【7】人脸重建:Hands on Shape from Shading阅读笔记

    Shape from Shading(sfs)是一个很基础也很经典的3D重建方法.其基本原理是利用灰度图片的亮度信息,加上亮度生成原理,求得每个像素在3D空间中的法向量,最终根据法向量求得深度信息. ...

  8. 数据挖掘十大经典算法之——K-Means 算法

    数据挖掘十大经典算法系列,点击链接直接跳转: 数据挖掘简介及十大经典算法(大纲索引) 1. 数据挖掘十大经典算法之--C4.5 算法 2. 数据挖掘十大经典算法之--K-Means 算法 3. 数据挖 ...

  9. 机器学习经典算法具体解释及Python实现--K近邻(KNN)算法

    (一)KNN依旧是一种监督学习算法 KNN(K Nearest Neighbors,K近邻 )算法是机器学习全部算法中理论最简单.最好理解的.KNN是一种基于实例的学习,通过计算新数据与训练数据特征值 ...

最新文章

  1. 产品经理第一课(北京站)首波名单放榜啦!
  2. signature=6a8815f5009aacac86e725bea54f840f,A wave packet signature for complex networks
  3. STM32:RTC闹钟唤醒
  4. .NET Core性能测试组件BenchmarkDotNet 支持.NET Framework Mono
  5. CF613D-Kingdom and its Cities【虚树,LCA,树链剖分,贪心】
  6. bp matlab 训练参数,基于MATLABBP神经网络设计与训练.PDF
  7. python3简明教程-实验楼_#python实验楼教程#学Python哪里有一问一答的Python学习?求具体的~...
  8. CodeChef June Challenge 2017
  9. Ubuntu下网络调试助手 NetAssist(实际这个我启动不了)
  10. 在手机上共享屏幕,更专业的远程协助软件
  11. 2018年全国多校算法寒假训练营练习比赛(第三场)I 三角形【皮克公式+gcd】
  12. 周公恐惧流言日,王莽谦恭未篡时
  13. 星际2 正在连接服务器,星际征霸游戏连接服务器失败怎么办 解决方案分享
  14. 038--想和权证恋个爱
  15. 1-7 Burpsuite 爬虫介绍
  16. 深大uooc学术道德与学术规范教育第二章
  17. 台式计算机排行榜2018,CPU天梯图性能排行榜 台式电脑CPU天梯图2018年4月最新版...
  18. 腾讯文智自然语言处理-分词API Python小实验
  19. c语言兔子序列第8年不繁殖,基于链表的兔子序列生成研究.pdf
  20. 通过数据分析找出Netflix最适合学习英语的电影和电视剧

热门文章

  1. win7蓝屏0x000000f4修复_紧急提醒:关于电脑F4蓝屏的处理和预防方法
  2. 会声会影教程之图片音乐相册制作
  3. Java 多线程之-----守护进程
  4. 影驰名人堂送的机器人_顺丰影驰rtx2080s super名人堂hof好不好?老司机深度剖析真心话 | 智能扫地机器人评测...
  5. 低延迟流式语音识别技术在人机语音交互场景中的实践
  6. 美团面试官:MySQL主备、主从、读写分离你知道多少?
  7. 求斐波那契数列O(logn算法)
  8. Kali Linux 网络扫描秘籍 第三章 端口扫描(二)
  9. 神笔马良——把图形「画」在音频里(译文 Draw Into Sound)
  10. 粘土服务器怎么加按键显示,磐信定格动画(粘土动画)方案(14页)-原创力文档...