ASF Home Page | | Interferometry

Escher

Introduction

Escher, named after the Dutch artist M.C. Escher, unwraps a phase image using the Goldstein branch-cut method.

In phase unwrapping, we determine the absolute phase for an image given only the phase values wrapped around from 0 to 2pi. What happens when a phase jumps from near 2 pi at one pixel to near 0 at the next? When this occurs, we say that the phase has cycled and mark it. For example, if a string of pixels has phase values that increase in the following manner: 0, pi/2, pi, 3pi/2, 0, pi/2. We can reason that the jump from 3pi/2 to 0 is not a jump backwards, but a jump forwards to 2pi (which is detected as 0). Hence, we add 2pi to that 0, as well as all following pixels. Therefore, our new sequence looks like: 0, pi/2, pi, 3pi/2, 2pi, 5pi/2, etc.

However, one drawback to the branch-cut method is if we cannot reason out that a jump should be from one level to the next. If this occurs, we create what is called a singularity. If a singularity is found, escher searches for another singularity. When it finds one, escher draws a line (a branch-cut) between one singularity and the next. It then sets a flag stating that integration (or unwrapping of the image) cannot occur across that line. The program will have to integrate around this cut. These cuts can result in a loss of data-- not only the data lost in the cut, but also if cuts enclose an area of the file and prevent it from being integrated. Escher creates an unwrapping mask to show areas of cuts, integration, and zeroes (areas of non-integration).

Example

For details on the command line syntax, please see the man page.

A sample run looks like the following:

sparc1k [9]: escher ml12 uwp12
escher: begin unwrapping phase...
loading wrapped phase...
wrapped phase data loaded...
 - grounded border
starting to make mask...
 - made mask
                        
doStats():  after makeMask():          
                        
      5242880 sites                         
      5178540 zeros        98.773 %
            0 integrated    0.000 %
        50525 residues      0.964 %
->      25264 +residues     0.482 %
->      25261 -residues     0.482 %
        13815 grounds       0.264 %
            0 in tree       0.000 %
            0 cuts          0.000 %
                                   
 ** cordon file 'cordon' does not exist; skipped installation **
starting branch cut scan [cutMask()]...
  ...at 320 of 2560
  ...at 640 of 2560
  ...at 960 of 2560
  ...at 1280 of 2560
  ...at 1600 of 2560
  ...at 1920 of 2560
  ...at 2240 of 2560
 - finished branch cutting
                        
doStats():  after cutMask():          
                        
      5242880 sites                         
      5067746 zeros        96.660 %
            0 integrated    0.000 %
        50525 residues      0.964 %
->      25264 +residues     0.482 %
->      25261 -residues     0.482 %
        74167 grounds       1.415 %
            0 in tree       0.000 %
       161636 cuts          3.083 %
                                   
saved a mask array to the file test.phase.mask ...
initUwp() finished


calcParams() finished


starting integratePhase() at (1024, 1280), seed phase -2.575006

total integrated = 4900000
integratePhase() integrated 4943538 pixels...
                        
doStats():  after integratePhase():          
                        
      5242880 sites                         
       124208 zeros         2.369 %
      4943538 integrated   94.291 %
        50525 residues      0.964 %
->      25264 +residues     0.482 %
->      25261 -residues     0.482 %
        74167 grounds       1.415 %
            0 in tree       0.000 %
       161636 cuts          3.083 %
                                   
saved a mask array to the file uwp12.phase.mask ...saved unwrapped phase...
Total wall clock time = 211 seconds.


Note that the line integrated = ... will update as the program runs.

Description

Escher begins by loading the wrapped phase file, ml12.phase, into memory. The outer edge is grounded because an edge pixel is missing a set of neighbors to compare to. A ground works like a singularity with one major exception, grounding points do not need to pair up. If two singularities, one positive and one negative, meet up, they are considered neutral. A third singularity cannot connect with a neutral pair of singularities since it would make the pair non-neutral. However a ground, since it connects to the edge, is always considered neutral regardless of the amount of singularities that connect with it.

Escher then proceeds to make a mask of the image and determine where singularities lie. It informs, in both pixels and percentages, the amount of data in the file that is of a certain type. Zeroes are non-integrated data; residues are singularities; cuts are the lines between singularities; and grounds are cuts that connect to the edge. The important values for us are zeroes, residues, and integrated. We want to maximize the number of integrated pixels.

After making the mask and determining residues, escher connects or inserts cuts between the residues. After cutting, escher then integrates the entire image based upon a reference value determined from the seed location. If the default seed location is trapped by cuts, you should enter new seed values.

After integration, the data is saved to file and a mask is created. As you can see in the above mask image, our data set integrated extremely well. Do not always expect this kind of integration. Data in mountainous areas is notoriously difficult to integrate and can result in percentages around 50% or lower.


Back to main interferometry page.
Last Updated: September 1, 1998
If you have any questions, please feel free to email olawlor@acm.org