光场1.0——非聚焦型光场相机

news/2024/11/23 4:03:35/

本文概要

本文讲主要从光场硬件结构设计以及软件处理方式的层面来介绍一下光场的相关内容,关于光场的优势和具体应用点并不在本文的主要范围内。

光场1.0

1. 结构原理说明

首先来介绍一下光场相机,那么什么是光场相机呢,光场相机经历了两代的发展,首先我们来介绍一下一代光场相机的主要结构及内容,以下简称“光场1.0”。接下来,让我们回到2005年2月,重温以下光场相机刚被发明出来的那篇论文——Light Field Photography with a Hand-held Plenoptic Camera ,该论文第一次提出了光场相机的概念,该论文提到的相机概念示意图如下图所示:

 该相机由三部分组成:主镜头、微透镜阵列和对应的CCD(即上图中的Photosensor)。其中MLA(microlens array)放置在主透镜的成像面上(注意是成像面,不是焦平面,这也是很多初学者经常混淆的一个概念),CCD放置在对应的MLA的焦平面上。相机的这种布置有哪些优点呢?它又是如何做到可以记录光线的方向信息的呢?为了便于说明,我在图上添加了一些标记便于后续说明:1,2,3表示三条从物面发出的光线;4表示如果把ccd挪到mla的位置三条光线相交的像素点,5,6,7表示ccd在当前位置上面的三个像素点。

我们从上图可以看出:物面的Subject在Main lens的后面呈的是一个实像,假如我们把CCD放在对应的MLA的位置,那么上图中的subject发出的三条光线是不是就交互在了对应的ccd的一个像素4上,这样子通过这个像素4就无法分辨到底是三条光线的哪一条了,也就是一句常说的:传统相机成像是积分成像,可以说是三条光线的信息积分相加最终才是该点的像素的采集到的信息。

如果是把ccd后移到焦距位置,那么会有什么样的效果呢,5,6,7三个像素点分别代表交互在实像面位置的三条光线1,2,3的信息,这样子是不是就还原出了交互在4点的不同方向的光线信息,这就是一种在二维平面捕获光线的三维信息的方法。

但是难道不会出现8那个位置的光线也打到4对应的子透镜后面的像素区域造成混乱么,当然会啦,但是如果控制好对应的数值孔径匹配就行,该论文也提到了这一点内容如下图所示:

 主透镜有对应的通光口径,只要保证主透镜的通光孔径正确就可以实现上图的数值孔径匹配的效果,即每个宏像素(指的是上图的每一个小圆形的大的像素块)之间既不重叠,又刚好相切。数值孔径匹配的规则为:

\frac{D}{L}=\frac{d}{f}

其中:D为主透镜的通光孔径(再直白点叫主透镜的直径),L表示主透镜和MLA的距离(又叫做像距,因为MLA放在主透镜的像面位置。!!!此处千万注意,L不一定是焦距,很多人经常犯得一个错误!!!),d为mla的小透镜的直径,f为小透镜的焦距。

2. 算法处理

接下来我将给大家介绍一下一些图像预处理和五维光场函数处理相关的内容。我们先来找一个光场相机捕获的原始图像吧,这里我们可以访问斯坦福大学的光场相机拍摄的数据集,数据集链接:斯坦福光场数据集主页链接

Step1:

 Step2:

Step3:

 单击可以下载对应的Raw Data,文件比较大,打开后可以看到利用上述的结构拍摄到的原始光场图像(下左),放大后可以看到每一个对应的宏像素(下右)。

 接下来我将告诉大家如何处理这个原始光场图像,提取出对应的五维光场函数。首先我们要确定一下对应的图像参数:7574*5264的图像。接下来先放代码,然后具体讲解代码的含义(个人水平有限,代码仅供参考),此处仅提供部分核心代码。

main.py

