前言:本文将从此篇开始,记录自己从普通CVer入门三维重建的学习过程,可能过程比较坎坷,都在摸索阶段,但争取每次学习都能进一步,提高自己的能力,同时,每篇文章都会按情况相应地推出B站讲解视频,可以关注up 出门吃三碗饭 观看讲解视频,文章同步更新到公众号 AI知识物语 ,大家可以关注下助助力。另外本平台的评论私信不会看,有问题可以移步B站视频评论区or私信。

最后感谢相关博主,开源社区,github等对内容的贡献,也希望各位读者在读完后能有自己的收获,并且写文章分享自己的心得,希望这个社区越做越好。

个人对于该研究的展望以及背景:对我选择这个领域最大的感受是《头号玩家》电影,里面的画面我始终抱有着在不久地未来将会商业落地的期许。同时,XR(AR,VR)元宇宙、数字藏品等概念爆火,体现了虚拟场景相关的市场有极大的潜力。虽然目前三维重建相关方面的上市企业大部分是车企相关(基于自己调查的数据),做slam、点云方面的工作(应该是无人驾驶),一些近几年比较新的公司我看到有做虚拟偶像(也属于虚拟内容)等三维重建方面的工作(并不局限三维重建,还会融和动作捕捉等等其他cv技术)。

另外我最惊讶的是 Alex Yu在2022年,当时应该在UCB读大四时候基于最初Nerf提出的Plenoxels模型,并展示在CVPR上,后面有关注到他结合自己的论文算法,和导师创建了 LumaAI公司,使用Nerf技术去实现移动端的三维重建(拍照可以实现),目前只支持IOS系统。虽然其使用,交互设计,或者盈利模式还不是特别成熟,但我相信在不久的未来,该项技术能够很好地提高社会的生产力,为人们提供更好的生活服务。

LumaAI公司Nerf 三维建模产品链接

好,就唠嗑到这里了!让我们开始讲内容吧。任务伟大的成就、梦想,离不开一项项基础技术的支持。所以我们得脚踏实地去学习。

(一)Harris角点检测

什么是角点:

(1)轮廓间交点 (2)视角变化,也能检测到的点(比如我在角度X可以看到角点A,那么移动后,在角度Y需要也能看到角点A) (3)角点附近像素点梯度变化大,通俗来看,就是附近不平滑,或者颜色差异大

基本思想:以每个点为中心取固定窗口并在图像上任意方向滑动,比较滑动前后像素灰度变化,若变化大,则存在角点。

数学逻辑:先来看图,和角点检测的公式

在一张图片上,我们取一个点,并以他为中心取一个正方形框,作为检测区域。

公式和图里的符号的含义:

(1)[u,v] 是窗口偏移量,也就是移动方向 ,E代表灰度变化。E[u,v]就表示窗口偏移前后的灰度变化值 (2)公式 Σ 对每一个点都进行计算 (3)w(x,y)表示权重,可以设为全是1,那么所有像素点的贡献都是一样的。如果设为高斯权重,那么距离该点越近,其贡献越大 (4)I(x,y)表示取起点的像素,I(x+u,y+v)下一个点的像素。这里对两个像素取了平方差,这样的好处可以避免差值为负数,取绝对值也可以有相同的效果,平方差用得比较多,梯度下降里面平方差用得也挺多。 总得公式用语言来表达: 窗口移动前后变化差值 = 每个点逐次计算[每个点的权重 * 点移动前后像素平方差 ] (5)第一步到第二步的方式是通过泰勒展开(只需一阶展开即可),属于大学里高数的一般知识,不用慌,一开始慢慢看 泰勒展开参考文章 (6)对第二步进行化简,可以得到第三步的公式,这部分比较困难,我们一一来看。首先引入2个公式 把图像的梯度公式代入 第二行式子可以求得最终第三行的式子。 基于已经计算好的第3个式子,如上图一样进一步化简得出 E(u,v)关于λ1 和λ2的式子。 因为上图其化简格式像一个椭圆,为了更好地观察函数图像,不防把 E(u,v)设置为1,。如下图图像 根据上面的式子可以知道,椭圆的两边长 如蓝色的图里表示。 当λ1,λ2越大的时候,图像上可以看到椭圆上下和左右都会变得很窄,也就体现了实际检测的图片该区域梯度变化快,前后差异值大。如果λ1,λ2都接近0,其根号的倒数趋近于无穷大,那么这个椭圆会很宽,也就体现了实际检测的图片该区域梯度变化慢,不是位于角点区域,可以认为其区域相对平滑。

到这里可以看到λ1,λ2的巨大作用和直观表达性,那如何对其求解?

这里引入角点准则公式

角点检测算法实际上是对函数C进行阈值处理,C >threshold,取C的局部最大值。 这种算法容易造成响应的角点有可能会密集地集中在一小块区域,会造成计算的浪费,效率的降低。因此引入了 非极大值抑制,通过选取 上述一小块区域的 “局部响应最大值”,来避免重复的检测。

现在我们来回顾下整个的算法流程

(一)首先我们根据移动向量[u,v]来计算图像移动时的梯度变化 (二)移动过程中每个像素代入公式,计算其Harris矩阵的值为H (三,四)把H代入角点准则公式,当返回C的值大于一定的值的时候,把其设置为角点

代码:

简单介绍下使用的函数 (1)dst = cv.cornerHarris(src, blockSize, ksize, k[, dst[, borderType]]) 该功能在图像上运行Harris角检测器。 参数:       src: 输入单通道8位或浮点图像。       blockSize:它是考虑进行角点检测的邻域的大小       ksize:滑动核的大小。       k:角点响应值R计算公式中的α。     返回:       dst: 用于存储哈里斯探测器响应的图像。它的类型为CV_32FC1,大小与src相同。 (2)dst = cv.dilate(src, kernel[, dst[, anchor[, iterations[, borderType[, borderValue]]]]])   通过使用特定的结构元素来放大图像。该函数使用指定的结构化元素来扩展源图像,该结构化元素确定在其上获取最大值的像素邻域的形状。   参数:       src: 输入图像;通道数可以是任意的,但深度应为CV_8U,CV_16U,CV_16S,CV_32F或CV_64F之一。       kernel:用于扩张的结构元素;如果elemenat = Mat(),则使用3 x 3的矩形结构元素。       anchor: 锚在元素内的位置;默认值(-1,-1)表示锚点位于元素中心。       iterations:进行扩张的次数。     返回:       dst: 输出与src大小和类型相同的图像。 代码参考文章

import numpy as np

import cv2 as cv

filename = 'test_image/test_chessboard.jpg'

img = cv.imread(filename)

gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)

gray = np.float32(gray)

dst = cv.cornerHarris(gray,2,3,0.04)

#result is dilated for marking the corners, not important

dst = cv.dilate(dst,None)

# Threshold for an optimal value, it may vary depending on the image.

img[dst>0.01*dst.max()]=[0,0,255]

cv.imshow('dst',img)

if cv.waitKey(0) & 0xff == 27:

cv.destroyAllWindows()

第一小篇章到这里就先结束了,后序其实还有很多知识点,但因笔者数学功底不好,还未消化,所以迟迟未落笔。后续会继续更新相关方面的文章,从基础特征点检测,到sfm,稠密重建,点云网格重建等等。另外有时间会超出视频版的讲解,可以关注B站 出门吃三碗饭 以及公众号 AI知识物语 。另外如果文章有问题,不足之处,欢迎指出,谢谢观看。

好文链接

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: