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

news2024/11/17 1:30:47

本文概要

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

光场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 20s
    LF = 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 None
    LF_Raw = np.array(Image.open(imgPath))
    imgShape = LF_Raw.shape
    if 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]/width
        if maxCD == imgShape[1]/height:
            uRange = width
            vRange = height
            maxCD = int(maxCD)
        else:
            print("data check faild, process finished. ")
            return None

    LF = np.zeros((maxCD, maxCD, uRange, vRange, imgShape[2]))
    print("light field data dimension: LF({},{},{},{},{})".format(maxCD, maxCD, uRange, vRange,imgShape[2]))
    totalSubViewCount = maxCD*maxCD
    start = 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.shape
    totalSubViewCount = 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.coloradmin.cn/o/734637.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

c语言实现单链表

#include<stdio.h> #include<malloc.h>typedef struct LNode{double data;struct LNode *next; }LNode,*LinkList;bool InitList(LinkList &L){L(LNode*) malloc(sizeof(LNode));//分配一个头结点 if(LNULL) //内存不足&#xff0c;分配失败 return false;L-&g…

机器学习与深度学习——自定义函数进行线性回归模型

机器学习与深度学习——自定义函数进行线性回归模型 目的与要求 1、通过自定义函数进行线性回归模型对boston数据集前两个维度的数据进行模型训练并画出SSE和Epoch曲线图&#xff0c;画出真实值和预测值的散点图&#xff0c;最后进行二维和三维度可视化展示数据区域。 2、通过…

day68_Vue基础

