Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PyCuAmpcor: offer an option to fix the starting pixel locations #722

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions contrib/PyCuAmpcor/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,24 @@ If you are interested in a particular region instead of the whole image, you may
--startpixelac $startPixelAcross --startpixeldw $startPixelDown --nwa $numberOfWindowsAcross --nwd $numberOfWindowsDown
```

If you prefer to provide the location of the last pixel instead of the number of windows, you may use

```
--startpixelac $startPixelAcross --startpixeldw $startPixelDown --endpixelac $endPixelAcross --endpixeldw $endPixelDown
```

The program will calculate the number of windows based on the skip size and the window size.

If you prefer to provide the locations for the center of the starting/ending window, rather than those of the first/last pixels, you may add *--use-center 1* together with the above options, e.g.,

```
--startpixelac $startPixelAcross --startpixeldw $startPixelDown --use-center 1 --nwa $numberOfWindowsAcross --nwd $numberOfWindowsDown
```

Here, *($startPixelDown, $startPixelAcross)* is the coordinate of the first window center, and will be fixed if you vary the window size or search range.

But please note, the provided starting/ending pixels may go beyond the original reference/secondary image range. The program will still run but the offset results on the edge may be incorrect.

PyCuAmpcor supports two types of gross offset fields,
* static (--gross=0), i.e., a constant shift between reference and secondary images. The static gross offsets can be passed by *--rr $rgshift --aa $azshift*. Note that the margin as well as the starting pixel may be adjusted.
* dynamic (--gross=1), i.e., shifts between reference windows and secondary windows are varying in different locations. This is helpful to reduce the search range if you have a prior knowledge of the estimated offset fields, e.g., the velocity model of glaciers. You may prepare a BIP input file of the varying gross offsets (same format as the output offset fields), and use the option *--gross-file $grossOffsetFilename*. If you need the coordinates of reference windows, you may run *cuDenseOffsets.py* at first to find out the location of the starting pixel and the total number of windows. The coordinate for the starting pixel of the (iDown, iAcross) window will be (startPixelDown+iDown\*skipDown, startPixelAcross+iAcross\*skipAcross).
Expand Down
105 changes: 83 additions & 22 deletions contrib/PyCuAmpcor/examples/cuDenseOffsets.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@

EXAMPLE = '''example
cuDenseOffsets.py -r ./SLC/20151120/20151120.slc.full -s ./SLC/20151214/20151214.slc.full
cuDenseOffsets.py -r ./SLC/20151120/20151120.slc.full -s ./SLC/20151214/20151214.slc.full --outprefix ./offsets/20151120_20151214/offset --ww 256 --wh 256 --sw 8 --sh 8 --oo 32 --kw 300 --kh 100 --nwac 100 --nwdc 1 --gpuid 2
cuDenseOffsets.py -r ./SLC/20151120/20151120.slc.full -s ./SLC/20151214/20151214.slc.full --outprefix ./offsets/20151120_20151214/offset --ww 256 --wh 256 --sw 8 --sh 8 --oo 32 --kw 300 --kh 100 --nwac 100 --nwdc 1 --gpuid 0

# offset and its geometry
# tip: re-run with --full/out-geom and without --redo to generate geometry only
cuDenseOffsets.py -r ./SLC/20151120/20151120.slc.full -s ./SLC/20151214/20151214.slc.full --outprefix ./offsets/20151120_20151214/offset --ww 256 --wh 256 --sw 8 --sh 8 --oo 32 --kw 300 --kh 100 --nwac 100 --nwdc 1 --gpuid 2 --full-geom ./geom_reference --out-geom ./offset/geom_reference
cuDenseOffsets.py -r ./SLC/20151120/20151120.slc.full -s ./SLC/20151214/20151214.slc.full --outprefix ./offsets/20151120_20151214/offset --ww 256 --wh 256 --sw 8 --sh 8 --oo 32 --kw 300 --kh 100 --nwac 100 --nwdc 1 --gpuid 0 --full-geom ./geom_reference --out-geom ./offset/geom_reference
'''


Expand Down Expand Up @@ -70,6 +70,10 @@ def createParser():
parser.add_argument('--kh', type=int, dest='skiphgt', default=64,
help='Skip down (default: %(default)s).')

# use the chip center coordinates for starting pixels



# determine the number of windows
# either specify the starting pixel and the number of windows,
# or by setting them to -1, let the script to compute these parameters
Expand All @@ -79,12 +83,22 @@ def createParser():
help='Number of window across (default: %(default)s to be auto-determined).')
parser.add_argument('--nwd', type=int, dest='numWinDown', default=-1,
help='Number of window down (default: %(default)s).')
parser.add_argument('--startpixelac', dest='startpixelac', type=int, default=-1,
parser.add_argument('--startpixelac', dest='startpixelac', type=int, default=None,
help='Starting Pixel across of the reference image.' +
'Default: %(default)s to be determined by margin and search range.')
parser.add_argument('--startpixeldw', dest='startpixeldw', type=int, default=-1,
'Default: %(default)s to use the first pixel.')
parser.add_argument('--startpixeldw', dest='startpixeldw', type=int, default=None,
help='Starting Pixel down of the reference image.' +
'Default: %(default)s to be determined by margin and search range.')
'Default: %(default)s to use the first pixel.')
parser.add_argument('--use-center', dest='use_center', type=int, default=0,
help='whether to use the chip center coordinate as the starting pixel.' +
'Default: %(default)s not to use center coordinate.')
parser.add_argument('--endpixelac', dest='endpixelac', type=int, default=None,
help='Ending Pixel across of the reference image.' +
'Default: %(default)s to be determined by the image width.')
parser.add_argument('--endpixeldw', dest='endpixeldw', type=int, default=None,
help='Ending Pixel down of the reference image.' +
'Default: %(default)s to be determined by margin, search range and the image height.')


# cross-correlation algorithm
parser.add_argument('--alg', '--algorithm', dest='algorithm', type=int, default=0,
Expand Down Expand Up @@ -216,13 +230,6 @@ def estimateOffsetField(reference, secondary, inps=None):
# if using gross offset, adjust the margin
margin = max(inps.margin, abs(inps.azshift), abs(inps.rgshift))

# determine the number of windows down and across
# that's also the size of the output offset field
objOffset.numberWindowDown = inps.numWinDown if inps.numWinDown > 0 \
else (length-2*margin-2*inps.srchgt-inps.winhgt)//inps.skiphgt
objOffset.numberWindowAcross = inps.numWinAcross if inps.numWinAcross > 0 \
else (width-2*margin-2*inps.srcwidth-inps.winwidth)//inps.skipwidth
print('the number of windows: {} by {}'.format(objOffset.numberWindowDown, objOffset.numberWindowAcross))

# window size
objOffset.windowSizeHeight = inps.winhgt
Expand All @@ -234,20 +241,74 @@ def estimateOffsetField(reference, secondary, inps=None):
objOffset.halfSearchRangeAcross = inps.srcwidth
print('initial search range: {} by {}'.format(inps.srchgt, inps.srcwidth))

# starting pixel
objOffset.referenceStartPixelDownStatic = inps.startpixeldw if inps.startpixeldw != -1 \
else margin + objOffset.halfSearchRangeDown # use margin + halfSearchRange instead
objOffset.referenceStartPixelAcrossStatic = inps.startpixelac if inps.startpixelac != -1 \
else margin + objOffset.halfSearchRangeAcross

print('the first pixel in reference image is: ({}, {})'.format(
objOffset.referenceStartPixelDownStatic, objOffset.referenceStartPixelAcrossStatic))

# skip size
objOffset.skipSampleDown = inps.skiphgt
objOffset.skipSampleAcross = inps.skipwidth
print('search step: {} by {}'.format(inps.skiphgt, inps.skipwidth))

# starting pixel in the reference image
# along down direction
if inps.startpixeldw is not None:
# use the given starting pixel coordinate
startPixelDown = inps.startpixeldw
if inps.use_center != 0:
# the given starting coordinate is the center, adjust it
startPixelDown -= inps.winhgt//2
else:
# use margin + halfSearchHeight instead
startPixelDown = margin + inps.srchgt
# do the same for across direction
if inps.startpixelac is not None:
# use the given starting pixel coordinate
startPixelAcross = inps.startpixelac
if inps.use_center != 0:
# the given starting coordinate is the center, adjust it
startPixelAcross -= inps.winwidth//2
else:
# use margin + halfSearchRange instead
startPixelAcross = margin + inps.srcwidth

print('the first pixel in reference image is: ({}, {})'.format(
startPixelDown, startPixelAcross))
print('the center pixel of the first window is : ({}, {})'.format(
startPixelDown + inps.winhgt//2,
startPixelAcross + inps.winwidth//2))
if startPixelDown < inps.srchgt:
print('Warning: the starting pixel down is beyond the edge of the image')
if startPixelAcross < inps.srcwidth:
print('Warning: the starting pixel across is beyond the edge of the image')

# assign the values to objOffset
objOffset.referenceStartPixelDownStatic = startPixelDown
objOffset.referenceStartPixelAcrossStatic = startPixelAcross

# the ending pixel in the reference image
if inps.endpixeldw is not None:
endPixelDown = inps.endpixeldw
if inps.use_center !=0:
endPixelDown += inps.winhgt//2
else:
endPixelDown = length - margin - inps.srchgt
if inps.endpixelac is not None:
endPixelAcross = inps.endpixelac
if inps.use_center !=0:
endPixelAcross += inps.winwidth//2
else:
endPixelAcross = width - margin - inps.srcwidth

if endPixelDown >= length - inps.srchgt:
print('Warning: the ending pixel down is beyond the edge of the image')
if endPixelAcross >= width - inps.srcwidth:
print('Warning: the ending pixel across is beyond the edge of the image')

# determine the number of windows down and across
# that's also the size of the output offset field
objOffset.numberWindowDown = inps.numWinDown if inps.numWinDown > 0 \
else (endPixelDown-startPixelDown-inps.winhgt)//inps.skiphgt
objOffset.numberWindowAcross = inps.numWinAcross if inps.numWinAcross > 0 \
else (endPixelAcross-startPixelAcross-inps.winwidth)//inps.skipwidth
print('the number of windows: {} by {}'.format(objOffset.numberWindowDown, objOffset.numberWindowAcross))

# oversample raw data (SLC)
objOffset.rawDataOversamplingFactor = inps.raw_oversample

Expand Down
Loading