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

Binary striplog #95

Open
kwinkunks opened this issue Mar 1, 2019 · 10 comments
Open

Binary striplog #95

kwinkunks opened this issue Mar 1, 2019 · 10 comments
Projects

Comments

@kwinkunks
Copy link
Member

Maybe a binary striplog is a special thing? Where the main component property is True or False... then you could allow operations like dilate and erode. (Can't really see how you could allow this on non-binary logs).

@rgmyr
Copy link

rgmyr commented Mar 21, 2019

Typically dilate and erode functions (e.g., for binary images) require the user to specify a "structuring" or "selection" element. For a binary striplog I would think this will just be a single numeric value representing the height the depth/elevation window over which to min/max?

Also, should these methods enforce that the log is "clean", i.e. no gaps or overlaps?

@kwinkunks
Copy link
Member Author

Good questions. I had a go in this notebook > https://github.com/agile-geoscience/striplog/blob/master/tutorial/Striplog_with_a_binary_flag.ipynb

But yes, these require a strictly True/False value for the primary component... Not sure how it would handle gaps (or what one would want it to do with gaps).

I was chatting to Matteo Nicolli about 'greyscale' operations too, but I don't know much about those.

Anyway, as far as generalizing beds based on thickness goes, I quite like the result from a binary closing:

image

Where PAM is prune > anneal > merge (the current way to do this)

@rgmyr
Copy link

rgmyr commented Mar 21, 2019

Depending on the implementation, greyscale operations might be an easy generalization. Binary erode/dilate/opening/closing are really just special cases (0 & 1 values only) of more general algorithms:

# single operations w/ bool
dilated[i] = any(original[neighborhood(i)])
eroded[i] = all(original[neighborhood(i)])

# single operations w/ numeric 
dilated[i] = max(original[neighborhood(i)]) 
eroded[i] = min(original[neighborhood(i)]) 

I didn't see that plot or an implementation in the notebook, but I'm curious how you did it.

Originally I was thinking this would be an operation on intervals (figure out how much the top/base should be shifted, or if the interval should be removed), but another option that would accommodate numeric values would be to convert to_log (at a suitably fine resolution), perform operations on the log array, and then convert back from_log (setting cutoffs between unique values in the log).

@rgmyr
Copy link

rgmyr commented Mar 21, 2019

This is a little hacky so I won't PR it, but here's an example:

from scipy.ndimage import morphology

for iv in s:
    iv.data.update(iv.primary)

def dilate(s, field, height=0.75, step=0.01):
    
    blog, basis, _ = s.to_log(step=step, field='pay', return_meta=True)
    
    blog = morphology.binary_dilation(blog, structure=np.ones(int(height/step)))
    
    return Striplog.from_log(blog, cutoff=0.5, components=comps[::-1], basis=basis)
    

def erode(s, field, height=0.75, step=0.01):
    
    blog, basis, _ = s.to_log(step=step, field='pay', return_meta=True)
    
    blog = morphology.binary_erosion(blog, structure=np.ones(int(height/step)))
    
    return Striplog.from_log(blog, cutoff=0.5, components=comps[::-1], basis=basis)


dilated = dilate(s, 'pay')
for iv in dilated:
    iv.data.update(iv.primary)

eroded = erode(s, 'pay')
for iv in eroded:
    iv.data.update(iv.primary)

opened = dilate(eroded, 'pay')

closed = erode(dilated, 'pay')

I've double checked that the blog array comes out right, but for some reason it seems like the components get swapped and I have to use comps[::-1] list in from_log. Don't know why that's happening.

In any case, I made the structuring element a bit large for emphasis, but here's the plot:

binary_morphology_demo

@rgmyr
Copy link

rgmyr commented Mar 21, 2019

Did some more hacky stuff (to get around non-numeric components, etc.) and came up with this for the grey version (with three components mapping to log values of [1,2,3]):

grey_morphology_demo

@mycarta
Copy link

mycarta commented Mar 21, 2019

@rgmyr: brilliant!!

@kwinkunks
Copy link
Member Author

@rgmyr Ah, sorry, it's only on the develop branch and I linked to master... Check it out here >> https://github.com/agile-geoscience/striplog/blob/develop/tutorial/Striplog_with_a_binary_flag.ipynb

Scroll down to Dilate and erode and note that you'd need to be on the bleeding edge striplog for this to work.

I have a bit of nonsense in there to try to make sure we have something that can be interpreted as a binary striplog, but at its heart this is doing the same thing you're doing. I put all the binary ops in one function, since they all basically work in the same way.

I started a generalize function to perform generalization in an even more abstract way, but as you can see I abandoned it... I was thinking it would handle binary and non-binary logs, and give the user a really high-level way to do these things.

In this example (below) I computed net:gross as I think the user might want to know how the generalization is potentially changing some statistics... it would be interesting to explore ways to do the generalization in a way that preserves the statistics of the striplog!

image

@rgmyr
Copy link

rgmyr commented Mar 22, 2019

Hmm... I'm not sure about analogous operations with e.g., a constant sum constraint. I might post something on stack exchange and see if anyone has any neat ideas -- maybe there's something clever that can be done with a variable size structuring element, but I'm not really sure how to formulate that as a solvable optimization problem with a unique solution.

The only hacky thing I can think of is an iterative approach where we take the output of opening or closing and just erode to lower n:g and dilate to raise it, until we can't get any closer to the original n:g. I'd actually be interested to see what happens with that, might give it a shot in the near future.

@kwinkunks
Copy link
Member Author

FWIW, I just pushed v0.8.1 with binary morphology. I wanted to avoid depending on scipy (not sure why) so hacked my own binary operators... as a result they can't do greyscale morphology or 'weird' (non-boxcar) structuring elements.

If anyone feels like implementing the greyscale operations, especially if it's not too hard w/o scipy, then that would be lovely. Or I guess we can add scipy as a dependency and get it almost for 'free' (or however @rgmyr did it above).

@kwinkunks kwinkunks added this to To do in T21 Mar 30, 2021
@kwinkunks kwinkunks moved this from To do to In progress in T21 Apr 19, 2021
@kwinkunks
Copy link
Member Author

We do now depend on scipy, so we should implement the gray-level version of this algo.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
No open projects
T21
In progress
Development

No branches or pull requests

3 participants