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)算法研究与实践的更多相关文章

  1. 【C#代码实战】群蚁算法理论与实践全攻略——旅行商等路径优化问题的新方法

    若干年前读研的时候,学院有一个教授,专门做群蚁算法的,很厉害,偶尔了解了一点点.感觉也是生物智能的一个体现,和遗传算法.神经网络有异曲同工之妙.只不过当时没有实际需求学习,所以没去研究.最近有一个这样 ...

  2. Akamai在内容分发网络中的算法研究(翻译总结)

    作者 | 钱坤 钱坤,腾讯后台开发工程师,从事领域为流媒体CDN相关,参与腾讯TVideo平台开发维护. 原文是<Algorithmic Nuggets in Content Delivery& ...

  3. 静态频繁子图挖掘算法用于动态网络——gSpan算法研究

    摘要 随着信息技术的不断发展,人类可以很容易地收集和储存大量的数据,然而,如何在海量的数据中提取对用户有用的信息逐渐地成为巨大挑战.为了应对这种挑战,数据挖掘技术应运而生,成为了最近一段时期数据科学的 ...

  4. 【初码干货】使用阿里云对Web开发中的资源文件进行CDN加速的深入研究和实践

    提示:阅读本文需提前了解的相关知识 1.阿里云(https://www.aliyun.com) 2.阿里云CDN(https://www.aliyun.com/product/cdn) 3.阿里云OS ...

  5. 机器学习算法与Python实践之(四)支持向量机(SVM)实现

    机器学习算法与Python实践之(四)支持向量机(SVM)实现 机器学习算法与Python实践之(四)支持向量机(SVM)实现 zouxy09@qq.com http://blog.csdn.net/ ...

  6. 机器学习算法与Python实践之(三)支持向量机(SVM)进阶

    机器学习算法与Python实践之(三)支持向量机(SVM)进阶 机器学习算法与Python实践之(三)支持向量机(SVM)进阶 zouxy09@qq.com http://blog.csdn.net/ ...

  7. 机器学习算法与Python实践之(二)支持向量机(SVM)初级

    机器学习算法与Python实践之(二)支持向量机(SVM)初级 机器学习算法与Python实践之(二)支持向量机(SVM)初级 zouxy09@qq.com http://blog.csdn.net/ ...

  8. July-程序员面试、算法研究、编程艺术、红黑树、数据挖掘5大经典原创系列集锦与总结

    程序员面试.算法研究.编程艺术.红黑树.数据挖掘5大经典原创系列集锦与总结 http://blog.csdn.net/v_july_v/article/details/6543438

  9. 经典算法研究系列:二、Dijkstra 算法初探

    July   二零一一年一月 本文主要参考:算法导论 第二版.维基百科. 一.Dijkstra 算法的介绍 Dijkstra 算法,又叫迪科斯彻算法(Dijkstra),算法解决的是有向图中单个源点到 ...

随机推荐

  1. Tomcat+Nginx+Memcached综合案例

    Tomcat+Nginx+Memcached综合案例 说明 通过Nginx解析静态页面并将动态负载均衡调度给后面的多个Tomcat,Tomcat解析java动态程序. 由于http是无状态的协议,你访 ...

  2. Electrification Plan 最小生成树(prim+krusl+堆优化prim)

    题目 题意: 无向图,给n个城市,n*n条边,每条边都有一个权值 代表修路的代价,其中有k个点有发电站,给出这k个点的编号,要每一个城市都连到发电站,问最小的修路代价. 思路: prim:把发电站之间 ...

  3. 手写简单的php生成Html网页

    这个是基本功,以前用到laravel及thinkphp时,这一步,都被设置好了吧. 这里只依靠纯的php环境,而没有任何框架, 而框架,只是将这一切规范化,加快代码效率及减小沟通成本,维护升级也方便, ...

  4. c语言的可变参数实例

    可变参数函数实现的步骤如下: 1.在函数中创建一个va_list类型变量 2.使用va_start对其进行初始化 3.使用va_arg访问参数值 4.使用va_end完成清理工作 接下来我们来实现一个 ...

  5. git version info & svn version info map(七)

    To generate the same version number as SVN, we can generate the same version number as SVN with the ...

  6. nginx syslog 配置

    以下是一个简单的实践,主要是打算测试nginx 与graylog 的集成,为了简单都是使用容器运行的,同时也测试了 nginx 对于配置多个access_log 的处理 环境准备 docker-com ...

  7. circus web console 依赖tornado>3.2 无法访问的bug

    circus web console 是一个很不错的web 监控circus 工具,但是对于高版本一直存在一个bug 信息如下 Traceback (most recent call last): F ...

  8. Xamarin.Forms 开发热加载利器 HotReload 推荐

    https://github.com/AndreiMisiukevich/HotReload

  9. video.js学习笔记

    video.js学习笔记获取用户观看时长

  10. P2624 [HNOI2008]明明的烦恼

    #include<iostream> #include<cstdio> #include<cstring> #include<cmath> #inclu ...