• 相位展开(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
    ");
    	fread(Data, sizeof(float), length, ifptr);
    	fclose(ifptr);
    	printf(" Done.
    ");
    }
    
    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
    ");
    	fwrite(Data, sizeof(float), length, ifptr);
    	fclose(ifptr);
    	printf(" Done.
    ");
    }
    
    //---------------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

  • 相关阅读:
    WordPress Uploader插件‘blog’参数跨站脚本漏洞
    WordPress Counter Per Day插件拒绝服务漏洞
    OpenSSH 远程拒绝服务漏洞
    WordPress Count Per Day插件 ‘daytoshow’参数跨站脚本漏洞
    昨日关注-每日编译(DailyBuild) 参考
    产品这么卖很好玩
    知己知彼
    让一切有调理
    昨日关注SqlServer中区分大小写
    软件公司到底有几种
  • 原文地址:https://www.cnblogs.com/carsonzhu/p/11197041.html
Copyright © 2020-2023  润新知