研究光度立体法阶段性小结和优化(可20ms获取4个2500*2000灰度图的Normal Map)。
这个东西是我接触的第一个非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)。的更多相关文章
- photometric_stereo halcon光度立体法三维表面重建
官方文档翻译 名称: photometric_stereo -- 通过光度立体技术重建表面. 签名: photometric_stereo(Images : HeightField, Gradient ...
- halcon——缺陷检测常用方法总结(光度立体)
引言 机器视觉中缺陷检测分为一下几种: blob+特征(官方示例surface_scratch.hdev) blob+差分+特征(官方示例pcb_inspection.hdev) 光度立体 特征训练 ...
- 『嗨威说』算法设计与分析 - 回溯法思想小结(USACO-cha1-sec1.5 Checker Challenge 八皇后升级版)
本文索引目录: 一.回溯算法的基本思想以及个人理解 二.“子集和”问题的解空间结构和约束函数 三.一道经典回溯法题点拨升华回溯法思想 四.结对编程情况 一.回溯算法的基本思想以及个人理解: 1.1 基 ...
- Ofbiz项目学习——阶段性小结——删除数据
一.根据主键进行删除 /** * 按主键进行删除 * @param dctx * @param context * @return */ public static Map<String,Obj ...
- Ofbiz项目学习——阶段性小结——更新数据
一.根据一个字段进行修改 /** * 根据一个字段进行修改(这个条件字段可以是主键, 也可以不是主键) * @param dctx * @param context * @return */ publ ...
- Ofbiz项目学习——阶段性小结——插入数据
一.通用插入操作 /** * * 编写一个服务createUomOneDemo, * 该服务的作用是在表Uom中增加一条记录,其中: * 字段uomId的值为“BaseLineProduct”. * ...
- Ofbiz项目学习——阶段性小结——服务返回结果
一.返回成功 1.在.DispatcherReturnDemoService类中编写服务[returnSuccess],内容如下: /** * 返回成功结果 * @param dctx * @para ...
- Ofbiz项目学习——阶段性小结——视图
一.简要介绍 1.按照SQL的视图概念:在 SQL 中,视图是基于 SQL 语句的结果集的可视化的表.视图包含行和列,就像一个真实的表.视图中的字段就是来自一个或多个数据库中的真实的表中的字段. 2. ...
- Ofbiz项目学习——阶段性小结——查询
一.组装参数的学习 首先是查询条件,对于查询条件,需要判断是否从前端传递空值?——怎么处理查询空值? 当然可以一个一个进行判断,但是这样代码会导致很多,可以统一处理,形成一个公共方法. 1. 单个处理 ...
- halcon小结
持更 应用范围 (罗列自官方帮助文档,以后有空了按照需求展开叙述) 1. 安全系统 2. 表面检测 3. 定位 4. 二维测量比较 5. 二维码识别 6. 二维位置定位 7. 二维物体识别 8. 光学 ...
随机推荐
- [C/C++]C语言-踩坑记录
很久没写C语言的代码,发现很多小细节,记下来备查. 0. C语言常规头文件 #include <stdlib.h> #include <stdio.h> 1. 二维数组的开辟和 ...
- this的指向问题、bind/call/apply改变this指向
this的指向问题 全局作用域下的this指向 无论是否是严格模式,全局作用域下的this始终指向window 函数内部的this 严格模式下: function test() { 'use stri ...
- Lua脚本在Redis事务中的应用实践
使用过Redis事务的应该清楚,Redis事务实现是通过打包多条命令,单独的隔离操作,事务中的所有命令都会按顺序地执行.事务在执行的过程中,不会被其他客户端发送来的命令请求所打断.事务中的命令要么全部 ...
- MySQL8 二进制日志
启用二进制日志 # cat /etc/my.cnf [mysqld] server_id=100 log_bin=/var/log/mysql/binlogs/server1 # mkdir -p / ...
- 使用 Elastic Stack 分析地理空间数据 (一)
文章转载自:https://blog.csdn.net/UbuntuTouch/article/details/106531939 随着人类在不断地探索空间,地理空间数据越来越多. 收集信息的速度以及 ...
- Prometheus告警处理
在Prometheus Server中定义告警规则以及产生告警,Alertmanager组件则用于处理这些由Prometheus产生的告警.Alertmanager即Prometheus体系中告警的统 ...
- Prometheus高可用部署
Prometheus的本地存储给Prometheus带来了简单高效的使用体验,可以让Promthues在单节点的情况下满足大部分用户的监控需求.但是本地存储也同时限制了Prometheus的可扩展性, ...
- Ubuntu20.04和Docker环境下安装Redash中文版
创建Ubunt20.04虚拟机,请参考:https://www.linuxidc.com/Linux/2020-03/162547.htm 一.安装基础环境: # 1.更换APT国内源 sudo se ...
- 【Azure 应用服务】App Service频繁出现 Microsoft.WindowsAzure.Diagnostics.DiagnosticMonitorTraceListener 异常分析
问题描述 在使用App Service的过程中,发现应用频繁出现503错误,通过Kudu站点获取到Logfiles. 在 Eventlog.xml 文件中,发现大量的 Microsoft.Window ...
- Python实现改进后的Bi-RRT算法实例
Python实现改进后的Bi-RRT算法实例 1.背景说明 以下代码是参照上海交通大学海洋工程国家重点实验室<基于改进双向RRT的无人艇局部路径规划算法研究>的算法思想实现的. 2.算法流 ...