def test_StanfordLF():'''加载并处理斯坦福大学的光场数据集'''lytroRawImagePath = 'flowers_plants_14_eslf.png'if os.path.exists(lytroRawImagePath) is False:print('start to download light field png...')toolsImageProcess.request_download('http://lightfields.stanford.edu/images/flowers_plants/raw/flowers_plants_1_eslf.png','', lytroRawImagePath)print('png download successfully. ')print('start to load Stanford Lytro Light Field Archive image {}'.format(lytroRawImagePath))t = time.time()       # load time about 20sLF = toolsImageProcess.LFReadRawImage(lytroRawImagePath)print("Stanford Lytro Light Field Archive image load successfully, time cost: {}s".format(time.time() - t))toolsImageProcess.LFSaveAllSubViewImages(LF, "SubView Images", "")

toolsImageProcess.py

'''
根据对应的子孔径图像重构光场原始图片
参数:LF 五维光场函数
返回值:LF_Raw 原始的光场采集图像
'''
def LFReadRawImage(imgPath, width=None, height=None):if os.path.exists(imgPath) is False:return NoneLF_Raw = np.array(Image.open(imgPath))imgShape = LF_Raw.shapeif width is None or height is None:maxCD = maxCommonDivisor(imgShape[0], imgShape[1])uRange = int(imgShape[0] / maxCD)vRange = int(imgShape[1] / maxCD)else:maxCD = imgShape[0]/widthif maxCD == imgShape[1]/height:uRange = widthvRange = heightmaxCD = int(maxCD)else:print("data check faild, process finished. ")return NoneLF = np.zeros((maxCD, maxCD, uRange, vRange, imgShape[2]))print("light field data dimension: LF({},{},{},{},{})".format(maxCD, maxCD, uRange, vRange,imgShape[2]))totalSubViewCount = maxCD*maxCDstart = time.time()  # 下载开始时间for x in range(maxCD):for y in range(maxCD):print('\rloading process: {:.2f}%'.format((x * maxCD + y)*100/totalSubViewCount), end=' ')for u in range(uRange):for v in range(vRange):LF[x, y, u, v, :] = LF_Raw[u*maxCD+x, v*maxCD+y, :]print('\rloading process: 100.00%')print('the 4D light field load successfully, time cost: %.2fs' % (time.time() - start))  #输出下载用时时间return LF.astype(np.uint8)
def LFSaveAllSubViewImages(LF, dir, dir_name):# 首先判断 LF 数据类型,如果是 float 类型需要预处理LFShape = LF.shapetotalSubViewCount = LFShape[0]*LFShape[1]path_save = os.path.join(dir, dir_name)if dir != "" and os.path.exists(dir) is False:os.mkdir(dir)if os.path.exists(path_save) is False:os.mkdir(path_save)for i in range(LFShape[0]):for j in range(LFShape[1]):img = LF[i, j, :, :, :]# plt.subplot(LFShape[2], LFShape[3], i*LFShape[2]+j+1)# plt.imshow(img)cv2.imwrite(os.path.join(path_save, "{}_{:0>2d}_{:0>2d}.png".format(dir_name, i, j)), img)print('\rprocess progress: {}/{} image'.format(i*LFShape[1]+j+1, totalSubViewCount), end=' ')print('\nall sub view images has been saved to {} successfully. '.format(path_save))
'''
参数:url: 下载的链接path: 下载的文件存放路径filename: 下载的文件名# 可以可视化的动态显示下载进度,便于使用
'''
def request_download(url, path, filename):if path!='' and (not os.path.exists(path)):  # 看是否有该文件夹,没有则创建文件夹os.mkdir(path)start = time.time() #下载开始时间response = requests.get(url, stream=True) #stream=True必须写上size = 0    #初始化已下载大小chunk_size = 1024  # 每次下载的数据大小content_size = int(response.headers['content-length'])  # 下载文件总大小try:if response.status_code == 200:   #判断是否响应成功print('Start download,[File size]:{size:.2f} MB'.format(size = content_size / chunk_size /1024))   #开始下载,显示下载文件大小filepath = os.path.join(path, filename)with open(filepath, 'wb') as file:   #显示进度条for data in response.iter_content(chunk_size = chunk_size):file.write(data)size +=len(data)print('\r'+'[下载进度]:%s%.2f%%' % ('>'*int(size*50/ content_size), float(size / content_size * 100)) ,end=' ')end = time.time()   #下载结束时间print('\nDownload completed!,times: %.2f秒' % (end - start))  #输出下载用时时间except:print('download error! ')

