Repository: JackHCC/Computer-Generated-Hologram
Branch: main
Commit: 5ce72697d2ee
Files: 30
Total size: 94.4 KB
Directory structure:
gitextract_teb12ani/
├── .gitignore
├── CGH/
│ └── README.md
├── Doc/
│ ├── Awesome.md
│ ├── Experiment.md
│ ├── Fourier_Hologram/
│ │ └── README.md
│ ├── Interference_Hologram/
│ │ └── README.md
│ ├── Kinoform/
│ │ └── README.md
│ └── Tips.md
├── GUI/
│ └── README.md
├── Matlab/
│ ├── fourier_hologram.m
│ ├── kinoforms.m
│ ├── offaxis_interference_hologram.m
│ └── propagator/
│ └── angular_spectrum/
│ ├── ASM.m
│ ├── ASMexample.m
│ ├── ASMshift.m
│ ├── double_phase_hologram.m
│ └── layer_based_method.m
├── Python/
│ ├── double_phase_hologram.py
│ ├── fourier_hologram.py
│ ├── fresnel_hologram.py
│ ├── kinoforms.py
│ ├── layer_based_method.py
│ ├── offaxis_interference_hologram.py
│ ├── phase_optimization/
│ │ └── iterative_methods/
│ │ ├── Error_Diffusion.py
│ │ ├── Fienup.py
│ │ └── GS.py
│ └── propagator/
│ ├── angular_spectrum.py
│ └── fresnel_diffraction.py
├── README.md
└── requirements.txt
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
.idea/
.DS_Store
__pycache__
================================================
FILE: CGH/README.md
================================================
# Todo: This is a SDK
================================================
FILE: Doc/Awesome.md
================================================
# awesome-holography
A curated list of resources on holographic displays, inspired by [awesome-computer-vision](https://github.com/jbhuang0604/awesome-computer-vision).
## Disclaimer
This list is compiled during my paper survey about holographic displays, and is not meant to be exhuastive. The list is organized for me to easily navigate different topics in holography. I would like to thank the authors of the following papers for providing great references:
- [Neural Holography with Camera-in-the-loop Training](https://www.computationalimaging.org/publications/neuralholography/) (Peng et al. 2020)
- [Learned Hardware-in-the-loop Phase Retrieval for Holographic Near-Eye Displays](https://light.princeton.edu/publication/hil-holography/) (Chakravarthula et al. 2020)
## Table of Contents
- [Background, Theory, and Survey](#background-theory-and-survey)
- [Computer Generated Holography (CGH)](#computer-generated-holography-cgh)
- [Traditional Heuristic Methods](#traditional-heuristic-methods)
- [Iterative Methods](#iterative-methods)
- [Data-driven (Learning-based) Methods](#data-driven-learning-based-methods)
- [Holographic Display Architectures and Optics](#holographic-display-architectures-and-optics)
- [Etendue, Eyebox, Pupil Related](#etendue-eyebox-pupil-related)
- [Labs and Researchers](#labs-and-researchers)
## Background, Theory, and Survey
### Background and Theory
- [Introduction to Fourier Optics](https://books.google.com.tw/books/about/Introduction_to_Fourier_Optics.html?id=QllRAAAAMAAJ&redir_esc=y) by Joseph W. Goodman is a great book to learn the basics of wave propagation and holography.
### Survey Papers
- [Toward the next-generation VR/AR optics: a review of holographic near-eye displays from a human-centric perspective](https://opg.optica.org/optica/fulltext.cfm?uri=optica-7-11-1563&id=442336) (Chang et al. 2020)
- [Deep learning in holography and coherent imaging](https://www.nature.com/articles/s41377-019-0196-0) (Rivenson et al. 2019)
## Computer Generated Holography (CGH)
### Traditional Heuristic Methods
#### Point-based Methods
Some methods are based on the double phase encoding scheme, where two phase-only modulation patterns are interleaved on a single SLM:
- [Computer-generated double-phase holograms](https://opg.optica.org/ao/abstract.cfm?uri=ao-17-24-3874) (Hsueh et al. 1978) proposed to decompose a complex field into two phase-only components to generate holograms using a single phase-only SLM.
- [Holographic Near-Eye Displays for Virtual and Augmented Reality](https://www.microsoft.com/en-us/research/wp-content/uploads/2017/05/holo_author.pdf) (Maimone et al. 2017) proposed a holographic near-eye display system based on the double phase encoding scheme.
Others methods include:
- [Near-eye Light Field Holographic Rendering with Spherical Waves for Wide Field of View Interactive 3D Computer Graphics](https://people.csail.mit.edu/liangs/papers/ToG17.pdf) (Shi et al. 2017)
#### Polygon/Mesh-based Methods
- [Computer-generated holograms of 3-D objects composed of tilted planar segments](https://opg.optica.org/ao/abstract.cfm?uri=ao-27-14-3020) (Leseberg et al. 1988)
- [Computer-generated holograms of tilted planes by a spatial frequency approach](https://opg.optica.org/josaa/ViewMedia.cfm?uri=josaa-10-2-299&seq=0&guid=37d8e19b-51f8-478e-936a-7a3c8c405b54) (Tommasi et al. 1993)
- [Computer-generated holograms for three-dimensional surface objects with shade and texture](https://opg.optica.org/ao/abstract.cfm?uri=ao-44-22-4607) (Matsushima 2005)
- [Extremely high-definition full-parallax computer-generated hologram created by the polygon-based method](https://opg.optica.org/ao/fulltext.cfm?uri=ao-48-34-H54&id=186427) (Matsushima et al. 2009)
- [Silhouette method for hidden surface removal in computer holography and its acceleration using the switch-back technique](https://opg.optica.org/oe/fulltext.cfm?uri=oe-22-20-24450&id=301771) (Matsushima et al. 2014)
- [Computer generated holograms from three dimensional meshes using an analytic light transport model](https://opg.optica.org/ao/abstract.cfm?uri=ao-47-10-1567) (Ahrenberg et al. 2008)
- [Fast and effective occlusion culling for 3D holographic displays by inverse orthographic projection with low angular sampling](https://opg.optica.org/ao/abstract.cfm?uri=ao-53-27-6287) (Jia et al. 2014)
#### Layer-based Methods
- [Computer-generated hologram with occlusion effect using layer-based processing](https://opg.optica.org/ao/abstract.cfm?uri=ao-56-13-F138) (Zhang et al. 2017)
- [Accurate calculation of computer-generated holograms using angular-spectrum layer-oriented method](https://opg.optica.org/oe/fulltext.cfm?uri=oe-23-20-25440&id=326909) (Zhao et al. 2015)
- [Improved layer-based method for rapid hologram generation and real-time interactive holographic display applications](https://opg.optica.org/oe/fulltext.cfm?uri=oe-23-14-18143&id=321638) (Chen et al. 2015)
- [Computer generated hologram with geometric occlusion using GPU-accelerated depth buffer rasterization for three-dimensional display](https://opg.optica.org/ao/abstract.cfm?uri=ao-48-21-4246) (Chen et al. 2009)
#### Holographic Stereograms
- [Holographic near-eye displays based on overlap-add stereograms](http://www.computationalimaging.org/publications/holographic-near-eye-displays-based-on-overlap-add-stereograms-siggraph-asia-2019/) (Padmanaban et al. 2019)
- [Layered holographic stereogram based on inverse Fresnel diffraction](https://opg.optica.org/ao/abstract.cfm?uri=ao-55-3-A154) (Zhang et al. 2016)
- [Fully computed holographic stereogram based algorithm for computer-generated holograms with accurate depth cues](https://opg.optica.org/oe/fulltext.cfm?uri=oe-23-4-3901&id=311865) (Zhang et al. 2015)
### Iterative Methods
A family of iterative methods is based on the **Gerchberg-Saxton (GS) Algorithm** where the phase and amplitute patterns at two planes are updated iteratively as the wave propagates back and forth between the two planes:
- [A practical algorithm for the determination of phase from image and diffraction plane pictures](http://www.u.arizona.edu/~ppoon/GerchbergandSaxton1972.pdf) (Gerchberg et al. 1972) proposed the **Gerchberg-Saxton (GS) Algorithm**
- [Mix-and-Match Holography](http://www.cs.ubc.ca/labs/imager/tr/2017/MixMatchHolography/MixMatchHolography_YPeng_SA17_LowRes.pdf) (Peng et al. 2017) proposed an interative phase-retrieval method built upon GS
- [Fresnel ping-pong algorithm for two-plane computer-generated hologram display](https://opg.optica.org/ao/ViewMedia.cfm?uri=ao-33-5-869&seq=0&guid=cd9375f1-824e-4719-a271-624d5c09ccca&html=true) (Dorsch et al. 1994)
Other optimization based methods leverage gradient descent or non-convex optimization techniques to optimize the phase pattern of the SLM:
- [Hogel-free Holography](https://dl.acm.org/doi/pdf/10.1145/3516428)(Chakravarthula et al. 2022)
- [Multi-depth hologram generation using stochastic gradient descent algorithm with complex loss function](https://opg.optica.org/oe/fulltext.cfm?uri=oe-29-10-15089&id=450644) (Chen et al. 2021)
- [Realistic Defocus Blur for Multiplane Computer-Generated Holography](https://arxiv.org/abs/2205.07030) (Kavaklı et al. 2021) proposed a novel loss function aimed to synthesize high quality defocus blur, and can be intergated in various iterative (GS, gradient-descent) and non-iterative (double phase encoding) methods.
- [Wirtinger Holography for Near-Eye Displays](https://www.cs.princeton.edu/~fheide/wirtingerholography) (Chakravarthula et al. 2019) optimizes the phase-only SLM pattern using closed-form Wirtinger complex derivatives in gradient descent.
- [3D computer-generated holography by non-convex optimization](https://opg.optica.org/optica/fulltext.cfm?uri=optica-4-10-1306&id=375391) (Zhang et al. 2017)
Unfortunately, iterative methods are inherently slow and thus not suitble for real-time CGH.
### Data-driven (Learning-based) Methods
A major focus in deep learning for CGH is using camera-in-the-loop (CITL) training to learn an accurate free space wave propagation and optical hardware model for holographic displays:
- [Neural Holography with Camera-in-the-loop Training](https://www.computationalimaging.org/publications/neuralholography/) (Peng et al. 2020) is the first to use **camera-in-the-loop training (CITL)** to optimize a parameterized wave propagation model, where optical aberrations, SLM non-linearities, and etc are learned from data. A CNN is also proposed to synthesize 2D and 3D holograms in real-time.
- [Neural 3D Holography: Learning Accurate Wave Propagation Models for 3D Holographic Virtual and Augmented Reality Displays](https://www.computationalimaging.org/publications/neuralholography3d/) (Choi et al. 2021) uses two CNNs to directly model optical aberrations, SLM non-linearities, and etc, at the input plane and **multiple** target planes. The usage of two CNNs introduces more degrees of freedom than that of the parameterized propagation model proposed in Peng et al. 2020, such that higher quality 3D holograms can be achieved.
- [Time-multiplexed Neural Holography: A Flexible Framework for Holographic Near-eye Displays with Fast Heavily-quantized Spatial Light Modulators](https://www.computationalimaging.org/publications/time-multiplexed-neural-holography/) (Choi et al. 2022) leveraged time-multiplexed quantized SLM patterns to synthesize high quality defocus blur.
- [Learned Hardware-in-the-loop Phase Retrieval for Holographic Near-Eye Displays](https://light.princeton.edu/publication/hil-holography/) (Chakravarthula et al. 2020) uses CITL to learn an aberration approximator that models the residual between holograms generated from ideal wave propagation (i.e. ASM) and real-world wave propagation models. An adversarial loss is used in addition to reconstruction loss to optimize the synthesized holograms.
Instead of using a predetermined convolution kernel to compute wave propagation (i.e. the angular spectrum method), [Learned holographic light transport](https://arxiv.org/pdf/2108.08253.pdf) (Kavaklı et al. 2021) learns the wave propagation convolution kernel directly from images captured by a physical holographic display.
Previous works assume a naive wave propagation model (i.e. the angular spectrum method), and directly regresses complex holograms using different CNN architectures:
- [Towards real-time photorealistic 3D holography with deep neural networks](https://cdfg.mit.edu/publications/tensor-holography) (Shi et al. 2021)
- [DeepCGH: 3D computer-generated holography using deep learning](https://opg.optica.org/oe/fulltext.cfm?uri=oe-28-18-26636&id=437573) (Eybposh et al. 2020) uses a CNN to estimate a complex field at a fixed plane from a set of 3D target multiplane inputs; the complex field is then reverse propagated to the SLM plane to generate a phase pattern.
- [Deep neural network for multi-depth hologram generation and its training strategy](https://opg.optica.org/oe/fulltext.cfm?uri=oe-28-18-27137&id=437709) (Lee et al. 2020) directly estimates the SLM phase pattern from 3D target multiplane inputs using a CNN.
- [Deep-learning-generated holography](https://opg.optica.org/ao/abstract.cfm?uri=ao-57-14-3859) (Horisaki et al. 2018)
- [Phase recovery and holographic image reconstruction using deep learning in neural networks](https://www.nature.com/articles/lsa2017141) (Rivenson et al. 2018)
## Holographic Display Architectures and Optics
Most CGH display frameworks use coherent light source (laser) and a single phase-only SLM. The following works explore alternatives to the current paradigm, such as using partially-coherent light sources, amplitude SLMs, and adding additional optical elements.
Partially-coherent light sources are used to reduce speckle artifacts:
- [Speckle-free holography with partially coherent light sources and camera-in-the-loop calibration](https://www.computationalimaging.org/publications/partiallycoherentholography/) (Peng et al. 2021) uses partially coherent light sources and camera-in-the-loop optimization to reduce speckle artifacts.
- [Light source optimization for partially coherent holographic displays with consideration of speckle contrast, resolution, and depth of field](https://www.nature.com/articles/s41598-020-75947-0)
- [Holographic head-mounted display with RGB light emitting diode light source](https://opg.optica.org/oe/fulltext.cfm?uri=oe-22-6-6526&id=281866) (Moon et al. 2014)
Special optical elements are used to improve the holographic display quality:
- [Monocular 3D see-through head-mounted display via complex amplitude modulation](https://opg.optica.org/oe/fulltext.cfm?uri=oe-24-15-17372&id=348011) (Gao et al. 2016)
- [Optimizing image quality for holographic near-eye displays with Michelson Holography](https://opg.optica.org/optica/fulltext.cfm?uri=optica-8-2-143&id=446984) (Choi et al. 2021)
- [Holographic Optics for Thin and Lightweight Virtual Reality](https://dl.acm.org/doi/abs/10.1145/3386569.3392416) (Maimone et al. 2020)
- [Retinal 3D: augmented reality near-eye display via pupil-tracked light field projection on retina](https://dl.acm.org/doi/10.1145/3130800.3130889) (Jang et al. 2017)
- [Holographic display for see-through augmented reality using mirror-lens holographic optical element](https://opg.optica.org/ol/abstract.cfm?uri=ol-41-11-2486) (Li et al. 2016)
- [3D holographic head mounted display using holographic optical elements with astigmatism aberration compensation](https://opg.optica.org/oe/fulltext.cfm?uri=oe-23-25-32025&id=333174) (Yeom et al. 2015)
Bulky headsets hamper the development of AR/VR. Reducing the size of holographic displays are important:
- [Holographic Glasses for Virtual Reality](https://research.nvidia.com/publication/2022-08_holographic-glasses-virtual-reality) (Kim et al. 2022) presents a holographic display system with eyeglasses-like form factor. An optical stack of 2.5mm is achieved by combining pupil-replicating waveguide, SLMs, and geometric phase lenses.
## Etendue, Eyebox, Pupil Related
- [Pupil-aware Holography](https://arxiv.org/pdf/2203.14939.pdf) (Chakravarthula et al. 2022)
- [Neural Etendue Expander for Ultra-Wide-Angle High-Fidelity Holographic Display](https://arxiv.org/abs/2109.08123) (Baek et al. 2022)
- [High Resolution étendue expansion for holographic displays](https://dl.acm.org/doi/abs/10.1145/3386569.3392414) (Kuo et al. 2020)
- [Holographic Near-eye Display with Expanded Eye-box](https://dl.acm.org/doi/10.1145/3272127.3275069) (Jang et al. 2018)
## Labs and Researchers
- [Computational Imaging Lab, Stanford University](https://www.computationalimaging.org)
- [Computational Imaging Lab, Princeton University](https://light.princeton.edu)
- [Computational Biophotonics Laboratory, UNC Chapel Hill](http://www.nicolaspegard.com/index.php)
- [Graphics and Virtual Reality Group, UNC Chapel Hill](https://telepresence.web.unc.edu)
- [Computational Light Laboratory, University College London](https://complightlab.com)
- [Computational Imaging Group, KAUST](https://vccimaging.org/publications.html)
- [Optical Engineering and Quantum Electronics Lab, Seoul National University](http://oeqelab.snu.ac.kr)
- [NVIDIA Research](https://www.nvidia.com/en-us/research/)
## Reference
- Ref Link: [https://github.com/bchao1/awesome-holography](https://github.com/bchao1/awesome-holography)
================================================
FILE: Doc/Experiment.md
================================================
## Experiment
### Before Experiment
Before experimenting, it's best to understand common image formats and their fundamentals. Understanding the pixel level of an image will help you experiment better and give you a better understanding of the fundamentals of image processing.
Here are some examples of images you should pay more attention to the suffix of the image, and the size of the image, so that you can work with the image later.

### Fourier Hologram
Circuitous Phase Type Hologram/Fourier Hologram is Binary hologram.
#### DataSet
For this experiment we used this image for testing

#### Experimental Principle
Please read this [Doc](Fourier_Hologram/README.md)ument.
#### Experimental Procedure
Two ways to do experiments are provided here, Matlab or Python, and you can choose the familiar way to run the code.
- Run the `fourier_hologram.m` or `fourier_hologram.py`, They are in the Python and Matlab folders respectively.
- Then you will get Circuitous Phase Type Hologram/Fourier Hologram below.

+ Finally, after running the program, you can get the reproduced graph and compare it with the original image.

### Kinoform
#### DataSet
For this experiment we used this image for testing

#### Experimental Principle
Please read this [Doc](Kinoform/README.md)ument.
#### Experimental Procedure
Two ways to do experiments are provided here, Matlab or Python, and you can choose the familiar way to run the code.
- Run the `kinoforms.m` or `kinoforms.py`, They are in the Python and Matlab folders respectively.
- Then you will get Kinoform below.

- Finally, after running the program, you can get the reproduced graph and compare it with the original image.

### Off Axis Interference Hologram
#### DataSet
For this experiment we used this image for testing
#### Experimental Principle
Please read this [Doc](Interference_Hologram/README.md)ument.
#### Experimental Procedure
Two ways to do experiments are provided here, Matlab or Python, and you can choose the familiar way to run the code.
- Run the `offaxis_interference_hologram.m` or `offaxis_interference_hologram.py`, They are in the Python and Matlab folders respectively.
- Then you will get Off Axis Interference Hologram below.

- Finally, after running the program, you can get the reproduced graph and compare it with the original image.

================================================
FILE: Doc/Fourier_Hologram/README.md
================================================
# Before Read
注:此文档分中英文撰写,根据需要跳转到相应位置阅读
Note: This document is written in Both Chinese and English, skip to the corresponding location to read if necessary
# 迂回位相型全息图
## 什么是迂回位相型全息图?
1960年,布朗恩( Brown)和罗曼应用迂回位相技术制成二元计算全息图,现在习惯称之为迂回位相型全息图。这种全息图有三个特点:
1. 全息图的透过率是二元的,即只取0或1。
2. 应用迁回位相编码物光波的位相,全息图可以同时记录复值函数的振幅和位相。
3. 全息图记录时没有用到参考光波或加偏分量。
这种迁回位相编码制作的二元计算全息图是计算全息的开创篇,正是它的特点使得它在后来的很多编码技术中得到了广泛的使用。
## 原理
二元付里叶变换计算全息图的制作过程一般分为四个步骤:
### 物面和全息面的抽样
在把物面信息输入计算机作离散付里叶变换之前,要先对物面和全息面分别按抽样定理进行抽样,求出各样点的幅值和位相信息。
物面函数:
$$
f(x, y)=a(x, y) \exp [j \phi(x, y)]
$$
傅里叶变换:
$$
F(\mu, v)=A(\mu, v) \cdot \exp [j \Phi(\mu, \nu)]
$$
即物函数$f(x,y)$在空间中大小是有限的。同时从物理意义上来说,它在空间域频率也是近似有限的。可以这样来理解,即物函数在空间是缓慢变化的,故其空间频率域中的高频部分可近似为零。
具体的抽样过程如图所示:

### 计算离散傅里叶变换(DFT)
由于制作的是付里叶变换全息图,故要算出全息图面上谱的复振幅分布$F(\mu, v)$,必须进行离散的付里叶变换。离散的付里叶变换可写成下式:
$$
F(u, v)=1 / M N \sum_{x=0}^{M-1}\left[\sum_{y=0}^{N-1} f(x, y) \exp (-j 2 \pi v / N)\right] \exp (-j 2 \pi c x / M)
$$
### 编码
即将算出的全息图面上样点处的幅值和位相,仍在计算机内进行编码处理,然后把编码后的信息输给绘图仪绘图,或由微密度计显示产生计算全息原图。由编码理论,可知编码的目的是要把复数值转变为实的非负函数。在迂回位相二元全息图中,罗曼等人是用下述精巧的方法分別编码振幅和位相的。在全息图的每个抽样单元中,放置一个通光孔径,改变此通光孔径的面积来调制波面的幅值,改变通光孔径中心距抽样单元中心的位置来编码波面的位相。通光孔径的形状可以是多种多样的,这主要依据绘图仪的作图能力和数学描述的方便来取定。在罗曼等人的工作中,选择了矩形孔径。矩形孔的可变参数可以有好几个,但由于只编码幅值和位相,故孔径的变参数仅取两个。罗曼编码方式分为Ⅰ型、Ⅱ型、Ⅲ型。
以罗曼Ⅲ型为例,处理方法如图:

### 绘图显示
当计算机已经完成幅值和位相编码后,下一步就是制作计算全息原图并把它缩小到合适的尺寸。绘图仪、阴极射线管、或计算机控制的微密度计都可用来制作原图。光学缩版后就变成实际可用的计算全息片了。如果采用特殊的输出(如电子束)直接把全息图记录在胶片上,就可省去制作原图和缩版的步骤,这样全息图的制作再现精度会更高些。
## 如何制作迂回位相型全息图?
在这个实验中,我们使用这个图像进行测试:

这里提供了两种进行实验的方法,Matlab或Python,您可以选择熟悉的方法来运行代码。
- 运行[`fourier_hologram.m`](../../Matlab/fourier_hologram.m) 或 [`fourier_hologram.py`](../../Python/fourier_hologram.py),它们分别在Python和Matlab文件夹中。
- 然后你会在下面得到Circuitous Phase Type Hologram/Fourier Hologram。

+ 最后,运行程序后,可以得到复现的图像,并将其与原始图像进行比较。

# Circuitous Phase Type Hologram
## What is Circuitous Phase Type Hologram?
In 1960, Brown and Roman used devolution phase technology to make binary computed holograms, now commonly known as devolution phase holograms. This hologram has three characteristics:
1. The transmittance of holograms is binary, that is, 0 or 1.
2. The hologram can record both the amplitude and the phase of the complex function by reverting to the phase of the object light wave.
3. No reference light wave or offset component is used in hologram recording.
This kind of binary CGH is the first part of CGH. It is its characteristic that makes it widely used in many coding technologies.
## Principle
The production process of binary Fourier transform CGH is generally divided into four steps:
### Sampling of object and holographic surfaces
Before input the information of object plane into computer for discrete Fourier transform, the object plane and holographic plane should be sampled respectively according to sampling theorem, and the amplitude and phase information of each point can be obtained.
Object surface function:
$$
f(x, y)=a(x, y) \exp [j \phi(x, y)]
$$
Fourier transform:
$$
F(\mu, v)=A(\mu, v) \cdot \exp [j \Phi(\mu, \nu)]
$$
That is, the matter function $f(x,y)$is finite in space. At the same time, in a physical sense, its frequency in the space domain is approximately finite. It can be understood that the matter function changes slowly in space, so the high frequency part of its spatial frequency domain can be approximately zero.
The specific sampling process is shown in the figure:

### Compute the Discrete Fourier Transform (DFT)
A discrete Fourier transform is necessary to calculate the complex amplitude distribution $F(\mu, v)$of the hologram. The discrete Fourier transform can be written as follows:
$$
F(u, v)=1 / M N \sum_{x=0}^{M-1}\left[\sum_{y=0}^{N-1} f(x, y) \exp (-j 2 \pi v / N)\right] \exp (-j 2 \pi c x / M)
$$
### Codes
The amplitude and phase of the sample point on the hologram plane to be calculated are still coded in the computer, and then the coded information is transferred to the plotter for drawing, or the original cHOLogram is generated by the micro-densitometer display. From coding theory, we know that the purpose of coding is to transform complex values into real non-negative functions. In a roundabout phase binary hologram Roman et al. coded the amplitude and phase separately in the following ingenious way. In each sampling element of the hologram, an aperture is placed, the amplitude of the wave surface is modulated by changing the area of the aperture, and the phase of the wave surface is encoded by changing the position between the center of the aperture and the center of the sampling element. The shape of aperture can be various, which is mainly based on the plotting ability of plotter and the convenience of mathematical description. In the work of Roman et al., rectangular apertures were chosen. There can be several variable parameters of rectangular hole, but only two variable parameters of aperture are selected because only amplitude and phase are encoded. Romanesque coding is divided into type ⅰ, type ⅱ and type ⅲ.
Taking Roman ⅲ type as an example, the treatment method is shown as follows:

### Drawing and Display
Once the computer has encoded the amplitude and phase, the next step is to make the CGH original and reduce it to the right size. Plotters, cathode-ray tubes, or computer-controlled microdensitometers can be used to make original drawings. The optical version is reduced to a practical CGH. If a special output (such as an electron beam) is used to record the hologram directly on the film, the process of making the original image and reducing the size of the hologram can be eliminated and the reproduction of the hologram will be more accurate.
## How to make Circuitous Phase Type Hologram?
Circuitous Phase Type Hologram/Fourier Hologram is Binary hologram.
For this experiment we used this image for testing

Two ways to do experiments are provided here, Matlab or Python, and you can choose the familiar way to run the code.
- Run the `fourier_hologram.m` or `fourier_hologram.py`, They are in the Python and Matlab folders respectively.
- Then you will get Circuitous Phase Type Hologram/Fourier Hologram below.

+ Finally, after running the program, you can get the reproduced graph and compare it with the original image.

================================================
FILE: Doc/Interference_Hologram/README.md
================================================
# Before Read
注:此文档分中英文撰写,根据需要跳转到相应位置阅读
Note: This document is written in Both Chinese and English, skip to the corresponding location to read if necessary
# 计算全息干涉图
## 什么是计算全息干涉图?
干涉是光学中的基本现象,相干的双光束或多光束叠加就形成干涉条纹。以往的干涉都是应用光学方法来实现,但光学的干涉图却完全可用计算来仿真( simulation),即计算机产生的干涉图。全息摄像主要经历光学全息,数字全息,和计算全息这样几个过程,其基本原理都是通过干涉纪录及衍射重建。当两束光波进行干涉时,记录物体的振幅和相位信息,通过衍射计算,重构物体的振幅和相位信息。
用计算机模拟产生光学干涉图,只预先知道干涉图样的数学模式即可。但是一般的光学干涉图,其透过率是连续变化的函数,而用计算机输出的数字讯号经绘图仪或CRT显示来制作的计算全息,干涉图,常常希望只得到二元透过率(取0或1值),即二元计算全息干涉图。为了达到这一目的,就必须把连续透过率函数进行非线性变换,转化成二元形式,而且此二元形式的干涉图仍应保存物波的全部信息,在再现时能得到所需的物光波。
## 原理
普通的离轴型光学全息图,可以把它看成是物光和参考光“双光束”相叠加而形成的干涉图,其透过率为
$$
\begin{aligned}
h(x, y) &=|R \exp (j 2 \pi x / T)+A(x, y) \exp (j \phi(x, y))|^{2} \\
&=R^{2}+|A(x, y)|^{2}+2 R A(x, y) \cos (2 \pi x / T-\phi(x, y))
\end{aligned}
$$
其中,$R \exp (j 2 \pi x / T)$为参考光复振幅,$A(x, y) \exp (j \phi(x, y))$为物光复振幅。
当物光仅仅只有相位变化时,上式可简化为:
$$
h(x, y)=\frac{1}{2}(1+\cos \{2 \pi x / T-\phi(x, y)\})
$$
根据上式可以得出振幅最大值和最小值位置,得到干涉条纹。但是透过率是连续的,干涉条纹的对比是不高的。如果只是为了要提高条纹的对比,以致在极端的情况下能产生二元值化(0,1)的条纹,一种方法是可以用多光束相干涉,当参加干涉的光束数越多时,条纹就越锐,逐渐趋向于二元形式,这时的透过率函数可写成多光束迭加求和的形式。另一常规的方法是用高反差的胶片来记录此干涉条纹,这种高反差胶片的硬限幅特性能把连续色调的干涉条纹变成二元干涉图。后一种方法启示我们,若要计算机来制作二元计算全息干涉图,可以借用电讯系统中的非线硬限幅器的模型来进行处理。
我们举三个例子来说明二元计算全息图的制作技术及其再现情况。这三个例子都是记录的位相型波面,它们在光学干涉量度中有很大的应用价值。其中第一个例子是球面波,它通常在光学中是由透镜或波带板状得到的;第二个例子是锥形波面,也可由光学的旋转三棱镜获得;而第三个例子是螺旋形波面,其位相在方位方向上是线性变化的,这种波面用通常的光学元件却是得不到的。故最后一个例子说明了,由于计算机仿真干涉图的灵活性大,我们完全可以得到用光学制作技术难以得的特殊位相型变化波前。这使得计算全息干涉图很适用于光学的量度术中去检特殊的光学波面。
**球面波**
球面波的位相变化为:
$$
\phi(x, y)=\frac{k}{2 f}\left(x^{2}+y^{2}\right)
$$
其中,$k=\frac{2 \pi}{\lambda}$,$f$是球面波曲率半径。
计算得到条纹数:
$$
N_{p}=\left.\phi(x, y)\right|_{\max }=\frac{\pi \cdot \frac{D^{2}}{4}}{\lambda \cdot f \cdot 2 \pi}=\frac{D^{2}}{8 \lambda f}=\frac{N}{16}
$$
**锥形波面**
锥形面波的位相变化为:
$$
\phi(x, y)=2 \pi r / r_{0}
$$
其中,$r=\left(x^{2}+y^{2}\right)^{1 / 2}$。
计算得到条纹数:
$$
N_{\mathrm{p}}=\frac{D}{2 \cdot r_{0}}=\frac{N}{8}
$$
**螺旋形波面**
相对变化:
$$
\phi(x, y)=2 \pi \theta / \theta_0
$$
其中,$\theta=\tan ^{-1} y / x$
## 如何制作计算全息干涉图?
在这个实验中,我们使用这个图像进行测试:
这里提供了两种进行实验的方法,Matlab或Python,您可以选择熟悉的方法来运行代码。
- 运行[`offaxis_interference_hologram.m`](../../Matlab/offaxis_interference_hologram.m) 或 [`offaxis_interference_hologram.py`](../../Python/offaxis_interference_hologram.py),它们分别在Python和Matlab文件夹中。
- 然后你会在下面得到Off Axis Interference Hologram。

- 最后,运行程序后,可以得到复现的图像,并将其与原始图像进行比较。

# Computational Interference Holograms
## What is Computational Interference Holograms?
Interference is a basic phenomenon in optics. Interference fringes are formed when two or more coherent beams are superimposed. In the past, interference is realized by optical method, but the optical interferogram can be completely simulated by calculation, that is, the interferogram generated by computer. Holography mainly goes through optical holography, digital holography and computational holography. The basic principle of holography is interference recording and diffraction reconstruction. When two light waves interfere, the amplitude and phase information of the object are recorded, and the amplitude and phase information of the object are reconstructed by diffraction calculation.
To produce optical interferograms by computer simulation, only the mathematical pattern of interference pattern is known in advance. However, the transmittance of general optical interferogram is a function of continuous change, while the computed hologram (CGH), which is made by using the digital signal output by computer and displayed by plotter or CRT, usually hopes to get only binary transmittance (0 or 1), namely binary CGH interferogram. In order to achieve this goal, it is necessary to transform the continuous transmittance function into a binary form by nonlinear transformation, and the binary interferogram should still preserve all the information of object wave, so as to obtain the desired object wave when reproducing.
## Principle
The common off-axis optical hologram can be regarded as an interferogram formed by the superposition of object light and reference light "double beam", and its transmittance is
$$
\begin{aligned}
h(x, y) &=|R \exp (j 2 \pi x / T)+A(x, y) \exp (j \phi(x, y))|^{2} \\
&=R^{2}+|A(x, y)|^{2}+2 R A(x, y) \cos (2 \pi x / T-\phi(x, y))
\end{aligned}
$$
Where,$R \exp (j 2 \pi x / T)$is the reference light recovery amplitude and i$A(x, y) \exp (j \phi(x, y))$s the object light recovery amplitude.
When the object light only changes in phase, the above equation can be simplified as:
$$
h(x, y)=\frac{1}{2}(1+\cos \{2 \pi x / T-\phi(x, y)\})
$$
According to the above formula, the position of the maximum and minimum amplitude can be obtained, and the interference fringe can be obtained. But the transmittance is continuous and the contrast of interference fringes is not high. If only in order to improve the contrast of stripe, so that in extreme cases can generate binary value (0, 1) stripes, a kind of method is you can use multiple beam interference, when attend the more the number of beam interference stripe is more sharp, gradually tend to be binary form, the transmittance function can be written in the form of multiple beam superposition summation. Another conventional method is to record the interference fringes on high-contrast film. The hard limiting property of this high-contrast film can transform the continuous tone interference fringes into binary interferograms. The latter method suggests that the model of non-linear hard limiter in telecommunication system can be used to make binary CGH interferogram by computer.
Three examples are given to illustrate the fabrication and reproduction of binary CGH. These three examples are all recorded phase type wavefronts which have great application value in optical interferometry. The first example is spherical waves, which are usually obtained in optics by lenses or waveband plates; The second example is the conical wavefront, also obtained by optical rotating prisms; A third example is a helical wave surface, whose phase varies linearly in orientation, which is not available with ordinary optical elements. Therefore, the last example illustrates that, due to the flexibility of computer simulation interferogram, we can get special phase change wavefront which is difficult to obtain by optical fabrication technology. This makes CGH very suitable for optical measurement to detect special optical wavefronts.
**Spherical wave**
The potential transformation of spherical waves is transformed into:
$$
\phi(x, y)=\frac{k}{2 f}\left(x^{2}+y^{2}\right)
$$
Where, $k=\frac{2 \ PI}{\lambda}$, $f$is the radius of spherical wave curvature.
Calculate the number of fringe:
$$
N_{p}=\left.\phi(x, y)\right|_{\max }=\frac{\pi \cdot \frac{D^{2}}{4}}{\lambda \cdot f \cdot 2 \pi}=\frac{D^{2}}{8 \lambda f}=\frac{N}{16}
$$
**Conical wave surface**
The potential phase transformation of the conical surface wave transforms into:
$$
\phi(x, y)=2 \pi r / r_{0}
$$
Where,$r= left(x^{2}+y^{2})^{1/2}$
Calculate the number of fringe:
$$
N_{\mathrm{p}}=\frac{D}{2 \cdot r_{0}}=\frac{N}{8}
$$
**Spiral wave surface **
Relative change:
$$
\phi(x, y)=2 \pi \theta / \theta_0
$$
Where,$\theta=\tan ^{-1} y/x$
## How to make Computational Interference Holograms?
For this experiment we used this image for testing
Two ways to do experiments are provided here, Matlab or Python, and you can choose the familiar way to run the code.
- Run the `offaxis_interference_hologram.m` or `offaxis_interference_hologram.py`, They are in the Python and Matlab folders respectively.
- Then you will get Off Axis Interference Hologram below.

- Finally, after running the program, you can get the reproduced graph and compare it with the original image.

================================================
FILE: Doc/Kinoform/README.md
================================================
# Before Read
注:此文档分中英文撰写,根据需要跳转到相应位置阅读
Note: This document is written in Both Chinese and English, skip to the corresponding location to read if necessary
# 相息图
## 什么是相息图?
相息图是假设在整个记录平面内光波振幅为常数的条件下,仅记录波前位相信息的元件。因此,相息图再现时也只给出物波的位相信息,而丢失了物波的振幅信息(振幅为常数)。随着相息图技术的发展,后来的相息图不仅能保存物波的位相信息,而且同时能记录和再现物波的振幅信息,这种扩展了的相息图就完全保存了物体的全部信息,因而是一种新型的全息图。
光学全息和计算全息图都将光波信息转化为全息图的透过率变化或干涉条纹图形而记录在胶片上,但相息图却只将光波的位相信息以浮雕形式记录在胶片上。光学全息和计算全息的再现复数波场都是建立在光的衍射理论的基础上,而相息图却似菲涅尔透镜那样,只是通过改变光学厚度去变化照射光波的位相分布,从而再现出原始的物光波。因此相息图可以看成是一块由计算机制作的复杂透镜,其表面形状,对同轴再现的相息图来说,很像光学菲涅尔透镜,而对离轴像的再现来讲,相息图则像一块精密制作的闪耀光栅。
相息图的最大优点也许是其衍射效率特高。一张相息图完全是一透明片,不会衰减入射光强。照明相息图只得到单一的衍射级,再现单一的图像,没有共轭像或杂散图像叠加其上。因此它既不像光学全息中的由于实、虚共轭像的存在而减弱再现像的光强,也不像二元计算全息中有多余的衍射级存在而分散入射光强。在理想情况下,相息图可把全部入射光用来重建这个单个像,故衍射效率可达到100%。
## 原理
相息图是在个基本假定下制作的,即认为待记录的物体是理想的漫射体,从物体上发出的漫射光均匀地照射在整个相息图平面上,因此相息图平面内的光振幅为常数,而且物体的全部信息都均匀地扩展到整个相息图平面。这样,要构造这个漫射性质的物体,仅仅只要记录散射光波的位相信息就可以了。相息图平面内的光波复振幅分布为:
$$
U(x, y)=A \cdot \exp (j \phi(x, y))
$$
然而在通常的情况下,相息图平面内的光振幅A不可能总是常数,因此常数振幅的假设是有问題的。但我们可以改变原始物体的位相函数,努力做到此物体的散射光到达相息图平面时实质上是均匀分布的,即光振幅可为常数。在物理上,相当于通过漫射体(如毛玻璃)来照明物体,这个漫射体扩展了照明光波,并把入射光波的位相随机地散布在物体的各个部分,结果是相息图上的每一部分都接收到了物体的全部信息。
现在我们从数学处理上来寻找物体为漫射体的合适描述。常用的方法是把物体表示成二维(平面)或三维(立体)点孔阵列的集合。毎个小孔波场的复振幅为$T_k$,并向空间发射球面次波。
$$
T_{\mathrm{k}}=t_{\mathrm{k}} \exp \left(j \alpha_{\mathrm{k}}\right)
$$
其中,$t_k$表示第$k$个点孔的透射率,$t_k$=0表示点孔阻拦光波,$t_k$=1表示点孔完全透光,$t_k$在(0,1)之间取值,表示不同的透光情况。$\alpha_k$是各点的位相变化函数。把物体表示成点孔集合这一模式,优点在于以后作数学运算时比较方便,物理意义地很清楚,它自动地保证了光信息的空间漫射(毎个点源向整个空间发射球面波).
给出了物体的数学表达式,下面就可说明相息图的实际计算和制作过程,为了简化,我们以一维为例,但它可以很方便地推广到二维或三维情况。下图表示物面到相息图的菲涅尔衍射。

物面上中心在$a_k$,线度为$\delta$的孔径,发射光波传播到距离为$E$处的的相息图平面$x$.根据克希霍夫衍射理论,相息图平面上的光波复振幅为
$$
U\left(x, a_{\mathrm{k}}\right)=C \int_{a_{\mathrm{k}}-\delta / 2}^{a_{\mathrm{k}}+\delta / 2} \exp \left[j \frac{2 \pi}{\lambda}\left\{(x-a)^{2}+z^{2}\right\}^{\frac{1}{2}}\right] d a
$$
如果$\delta$的孔径无限大,同时光波是一种电磁波,它满足麦克斯韦方程组,将光波表示成球面波的形式,根据推导可以获得标量场下光波的菲涅尔衍射积分的表达式如下:
$$
U(x, y)=\frac{\exp (j k d)}{j \lambda d} \iint_{-\infty}^{\infty} U_{0}\left(x_{0}, y_{0}\right) \exp \left(\frac{j k}{2 d}\left[\left(x-x_{0}\right)^{2}+\left(y-y_{0}\right)^{2}\right]\right) d x d y
$$
将上式改写为离散的傅里叶变换的形式为:
$$
\begin{array}{c}
U(p \Delta x, q \Delta y)=\frac{\exp (j k d)}{j \lambda d} \exp \left[\frac{j k}{2 d}\left(p \Delta x^{2}\right)+q \Delta y^{2}\right] \\
\times I\left[U_{0}\left(m \Delta x_{0}, n \Delta y_{0}\right) \times \exp \left(\frac{j k}{2 d}\left(m \Delta x_{0}\right)^{2},\left(n \Delta y_{0}\right)^{2}\right)\right]_{\frac{p \Delta x}{\lambda d}, \frac{p \Delta y}{\lambda d}}
\end{array}
$$
相息图平面上的复振幅分布(离散形式)为
$$
U(x, y)=U_{\mathrm{R}}(x, y)+j U_{\mathrm{I}}(x, y)
$$
其相角为:
$$
\phi(x, y)=\tan ^{-1}\left(U_{\mathrm{I}}(x, y) / U_{\mathrm{R}}(x, y)\right)
$$
由于上述的相息图不能记录光场的振幅信息,这总会给再现像的逼真度产生影响。但是相息图又有比全息图衍射效率高,同轴再现时无共轭像干扰等的优点,故自然就想到,要在保持相息图优点的条件下,进一步对相息图改进,消除其不足之处。下面几种相息图的扩展技术,它们都能同时记录物波的位相和振幅全部信息。
**无参考光同轴复式全息图 ROACH**
这种方法是想法寻找特殊的全息照相记录介质,它不仅能用漂白技术来形成浮雕像,达到调制光波位相的目的,而且也能引入光波的振幅调制。这种照相记录介质就是用多层乳胶的柯达Ⅱ彩色胶片( Kodacolor Ⅱ),其中不同的乳胶层只对不同的色光曝光。当用单色光照明处理以后的胶片时,一层乳胶将吸收光能,以调制入射波的振幅,而其余两层仍是透明的,只能产生入射光的位相信息。其工作原理图下图:

**纯位相型全息图**
另外一种相息图扩展技术是对相息图记录的位相再调制。制作的办法是在相息图上不直接记录物波经付里叶变换后的位相,而是记录由物波的付里叶变换振幅重新调制的位相。通常是在原先的位相项中加进额外的位相项,再现时用一项位相变化去调物波振幅。这祥制作的相息图也叫做纯位相型全息图。尽管全息图面上的振幅仍为常数,但这种纯位相型全息图同时包含了物波的全部信息。当然,由于在再现波中引进了振幅变化,再现时光波必然产生偏离,这将减少再现像的衍射效率。
## 如何制作相息图?
在这个实验中,我们使用这个图像进行测试:

这里提供了两种进行实验的方法,Matlab或Python,您可以选择熟悉的方法来运行代码。
- 运行[`kinoforms.m`](../../Matlab/kinoforms.m) 或 [`kinoforms.py`](../../Python/kinoforms.py),它们分别在Python和Matlab文件夹中。
- 然后你会在下面得到Kinoform。

- 最后,运行程序后,可以得到复现的图像,并将其与原始图像进行比较。

# Kinoform
## What is Kinoform?
A kinoform is an element that records only the phase information of the wave front under the assumption that the amplitude of the light wave in the whole recording plane is constant. Therefore, only the phase information of the object wave is given, but the amplitude information of the object wave is lost (the amplitude is constant). With the development of kinoform technology, the later kinoform can not only save the phase information of object wave, but also record and reproduce the amplitude information of object wave. This extended kinoform completely preserves all the information of object, so it is a new type of hologram.
Both optical holography and CGH record the light wave information on film by converting the transmittance change or interference fringe pattern of hologram, but the phase pattern only records the light wave phase information in relief form on film. The reconstruction of complex wave field of optical holography and computational holography is based on the diffraction theory of light, while the kinoform is just like Fresnel lens, which only changes the phase distribution of the irradiating light wave by changing the optical thickness, so as to reproduce the original object light wave. Thus, a kinoform can be thought of as a complex computer-generated lens whose surface shape looks much like an optical Fresnel lens for a coaxial representation of the kinoform, and like a precisely fabricated sparkle grating for an off-axis representation.
Perhaps the greatest advantage of the kinoform is its high diffraction efficiency. A kinoform is completely transparent and does not attenuate the incident light intensity. Illumination kinoform only gets a single diffraction order, reproduces a single image, no conjugate image or stray image superimposed on it. Therefore, it is not like optical holography which weakens the light intensity of the reconstructed image due to the existence of real and virtual conjugated images, nor like binary CGH which disperses the incident light intensity due to the existence of redundant diffraction levels. Under ideal conditions, the kinoform can be used to reconstruct the single image with all incident light, so the diffraction efficiency can reach 100%.
## Principle
The kinoform is made under the basic assumption that the object to be recorded is an ideal diffuse body, the diffuse light from the object is uniformly illuminated on the whole kinoform plane, so the amplitude of the light in the kinoform plane is constant, and all the information of the object is uniformly extended to the whole kinoform plane. Thus, to construct the diffuse object, it is only necessary to record the phase information of the scattered light wave. The complex amplitude distribution of light wave in the kinoform plane is:
$$
U(x, y)=A \cdot \exp (j \phi(x, y))
$$
In general, however, the optical amplitude A in the kinoform plane cannot always be constant, so the assumption of constant amplitude is problematic. However, we can change the phase function of the original object and try to achieve that the scattered light of the object is essentially evenly distributed when it reaches the plane of the kinoform, that is, the amplitude of the light can be constant. In physics, it is equivalent to illuminating an object with a diffuse object (such as ground glass), which expands the illumination wave and randomly disperses the phase of the incident light wave over various parts of the object, so that each part of the kinoform receives all the information of the object.
Now let's look at the mathematical process to find a suitable description of the object as diffuse. A common method is to represent an object as a collection of two-dimensional (flat) or three-dimensional (solid) point-hole arrays. Each keyhole wave field has a complex amplitude of $T_k$and emits spherical secondary waves into space.
$$
T_{\mathrm{k}}=t_{\mathrm{k}} \exp \left(j \alpha_{\mathrm{k}}\right)
$$
$t_k$=0; $t_k$=1; $t_k$=0; $t_k$=1; $\alpha_k$is the phase change function of each point. The advantage of this model is that the object is represented as a set of point holes, which is convenient for mathematical calculation and has a clear physical meaning. It automatically ensures the spatial diffusion of optical information (every point source emits spherical waves to the whole space).
Given the mathematical expression of the object, the actual calculation and production process of the kinoform can be illustrated below. For simplicity, we use one dimension as an example, but it can be easily generalized to two or three dimensions. The figure below shows Fresnel diffraction from the surface to the kinoform.

The aperture centered at $a_k$and linear at $\delta$is transmitted to the kinoform plane $X $at distance $E$. According to kirchhoff diffraction theory, the complex amplitude of light wave on the kinoform plane is
$$
U\left(x, a_{\mathrm{k}}\right)=C \int_{a_{\mathrm{k}}-\delta / 2}^{a_{\mathrm{k}}+\delta / 2} \exp \left[j \frac{2 \pi}{\lambda}\left\{(x-a)^{2}+z^{2}\right\}^{\frac{1}{2}}\right] d a
$$
If the aperture of $\delta$is infinite and the light wave is a kind of electromagnetic wave, which satisfies Maxwell's equations and is expressed in the form of spherical wave, the Fresnel diffraction integral of the light wave under scalar field can be obtained as follows:
$$
U(x, y)=\frac{\exp (j k d)}{j \lambda d} \iint_{-\infty}^{\infty} U_{0}\left(x_{0}, y_{0}\right) \exp \left(\frac{j k}{2 d}\left[\left(x-x_{0}\right)^{2}+\left(y-y_{0}\right)^{2}\right]\right) d x d y
$$
The formula above can be rewritten as the discrete Fourier transform:
$$
\begin{array}{c}
U(p \Delta x, q \Delta y)=\frac{\exp (j k d)}{j \lambda d} \exp \left[\frac{j k}{2 d}\left(p \Delta x^{2}\right)+q \Delta y^{2}\right] \ \
\times I\left[U_{0}\left(m \Delta x_{0}, n \Delta y_{0}\right) \times \exp \left(\frac{j k}{2 d}\left(m \Delta x_{0}\right)^{2},\left(n \Delta y_{0}\right)^{2}\right)\right]_{\frac{p \Delta x}{\lambda d}, \frac{p \Delta y}{\lambda d}}
\end{array}
$$
The complex amplitude distribution (discrete form) on the kinoform plane is
$$
U(x, y)=U_{\mathrm{R}}(x, y)+j U_{\mathrm{I}}(x, y)
$$
Its phase Angle is:
$$
\phi(x, y)=\tan ^{-1}\left(U_{\mathrm{I}}(x, y) / U_{\mathrm{R}}(x, y)\right)
$$
Since the above kinoform cannot record the amplitude information of the light field, it will always affect the fidelity of the reconstructed image. However, the phase and kinoform has the advantages of higher diffraction efficiency than hologram and no conjugate image interference in coaxial reproduction. Therefore, it naturally occurred to us to further improve the phase and kinoform to eliminate its shortcomings while maintaining the advantages of the phase and kinoform. The following are several extended kinoform techniques that simultaneously record all phase and amplitude information of object waves.
**Coaxial compound hologram without reference light ROACH**
This method is to find a special hologram recording medium, which can not only use bleaching technology to form floating statues to achieve the purpose of modulation of light wave phase, but also can introduce the amplitude modulation of light wave. The photographic recording medium is Kodacolor ii, which uses multiple layers of latex, in which different layers of latex are exposed only to different colors. When the resulting film is illuminated with monochromatic light, one layer of latex absorbs light energy to modulate the amplitude of the incident wave, while the other two layers remain transparent, producing only phase information about the incident light. Its working principle diagram is as follows:

**Pure phase hologram**
Another phase - and - kinoform extension technique is phase - modulation of the phase - and - kinoform record. The method is to record the phase of the object wave modulated by the Fourier transform amplitude of the object wave on the kinoform instead of directly recording the phase after the Fourier transform. Usually, an additional phase term is added to the original phase term and a phase change is used to modulate the amplitude of the matter wave during reproduction. Such a kinoform is also called a pure phase hologram. Although the amplitude of the hologram is constant, the hologram of pure phase contains all the information of matter wave. Of course, due to the introduction of amplitude changes in the reconstructed wave, the light wave will inevitably deviate during the reconstruction, which will reduce the diffraction efficiency of the reconstructed image.
## How to make Kinoform?
For this experiment we used this image for testing

Two ways to do experiments are provided here, Matlab or Python, and you can choose the familiar way to run the code.
- Run the [`kinoforms.m`](../../Matlab/kinoforms.m) or [`kinoforms.py`](../../Python/kinoforms.py), They are in the Python and Matlab folders respectively.
- Then you will get Kinoform below.

- Finally, after running the program, you can get the reproduced graph and compare it with the original image.

###
================================================
FILE: Doc/Tips.md
================================================
Tips:
- 基于振幅的全息图会**产生共轭像【菲涅尔离轴参考光全息图】**、基于相位的全息图不会【**相息图**】、基于傅里叶变换的全息图会产生很多像【**傅里叶全息图**】,其中最中间的像最清晰
- **像全息图,菲涅尔全息图,夫琅禾夫全息图**是根据**物与像的距离**来判断,**角谱法【场传播】**这不涉及距离限制,一般夫琅禾夫全息图可用**凸透镜**代替
- 常见分类:**基于点,基于多边形,基于层,立体全息图,基于射线**
- **POH相比AOH衍射效率更高**,效果更好,更常用,且不会产生共轭像。AOH提高衍射效率一般需要手动添加**C_hist**参数
- **将空间复函数表示的信号转变为透过率变化函数的过程称为编码**
- RGB 通道中采用的红绿蓝光波长分别为 **633nm、532nm、450nm**,采样间隔为 21μm、19μm、17μm
- 菲涅耳离轴全息图的制作过程包括了**菲涅耳衍射和离轴参考光干涉**两个部分
- **离轴参考光干涉**
- **菲涅耳衍射:**指通过菲涅耳衍射积分来计算物体在全息记录面的物光波前,具体来说它由以下两步组成:(1)使用菲涅耳衍射积分来计算原始物体上每一点到达全息记录面的菲涅尔衍射光波(2)对到达全息记录面的原始物体上的每一点的菲涅尔衍射光波进行叠加

- 数值场的传播基于**标量绕射理论**
- **Helmholtz方程**用来求解波传播场的算子
- **计算全息的视角定义为物场最大衍射角的两倍**
- 对于傅里叶变换全息术,**计算全息尺寸越大,焦距越短,视角越大**。
### 全息分类【大全】
**光学**角度(物体与记录平面距离):
- 像全息图:超近距离
- 菲涅尔全息图:适中距离
- 基于卷积计算
- 基于傅里叶变换计算
- 夫琅禾夫全息图:远距离
- 傅里叶变换【凸透镜全息图】

光学记录材料分类:
- 薄全息图(thin hologram):**条纹波矢量K几乎平行于材料的表面**。
- 体全息图(volume hologram):**条纹波矢量K近似垂直于表面**

计算**平面间传播场**的方式:
- 菲涅尔衍射方法【基于单傅里叶变换和基于卷积计算】
- 传递函数

- 传播核

- **角谱法**
- 传递函数

- 传播核

编码复值函数的方式分类:
- 使用**两个实值函数来表示复值函数**,两个实值函数分别记录了物体的幅值和相位信息,对幅值进行编码可以采用空间脉冲带宽调制的方法,对相位编码可以采用空间脉冲相位调制的方法
- 模仿**光学全息图编码方式**,在制作离轴光学全息图时,使用离轴参考光偏置分别对物体波面进行调幅和调相,从而转化为实值函数,便可以记录在全息平面上
数值场传播方式分类:
- **最基本的传播**;**源波场在与源波场平行的平面中传播到目的波场**
- **离轴传播或移位传播**
- **波场的旋转变换**

**CGH**分类【****Traditional Heuristic Methods****】:
- **Point-based** methods:点光源,基于物理的方法,模拟了从3D场景到全息图平面的光传输过程。例如:双相位编码全息图
- **Polygon-based** methods:将3D对象视为数千个多边形,而不是数百万个点。将每个多边形视为一个多边形孔径,将所有多边形孔径的衍射图形相加得到CGHs
- **Layer-based** methods:将三维物体划分为平行于全息图平面的多个层,每一层都作为一个独立的计算单元。然后利用菲涅尔衍射计算各层的子全息图,将所有子全息图叠加得到cgh。
- **Ray-tracing**:射线追踪是一种**模拟光传输**的计算机图形技术。其主要思想是**跟踪通过虚拟场景和与材料交互的单个光线,准确计算到达虚拟相机每个像素的光量**。
- Geometric primitives & basis functions:全息图可以由**比点扩散函数(psf)更复杂的元素生成**。在许多情况下,2D和3D对象可以分解为相对较少的基本元素,可以有效地计算。
- ****Holographic Stereograms:****以数字方式生成或以光学方式捕获的角度多路复用二维(2D)视差视图,全息图在空间上被分割为多个全息元素(HOGEL)

---
- **Color** Holographic Display
- **空间**复用
- **时间**复用
从**SLM**角度:
- 单SLM
- AOH:仅振幅
- POH:仅相位
- 多SLM
- 振幅相位分别用一个SLM再现
- 双相位全息图(DPH)
- 全息图漂白法
- 双约束迭代法
**Holographic optimization algorithm**:
- **Phase** optimization method
- 迭代算法
- **GS,GSW,Fienup,AA**
- 误差扩散算法
- 非迭代算法
- 随机相位
- 采样类方法
- 模式化掩膜与二次相位掩膜
- **双相位编码**
- 非随机相位
- 直接计算
- 直接搜索算法(Direct Search Algorithm)
- 模拟退火算法(Simulated Annealing Algorithm)
- 遗传算法(Genetic Algorithm)
- 迭代与非迭代结合
- 基于 Wirtinger Flow的相位提取
- **深度学习**
宏观**全息图**分类:
- **在光学全息术中,物场的编码过程是通过与参考场的光学干涉提供的**,最终确定的感光材料是全息图。
- 在**计算机全息术**中,**必须使用打印机打印条纹图案t(x,y)来制作计算全息图**,然后从打印的条纹重建3D图像。
- 在**电子全息术中,条纹图案不是打印出来的,而是由某些电子设备直接显示出来的**。
Algorithmic **CGH acceleration** techniques:
- Sparsity
- Wavefront recording planes
- Stereogram approximations
- Coefficient shrinking methods
- Look-up tables
- Dynamic CGH acceleration techniques
- **Deep-learning based acceleration**
**计算机全息术和计算机图形学:**
- **CG将光线视为一组仅垂直于屏幕传播的光线**
- **计算机全息术将光视为波场,它不仅包括垂直于全息图的光的分量,而且包括以不同角度传播到全息图平面的光的所有分量**

================================================
FILE: GUI/README.md
================================================
# Todo: This is a GUI application
================================================
FILE: Matlab/fourier_hologram.m
================================================
clear;
close all;
x32=4;
y32=4;
s=64*8;
g=imread ('../Res/image64/test.bmp');
%G=Rgb2gray (g);
G=g;
G=im2double (G);
[p q]=size(G); %p, q图像的像素
Z=G;
R1=rand(p);
A=Z.*exp(i*2*pi*R1);%乘以单位振幅的随机指数函数,平滑傅里叶变换
A=fftshift(fft2(fftshift(A)));%fftshift的作用正是让正半轴部分和负半轴部分的图像分别关于各自的中心对称
figure, imshow (A);
A1=abs(A);%求绝对值
B1=mod(angle(A),2*pi)/(2*pi);%取模运算
C=max(max(A1));%求出矩阵的最大元素
A2=s/p;
B2=A2;
Z=zeros(s,s);
for I=1:p
y0=y32+(I-1)*B2;
for J=1:q
x0= x32+(J-1)*A2;
H=round(A1(I,J)*B2/C); %矩空高度
F1=round(B1(I,J)*A2); %中心偏离值
W=A2/2; %矩形宽度
x1=round (x0+F1-W/2);
x2=x1+W-1;
y1=round (y0-H/2+0.5);
y2=y1+H-1;
if x21)'); %动态输入的话打开注释
X1=imresize(X0,N/N1*m0);
[M1,N1]=size(X1);
X=zeros(N,N);
X(N/2-M1/2+1:N/2+M1/2,N/2-N1/2+1:N/2+N1/2)=X1(1:M1,1:N1);
h=0.532e-3; %波长(mm), 可按需要修改
k=2*pi/h;
pix=0.0064; %SLM像素宽度(mm), 可按需要修改
L=N*pix; %SLM宽度(mm)
z0=1200; %----衍射距离(mm),
%z0=input('衍射距离(mm)'); %衍射距离如果需要动态设置,打开注释
L0=h*z0/pix; %重建像平面宽度(mm)
Y=double(X);
a=ones(N,N);
b=rand(N,N)*2*pi;
U0=Y.*exp(1i.*b); %叠加随机相位噪声,形成振幅正比于图像的初始场复振幅
X0=abs(U0); %初始场振幅,后面叠代运算用
figstr=strcat('SLM平面宽度=',num2str(L),'mm');
figstr0=strcat('初始物平面宽度=',num2str(L0),'mm');
figure(1),imshow(X,[]),colormap(gray); xlabel(figstr);title('物平面图像');
np=0;
%np=input('叠代次数'); %迭代次数需要次数动态设置,打开注释
%% 梅涅尔衍射的计算
for p=1:np+1 %叠代次数
%菲涅耳衍射的S-FFT计算开始,相息图记录
n=1:N;
x=-L0/2+L0/N*(n-1);
y=x;
[yy,xx] = meshgrid(y,x);
Fresnel=exp(1i*k/2/z0*(xx.^2+yy.^2));
f2=U0.*Fresnel;
Uf=fft2(f2,N,N);
Uf=fftshift(Uf);
x=-L/2+L/N*(n-1);%SLM宽度取样(mm)
y=x;
[yy,xx] = meshgrid(y,x);
phase=exp(1i*k*z0)/(1i*h*z0)*exp(1i*k/2/z0*(xx.^2+yy.^2));
Uf=Uf.*phase;
%菲涅耳衍射的S-FFT计算结束
figstr=strcat('SLM宽度=',num2str(L),'mm');
figure(2),imshow(abs(Uf),[]),colormap(gray); xlabel(figstr);title('到达SLM平面的物光振幅分布');
Phase=angle(Uf)+pi;
Ih=uint8(Phase/2/pi*255);%形成0-255灰度级的相息图
figure(3),imshow(Phase,[]),colormap(gray); xlabel(figstr);title('相息图');
%菲涅耳衍射的S-IFFT计算开始,相息图重建
U0=cos(Phase-pi)+1i*sin(Phase-pi);
n=1:N;
x=-L/2+L/N*(n-1);
y=x;
[yy,xx] = meshgrid(y,x);
Fresnel=exp(-1i*k/2/z0*(xx.^2+yy.^2));
f2=U0.*Fresnel;
Uf=ifft2(f2,N,N);
x=-L0/2+L0/N*(n-1); %SLM宽度取样(mm)
y=x;
[yy,xx] = meshgrid(y,x);
phase=exp(-1i*k*z0)/(-1i*h*z0)*exp(-1i*k/2/z0*(xx.^2+yy.^2));
Uf=Uf.*phase;
figure(4),imshow(abs(Uf),[]),colormap(gray); xlabel(figstr0);title('逆运算重建的物平面振幅分布');
%保持相位不变,引用原图振幅,重新开始新一轮计算
Phase=angle(Uf);
U0=X0.*(cos(Phase)+1i*sin(Phase));
end
%figure(5),imshow(Ih,[]),colormap(gray); xlabel(figstr);title('相息图');
================================================
FILE: Matlab/offaxis_interference_hologram.m
================================================
% h ——波长(mm); I ——数字全息图;
% L ——全息图宽度(mm); z0——记录全息图的距离(mm);
%% Image Read and preprocess
XRGB=imread('./images/pku.jpg');
X0=rgb2gray(XRGB);
% figure,imshow(X0,[]);
[M0,N0]=size(X0);
%% Set Basic parameters
N1=min(M0,N0);
N=1024; %模拟形成的全息图取样数
X1=imresize(X0,N/4/N1);
[M1,N1]=size(X1);
X=zeros(N,N);
X(N/2-M1/2+1:N/2+M1/2,N/2-N1/2+1:N/2+N1/2)=X1(1:M1,1:N1);
h=0.632e-3; %波长(mm), 可按需要修改
k=2*pi/h;
% CCD:Charge Coupled Device(电荷耦合元件),是一种将图像转换为电信号的半导体元件。由类似棋盘的格状排列的小像素 (pixel) 组成。
pix=0.00465 ;%CCD像素宽度(mm), 可按需要修改
L=N*pix; %CCD宽度(mm)
z0=1000; %衍射距离(mm), 可按需要修改
L0=h*N*z0/L; %物平面宽度(mm)
Y=double(X);
%a=ones(N,N);
b=rand(N,N)*2*pi;
f=Y.*exp(1i.*b); %叠加随机相位噪声,形成振幅正比于图像的初始场复振幅
figstr=strcat('初始物平面宽度=',num2str(L0),'mm');
figure(1),imshow(X,[]),colormap(gray); xlabel(figstr);title('物平面图像');
%% Fresnell
%---------------菲涅耳衍射的S-FFT计算开始
n=1:N;
x=-L0/2+L0/N*(n-1);
y=x;
[yy,xx] = meshgrid(y,x); %网格化数据平面
Fresnel=exp(1i*k/2/z0*(xx.^2+yy.^2));
f2=f.*Fresnel;
Uf=fft2(f2,N,N);
Uf=fftshift(Uf);
x=-L/2+L/N*(n-1); %CCD宽度取样(mm)
y=x;
[yy,xx] = meshgrid(y,x);
phase=exp(1i*k*z0)/(1i*h*z0)*exp(1i*k/2/z0*(xx.^2+yy.^2));%菲涅耳衍射积分前方的相位因子
Uf=Uf.*phase;
%---------------S-FFT计算结束
figstr=strcat('模拟CCD宽度=',num2str(L),'mm');
figure(2),imshow(abs(Uf),[]),colormap(gray); xlabel(figstr);title('到达CCD平面的物光振幅分布');
%% Reference Light
%---------------形成0-255灰度级的数字全息图
fex=N/L;
Qx=(4-2.5)*L0/8/z0; %按照优化设计定义参考光方向余弦
Qy=Qx;
x=[-L/2:L/N:L/2-L/N];
y=x;
[X,Y]=meshgrid(x,y);
Ar=max(max(abs(Uf))); %按物光场振幅最大值定义参考光振幅
Ur=Ar*exp(1i*k*(X.*Qx+Y.*Qy));%参考光复振幅
%% Interference
Uh=Ur+Uf; %物光与参考光干涉
Wh=Uh.*conj(Uh); %干涉场强度
Imax=max(max(Wh));
I=uint8(Wh./Imax*255); %形成0-255灰度级的数字全息图
Ih=I;
imwrite(I,'./Ih.bmp'); %形成数字全息图文件
figstr=strcat('全息图宽度=',num2str(L),'mm');
figure(3),imshow(Ih,[]),colormap(gray);xlabel(figstr);title('模拟形成的数字全息图');
%% Reconstruction
%基于S-FFT的全息重建
f0 = double(Ih);
[N1,N2]=size(f0);
N=min(N1,N2);
h=0.000632; %波长(mm)
z0=1000;
L=N*pix; %CCD宽度(mm)
In(1:N,1:N)=f0(1:N,1:N);
%-----------------------------1-FFT重建开始
n=1:N;
x=-L/2+L/N*(n-1);
y=x;
[yy,xx] = meshgrid(y,x);
k=2*pi/h;
Fresnel=exp(1i*k/2/z0*(xx.^2+yy.^2));
f2=In.*Fresnel;
Uf=fft2(f2,N,N);
Uf=fftshift(Uf);
L0=h*z0*N/L;
x=-L0/2+L0/N*(n-1);
y=x;
[yy,xx] = meshgrid(y,x);
phase=exp(1i*k*z0)/(1i*h*z0)*exp(1i*k/2/z0*(xx.^2+yy.^2));
U0=Uf.*phase; %积分运算结果乘积分号前方相位因子
%-----------------------------1-FFT重建结束
If=U0*conj(U0);
Gmax=max(max(abs(U0)));
Gmin=min(min(abs(U0)));
figstr=strcat('重建物平面宽度=',num2str(L0),'mm');
figure(4),
imshow(abs(U0),[Gmin Gmax/1]),colormap(gray); xlabel(figstr);title('1-FFT物平面重建图像');
%% Light intensity change
p=10;
while p
figure(5);
imshow(abs(U0),[Gmin Gmax/p]),colormap(gray);xlabel(figstr);title('1-FFT物平面重建图像');
p=input('Gmax/p,p=10?');
end
Up=fft2(U0);
figure(6),imshow(abs(Up),[])
figure(7),plot(abs(Up(round(512)+1,:)));
hold on;
================================================
FILE: Matlab/propagator/angular_spectrum/ASM.m
================================================
%angular spectrum method of fast calculation of diffraction 角谱衍射计算
%cut:output is set as the same size of input 要不要剪裁为原图大小
%direction:direction of the propagation 传播方向
%bandlimit:band-limit ASM 是否用带限角谱
%quan:input of the complex wave field 输入复振幅
%mu:zero padding size(How many times the size of the original complex wave
% field) 填0为原图大小的几倍
%z:distance 距离
%pitch: pixel size 像素大小
%lambda: wavelength 波长
function[final] = ASM(cut,direction,bandlimit,quan,mu,z,pitch,lambda)
[kuan,chang] = size(quan);
a=mu*kuan;
b=mu*chang;
u0=1/b/pitch;
v0=1/a/pitch;
quan2=zeros(a,b);
yy=-a/2+0.5:(a/2-1)+0.5;
xx=-b/2+0.5:(b/2-1)+0.5;
[x,y]=meshgrid(xx*u0,yy*v0);
quan2(1+a/2-kuan/2:a/2+kuan/2,1+b/2-chang/2:b/2+chang/2)=quan;
if(strcmp(direction,'forward'))
trans=exp(1i*2*pi/lambda*z*sqrt(1-(lambda*x).^2-(lambda*y).^2));
else
trans=exp(-1i*2*pi/lambda*z*sqrt(1-(lambda*x).^2-(lambda*y).^2));
end
if(strcmp(bandlimit,'limit'))
xlimit=1/sqrt((2*1/b/pitch*z)^2+1)/lambda;
ylimit=1/sqrt((2*1/a/pitch*z)^2+1)/lambda;
trans(abs(x)>xlimit)=0;
trans(abs(y)>ylimit)=0;
end
final=fftshift(ifft2(fftshift(trans.*fftshift(fft2(fftshift(quan2))))));
if(strcmp(cut,'cut'))
cutfinal=final(1+a/2-kuan/2:a/2+kuan/2,1+b/2-chang/2:b/2+chang/2);
final=cutfinal;
end
end
================================================
FILE: Matlab/propagator/angular_spectrum/ASMexample.m
================================================
clc;
clear;
p=zeros(1024,1024);
p(256:768,256:768)=1;
pitch=8*10^(-3);
z=pitch*1024*200;
pitch=8*10^(-3);
lambda=638*10^(-6);
final=ASM('cut','forward','nolimit',p,1,z,pitch,lambda);
finallimit=ASM('cut','forward','limit',p,1,z,pitch,lambda);
subplot(1,3,1)
imshow(p);
final=abs(final);
final=final./max(max(final));
subplot(1,3,2)
imshow(final);
finallimit=abs(finallimit);
finallimit=finallimit./max(max(finallimit));
subplot(1,3,3)
imshow(finallimit);
================================================
FILE: Matlab/propagator/angular_spectrum/ASMshift.m
================================================
%angular spectrum method of fast calculation of diffraction 角谱衍射计算
%shift:fftshift 要不要加fftshift
%cut:output is set as the same size of input 要不要剪裁为原图大小
%direction:direction of the propagation 传播方向
%bandlimit:band-limit ASM 是否用带限角谱
%quan:input of the complex wave field 输入复振幅
%mu:zero padding size(How many times the size of the original complex wave
% field) 填0为原图大小的几倍
%z:distance 距离
%pitch: pixel size 像素大小
%lambda: wavelength 波长
%example:示例 quan=ASM(1,1,1,1,p,2,300,8*10^(-3),638*10^(-6));
function[final] = ASM(shift,cut,direction,bandlimit,quan,mu,z,pitch,lambda)
[kuan,chang] = size(quan);
% pitch=8*10^(-3);
% lambda=638*10^(-6);
a=mu*kuan;
b=mu*chang;
u0=1/b/pitch;
v0=1/a/pitch;
quan2=zeros(a,b);
yy=-a/2+0.5:(a/2-1)+0.5;
xx=-b/2+0.5:(b/2-1)+0.5;
[x,y]=meshgrid(xx*u0,yy*v0);
quan2(1+a/2-kuan/2:a/2+kuan/2,1+b/2-chang/2:b/2+chang/2)=quan;
if(strcmp(direction,'forward'))
trans=exp(1i*2*pi/lambda*z*sqrt(1-(lambda*x).^2-(lambda*y).^2));
else
trans=exp(-1i*2*pi/lambda*z*sqrt(1-(lambda*x).^2-(lambda*y).^2));
end
if(strcmp(bandlimit,'limit'))
xlimit=1/sqrt((2*1/b/pitch*z)^2+1)/lambda;
ylimit=1/sqrt((2*1/a/pitch*z)^2+1)/lambda;
trans(abs(x)>xlimit)=0;
trans(abs(y)>ylimit)=0;
end
if(strcmp(shift,'shift'))
final=ifft2(trans.*fftshift(fft2(quan2)));
else
final=ifft2(trans.*(fft2(quan2)));
end
if(strcmp(cut,'cut'))
cutfinal=final(1+a/2-kuan/2:a/2+kuan/2,1+b/2-chang/2:b/2+chang/2);
final=cutfinal;
end
end
================================================
FILE: Matlab/propagator/angular_spectrum/double_phase_hologram.m
================================================
clc
clear
p=im2double(rgb2gray(imread('triss1024.png')));
figure(1)
imshow(p);
pitch=8*10^(-3);
lambda=638*10^(-6);
B=rand(1024,1024);
quan1=p.*exp(1i*2*pi*B);
z=400;
%quan1=ASM('nocut','forward','limit',quan1,1,z,pitch,lambda);
%quan2=ASM('nocut','forward','limit',p,1,z,pitch,lambda);
quan1=ASMshift('shift','cut','forward','limit',quan1,2,z,pitch,lambda);
quan2=ASMshift('shift','cut','forward','limit',p,2,z,pitch,lambda);
ang=angle(quan2);
ang=mod(ang,2*pi);
amp=abs(quan2);
amp=amp./max(max(amp));
coss=acos(amp);
quana=ang+coss;
quanb=ang-coss;
qipan=zeros(1024,1024);
for i=1:1024
for j=1:1024
if(mod(i+j,2)==0)
qipan(i,j)=1;
end
end
end
qipan2=1-qipan;
quan2=quana.*qipan+quanb.*qipan2;
quan2=mod(quan2,2*pi);
quan2=quan2/2/pi;
ang=angle(quan1);
ang=mod(ang,2*pi);
quan1=ang/2/pi;
figure(2)
subplot(1,2,1)
imshow(quan1);
subplot(1,2,2)
imshow(quan2);
%imwrite(quan1,'1.png');
%imwrite(quan2,'2.png');
quan1=exp(1i*2*pi*quan1);
quan2=exp(1i*2*pi*quan2);
%image1=ASM('nocut','backward','limit',quan1,1,z,pitch,lambda);
%image2=ASM('nocut','backward','limit',quan2,1,z,pitch,lambda);
image1=ASMshift('noshift','cut','backward','limit',quan1,2,z,pitch,lambda);
image2=ASMshift('noshift','cut','backward','limit',quan2,2,z,pitch,lambda);
image1=abs(image1);
image2=abs(image2);
image1=image1./max(max(image1));
image2=image2./max(max(image2));
figure(3)
subplot(1,2,1)
imshow(image1);
subplot(1,2,2)
imshow(image2);
================================================
FILE: Matlab/propagator/angular_spectrum/layer_based_method.m
================================================
clc;
clear;
p=im2double(rgb2gray(imread('long.png')));
depth=im2double((imread('longdep.png')));
maxdepth=max(max(depth));
mindepth=min(depth(depth~=0));
fencengshu=9;
d=(maxdepth-mindepth)/fencengshu;
lambda=639*10^(-6);
pitch=8*10^(-3);
a=-960:959;
b=-540:539;
[u,v]=meshgrid(a*pitch,b*pitch);
B = rand([1080 1920]);
quan2=zeros(1080,1920);
part=zeros(1080,1920);
figure(1)
for n=1:fencengshu
part=p.*((depth>=(maxdepth-n*d))&(depth<(maxdepth-(n-1)*d)));
subplot(3,3,n)
imshow(part);
part=part.*exp(1i*2*pi*B);
f=300+n*5;
holo=ASMshift('shhift','cut','forward','limit',part,2,f,pitch,lambda);
quan2=quan2+holo;
n
end
quan2=angle(quan2);
quan2=mod(quan2,2*pi);
ang=quan2/2/pi;
figure(2)
imshow(ang);
%imwrite(ang,'1.png')
================================================
FILE: Python/double_phase_hologram.py
================================================
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
'''
@Project :Computer-Generated-Hologram
@File :double_phase_hologram.py
@Author :JackHCC
@Date :2022/10/5 16:01
@Desc :Todo: DPH need fix bugs
'''
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
from propagator.angular_spectrum import asm_shift, format_img
pitch = 8 * pow(10, -3)
lambda_ = 638 * pow(10, -6)
z = 400
# input the image path
# image_path = "../Res/Set5/GTmod12/butterfly.png"
image_path = "../Matlab/propagator/angular_spectrum/triss1024.png"
g = Image.open(image_path, mode="r")
# convert RGB image to Gray image
g = g.convert("L")
plt.figure(1)
plt.imshow(g, cmap="gray")
G = np.array(g)
G = G / 255
print(G)
M, N = G.shape
# 生成随机相位
B = np.random.rand(M, N)
object_ = G * np.exp(1j * 2 * np.pi * B)
# 带随机相位
final1 = asm_shift(object_, z, pitch, lambda_, mu=2)
# 仅振幅信息
final2 = asm_shift(G, z, pitch, lambda_, mu=2)
angle = np.angle(final2)
angle = np.mod(angle, 2 * np.pi)
amp = np.abs(final2)
amp = amp / np.max(amp)
coss = np.arccos(amp)
phase_1 = angle + coss
phase_2 = angle - coss
checkerboard_1 = np.zeros((M, N))
for i in range(M):
for j in range(N):
if np.mod(i + j, 2) == 0:
checkerboard_1[i, j] = 1
checkerboard_2 = 1 - checkerboard_1
final2 = phase_1 * checkerboard_1 + phase_2 + checkerboard_2
final2 = np.mod(final2, 2 * np.pi) / (2 * np.pi)
angle_1 = np.angle(final1)
angle_1 = np.mod(angle_1, 2 * np.pi)
final1 = angle_1 / (2 * np.pi)
# 随机相位
plt.figure(2)
plt.imshow(final1, cmap="gray")
# 双相位
plt.figure(3)
plt.imshow(final2, cmap="gray")
final1 = np.exp(1j * 2 * np.pi * final1)
final2 = np.exp(1j * 2 * np.pi * final2)
image1 = asm_shift(final1, z, pitch, lambda_, mu=2, direction="backward", shift=False)
image2 = asm_shift(final2, z, pitch, lambda_, mu=2, direction="backward", shift=False)
image1, image2 = np.abs(image1), np.abs(image2)
image1 = image1 / np.max(image1)
image2 = image2 / np.max(image2)
image2 = format_img(image2)
plt.figure(4)
plt.imshow(image1, cmap="gray")
plt.figure(5)
plt.imshow(image2, cmap="gray")
plt.show()
================================================
FILE: Python/fourier_hologram.py
================================================
from PIL import Image
import cv2
import numpy as np
from scipy.fftpack import fft2, ifft2, fftshift
import matplotlib.pyplot as plt
x32 = 4
y32 = 4
s = 64*8
# input the image path
image_path = "../Res/image64/test.bmp"
g = Image.open(image_path, mode="r")
# convert RGB image to Gray image
g = g.convert("L")
G = np.array(g)
# print(G.shape, G)
p, q = G.shape
# show the raw image
Z = G
plt.figure(0)
plt.imshow(Z, cmap="gray")
# generate a random numbers array of p size
R1 = np.random.rand(p)
# print(R1.shape)
# give random phase
A = Z * np.exp(1j * 2 * np.pi * R1)
# fft2
A = fftshift(fft2(fftshift(A)))
# print(A)
A_fre = np.abs(A)
plt.figure(1)
plt.imshow(A_fre, cmap="gray")
A1 = np.abs(A)
B1 = np.mod(np.angle(A), 2 * np.pi)/(2 * np.pi)
C = np.max(A1)
# print(C)
A2 = int(s/p)
B2 = A2
Z = np.zeros((s, s))
for I in range(0, p):
y0 = y32 + (I - 1) * B2
for J in range(0, q):
x0 = x32 + (J - 1) * A2
H = np.round(A1[I, J] * B2 / C)
F1 = round(B1[I, J] * A2)
W = A2 / 2
x1 = int(np.round(x0 + F1 - W/2))
x2 = int(x1 + W - 1)
y1 = int(np.round(y0 - H/2 + 0.5))
y2 = int(y1 + H - 1)
if x2 < J * A2:
Z[y1:y2, x1:x2] = 1
else:
Z[y1:y2, x1:J * A2] = 1
Z[y1:y2, (J-1) * A2 + 1:x2 - A2] = 1
# 傅里叶全息图
Z_mid = Z * 255
Z_mid_show = Image.fromarray(Z_mid).convert("L")
plt.figure(2)
plt.imshow(Z_mid_show, cmap="gray")
Z_mid_show.save("./result/fh_test_CGH.bmp", "bmp")
P = fftshift(ifft2(Z))
P_show = np.abs(P) * 256
P_reg = P_show * 255 / np.max(P_show)
plt.figure(3)
plt.imshow(P_reg, cmap="gray")
P1 = P_reg[int(s/2 - 128 + 1):int(s/2 + 128), int(s/2 - 128 + 1):int(s/2 + 128)]
plt.figure(4)
plt.imshow(P1, cmap="gray")
Z_large = Z_mid[int(s/2 - 64 + 1):int(s/2 + 64), int(s/2 - 64 + 1):int(s/2 + 64)]
plt.figure(5)
plt.imshow(Z_large, cmap="gray")
Z_large_show = Image.fromarray(Z_large).convert("L")
Z_large_show.save("./result/fh_test_large_CGH.bmp", "bmp")
Z_recover = np.abs(P1) * 255
Gmax = np.max(Z_recover)
Gmin = np.min(Z_recover)
# try to change the parameter to get the best image
p = 2
Gm = Gmax / p
np.clip(Z_recover, Gmin, Gm, out=Z_recover)
Z_recover = Z_recover * 255 / np.max(Z_recover)
# print(np.max(Z_recover))
plt.figure(6)
plt.imshow(Z_recover, cmap="gray")
Z_recover_im = Image.fromarray(Z_recover).convert("L")
Z_recover_im.save("./result/fh_test_recover.bmp", "bmp")
plt.show()
================================================
FILE: Python/fresnel_hologram.py
================================================
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
'''
@Project :Computer-Generated-Hologram
@File :fresnel_hologram.py
@Author :JackHCC
@Date :2022/6/15 22:17
@Desc :
'''
from PIL import Image
import numpy as np
from scipy.fftpack import fft2, fftshift
import matplotlib.pyplot as plt
cm = 1e-2
mm = 1e-3
um = 1e-6
nm = 1e-9
class Fresnel:
def __init__(self, lambda_=633 * nm, pix=3.45 * um, z0=1500 * mm, zr=1500 * mm, flag=0, shift=0):
# 默认红光
self.lambda_ = lambda_
self.pix = pix
self.z0 = z0
self.zr = zr
self.flag = flag
self.shift = shift
def zero_padding(self, raw_img):
width, height = raw_img.shape
m = 2 * width
n = 2 * height
pad_img = np.zeros((m, n))
posx = (m - width) // 2
posy = (n - height) // 2
pad_img[posx:posx + width, posy:posy + height] = raw_img[:, :] / 255
return pad_img
def fresnel(self, pad_img, flag=True):
M, N = pad_img.shape
Lx0 = np.sqrt(self.lambda_ * self.z0 * M) # FFT计算时同时满足振幅及相位取样条件的物光场宽度
Ly0 = np.sqrt(self.lambda_ * self.z0 * N)
if flag:
dx0 = Lx0 / M
dy0 = Ly0 / N
else:
dx0 = self.pix
dy0 = self.pix
# 菲涅尔全息计算
x = dx0 * np.array(range(-M // 2, M // 2))
y = dy0 * np.array(range(-N // 2, N // 2))
Y, X = np.meshgrid(y, x)
Fresnel = np.exp(1j * np.pi * (np.power(X, 2) + np.power(Y, 2)) / (self.lambda_ * self.z0))
f2 = pad_img * Fresnel
f2 = fftshift(f2)
Uf = fft2(f2)
Uf = fftshift(Uf)
dx1 = (self.lambda_ * self.z0) / (M * dx0)
dy1 = (self.lambda_ * self.z0) / (N * dy0)
x1 = dx1 * np.array(range(-M // 2, M // 2))
y1 = dy1 * np.array(range(-N // 2, N // 2))
Y1, X1 = np.meshgrid(y1, x1)
phase = np.exp(1j * 2 * np.pi * self.z0 / self.lambda_) / (1j * self.lambda_ * self.z0) * np.exp(
1j * np.pi / self.lambda_ / self.z0 * (np.power(X1, 2) + np.power(Y1, 2)))
Uf = Uf * phase
T = dx0 # 空域取样间隔
Uf = Uf * T * T # 二维离散变换量值补偿
return Uf
def wave(self, pad_img):
M, N = pad_img.shape
Lx0 = np.sqrt(self.lambda_ * self.z0 * M) # FFT计算时同时满足振幅及相位取样条件的物光场宽度
Ly0 = np.sqrt(self.lambda_ * self.z0 * N)
dx0 = Lx0 / M
dy0 = Ly0 / N
x0 = dx0 * np.array(range(-M // 2, M // 2))
y0 = dy0 * np.array(range(-N // 2, N // 2))
Y0, X0 = np.meshgrid(y0, x0)
dx1 = (self.lambda_ * self.zr) / (M * dx0)
dy1 = (self.lambda_ * self.zr) / (N * dy0)
x1 = dx1 * np.array(range(-M // 2, M // 2))
y1 = dy1 * np.array(range(-N // 2, N // 2))
X1, Y1 = np.meshgrid(x1, y1)
# 相位物体
p = np.sin(Y0 * np.pi / 50)
phaseObject = np.exp(1j * p)
# planeWave reference
# pr = 2 * np.pi * X1 * np.sin(5 * np.pi / 180) / self.lambda_ + self.shift
phi = 2 * np.pi * X1 * np.sin(np.pi / 2) / self.lambda_ + self.shift
planeWave = np.exp(1j * phi)
# sphericalWave
L = -N * dx1
xr = -L / 4
phi = np.pi * (np.power(X1 + xr, 2) + np.power(Y1 + xr, 2)) / (self.lambda_ * self.z0) + self.shift
sphericalWave = np.exp(1j * phi)
if self.flag == 1:
wave = planeWave
elif self.flag == 0:
wave = sphericalWave
else:
wave = phaseObject
return wave
def record(self, raw_img, flag=True):
# flag为True记录强度,否则记录振幅
pad_img = self.zero_padding(raw_img)
object_ = self.fresnel(pad_img)
refer_ = self.wave(pad_img)
# 干涉
w1 = object_ + 0.5 * refer_
w1 = np.power(np.abs(w1), 2) if flag else np.abs(w1) # 求出全息平面上的强度分布
return w1
def reconstruct(self, holo_img, RoomNo=10):
# image processing
holo_img = holo_img - np.mean(holo_img)
# 注意这里衍射因为用了条纹,使用了参考光才形成的,因此不用显式表达
U0 = self.fresnel(holo_img, False)
# 弥补AOH衍射效率底的问题
Gmax = np.max(np.abs(U0))
Gmin = np.min(np.abs(U0))
U1 = np.abs(U0)
U1 = (U1 - Gmin) / (Gmax / RoomNo - Gmin)
return U1
def format_img(self, img):
img = img ** 0.5
format_img = img * 255
format_img = format_img.astype(np.uint8)
return format_img
if __name__ == "__main__":
# input the image path
image_path = "../Res/Set5/GTmod12/butterfly.png"
g = Image.open(image_path, mode="r")
# convert RGB image to Gray image
g = g.convert("L")
plt.figure(1)
plt.imshow(g, cmap="gray")
G = np.array(g)
# flag=0: 球面波
# flag=1: 平面波
# 其他: 物体相位
fresnel = Fresnel(flag=0)
# 全息记录
holo = fresnel.record(G)
print(holo.shape, holo)
plt.figure(2)
plt.imshow(holo, cmap="gray")
holo_show = Image.fromarray(fresnel.format_img(holo)).convert("L")
holo_show.save("./result/fre_butterfly_CGH.bmp", "bmp")
# 全息再现
recon_img = fresnel.reconstruct(holo)
recon_img = fresnel.format_img(recon_img)
print(recon_img.shape, recon_img)
plt.figure(3)
plt.imshow(recon_img, cmap="gray")
recon_img_show = Image.fromarray(recon_img).convert("L")
recon_img_show.save("./result/fre_butterfly_recover.bmp", "bmp")
plt.show()
================================================
FILE: Python/kinoforms.py
================================================
import cv2
import numpy as np
from scipy.fftpack import fft2, ifft2, fftshift
import matplotlib.pyplot as plt
# input the image path
# image_path = "../Res/image256/lena.png"
image_path = "../Res/imageO/pku.jpg"
img = cv2.imread(image_path)
print(img.shape)
img_gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
print(img_gray.shape)
p, q = img_gray.shape
# show the raw image
plt.figure(0)
plt.imshow(img_gray, cmap="gray")
plt.title("Raw Image")
N1 = min(p, q)
N = 1080 # 采样率
scale = 0.5
size_scale = N / N1 * scale
size_scale_x = int(size_scale * p)
size_scale_y = int(size_scale * q)
print(size_scale_x)
X1 = cv2.resize(img_gray, [size_scale_x, size_scale_y])
M1, N1 = X1.shape
X = np.zeros((N, N))
X[int(N/2 - M1/2 + 1):int(N/2 + M1/2), int(N/2 - N1/2 + 1):int(N/2 + N1/2)] = X1[1:M1, 1:N1]
h = 0.532e-3 # 波长,单位mm
k = 2 * np.pi / h
pix = 0.0064 # SLM像素宽度
L = N * pix # SLM宽度
z0 = 1200 # 衍射距离
L0 = h * z0 / pix # 重建像平面宽度
Y = X
# a = np.ones((N, N))
b = np.random.rand(N, N) * 2 * np.pi
print(b, b.shape)
U0 = Y * np.exp(1j * b) # 叠加随机相位噪声,形成振幅正比于图像的初始场复振幅
X0 = np.abs(U0)
plt.figure(1)
plt.imshow(X, cmap="gray")
plt.title("Scale Image")
'''
Record:记录
'''
n = np.array(range(N))
print(n.shape)
x = -L0 / 2 + L0 / N * n
y = x
yy, xx = np.meshgrid(y, x)
print(yy.shape, xx.shape)
Fresnel = np.exp(1j * k / 2 / z0 * (xx * xx + yy * yy))
print(Fresnel)
f2 = U0 * Fresnel
Uf = fft2(f2, (N, N))
# Uf = fft2(f2)
Uf = fftshift(Uf)
print("Uf", Uf.shape)
x = -L / 2 + L / N * n
y = x
yy, xx = np.meshgrid(y, x)
phase = np.exp(1j * k * z0) / (1j * h * z0) * np.exp(1j * k / 2 / z0 * (np.power(xx, 2) + np.power(yy, 2)))
Uf = Uf * phase
print("Uf * phase", Uf)
plt.figure(2)
plt.imshow(np.abs(Uf), cmap="gray")
plt.title("Amplitude distribution of object light")
Phase = np.angle(Uf) + np.pi
# 形成0-255灰度级的相息图
ki = Phase / 2 / np.pi * 255
print(ki.shape)
plt.figure(3)
plt.imshow(Phase, cmap="gray")
plt.title("Kinoforms")
cv2.imwrite("./result/ki_pku_CGH.bmp", ki)
'''
Recon:再现
'''
U0 = np.cos(Phase - np.pi) + 1j * np.sin(Phase - np.pi)
n = np.array(range(N))
x = -L / 2 + L / N * n
y = x
yc, xc = np.meshgrid(y, x)
Fresnel = np.exp(-1j * k / 2 / z0 * (np.power(xc, 2) + np.power(yc, 2)))
f2 = U0 * Fresnel
Uf = ifft2(f2, (N, N))
x = -L0 / 2 + L0 / N * n
y = x
yy, xx = np.meshgrid(y, x)
phase = np.exp(-1j * k * z0) / (-1j * h * z0) * np.exp(-1j * k / 2 / z0 * (np.power(xx, 2) + np.power(yy, 2)))
Uf = Uf * phase
Uf = np.abs(Uf)
Uf = Uf * 255 / np.max(Uf)
plt.figure(4)
plt.imshow(Uf, cmap="gray")
plt.title("Amplitude distribution of object plane reconstructed by inverse operation")
cv2.imwrite("./result/ki_pku_recover.bmp", Uf)
plt.show()
================================================
FILE: Python/layer_based_method.py
================================================
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
'''
@Project :Computer-Generated-Hologram
@File :layer_based_method.py
@Author :JackHCC
@Date :2022/10/5 16:50
@Desc :
'''
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
from propagator.angular_spectrum import asm_shift, format_img
image_path = "../Matlab/propagator/angular_spectrum/long.png"
image_path_depth = "../Matlab/propagator/angular_spectrum/longdep.png"
g = Image.open(image_path, mode="r")
# convert RGB image to Gray image
g = g.convert("L")
G = np.array(g)
G = G / 255
M, N = G.shape
g_dep = Image.open(image_path_depth, mode="r")
g_dep = g_dep.convert("L")
G_dep = np.array(g_dep)
G_dep = G_dep / 255
max_depth = np.max(G_dep)
min_depth = np.min(G_dep[G_dep > 0])
layer = 9
d = (max_depth - min_depth) / layer
pitch = 8 * pow(10, -3)
lambda_ = 639 * pow(10, -6)
yy = np.array(range(-M // 2, M // 2))
xx = np.array(range(-N // 2, N // 2))
y, x = np.meshgrid(yy * pitch, xx * pitch)
B = np.random.rand(M, N)
pad_img = np.zeros((M, N))
pad_img = pad_img.astype(complex)
part = np.zeros((M, N))
plt.figure(1)
for i in range(1, layer+1):
part = G * ((G_dep >= (max_depth - i * d)) & (G_dep < (max_depth - (i - 1) * d)))
plt.subplot(3, 3, i)
plt.imshow(part, cmap="gray")
part = part * np.exp(1j * 2 * np.pi * B)
f = 300 + i * 5
holo = asm_shift(part, f, pitch, lambda_, mu=2, shift=True)
pad_img += holo
pad_img = np.angle(pad_img)
pad_img = np.mod(pad_img, 2 * np.pi) / (2 * np.pi)
plt.figure(2)
plt.imshow(pad_img, cmap="gray")
plt.show()
================================================
FILE: Python/offaxis_interference_hologram.py
================================================
import cv2
import numpy as np
from scipy.fftpack import fft2, ifft2, fftshift
import matplotlib.pyplot as plt
# input the image path
image_path = "../Res/imageO/pku.jpg"
img = cv2.imread(image_path)
img_gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
print(img_gray.shape)
p, q = img_gray.shape
# show the raw image
plt.figure(0)
plt.imshow(img_gray, cmap="gray")
plt.title("Raw Image")
# Set Basic parameters
N1 = min(p, q)
N = 1024 # 采样率
scale = 1/4
size_scale = N / N1 * scale
size_scale_x = int(size_scale * p)
size_scale_y = int(size_scale * q)
print(size_scale_x)
X1 = cv2.resize(img_gray, [size_scale_x, size_scale_y])
M1, N1 = X1.shape
X = np.zeros((N, N))
X[int(N/2 - M1/2 + 1):int(N/2 + M1/2), int(N/2 - N1/2 + 1):int(N/2 + N1/2)] = X1[1:M1, 1:N1]
h = 0.632e-3 # 波长,单位mm
k = 2 * np.pi / h
pix = 0.00465 # CCD像素宽度
L = N * pix # CCD宽度
z0 = 1000 # 衍射距离
L0 = h * z0 / pix # 重建像平面宽度
Y = X
b = np.random.rand(N, N) * 2 * np.pi
f = Y * np.exp(1j * b) # 叠加随机相位噪声,形成振幅正比于图像的初始场复振幅
X0 = np.abs(f)
plt.figure(1)
plt.imshow(X, cmap="gray")
plt.title("Scale Image")
# Fresnell
n = np.array(range(N))
x = -L0 / 2 + L0 / N * n
y = x
yy, xx = np.meshgrid(y, x)
Fresnel = np.exp(1j * k / 2 / z0 * (xx * xx + yy * yy))
f2 = f * Fresnel
Uf = fft2(f2, (N, N))
Uf = fftshift(Uf)
x = -L / 2 + L / N * n
y = x
yy, xx = np.meshgrid(y, x)
phase = np.exp(1j * k * z0) / (1j * h * z0) * np.exp(1j * k / 2 / z0 * (np.power(xx, 2) + np.power(yy, 2)))
Uf = Uf * phase
plt.figure(2)
plt.imshow(np.abs(Uf), cmap="gray")
plt.title("Amplitude distribution of object light")
# Reference Light
Qx = (4 - 2.5) * L0 / 8 / z0
Qy = Qx
x = np.linspace(-L/2, L/2 - L/N, N)
y = x
X, Y = np.meshgrid(x, y)
Ar = np.max(np.abs(Uf))
Ur = Ar * np.exp(1j * k * (X * Qx + Y * Qy))
# Interference
Uh = Ur + Uf
Wh = Uh * np.conj(Uf)
Wh = np.abs(Wh)
Imax = np.max(Wh)
Ih = Wh / Imax * 255
plt.figure(3)
plt.imshow(Ih, cmap="gray")
plt.title("Interference Hologram")
cv2.imwrite("./result/oaih_pku_CGH.bmp", Ih)
# Reconstruction
N1, N2 = Ih.shape
N = min(N1, N2)
h = 0.000632 # 波长(mm)
z0 = 1000
L = N * pix # CCD宽度(mm)
In = Ih
n = np.array(range(N))
x = -L / 2 + L / N * n
y = x
yy, xx = np.meshgrid(y, x)
k = 2 * np.pi / h
Fresnel = np.exp(-1j * k / 2 / z0 * (np.power(xx, 2) + np.power(yy, 2)))
f2 = In * Fresnel
Uf = ifft2(f2, (N, N))
Uf = fftshift(Uf)
L0 = h * z0 / pix
x = -L0 / 2 + L0 / N * n
y = x
yy, xx = np.meshgrid(y, x)
phase = np.exp(-1j * k * z0) / (-1j * h * z0) * np.exp(-1j * k / 2 / z0 * (np.power(xx, 2) + np.power(yy, 2)))
U0 = Uf * phase
U0 = abs(U0)
Gmax = np.max(U0)
Gmin = np.min(U0)
# U0 = U0 / Gmax * 255
# try to change the parameter to get the best image
p = 10
Gm = Gmax / p
np.clip(U0, Gmin, Gm, out=U0)
U = U0 / Gm * 255
plt.figure(4)
plt.imshow(U0, cmap="gray")
plt.title("Amplitude distribution of object plane reconstructed by inverse operation")
cv2.imwrite("./result/oaih_pku_recover.bmp", U)
plt.show()
================================================
FILE: Python/phase_optimization/iterative_methods/Error_Diffusion.py
================================================
import cv2 as cv
import copy
import math
from matplotlib import pyplot as plt
img = cv.imread("../../../Res/image256/lena.png") # image to perform processing on
grayimg = cv.cvtColor(img, cv.COLOR_BGR2GRAY) # converting to grayscale
cv.imshow("Original Image", grayimg)
cv.waitKey(0)
compression_rate = 64 # 4 Quantization levels
# Reducing color range without error diffusion
without_err_diffuse = copy.deepcopy(grayimg)
for row in range(len(without_err_diffuse)):
for col in range(len(without_err_diffuse[0])):
oldpixel = without_err_diffuse[row][col]
newpixel = math.floor(oldpixel / compression_rate)
without_err_diffuse[row][col] = newpixel * compression_rate
cv.imshow("Without Dithering", without_err_diffuse)
cv.waitKey(0)
sum1 = 0
sum2 = 0
# Reducing color range with error diffusion
with_err_diffuse = copy.deepcopy(grayimg)
for i in range(len(with_err_diffuse)):
for j in range(len(with_err_diffuse[0])):
oldpixel = with_err_diffuse[i][j]
newpixel = math.floor(oldpixel / compression_rate)
with_err_diffuse[i][j] = newpixel * compression_rate
error = oldpixel - with_err_diffuse[i][j]
if (j + 1) < len(with_err_diffuse[0]):
with_err_diffuse[i][j + 1] = with_err_diffuse[i][j + 1] + (
error * (7 / 16)) ##error diffused to right pixel
if (i + 1) < len(with_err_diffuse) and (j - 1) >= 0:
with_err_diffuse[i + 1][j - 1] = with_err_diffuse[i + 1][j - 1] + (
error * (3 / 16)) ##error diffused to bottom left pixel
if (i + 1) < len(with_err_diffuse):
with_err_diffuse[i + 1][j] = with_err_diffuse[i + 1][j] + (
error * (5 / 16)) ##error diffused to bottom pixel
if (i + 1) < len(with_err_diffuse) and (j + 1) < len(with_err_diffuse[0]):
with_err_diffuse[i + 1][j + 1] = with_err_diffuse[i + 1][j + 1] + (
error * (1 / 16)) ##error diffsued to bottom right pixel
cv.imshow("After Floyd Steinberg Dithering ", with_err_diffuse)
cv.waitKey(0)
cv.destroyAllWindows()
# Histograms of all three images
plt.hist(grayimg.ravel(), 256, [0, 256])
plt.title("Original image")
plt.show()
plt.hist(without_err_diffuse.ravel(), 256, [0, 256])
plt.title("Image: without error diffusion")
plt.show()
plt.hist(with_err_diffuse.ravel(), 256, [0, 256])
plt.title("Image: with error diffusion")
plt.show()
================================================
FILE: Python/phase_optimization/iterative_methods/Fienup.py
================================================
from PIL import Image
import numpy as np
from scipy.fftpack import fft2, ifft2, fftshift
import matplotlib.pyplot as plt
from tqdm import tqdm
class Fienup:
def __init__(self, image, step_size):
self.raw_image = np.array(image)
self.width, self.height = self.raw_image.shape[0], self.raw_image.shape[1]
self.amplitude = self.norm_amplitude()
self.phase = 2 * np.pi * np.random.rand(self.width, self.height)
self.step_size = step_size # 设置反馈参量,范围为[0,1],step_size=0时为GS算法
# 初始复振幅
self.complex_amplitude = self.amplitude * np.exp(1j * self.phase)
self.RMSE = None
# 相位全息
self.phase_result = None
self.result = None
def norm_amplitude(self):
return self.raw_image / np.max(self.raw_image)
def train(self, epoch=500):
self.RMSE = np.zeros(epoch)
for i in tqdm(range(epoch)):
# 逆傅立叶变换到频域
freq_img = ifft2(fftshift(self.complex_amplitude))
# 取相位值, 频域作全1幅值约束,相位全息图
# f_img_norm = 1 * freq_img / np.abs(freq_img)
f_img_phase = np.angle(freq_img)
f_img_norm = self.amplitude * np.exp(1j * f_img_phase)
# 作傅里叶变换返回空域
space_img = fft2(fftshift(f_img_norm))
error = np.abs(self.amplitude) - fftshift(np.abs(space_img) / np.max(space_img))
self.RMSE[i] = np.sqrt(np.mean(np.power(error, 2)))
# 引入反馈调节
self.complex_amplitude = np.abs(self.amplitude + error * self.step_size) * (space_img / np.abs(space_img))
self.phase_result = np.abs(f_img_phase)
self.result = np.abs(fftshift(space_img))
plt.figure(0)
plt.imshow(self.raw_image, cmap="gray")
# 相位原件分布
plt.figure(1)
plt.imshow(self.phase_result, cmap="gray")
# 模拟衍射输出
plt.figure(2)
plt.imshow(self.format_image(self.result), cmap="gray")
plt.figure(3)
plt.plot(list(range(epoch)), self.RMSE)
plt.show()
def format_image(self, img):
img = img * 255 / np.max(img)
img = img.astype(np.uint8)
return img
if __name__ == "__main__":
image_path = "../../../Res/image256/lena.png"
g = Image.open(image_path, mode="r")
# convert RGB image to Gray image
g = g.convert("L")
# Resize
g = g.resize((512, 512), Image.BILINEAR)
# G = np.array(g)
fien = Fienup(g, 0.2)
fien.train()
================================================
FILE: Python/phase_optimization/iterative_methods/GS.py
================================================
from PIL import Image
import numpy as np
from scipy.fftpack import fft2, ifft2, fftshift
import matplotlib.pyplot as plt
from tqdm import tqdm
class GS:
def __init__(self, image):
self.raw_image = np.array(image)
self.width, self.height = self.raw_image.shape[0], self.raw_image.shape[1]
self.amplitude = self.norm_amplitude()
self.phase = 2 * np.pi * np.random.rand(self.width, self.height)
# 初始复振幅
self.complex_amplitude = self.amplitude * np.exp(1j * self.phase)
self.RMSE = None
# 相位全息
self.phase_result = None
self.result = None
def norm_amplitude(self):
return self.raw_image / np.max(self.raw_image)
def train(self, epoch=500):
self.RMSE = np.zeros(epoch)
for i in tqdm(range(epoch)):
# 逆傅立叶变换到频域
freq_img = ifft2(fftshift(self.complex_amplitude))
# 取相位值, 频域作全1幅值约束,相位全息图
# f_img_norm = 1 * freq_img / np.abs(freq_img)
f_img_phase = np.angle(freq_img)
f_img_norm = self.amplitude * np.exp(1j * f_img_phase)
# 作傅里叶变换返回空域
space_img = fft2(fftshift(f_img_norm))
error = np.abs(self.amplitude) - fftshift(np.abs(space_img) / np.max(space_img))
self.RMSE[i] = np.sqrt(np.mean(np.power(error, 2)))
# 引入反馈调节
self.complex_amplitude = np.abs(self.amplitude) * (space_img / np.abs(space_img))
self.phase_result = np.abs(f_img_phase)
self.result = np.abs(fftshift(space_img))
plt.figure(0)
plt.imshow(self.raw_image, cmap="gray")
# 相位原件分布
plt.figure(1)
plt.imshow(self.phase_result, cmap="gray")
# 模拟衍射输出
plt.figure(2)
plt.imshow(self.format_image(self.result), cmap="gray")
plt.figure(3)
plt.plot(list(range(epoch)), self.RMSE)
plt.show()
def format_image(self, img):
img = img * 255 / np.max(img)
img = img.astype(np.uint8)
return img
if __name__ == "__main__":
image_path = "../../../Res/image256/lena.png"
g = Image.open(image_path, mode="r")
# convert RGB image to Gray image
g = g.convert("L")
# Resize
g = g.resize((512, 512), Image.BILINEAR)
# G = np.array(g)
gs = GS(g)
gs.train()
================================================
FILE: Python/propagator/angular_spectrum.py
================================================
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
'''
@Project :Computer-Generated-Hologram
@File :angular_spectrum.py
@Author :JackHCC
@Date :2022/10/5 14:10
@Desc :
'''
from PIL import Image
import numpy as np
from scipy.fftpack import fft2, fftshift, ifft2
import matplotlib.pyplot as plt
def format_img(img):
# img = img ** 0.5
format_img = img * 255
format_img = format_img.astype(np.uint8)
return format_img
def asm(input_image, z, pitch, lambda_, mu=1, cut=True, direction="forward", band_limit=True):
input_image = np.array(input_image)
h, w = input_image.shape
height, width = h * mu, w * mu
u0 = 1 / width / pitch
v0 = 1 / height / pitch
pad_img = np.zeros((height, width))
yy = v0 * np.array(range(-height // 2, height // 2))
xx = u0 * np.array(range(-width // 2, width // 2))
x, y = np.meshgrid(xx, yy)
pad_img[height//2-h//2:height//2+h//2, width//2-w//2:width//2+w//2] = input_image
if direction == "forward":
trans = np.exp(1j * 2 * np.pi / lambda_ * z * np.sqrt(1 - np.power(lambda_ * x, 2) - np.power(lambda_ * y, 2)))
else:
trans = np.exp(-1j * 2 * np.pi / lambda_ * z * np.sqrt(1 - np.power(lambda_ * x, 2) - np.power(lambda_ * y, 2)))
if band_limit:
x_limit = 1 / np.sqrt(np.power(2 * 1 / width / pitch * z, 2) + 1) / lambda_
y_limit = 1 / np.sqrt(np.power(2 * 1 / height / pitch * z, 2) + 1) / lambda_
trans[np.abs(x) > x_limit] = 0
trans[np.abs(y) > y_limit] = 0
final = fftshift(ifft2(fftshift(trans * fftshift(fft2(fftshift(pad_img))))))
if cut:
final = final[height//2-h//2:height//2+h//2, width//2-w//2:width//2+w//2]
return final
def asm_shift(input_image, z, pitch, lambda_, mu=1, cut=True, direction="forward", band_limit=True, shift=True):
input_image = np.array(input_image)
h, w = input_image.shape
height, width = h * mu, w * mu
u0 = 1 / width / pitch
v0 = 1 / height / pitch
pad_img = np.zeros((height, width))
yy = v0 * np.array(range(-height // 2, height // 2))
xx = u0 * np.array(range(-width // 2, width // 2))
x, y = np.meshgrid(xx, yy)
pad_img[height // 2 - h // 2:height // 2 + h // 2, width // 2 - w // 2:width // 2 + w // 2] = input_image
if direction == "forward":
trans = np.exp(1j * 2 * np.pi / lambda_ * z * np.sqrt(1 - np.power(lambda_ * x, 2) - np.power(lambda_ * y, 2)))
else:
trans = np.exp(-1j * 2 * np.pi / lambda_ * z * np.sqrt(1 - np.power(lambda_ * x, 2) - np.power(lambda_ * y, 2)))
if band_limit:
x_limit = 1 / np.sqrt(np.power(2 * 1 / width / pitch * z, 2) + 1) / lambda_
y_limit = 1 / np.sqrt(np.power(2 * 1 / height / pitch * z, 2) + 1) / lambda_
trans[np.abs(x) > x_limit] = 0
trans[np.abs(y) > y_limit] = 0
if shift:
final = ifft2(trans * fftshift(fft2(pad_img)))
else:
final = ifft2(trans * fft2(pad_img))
if cut:
final = final[height // 2 - h // 2:height // 2 + h // 2, width // 2 - w // 2:width // 2 + w // 2]
return final
if __name__ == "__main__":
p = np.zeros((1024, 1024))
p[256:768, 256:768] = 1
# image_path = "../../Res/Set5/GTmod12/butterfly.png"
# p = Image.open(image_path, mode="r")
# # convert RGB image to Gray image
# p = p.convert("L")
plt.figure(1)
plt.imshow(p, cmap="gray")
pitch = 8 * pow(10, -3)
z = pitch * 1024 * 200
lambda_ = 638 * pow(10, -6)
final = asm(p, z, pitch, lambda_, band_limit=False)
final_limit = asm(p, z, pitch, lambda_, band_limit=True)
final_show = np.abs(final)
final_show /= np.max(final_show)
final_show = format_img(final_show)
plt.figure(2)
plt.imshow(final_show, cmap="gray")
final_limit_show = np.abs(final_limit)
final_limit_show /= np.max(final_limit_show)
plt.figure(3)
plt.imshow(final_limit_show, cmap="gray")
plt.show()
================================================
FILE: Python/propagator/fresnel_diffraction.py
================================================
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
'''
@Project :Computer-Generated-Hologram
@File :fresnel_diffraction.py
@Author :JackHCC
@Date :2022/10/5 14:11
@Desc :Todo
'''
def fred(input_img):
raise NotImplemented
================================================
FILE: README.md
================================================
# Computer-Generated-Hologram
✨This library introduces the current production process of computer holography, and uses MATLAB and Python to record and reproduce holograms. In the future, I will build a computer hologram simulation framework or a simulation application program.

## Introduction
CGH stands for computer-generated holograms (CGH). Holograms are unique in their ability to record both the intensity and phase of information.
More Resource to learn holography 👉 [Awesome Holography](./Doc/Awesome.md)👈
Summary of CGH Tips: [Tips](./Doc/Tips.md)
### Types of CGH
- **Point-based** methods
- **Polygon-based** methods
- **Layer-based** methods
- **Ray-tracing**
- **Geometric primitives & basis functions**
- **Holographic Stereograms**
### Phase Optimization Methods
#### Overview
- Iterative Method
- GS,GSW,Fienup,AA
- Error Diffusion Method
- Non-Iterative Method
- Random Phase
- Sample Method
- Sampled-Phase-only Hologram
- Complementary phase-only hologram
- Adaptive Down-Sampling Mask
- Patterned Phase-Only Hologram and Quadratic Phase
- **Double-Phase Method**
- Non-Random Phase-Free Method
- Direct Computation
- Direct Search Algorithm
- Simulated Annealing Algorithm
- Genetic Algorithm
- Combination of iteration and non-iteration
- Wirtinger Flow
- **Deep Learning**
#### Iterative Method
The iterative algorithm usually starts from an approximation of the target hologram, and continuously optimizes the approximate hologram through a series of repeated operations until the reconstructed image obtained by the approximation meets certain error requirements.
##### GS-Base Algorithm
According to the amplitude distribution of the hologram plane and the reconstructed image plane, the phase information of the light field in the hologram plane can be obtained by iterating the forward and reverse light wave transmission and the restrictions imposed on the two planes.
| Algorithm | Paper | Link |
| :----------------------------: | :----------------------------------------------------------: | :------------------------------------------: |
| GS(Gerchberg-Saxton) Algorithm | 👉[Paper](https://scholar.google.com/scholar?q=A%20practical%20algorithm%20for%20the%20determination%20of%20phase%20from%20image%20and%20diffraction%20plane%20pictures) | [Code](Python/phase_optimization/iterative_methods/GS.py) |
| Fienup Algorithm | 👉[Paper](https://labsites.rochester.edu/fienup/wp-content/uploads/2019/07/OEngr1980_ITAimRecCGH.pdf) | [Code](Python/phase_optimization/iterative_methods/Fienup.py) |
##### Error Diffusion Method
The error diffusion algorithm iterates between the pixels of the hologram plane in turn, rather than between the hologram plane and the object image plane,Without any information of the object image, only the complex amplitude hologram itself can be directly operated on it and a pure phase hologram can be calculated.
| Algorithm | Paper | Link |
| :-----------------------: | :----: |:-----------------------------------------------------:|
| Error Diffusion Algorithm | 👉Paper | [Code](Python/phase_optimization/iterative_methods/Error_Diffusion.py) |
### Complex Amplitude Modulation
- [x] Double-Phase hologram (DPH):[Code](./Python/double_phase_hologram.py) | [Paper](https://opg.optica.org/ao/ViewMedia.cfm?uri=ao-17-24-3874&seq=0&guid=ff8146ce-78dc-4f66-875b-e6334fb4969e&html=true)
- [ ] Hologram bleaching
- [ ] Double-constraint iterative method
### Propagation Field
#### Fresnel diffraction method
- Based on single Fourier transform and Convolution calculation.
- Fresnel diffraction propagator is implemented [Here](./Python/propagator/fresnel_diffraction.py).
#### Angular spectrum method
- Angular spectrum propagator is implemented [Here](./Python/propagator/angular_spectrum.py).
## CGH Examples
| CGH Type | Document | Link |
|:-----------------------------------------------:| :-----------------------------------------: |:-------------------------------------------------:|
| Circuitous Phase Type Hologram/Fourier Hologram | 👉[Doc](Doc/Fourier_Hologram/README.md) | [Code](./Python/fourier_hologram.py) |
| Kinoform【POH】 | 👉[Doc](Doc/Kinoform/README.md) | [Code](./Python/kinoforms.py) |
| Fresnel Hologram【AOH】 | 👉Doc | [Code](./Python/fresnel_hologram.py) |
| Off Axis Interference Hologram【AOH】 | 👉[Doc](Doc/Interference_Hologram/README.md) | [Code](./Python/offaxis_interference_hologram.py) |
| Layer_Based Hologram【POH】 | 👉Doc | [Code](./Python/layer_based_method.py) |
## Usage
Working on a hologram simulation API.
```shell
git clone https://github.com/JackHCC/Computer-Generated-Hologram.git
cd Computer-Generated-Hologram
pip install requirements.txt
```
## Experiment
Go 👉[Here](./Doc/Experiment.md)👈 to try generating CGH!
You can get some awesome holograms and images!
## Contact
If you have any questions or good ideas, please contact: jackcc0701@163.com
## References
- Hao-zhen BU, Shu-ming JIAO. Review of computer-generated phase-only hologram optimization algorithm[J]. Chinese Journal of Liquid Crystals and Displays, 2021, 36(6):810-826. DOI: 10.37188/CJLCD.2021-0035.
- Pi, D., Liu, J. & Wang, Y. Review of computer-generated hologram algorithms for color dynamic holographic three-dimensional display. Light Sci Appl 11, 231 (2022).
- David Blinder, Tobias Birnbaum, Tomoyoshi Ito, Tomoyoshi Shimobaba. The state-of-the-art in computer generated holography for 3D display[J]. Light: Advanced Manufacturing 3, 35(2022).
================================================
FILE: requirements.txt
================================================
numpy
pillow
matplotlib
scipy
opencv-python
tqdm