这个东西是我接触的第一个非2D方面的算法,到目前为止其实也没有完全搞定,不过可能短时间内也无法突破。先把能搞定的搞定吧。

这个东西也有一大堆参考资料,不过呢,搜来搜去其实也就那些同样的东西,个人觉得就属这个文章最经典,既有说明,也有图片,还有代码:

Photometric Stereo    Chaman Singh Verma and Mon-Ju Wu

       https://pages.cs.wisc.edu/~csverma/CS766_09/Stereo/stereo.html

  另外,github上也应该有一些参考的资料吧,我主要参考的是 https://github.com/chaochaojnu这个中国小哥的博客。

  目前为止,我只实现了提取Albedo、Normal Map和Normal Vectors三个结果。

  从硬件上讲,这算法应该需要一个固定位置的相机(应该是要和目标垂直吧),以及至少3个以上的平行光源,一般实际上可能需要至少4个以上的光源吧,然后每个光源单独打光,单独拍一张图片,共得到N个不同的图片,然后根据这个N个图片,合成一个结果图以及得到额外的梯度和高度信息。

  在Halcon中,有对应的photometric_stereo算子实现该功能,该算子除了要提供N个图片,还需要提供 Slants和Tilts两个参数,你去看他们的英语翻译,其实都是倾斜角,个人理解Tilts就是光源在XY平面投影时和X轴的夹角,而Slants就是光源和XY平面的夹角。

  在我刚刚提供的两个链接里,他们都不是直接提供 Slants和Tilts,而是直接利用标准物体在对应光源下拍照,得到几幅标准图像,然后由标准图像的像素值推算出对应的归一化光源向量,这个方法也是不错了,省去了相机和光源位置的标定。

  有了这些参数,就可以进行算法的执行了,对于Normal Map的获取,在Photometric Stereo这个文章里有一大堆推导,开始看不懂,慢慢的又觉得懂了,然后又有点懵逼,接着折腾又似乎清晰了。

  其实不用管那么多,我们看看Photometric Stereo给出的NormalMap.m代码里的细节吧:

   for i = 1:nrows
for j = 1:ncols
if( maskImage(i,j) )
for im = 1:numImages
I(im) = double(grayimages(i,j,im));
end
[NP,R,fail] = PixelNormal(I, lightMatrix);
surfNormals(i,j,1) = NP(1);
surfNormals(i,j,2) = NP(2);
surfNormals(i,j,3) = NP(3);
albedo(i,j) = R;
end
end
end

  这里的surfNormals就是对应上图中的Normal Vectors,albedo就是反射率图。

  lightMatrix是多个光源的向量,I是多个图对应的像素值,这里的关键在于PixelNormal函数。

unction [N,R, fail] = PixelNormal(I, L)
fail = 0;
I = I';
LT = L';
A = LT*L;
b = LT*I;
g = inv(A)*b;
R = norm(g);
N = g/R;
if( norm(I) < 1.0E-06)
fprintf( ' Warning: Pixel intensity is zero \n' );
N(1) = 0.0;
N(2) = 0.0;
N(3) = 0.0;
R = 0.0;
fail = 1;
end
end

  仔细看这个函数,其实就是上面工时最后一部分的直接实现,什么转置、乘积、求逆、归一化等等。

这个M代码要稍微修改才可以运行,我尝试了下只是运行获取Normal Map这一块,4个500*500的大小的灰度图,需要大概2s的时间,这个时间其实对于工程项目本身来说是没有任何意义的。所以也验证了一句话,matlab只是实验里的工具。