部分代码的逻辑说明:

LFReadRawImage:

由于所有宏像素的长宽是相等的(圆形和方形的光阑必相等,其他形状目前没见过,不太可能),所以首先是如果不清楚图像解码的光场的LF(x,y,u,v)参数会首先计算图像长宽的最大公约数,以最大公约数作为对应的u和v的值,上述斯坦福大学的光场数据格式为LF(14,14,376,541,4)。

正常的运行结果(控制台输出):

start to download light field png...
Start download,[File size]:178.75 MB
[下载进度]:>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>100.00% 
Download completed!,times: 60.19秒
png download successfully. 
start to load Stanford Lytro Light Field Archive image flowers_plants_14_eslf.png
light field data dimension: LF(14,14,376,541,4)
loading process: 100.00%
the 4D light field load successfully, time cost: 32.53s
Stanford Lytro Light Field Archive image load successfully, time cost: 35.881481885910034s
process progress: 196/196 image 
all sub view images has been saved to SubView Images\ successfully. 

结果输出的多视角图像效果(采用gif录制了一下不同图像之间连续变化的效果): 

现在已经拿到了五维光场函数,后续的许多操作例如EPI和重聚焦等操作就可以通过对LF操作来实现,本文讨论重心不在光场1.0,因此此内容此处不做过多赘述。


http://www.ppmy.cn/news/800845.html

相关文章

改进YOLOv8 | 主干网络篇 | YOLOv8 更换主干网络之 MobileViT |《轻巧、通用、便于移动的视觉转换器》

《MobileViT:轻巧、通用、便于移动的视觉转换器》 论文地址:https://arxiv.org/abs/2110.02178 代码地址:https://github.com/chinhsuanwu/mobilevit-pytorch/blob/master 轻量级卷积神经网络(CNN)实际上是用于移动视觉任务的。他们的空间归纳偏差使他们能够在不同的视觉…

学习分布式锁原理的一些个人思考

首先分布式锁和我们平常讲到的锁原理基本一样,目的就是确保,在多个线程并发时,只有一个线程在同一刻操作这个业务或者说方法、变量。 在一个进程中,也就是一个jvm 或者说应用中,我们很容易去处理控制,在jd…

【代码随想录day6】快乐数

题目 编写一个算法来判断一个数 n 是不是快乐数。 「快乐数」 定义为: 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。 然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。 如果这个过程 结果为 1&am…

精心制作新游戏,弱联网单机游戏

这段时间没上班,专心把去年开头了没结尾的项目做完。新游戏暂时还在找独代,不知道找不找得到合适的,先发个博文意思一下。 这个游戏是全平台的,手游,页游,端游,flash都能输出,名字暂时不贴出来先…

单机和弱联网游戏内购,白嫖的机会来了

往期推荐 ASsmalidea插件动态调式 JEB动态调试 Method Profiling 方法栈跟踪 内购的概念是很好理解,就比如游戏本身是免费的,一般是手机游戏,但是游戏里面会有道具或者金币等需要花钱来购买,这样在游戏内部收费的方式&#x…

计算机里没有游戏文件共享,共享文件联机游戏有Win7电脑一切简单

共享文件联机游戏有Win7电脑一切简单 2012年04月25日 09:30作者:陈涛编辑:陈涛文章出处:泡泡网原创 分享 泡泡网软件频道4月25日 大学生时代可以说是我们一生最美好的时代,宿舍的几个舍友联机玩一个游戏,那简直是爽死了…

微信小程序| 做一款多人实时线上的五指棋联机游戏

📌个人主页:个人主页 ​🧀 推荐专栏:小程序开发成神之路 --【这是一个为想要入门和进阶小程序开发专门开启的精品专栏!从个人到商业的全套开发教程,实打实的干货分享,确定不来看看? …

rust 局域网联机_Steam上有哪些值得推荐的可以多人局域网联机的游戏?

前面说的很多了,但是我发现没说到我那肝了一两年的糜烂的大学回忆啊! 方舟:生存进化... 方舟的世界里,需要采集资源,制作食物,制作武器建造防御工事,抵御来自大自然的天气以及体型巨大的史前恐龙。当然也可…