相位展开(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),算法解决的是有向图中单个源点到 ...
随机推荐
- 案例实战之如何写一个webpack plugin
案例实战之如何写一个webpack plugin 1.写一个生成打包文件目录的file.md文件 // 生成一个目录项目目录的文件夹 class FileListPlugin { constructo ...
- scala 中的匹配模式
unapply 仅作匹配,不作其它输出.返回 Boolean 值 object UpperCase { def unapply(s: String): Boolean = s.toUpperCase ...
- Kafaka 总结
Kafka是一个分布式的Streaming处理平台,Kafka可以用于数据库中数据的导入导出,也可以用于实时流的处理,但是Kafka最核心的功能就是作为分布式的消息中间件. Kafka集群是由多个Br ...
- 5 Successful Business Models for Web-Based Open-Source Projects
https://handsontable.com/blog/articles/2016/3/5-successful-business-models-for-web-based-open-source ...
- Django 中使用redis
Django使用redis 方式一,使用Django-redis模块 #安装: pip3 install django-redis CACHES = { "default": ...
- 持续集成学习9 jenkins执行脚本
一.配置 1.首先在slave节点上写一脚本 [root@node1 script]# cat /application/script/test.sh #!/bin/bash echo "h ...
- 从TEB到PEB再到SEH(二)
什么是SEH? SEH( Structured Exception Handling , 结构化异常处理 ) 结构化异常处理(SEH)是Windows操作系统提供的强大异常处理功能.而Visual C ...
- python(二)——if条件语句与基本数据类型
if语句 缩进要保持一致 if 1 == 1: print('hello') if 2 == 2: print('world') else: print('python') elif inp = in ...
- 推荐一款分布式微服务框架 Surging
surging surging 是一个分布式微服务框架,提供高性能RPC远程服务调用,采用Zookeeper.Consul作为surging服务的注册中心,集成了哈希,随机,轮询,压力最小优先作为 ...
- SQL基础-创建新的输出字段
一.创建新的输出字段 1.建表.插数据 ### CREATE TABLE `t_stock_trans_dtl` ( `trans_id` varchar(100) NOT NULL COMMENT ...