当然,M代码本身也常常只是用来作为验证一个算法的结果是否正确的第一步而已。

  要真正让他变得有意义,像这么大的图,一个合理的处理时间是不大于2ms,这个优化其实也不是很困难,只要你仔细的看看PixelNormal函数里的数据和代码。

  里面最耗时的其实是inv(A),矩阵求逆需要用到LU分解,很少麻烦,但是实际上,我们注意到这里的A值其实是由L一个值决定的,L是什么,是光源的向量矩阵,这意味着什么,就是L是不变的。没有必要每次在循环里计算矩阵的逆的。 这是最重要的一个问题和耗时点所在。

  了解到这个问题后,我们其他的优化手段就是代码层次上的了,比如用C++写算法、把PixelNormal这个小函数直接集成到循环内部、使用SIMD指令加速等等。

  在几个matlab代码里,还要求提供一个mask图,有这个的原因是很多立体光度法拍摄的图片其实有很多黑色的部分或者说可以确定不是目标的部分,这部分如果处理, 是会拖累算法的速度的,因此用个标定好的MASK去删除他,这也无可厚非,不过在halcon里似乎没有这个参数。

  我目前也就只研究到这里,至于后面的深度图或者说是高度图的实现,文章里提供的都是解一个很大的稀疏矩阵,这个已经超出了我所能自行编程的范围。暂时没有能力去解决了。

在Halcon中,利用光度立体法去实现一些检测目标的一个重要应用是通过photometric_stereo算子获取对应的gradient,然后在利用derivate_vector_field 获得梯度的平均曲率场,我目前还不明白这个gradient到底代表了什么值,是上面的M代码里的surfNormals向量吗?有没有哪位朋友知道呢。

  通过和halcon比较,目前获取的反射率图,基本还是差不多正确的,比如下面几个halcon的测试图:

     

 合成后的反射率图为:

再比如:

     

  合成后为:

  下面这个四个图更能合适的看到多光源的合成效果:

      

  合成后为:

  合成后的图各个方向的光线都比较均匀了。

个人觉得这种合成似乎也可以用多图的HDR来做,不过多图HDR还是不能获取一些额外的信息。

  关于光度立体法目前也只能研究这么多了。希望以后有契机再去研究后续的其他细节。

  目前,如果是纯粹的只是获取Normal Map图,我的优化的程序速度非常快,在4个方向 2500*2000像素的灰度图,获取大概只需要25ms,预计比原始的M代码快近2000倍。

  

  提供一个简易的测试DEMO:https://files.cnblogs.com/files/Imageshop/stereo.rar?t=1669368744