今日内容 零、 复习昨日 零、 复习昨日 一、Vue简介 1.1 简介 Vue (读音 /vjuː/&#xff0c;类似于 view) 是一套用于构建用户界面的渐进式的js框架&#xff0c;发布于 2014 年 2 月。与其它大型框架不同的是&#xff0c;Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注…

100、基于STM32单片机自动跟随小车 红外遥控控制小车避障模式 跟随模式设计(程序+原理图+PCB源文件+流程图+硬件设计资料+元器件清单等)

绪 论 智能小车通过各种感应器获得外部环境信息和内部运动状态&#xff0c;实现在复杂环境背景下的自主运动&#xff0c;从而完成具有特定功能的机器人系统。而随着智能化电器时代的到来&#xff0c;它们在为人们提供的舒适的生活环境的同时&#xff0c;也提高了制造智能化电器…

系统上线前,SQL脚本的9大坑

前言 系统上线时&#xff0c;非常容易出问题。 即使之前在测试环境&#xff0c;已经执行过SQL脚本了。但是有时候&#xff0c;在系统上线时&#xff0c;在生产环境执行相同的SQL脚本&#xff0c;还是有可能出现一些问题。 有些小公司&#xff0c;SQL脚本是开发自己执行的&am…

React Dva修改路由设置,不要井号

我们Dva项目的路由 他默认是设置了带井号的这种 其实我觉得到还可以 但是有些人会觉得不太美观 如果 你想去除他 那么 你先要在终端执行 npm install --save history将 history 引入进来 装好之后 我们来到src下的 index.js 加上如下代码 import {createBrowserHistory as …

nginx配置例子-反向代理实现

4.1 反向代理实现&#xff08;实例1&#xff09; 4.1.1需要实现的效果 (1)打开浏览器&#xff0c;在浏览器地址栏输入地址 www.123.com&#xff0c;跳转到liunx.系统tomat主页面中 4.1.2 准备工作 (1&#xff09;在liunx, 系统安装 tomcat, 使用默认端口8080. tomcat安装文…

【C++】-vector的具体使用(迭代器失效问题)

&#x1f496;作者&#xff1a;小树苗渴望变成参天大树&#x1f388; &#x1f389;作者宣言&#xff1a;认真写好每一篇博客&#x1f4a4; &#x1f38a;作者gitee:gitee✨ &#x1f49e;作者专栏&#xff1a;C语言,数据结构初阶,Linux,C 动态规划算法&#x1f384; 如 果 你 …

【Nacos】Nacos 2.2.4支持pg数据库适配改造

Nacos 2.2.4支持postgresql数据库 本文基源码&#xff1a;扩展插件包 网上资料都有&#xff0c;还是个人爬坑补充异常处理记录&#xff0c;以便后续升级改造有漏洞修复 下载源码 https://github.com/alibaba/nacos/releases 添加依赖 根pom添加pg依赖 <postgresql.vers…

跨平台轻量级RTSP服务模块设计思路及实现探讨

技术背景 为满足内网无纸化/电子教室等内网超低延迟需求&#xff0c;避免让用户配置单独的服务器&#xff0c;我们发布了轻量级RTSP服务模块&#xff0c;轻量级RTSP服务解决的核心痛点是避免用户或者开发者单独部署RTSP或者RTMP服务&#xff0c;实现本地的音视频数据&#xff…

(4)【轨迹优化篇】方法一:基于Frenet车道线坐标系,采用解耦采样五次多项式拟合进行局部规划

系列文章目录 提示&#xff1a;这里可以添加系列文章的所有文章的目录&#xff0c;目录需要自己手动添加 TODO:写完再整理 文章目录 系列文章目录前言A、第一章&#xff1a;Frenet车道线坐标系介绍及坐标转换一、frenet坐标系介绍1.Frenet坐标的定义2.ST图&#xff08;纵向速度…

【ARM Coresight 系列文章 3 - ARM Coresight 组件 DAP(Debug Access Port) 介绍】

文章目录 1.1 Debug Access Port1.2 Access Port1.2.1 IDR 寄存器 1.3 Mem-APs 介绍1.3.1 Debug 寄存器访问模型1.3.2 APs 中寄存器的介绍 1.1 Debug Access Port 外部 Debugger(DS-5/Trace32) 会通过JTAG接口或者SWD接口和DAP相连&#xff1a; JITAG 一般是5个pin&#xff1…

JAVA每日一练(1)

【程序1】 题目&#xff1a;古典问题&#xff1a;有一对兔子&#xff0c;从出生后第3个月起每个月都生一对兔子&#xff0c;小兔子长到第三个月后每个月又生一对兔子&#xff0c;假如兔子都不死&#xff0c;问每个月的兔子对数为多少&#xff1f; import java.util.Scanner;/*…

【ElasticSearch】数据聚合语法与Java实现

文章目录 1、聚合的分类2、DSL实现bucket聚合3、DSL实现Metrics 聚合4、RestClient实现聚合5、需求&#xff1a;返回过滤条件的信息6、带过滤条件的聚合 1、聚合的分类 聚合&#xff08;aggregations&#xff09;可以实现对文档数据的统计、分析、运算。&#xff08;类比MySQL…

如何记牢托福口语考试的关键词?

一般情况下&#xff0c;托福独立口语一类问题是自由回答间题(Free-choice Response)&#xff0c;如&#xff1a;If you could have any job in the world, what would it be? Use details to support your. response;另一类是选择类问题(Paired-choice Response)&#xff0c;如…

BERT论文解读及实现(一)

BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding 1 论文解读 1.1 模型概览 There are two steps in our framework: pre-training and fine-tuning. bert由预训练模型微调模型组成。 ① pre-training, the model is trained on unlabele…

前端Vue入门-day01

(创作不易&#xff0c;感谢有你&#xff0c;你的支持&#xff0c;就是我前行的最大动力&#xff0c;如果看完对你有帮助&#xff0c;请留下您的足迹&#xff09; 目录 Vue 快速上手 Vue 概念 创建实例 插值表达式 响应式特性 开发者工具 Vue 指令 v-show v-if …

【Spring Boot】第一个Spring Boot项目:helloworld

第一个Spring Boot项目&#xff1a;helloworld 本节从简单的helloworld程序开始介绍创建Spring Boot项目的方法和流程&#xff0c;以及Spring Boot项目结构&#xff0c;最后介绍项目中非常重要的pom.xml文件。 1.创建Spring Boot项目 有两种方式来构建Spring Boot项目的基础…

【1++的C++初阶】之string

&#x1f44d;作者主页&#xff1a;进击的1 &#x1f929; 专栏链接&#xff1a;【1的C初阶】 文章目录 一&#xff0c;浅谈string类二&#xff0c;string 类常用接口2.1 string的构造2.2 string类对象的容量操作2.3 string类对象的访问及遍历操作2.4 string类对象的修改操作2.…

Python 有趣的模块之pynupt——通过pynput控制鼠标和键盘

Python 有趣的模块之pynupt ——通过pynput控制鼠标和键盘 文章目录 Python 有趣的模块之pynupt ——通过pynput控制鼠标和键盘1️⃣简介2️⃣鼠标控制与移动3️⃣键盘控制与输入4️⃣结语&#x1f4e2; 1️⃣简介 &#x1f680;&#x1f680;&#x1f680;学会控制鼠标和键盘是…