On 11/22/11 5:47 PM, Dr G. wrote:
> On Nov 19, 7:59 am, Jeremy Bailin<astroco...@gmail.com> wrote:
>> On 11/18/11 2:53 PM, Jeremy Bailin wrote:
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>> On 11/18/11 10:04 AM, Dr G. wrote:
>>>> Hi Folks,
>>
>>>> Q: Can the IDL geometry geniuses out there think of a fast way to
>>>> create a 2D mask that automatically half�s an irregularly shaped 2D
>>>> array along its x axis (i.e., from top to bottom) Eg:
>>
>>>> [0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0]
>>>> [0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0]
>>>> [0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0]
>>>> [0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0]
>>>> [0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0]
>>>> [0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0]
>>>> [0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0]
>>>> [0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0]
>>>> [0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0]
>>>> [0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0]
>>>> [0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0]
>>>> [0,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0]
>>
>>>> Merci.
>>
>>>> Gf
>>
>>> If the input mask is "inmask":
>>
>>> ; how many 1s are there?
>>> rowtot = total(inmask, 1, /int)
>>> ; and it by checking if the cumulative total along the row is less
>>> ; than half of rowtot
>>> outmask = inmask and (total(inmask, 1, /int, /cumul) le $
>>> rebin(transpose(rowtot/2), masksize, /sample))
>>
>>> -Jeremy.
>>
>> Oops, missed the first line when I copied that in:
>>
>> masksize = size(inmask, /dimen)
>>
>> -Jeremy.
>
> Hi Jeremy,
>
> This is pretty amazing. Much better than a nasty for-next for each
> row. Thank you. This is truly geometry genius. My intention is to
> apply your method to masks 60,000 rows deep!!! So far in my tests,
> your solution rapidly works for most situations, but the output is a
> little strange when the input mask is very strangely shaped. One
> alternative to this, is to rotate the mask 90 degrees so that columns
> become rows, and then apply it.
>
> Jeremy, can you please take a moment and explain to me how the rebin&
> transpose combo works? I've read the help file on these but cannot
> figure it out the geometry genius you use.
>
> Additionally, you write "...and it by checking if the cumulative
> total ..." do you mean 'add it...'?
>
> Thank you for your consideration.
>
> Dr G.
The only to worry about when applying it to very large arrays is, of
course, memory - it internally needs two arrays of the same size as the
input mask. But if you run into problems, you could always try breaking
it up into a few chunks and doing one chunk at a time, since each row is
independent.
When you say the output is a little strange, what exactly does the input
mask do? My solution assumes that each row has only one string of 1s in
it - if it has more, then it won't break up each individual string, but
will just cut out the last half of them.... a correct solution would
require some fancy footwork with label_region.
I mean "and" as in "bitwise and"... it takes the input mask and performs
a bitwise and with the test mask. Here's a breakdown of what it does.
Let's say the input is:
inmask = [[0b,0,1,1,1,1,1,0], [0,1,1,1,1,0,0,0], [1,1,1,1,1,1,0,0]]
Then masksize is just the dimensions, in this case [8,3]. The first line
figures out how many 1s there are in each row: [5,4,6].
The line that does the work takes two arrays of the same dimension as
inmask and compares them. To cut the string of 1s in half, we want
rowtot/2 of them to remain. The rebin(transpose(... part generates an
8x3 array where each row contains that value. So rowtot/2 is a 3-element
array containing [2,2,3], transpose(rowtot/2) is a 1x3 array containing
[2,2,3] in the column, and rebin(transpose(...) turns it into an 8x3
array where the [2,2,3] column is expanded out along the first dimension:
IDL> print, fix(rebin(transpose(rowtot/2), masksize, /sample))
2 2 2 2 2 2 2 2
2 2 2 2 2 2 2 2
3 3 3 3 3 3 3 3
(I'm just using fix to turn the longs into short ints so they display
nicely). I then compare that to the cumulative number of 1s along the row:
IDL> print, fix(total(inmask, 1, /int, /cumul))
0 0 1 2 3 4 5 5
0 1 2 3 4 4 4 4
1 2 3 4 5 6 6 6
When the cumulative count (that second array) reaches half of the total
(the first array), that's all of the ones we want to preserve. So this
is the mask where that's true:
IDL> print, total(inmask, 1, /int, /cumul) le $
IDL> rebin(transpose(rowtot/2), masksize, /sample)
1 1 1 1 0 0 0 0
1 1 1 0 0 0 0 0
1 1 1 0 0 0 0 0
Compare that to the input mask:
IDL> print, inmask
0 0 1 1 1 1 1 0
0 1 1 1 1 0 0 0
1 1 1 1 1 1 0 0
You can see that the mask we've generated picks out the first half of
each string of 1s in inmask. So then we bitwise and them and we're done:
IDL> print, inmask and (total(inmask, 1, /int, /cumul) le $
IDL> rebin(transpose(rowtot/2), masksize, /sample))
0 0 1 1 0 0 0 0
0 1 1 0 0 0 0 0
1 1 1 0 0 0 0 0
-Jeremy.
|