研究光度立体法阶段性小结和优化(可20ms获取4个2500*2000灰度图的Normal Map)。的更多相关文章

  1. photometric_stereo halcon光度立体法三维表面重建

    官方文档翻译 名称: photometric_stereo -- 通过光度立体技术重建表面. 签名: photometric_stereo(Images : HeightField, Gradient ...

  2. halcon——缺陷检测常用方法总结(光度立体)

    引言 机器视觉中缺陷检测分为一下几种: blob+特征(官方示例surface_scratch.hdev) blob+差分+特征(官方示例pcb_inspection.hdev) 光度立体 特征训练 ...

  3. 『嗨威说』算法设计与分析 - 回溯法思想小结(USACO-cha1-sec1.5 Checker Challenge 八皇后升级版)

    本文索引目录: 一.回溯算法的基本思想以及个人理解 二.“子集和”问题的解空间结构和约束函数 三.一道经典回溯法题点拨升华回溯法思想 四.结对编程情况 一.回溯算法的基本思想以及个人理解: 1.1 基 ...

  4. Ofbiz项目学习——阶段性小结——删除数据

    一.根据主键进行删除 /** * 按主键进行删除 * @param dctx * @param context * @return */ public static Map<String,Obj ...

  5. Ofbiz项目学习——阶段性小结——更新数据

    一.根据一个字段进行修改 /** * 根据一个字段进行修改(这个条件字段可以是主键, 也可以不是主键) * @param dctx * @param context * @return */ publ ...

  6. Ofbiz项目学习——阶段性小结——插入数据

    一.通用插入操作 /** * * 编写一个服务createUomOneDemo, * 该服务的作用是在表Uom中增加一条记录,其中: * 字段uomId的值为“BaseLineProduct”. * ...

  7. Ofbiz项目学习——阶段性小结——服务返回结果

    一.返回成功 1.在.DispatcherReturnDemoService类中编写服务[returnSuccess],内容如下: /** * 返回成功结果 * @param dctx * @para ...

  8. Ofbiz项目学习——阶段性小结——视图

    一.简要介绍 1.按照SQL的视图概念:在 SQL 中,视图是基于 SQL 语句的结果集的可视化的表.视图包含行和列,就像一个真实的表.视图中的字段就是来自一个或多个数据库中的真实的表中的字段. 2. ...

  9. Ofbiz项目学习——阶段性小结——查询

    一.组装参数的学习 首先是查询条件,对于查询条件,需要判断是否从前端传递空值?——怎么处理查询空值? 当然可以一个一个进行判断,但是这样代码会导致很多,可以统一处理,形成一个公共方法. 1. 单个处理 ...

  10. halcon小结

    持更 应用范围 (罗列自官方帮助文档,以后有空了按照需求展开叙述) 1. 安全系统 2. 表面检测 3. 定位 4. 二维测量比较 5. 二维码识别 6. 二维位置定位 7. 二维物体识别 8. 光学 ...

随机推荐

  1. Windows磁盘容量差异

    如果足够细心,你就能发现计算机管理里面显示的容量和我的电脑里面磁盘容量的显示有差异.我的电脑中显示的总会少一点. https://www.cnblogs.com/qishine/p/12125329. ...

  2. Apache开启目录浏览功能的正确姿势

    部分代码是抄的网友的,哪儿抄的忘了,我是自己修改了点,并非我本人原创,觉得侵权联系我,立马删 在宝塔面板中,打开网站的设置,在配置文件那里添加如下内容 Directory "文件绝对路径&q ...

  3. SQL注入篇——sqli-labs各关卡方法介绍

    主要是记下来了每关通过可以采用的注入方式,可能部分关卡的通关方式写的不全面,欢迎指出,具体的获取数据库信息请手动操作一下. 环境初始界面如下: sql注入流程语句: order by 3--+ #判断 ...

  4. Ceph分布式存储详述

    存储发展史 企业中使用存储按照其功能,使用场景,一直在持续发展和迭代,大体上可以分为四个阶段: DAS:Direct Attached Storage,即直连存储,第一代存储系统,通过SCSI总线扩展 ...

  5. flask-bootstrap 模版中所需的CSS/JS文件实现本地引入

    Flask-Bootstrap默认是加载CDN的css与js文件,每次刷新页面都要访问到外网的cdn来获取css与js文件; 模版扩展来自于bootstrap/base.html,就以bootstra ...

  6. NSIS V3.08 简体中文增强版

    说明: 该3.08版本属本人业余时间集成修改制作,首发博客园,欢迎反馈安装与使用中出现的BUG,转载请注明出处! 本版本母版源自NSIS(Nullsoft Scriptable Install Sys ...

  7. [题解] Atcoder Regular Contest ARC 147 A B C D E 题解

    点我看题 A - Max Mod Min 非常诈骗.一开始以为要观察什么神奇的性质,后来发现直接模拟就行了.可以证明总操作次数是\(O(nlog a_i)\)的.具体就是,每次操作都会有一个数a被b取 ...

  8. 学习ASP.NET Core Blazor编程系列五——列表页面

    学习ASP.NET Core Blazor编程系列一--综述 学习ASP.NET Core Blazor编程系列二--第一个Blazor应用程序(上) 学习ASP.NET Core Blazor编程系 ...

  9. Gson的使用与理解

    当今社会下,前后端分离,不同系统的信息交互,消息队列的数据传递,微服务的不同服务之间的数据处理,越来越多地方用到了序列化.序列化作为不同系统不同服务之间的数据桥梁.那么方便快捷的序列化工具还是必要的. ...

  10. 安装 LAMP 环境(yum 版本) shell脚本

    #!/bin/bash # 安装 LAMP 环境(yum 版本) # 本脚本适用于 RHEL7(RHEL6 中数据库为 mysql) yum makecache &>/dev/null ...