相位展开(phase unwrapping)算法研究与实践
1. 什么是相位展开?
相位展开(Phase Unwrapping)是一个经典的信号处理问题,它指的是从值区间中恢复原始相位值(原因在于:计算相位时,运用反正切函数,则相位图中提取的相位都是包裹在一个周期相位区间的包裹相位值,并不是真实得到的相位)。二维相位展开问题广泛存在于诸如光学测量技术(数字全息干涉和条纹投影轮廓术、合成孔径雷达(SAR)[2]和磁共振成像(MRI)[3]...)等许多应用中。从这些应用中估算出的相位与考虑到的物体形状、地形高程和磁场不均匀性等物理参数有关。
理想情况下,相位展开可以通过在每个像素上根据相邻像素之间的相位差加减来实现(最简单的二维相位展开就是将这个二维展开的问题划为两个一位相位展开,即首先在行方向或者列方向进行一维相位展开,然后将得到的一列值或者一行值在另一个方向进行一维相位展开,得到展开好的二维图像)。然而,在实际应用中,相位展开是一个非常具有挑战性的问题,因为存在噪声严重、相位突变和相位不连续等情况。
2.相位展开应用场景(以光学三维测量为例)
(具体原理图省略...),
原文算法是用C编写,MATLAB调用的算法:
//This program is written by Munther Gdeisat etc. to program the two-dimensional unwrapper
//entitled "Fast two-dimensional phase-unwrapping algorithm based on sorting by
//reliability following a noncontinuous path"
//by M. A. Herraez, D. R. Burton, M. J. Lalor, and M. A. Gdeisat
//published in the Applied Optics, Vol. 41, No. 35, pp. 7437, 2002.
//This program is written on 15th August 2007
//The wrapped phase map is floating point data type. Also, the unwrapped phase map is foloating point
#include <malloc.h>
#include<stdio.h>
#include <stdlib.h>
#include <string.h>
#include "mex.h" //--This one is required static float PI = 3.141592654;
static float TWOPI = 6.283185307; //pixel information
struct PIXEL
{
//int x; //x coordinate of the pixel
//int y; //y coordinate
int increment; //No. of 2*pi to add to the pixel to unwrap it
int number_of_pixels_in_group; //No. of pixels in the pixel group
float value; //value of the pixel
float reliability;
int group; //group No.
int new_group;
struct PIXEL *head; //pointer to the first pixel in the group in the linked list
struct PIXEL *last; //pointer to the last pixel in the group
struct PIXEL *next; //pointer to the next pixel in the group
}; //the EDGE is the line that connects two pixels.
//if we have S PIXELs, then we have S horizental edges and S vertical edges
struct EDGE
{
float reliab; //reliabilty of the edge and it depends on the two pixels
PIXEL *pointer_1; //pointer to the first pixel
PIXEL *pointer_2; //pointer to the second pixel
int increment; //No. of 2*pi to add to one of the pixels to unwrap it with respect to the second
}; //another version of Mixtogether but this function should only be use with the sort program
void Mix(EDGE *Pointer1, int *index1, int *index2, int size)
{
int counter1 = 0;
int counter2 = 0;
int *TemporalPointer = index1; int *Result = (int *)calloc(size * 2, sizeof(int));
int *Follower = Result; while ((counter1 < size) && (counter2 < size))
{
if ((Pointer1[*(index1 + counter1)].reliab <= Pointer1[*(index2 + counter2)].reliab))
{
*Follower = *(index1 + counter1);
Follower++;
counter1++;
}
else
{
*Follower = *(index2 + counter2);
Follower++;
counter2++;
}
}//while if (counter1 == size)
{
memcpy(Follower, (index2 + counter2), sizeof(int)*(size - counter2));
}
else
{
memcpy(Follower, (index1 + counter1), sizeof(int)*(size - counter1));
} Follower = Result;
index1 = TemporalPointer; int i;
for (i = 0; i < 2 * size; i++)
{
*index1 = *Follower;
index1++;
Follower++;
} free(Result);
} //this is may be the fastest sort program;
//see the explination in quickSort function below
void sort(EDGE *Pointer, int *index, int size)
{
if (size == 2)
{
if ((Pointer[*index].reliab) > (Pointer[*(index + 1)].reliab))
{
int Temp;
Temp = *index;
*index = *(index + 1);
*(index + 1) = Temp;
}
}
else if (size > 2)
{
sort(Pointer, index, size / 2);
sort(Pointer, (index + (size / 2)), size / 2);
Mix(Pointer, index, (index + (size / 2)), size / 2);
}
} //this function tries to implement a nice idea explained below
//we need to sort edge array. Each edge element conisists of 16 bytes.
//In normal sort program we compare two elements in the array and exchange
//their place under some conditions to do the sorting. It is very probable
// that an edge element may change its place hundred of times which makes
//the sorting a very time consuming operation. The idea in this function
//is to give each edge element an index and move the index not the edge
//element. The edge need 4 bytes which makes the sorting operation faster.
// After finishingthe sorting of the indexes, we know the position of each index.
//So we know how to sort edges
void quick_sort(EDGE *Pointer, int size)
{
int *index = (int *)calloc(size, sizeof(int));
int i; for (i = 0; i < size; ++i)
index[i] = i; sort(Pointer, index, size); EDGE * a = (EDGE *)calloc(size, sizeof(EDGE));
for (i = 0; i < size; ++i)
a[i] = Pointer[*(index + i)]; memcpy(Pointer, a, size * sizeof(EDGE)); free(index);
free(a);
} void read_data(char *inputfile, float *Data, int length)
{
printf("Reading the Wrapped Values form Binary File.............>");
FILE *ifptr;
ifptr = fopen(inputfile, "rb");
if (ifptr == NULL) printf("Error opening the file\n");
fread(Data, sizeof(float), length, ifptr);
fclose(ifptr);
printf(" Done.\n");
} void write_data(char *outputfile, float *Data, int length)
{
printf("Writing the Unwrapped Values to Binary File.............>");
FILE *ifptr;
ifptr = fopen(outputfile, "wb");
if (ifptr == NULL) printf("Error opening the file\n");
fwrite(Data, sizeof(float), length, ifptr);
fclose(ifptr);
printf(" Done.\n");
} //---------------start quicker_sort algorithm --------------------------------
#define swap(x,y) {EDGE t; t=x; x=y; y=t;}
#define order(x,y) if (x.reliab > y.reliab) swap(x,y)
#define o2(x,y) order(x,y)
#define o3(x,y,z) o2(x,y); o2(x,z); o2(y,z) typedef enum { yes, no } yes_no; yes_no find_pivot(EDGE *left, EDGE *right, float *pivot_ptr)
{
EDGE a, b, c, *p; a = *left;
b = *(left + (right - left) / 2);
c = *right;
o3(a, b, c); if (a.reliab < b.reliab)
{
*pivot_ptr = b.reliab;
return yes;
} if (b.reliab < c.reliab)
{
*pivot_ptr = c.reliab;
return yes;
} for (p = left + 1; p <= right; ++p)
{
if (p->reliab != left->reliab)
{
*pivot_ptr = (p->reliab < left->reliab) ? left->reliab : p->reliab;
return yes;
}
return no;
}
} EDGE *partition(EDGE *left, EDGE *right, float pivot)
{
while (left <= right)
{
while (left->reliab < pivot)
++left;
while (right->reliab >= pivot)
--right;
if (left < right)
{
swap(*left, *right);
++left;
--right;
}
}
return left;
} void quicker_sort(EDGE *left, EDGE *right)
{
EDGE *p;
float pivot; if (find_pivot(left, right, &pivot) == yes)
{
p = partition(left, right, pivot);
quicker_sort(left, p - 1);
quicker_sort(p, right);
}
} //--------------end quicker_sort algorithm ----------------------------------- //--------------------start initialse pixels ----------------------------------
//initialse pixels. See the explination of the pixel class above.
//initially every pixel is a gorup by its self
void initialisePIXELs(float *WrappedImage, PIXEL *pixel, int image_width, int image_height)
{
PIXEL *pixel_pointer = pixel;
float *wrapped_image_pointer = WrappedImage;
int i, j; for (i = 0; i < image_height; i++)
{
for (j = 0; j < image_width; j++)
{
//pixel_pointer->x = j;
//pixel_pointer->y = i;
pixel_pointer->increment = 0;
pixel_pointer->number_of_pixels_in_group = 1;
pixel_pointer->value = *wrapped_image_pointer;
pixel_pointer->reliability = 9999999 + rand();
pixel_pointer->head = pixel_pointer;
pixel_pointer->last = pixel_pointer;
pixel_pointer->next = NULL;
pixel_pointer->new_group = 0;
pixel_pointer->group = -1;
pixel_pointer++;
wrapped_image_pointer++;
}
}
}
//-------------------end initialise pixels ----------- //gamma function in the paper
float wrap(float pixel_value)
{
float wrapped_pixel_value;
if (pixel_value > PI) wrapped_pixel_value = pixel_value - TWOPI;
else if (pixel_value < -PI) wrapped_pixel_value = pixel_value + TWOPI;
else wrapped_pixel_value = pixel_value;
return wrapped_pixel_value;
} // pixelL_value is the left pixel, pixelR_value is the right pixel
int find_wrap(float pixelL_value, float pixelR_value)
{
float difference;
int wrap_value;
difference = pixelL_value - pixelR_value; if (difference > PI) wrap_value = -1;
else if (difference < -PI) wrap_value = 1;
else wrap_value = 0; return wrap_value;
} void calculate_reliability(float *wrappedImage, PIXEL *pixel, int image_width, int image_height)
{
int image_width_plus_one = image_width + 1;
int image_width_minus_one = image_width - 1;
PIXEL *pixel_pointer = pixel + image_width_plus_one;
float *WIP = wrappedImage + image_width_plus_one; //WIP is the wrapped image pointer
float H, V, D1, D2;
int i, j; for (i = 1; i < image_height - 1; ++i)
{
for (j = 1; j < image_width - 1; ++j)
{
H = wrap(*(WIP - 1) - *WIP) - wrap(*WIP - *(WIP + 1));
V = wrap(*(WIP - image_width) - *WIP) - wrap(*WIP - *(WIP + image_width));
D1 = wrap(*(WIP - image_width_plus_one) - *WIP) - wrap(*WIP - *(WIP + image_width_plus_one));
D2 = wrap(*(WIP - image_width_minus_one) - *WIP) - wrap(*WIP - *(WIP + image_width_minus_one));
pixel_pointer->reliability = H * H + V * V + D1 * D1 + D2 * D2;
pixel_pointer++;
WIP++;
}
pixel_pointer += 2;
WIP += 2;
}
} //calculate the reliability of the horizental edges of the image
//it is calculated by adding the reliability of pixel and the relibility of
//its right neighbour
//edge is calculated between a pixel and its next neighbour
void horizentalEDGEs(PIXEL *pixel, EDGE *edge, int image_width, int image_height)
{
int i, j;
EDGE *edge_pointer = edge;
PIXEL *pixel_pointer = pixel; for (i = 0; i < image_height; i++)
{
for (j = 0; j < image_width - 1; j++)
{
edge_pointer->pointer_1 = pixel_pointer;
edge_pointer->pointer_2 = (pixel_pointer + 1);
edge_pointer->reliab = pixel_pointer->reliability + (pixel_pointer + 1)->reliability;
edge_pointer->increment = find_wrap(pixel_pointer->value, (pixel_pointer + 1)->value);
pixel_pointer++;
edge_pointer++;
}
pixel_pointer++;
}
} //calculate the reliability of the vertical EDGEs of the image
//it is calculated by adding the reliability of pixel and the relibility of
//its lower neighbour in the image.
void verticalEDGEs(PIXEL *pixel, EDGE *edge, int image_width, int image_height)
{
int i, j; PIXEL *pixel_pointer = pixel;
EDGE *edge_pointer = edge + (image_height) * (image_width - 1); for (i = 0; i < image_height - 1; i++)
{
for (j = 0; j < image_width; j++)
{
edge_pointer->pointer_1 = pixel_pointer;
edge_pointer->pointer_2 = (pixel_pointer + image_width);
edge_pointer->reliab = pixel_pointer->reliability + (pixel_pointer + image_width)->reliability;
edge_pointer->increment = find_wrap(pixel_pointer->value, (pixel_pointer + image_width)->value);
pixel_pointer++;
edge_pointer++;
} //j loop
} // i loop
} //gather the pixels of the image into groups
void gatherPIXELs(EDGE *edge, int image_width, int image_height)
{
int k; //Number of rialiable edges (not at the borders of the image)
int no_EDGEs = (image_width - 1) * (image_height)+(image_width) * (image_height - 1);
PIXEL *PIXEL1;
PIXEL *PIXEL2; PIXEL *group1;
PIXEL *group2;
EDGE *pointer_edge = edge;
int incremento; for (k = 0; k < no_EDGEs; k++)
{
PIXEL1 = pointer_edge->pointer_1;
PIXEL2 = pointer_edge->pointer_2; //PIXEL 1 and PIXEL 2 belong to different groups
//initially each pixel is a group by it self and one pixel can construct a group
//no else or else if to this if
if (PIXEL2->head != PIXEL1->head)
{
//PIXEL 2 is alone in its group
//merge this pixel with PIXEL 1 group and find the number of 2 pi to add
//to or subtract to unwrap it
if ((PIXEL2->next == NULL) && (PIXEL2->head == PIXEL2))
{
PIXEL1->head->last->next = PIXEL2;
PIXEL1->head->last = PIXEL2;
(PIXEL1->head->number_of_pixels_in_group)++;
PIXEL2->head = PIXEL1->head;
PIXEL2->increment = PIXEL1->increment - pointer_edge->increment;
} //PIXEL 1 is alone in its group
//merge this pixel with PIXEL 2 group and find the number of 2 pi to add
//to or subtract to unwrap it
else if ((PIXEL1->next == NULL) && (PIXEL1->head == PIXEL1))
{
PIXEL2->head->last->next = PIXEL1;
PIXEL2->head->last = PIXEL1;
(PIXEL2->head->number_of_pixels_in_group)++;
PIXEL1->head = PIXEL2->head;
PIXEL1->increment = PIXEL2->increment + pointer_edge->increment;
} //PIXEL 1 and PIXEL 2 both have groups
else
{
group1 = PIXEL1->head;
group2 = PIXEL2->head;
//the no. of pixels in PIXEL 1 group is large than the no. of PIXELs
//in PIXEL 2 group. Merge PIXEL 2 group to PIXEL 1 group
//and find the number of wraps between PIXEL 2 group and PIXEL 1 group
//to unwrap PIXEL 2 group with respect to PIXEL 1 group.
//the no. of wraps will be added to PIXEL 2 grop in the future
if (group1->number_of_pixels_in_group > group2->number_of_pixels_in_group)
{
//merge PIXEL 2 with PIXEL 1 group
group1->last->next = group2;
group1->last = group2->last;
group1->number_of_pixels_in_group = group1->number_of_pixels_in_group + group2->number_of_pixels_in_group;
incremento = PIXEL1->increment - pointer_edge->increment - PIXEL2->increment;
//merge the other pixels in PIXEL 2 group to PIXEL 1 group
while (group2 != NULL)
{
group2->head = group1;
group2->increment += incremento;
group2 = group2->next;
}
} //the no. of PIXELs in PIXEL 2 group is large than the no. of PIXELs
//in PIXEL 1 group. Merge PIXEL 1 group to PIXEL 2 group
//and find the number of wraps between PIXEL 2 group and PIXEL 1 group
//to unwrap PIXEL 1 group with respect to PIXEL 2 group.
//the no. of wraps will be added to PIXEL 1 grop in the future
else
{
//merge PIXEL 1 with PIXEL 2 group
group2->last->next = group1;
group2->last = group1->last;
group2->number_of_pixels_in_group = group2->number_of_pixels_in_group + group1->number_of_pixels_in_group;
incremento = PIXEL2->increment + pointer_edge->increment - PIXEL1->increment;
//merge the other pixels in PIXEL 2 group to PIXEL 1 group
while (group1 != NULL)
{
group1->head = group2;
group1->increment += incremento;
group1 = group1->next;
} // while } // else
} //else
};//if pointer_edge++;
}
} //unwrap the image
void unwrapImage(PIXEL *pixel, int image_width, int image_height)
{
int i;
int image_size = image_width * image_height;
PIXEL *pixel_pointer = pixel; for (i = 0; i < image_size; i++)
{
pixel_pointer->value += TWOPI * (float)(pixel_pointer->increment);
pixel_pointer++;
}
} //the input to this unwrapper is an array that contains the wrapped phase map.
//copy the image on the buffer passed to this unwrapper to over write the unwrapped
//phase map on the buffer of the wrapped phase map.
void returnImage(PIXEL *pixel, float *unwrappedImage, int image_width, int image_height)
{
int i;
int image_size = image_width * image_height;
float *unwrappedImage_pointer = unwrappedImage;
PIXEL *pixel_pointer = pixel; for (i = 0; i < image_size; i++)
{
*unwrappedImage_pointer = pixel_pointer->value;
pixel_pointer++;
unwrappedImage_pointer++;
}
} //the main function of the unwrapper
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
//Declarations of getting two arrays from Matlab
//1)input wrapped image of type float and 2)mask of type unsigned char
float *WrappedImage = (float *)mxGetData(prhs[0]);
int image_width = mxGetM(prhs[0]);
int image_height = mxGetN(prhs[0]); //declare a place to store the unwrapped image and return it to Matlab
const mwSize *dims = mxGetDimensions(prhs[0]);
plhs[0] = mxCreateNumericArray(2, dims, mxSINGLE_CLASS, mxREAL);
float *UnwrappedImage = (float *)mxGetPr(plhs[0]); int i, j;
int image_size = image_height * image_width;
int two_image_size = 2 * image_size; int No_of_Edges = (image_width)*(image_height - 1) + (image_width - 1)*(image_height); PIXEL *pixel = (PIXEL *)calloc(image_size, sizeof(PIXEL));
EDGE *edge = (EDGE *)calloc(No_of_Edges, sizeof(EDGE));; //initialise the pixels
initialisePIXELs(WrappedImage, pixel, image_width, image_height); calculate_reliability(WrappedImage, pixel, image_width, image_height); horizentalEDGEs(pixel, edge, image_width, image_height); verticalEDGEs(pixel, edge, image_width, image_height); //sort the EDGEs depending on their reiability. The PIXELs with higher relibility (small value) first
//if your code stuck because of the quicker_sort() function, then use the quick_sort() function
//run only one of the two functions (quick_sort() or quicker_sort() )
//quick_sort(edge, No_of_Edges);
quicker_sort(edge, edge + No_of_Edges - 1); //gather PIXELs into groups
gatherPIXELs(edge, image_width, image_height); //unwrap the whole image
unwrapImage(pixel, image_width, image_height); //copy the image from PIXEL structure to the wrapped phase array passed to this function
returnImage(pixel, UnwrappedImage, image_width, image_height); free(edge);
free(pixel);
return;
}
https://www.mathworks.com/matlabcentral/fileexchange/65565-fast-2d-phase-unwrapping
https://blog.csdn.net/qq_35759050/article/details/74178395
相位展开(phase unwrapping)算法研究与实践的更多相关文章
- 【C#代码实战】群蚁算法理论与实践全攻略——旅行商等路径优化问题的新方法
若干年前读研的时候,学院有一个教授,专门做群蚁算法的,很厉害,偶尔了解了一点点.感觉也是生物智能的一个体现,和遗传算法.神经网络有异曲同工之妙.只不过当时没有实际需求学习,所以没去研究.最近有一个这样 ...
- Akamai在内容分发网络中的算法研究(翻译总结)
作者 | 钱坤 钱坤,腾讯后台开发工程师,从事领域为流媒体CDN相关,参与腾讯TVideo平台开发维护. 原文是<Algorithmic Nuggets in Content Delivery& ...
- 静态频繁子图挖掘算法用于动态网络——gSpan算法研究
摘要 随着信息技术的不断发展,人类可以很容易地收集和储存大量的数据,然而,如何在海量的数据中提取对用户有用的信息逐渐地成为巨大挑战.为了应对这种挑战,数据挖掘技术应运而生,成为了最近一段时期数据科学的 ...
- 【初码干货】使用阿里云对Web开发中的资源文件进行CDN加速的深入研究和实践
提示:阅读本文需提前了解的相关知识 1.阿里云(https://www.aliyun.com) 2.阿里云CDN(https://www.aliyun.com/product/cdn) 3.阿里云OS ...
- 机器学习算法与Python实践之(四)支持向量机(SVM)实现
机器学习算法与Python实践之(四)支持向量机(SVM)实现 机器学习算法与Python实践之(四)支持向量机(SVM)实现 zouxy09@qq.com http://blog.csdn.net/ ...
- 机器学习算法与Python实践之(三)支持向量机(SVM)进阶
机器学习算法与Python实践之(三)支持向量机(SVM)进阶 机器学习算法与Python实践之(三)支持向量机(SVM)进阶 zouxy09@qq.com http://blog.csdn.net/ ...
- 机器学习算法与Python实践之(二)支持向量机(SVM)初级
机器学习算法与Python实践之(二)支持向量机(SVM)初级 机器学习算法与Python实践之(二)支持向量机(SVM)初级 zouxy09@qq.com http://blog.csdn.net/ ...
- July-程序员面试、算法研究、编程艺术、红黑树、数据挖掘5大经典原创系列集锦与总结
程序员面试.算法研究.编程艺术.红黑树.数据挖掘5大经典原创系列集锦与总结 http://blog.csdn.net/v_july_v/article/details/6543438
- 经典算法研究系列:二、Dijkstra 算法初探
July 二零一一年一月 本文主要参考:算法导论 第二版.维基百科. 一.Dijkstra 算法的介绍 Dijkstra 算法,又叫迪科斯彻算法(Dijkstra),算法解决的是有向图中单个源点到 ...
随机推荐
- Linux-存储服务之NFS
NFS介绍 官方文档 NFS(Network File System)即网络文件系统,它最大的功能就是通过TCP/IP网络共享资源.在NFS的应用中,本地NFS的客户端应用可以透明地读写位于远端NFS ...
- 微信小程序~下拉刷新真机测试不弹回的处理办法
问题描述: 下拉刷新在手机上不会自动回弹,开发工具可以 解决办法: 主动调用wx.stopPullDownRefresh /** * 页面相关事件处理函数--监听用户下拉动作 */ onPullDow ...
- C#操作域用户ADHelper
在C#中操作域用户,在项目中写的帮助类: using System; using System.Collections.Generic; using System.DirectoryServices; ...
- WinForm利用AForge.NET调用电脑摄像头进行拍照和视频
当然了,你需要去官网下载类库,http://www.aforgenet.com/ 调用本机摄像头常用的组件: AForge AForge.Controls AForge.Imaging AForge. ...
- Dynamics 365 On-premises和Online 的不同
1.新建账号的不同:on-premises(下文简称op)是和ad绑定的,所以必须先在ad中新建账号后才能在CRM中新建.而online是和Office365(下文简称O365)绑定的,所以需在O36 ...
- Refactoring open source business models
https://opensource.com/business/16/4/refactoring-open-source-business-models They say you never forg ...
- screen对象及属性(availWidth、availHeight)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 学到了林海峰,武沛齐讲的Day50 django
http请求中产生两个核心对象: http请求:HttpRequest对象 http响应:HttpResponse对象 所在位置:django.http 5/8结束
- .NET Core入门程序及命令行练习
用命令行一步一步新建项目.添加Package.Restore.Build.Run 执行的实现方式,更让容易让我们了解.NET Core的运行机制. 准备工作 安装.NET Core 运行环境,下载地址 ...
- 1.typescirpt学习之路,*.d.ts和@types关系理解
今天看了看ts,文档上很多没用讲,小编疑惑了很久一个问题! *.d.ts和@types啥关系,小编查阅了很多文档,才弄明白. 首先,@types是npm的一个分支,我们把npm包发上去,npm包就会托 ...