-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
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
Resampling of nD arrays #511
Conversation
|
||
import numpy as np | ||
|
||
def downsample(image, factors, how = 'sum'): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PEP8: "Don't use spaces around the = sign when used to indicate a keyword argument or a default parameter value."
Also, I'm unsure if we have an official standard API for this but I believe a better kwarg would be mode
or method
.
Good beginnings! I left some comments in the code. That Travis failure has nothing to do with this PR. Thought to consider: could this easily be generalized to 3-D or n-D? I believe so... |
@JDWarner : Sure, that should be possible. Though, I would have to think a bit on how to generalize it to n-dimensions. |
@ankit-maverick Thanks for implementing this! Here's my comments:
|
@cdeil : Thanks a lot for the feedback. This seems a good amount of refactoring to do. I am currently busy with my end-terms, but will push as soon as it's possible for me. |
@cdeil 👍
Two additional thoughts:
|
@JDWarner Perhaps we can start with the case where only multiples of factor is supported. I agree that upsampling this way is a bit odd. |
@cdeil @JDWarner : I still haven't found any alternative to Python looping in numpy. If you have any idea about something better that can be used, please point me to that resource. Also, because of the above reason, the only way currently I can think of implementing these functions for 3D is by first testing the dimension of input ndarray and add code for 3 nested for loops which seems inefficient. Any ideas that you can think of? |
I have sth in mind, that could work for arbitrary dimensions... Not sure if it works, but I can show you when I get home. Johannes Schönberger Am 30.04.2013 um 16:12 schrieb "AnkitAgrawal" <notifications@github.commailto:notifications@github.com>: @cdeilhttps://github.com/cdeil @JDWarnerhttps://github.com/JDWarner : I still haven't found any alternative to Python looping in numpy. If you have any idea about something better that can be used, please point me to that resource. Also, because of the above reason, the only way currently I can think of implementing these functions for 3D is by first testing the dimension of input ndarray and add code for 3 nested for loops which seems inefficient. Any ideas that you can think of? — |
@ankit-maverick For vectorized looping over non-overlapping patches, check out >>> import numpy as np
>>> from skimage.util import view_as_blocks
>>> arr = np.arange(64).reshape((8, 8))
>>> view_as_blocks(arr, (2, 2)).shape
(4, 4, 2, 2)
>>> view_as_blocks(arr, (4, 4)).shape
(2, 2, 4, 4) Each The only gotcha here is that I'm sure there are other ways to do this, too. |
Credits to @seberg for suggesting this function to me on IRC. |
TO DECIDE :
|
|
||
def downsample(image, factors, method='sum'): | ||
|
||
# works only if image.shape is perfectly divisible by factors |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd like to relax this limitation and allow sums over arbitrary integer patches (obviously <= original array size). The method would be to zero pad each dimension which fails a residual check by the minimum necessary to allow the patch to fit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To support arbitrary patch sizes with zero padding but retain n-D generality, this utility function may be of use:
def _pad_asymmetric_zeros(arr, pad_amt, axis=-1):
"""Pads `arr` by `pad_amt` along specified `axis`"""
if axis == -1:
axis = arr.ndim - 1
zeroshape = tuple([x if i != axis else pad_amt
for (i, x) in enumerate(arr.shape)])
return np.concatenate((arr, np.zeros(zeroshape, dtype=arr.dtype)),
axis=axis)
Check each axis and if patch size does not divide evenly, apply this with appropriate pad_amt
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. Zero padding will be better than cropping because of loss of boundary information in the later, but then the boundary values may seem inconsistent with the neighbouring blocks. I am wondering if something like reflective padding can be better here? @JDWarner : Your thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Entirely depends on the goal. From what I understand ref. @cdeil the sum
method is aimed at being quantitative. In this case you definitely want to use zero padding, or you change the total sum of the image! This is really bad for scientific applications. If this ended up in skimage.measure
, or a wrapper for that method, I would definitely say zeros is the way to go.
On the other hand if you're going for looks rather than quantitative science, "downsampling" an image with local means, then I would say reflective padding would be appropriate - otherwise you'd get dark edges.
Thanks for the update, achieving n-D! In my opinion, the The |
Let's keep up/downsampling in the |
@JDWarner @stefanv @cdeil @ahojnnes : On further thought, I feel the current implementation of upsample is redundant and not meaningful since it does not increase the resolution of the image in the true sense, for eg: upsampling by a factor of (2, 2) with the current implementation will return image with 4x size but since 2x2 pixel blocks have same values, it's not of any use, but a waste of memory. Instead, we could do interpolation while upsampling like Image Resize Example in http://www.cambridgeincolour.com/tutorials/image-interpolation.htm. Also, check some interpolation results at scipy.interpolate doc : http://docs.scipy.org/doc/scipy/reference/tutorial/interpolate.html @ all : your thoughts? |
@ankit-maverick I have implemented all of these interpolation methods. See I think the best place to put your downsample function is |
@ahojnnes : Thanks for informing me.
I will update this in the next commit with tests and documentation probably tomorrow once I am done with my work on the SoC proposal. |
|
||
def downsample(array, factors, mode='sum'): | ||
"""Performs downsampling with integer factors. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need an in-depth description of the algorithm here. Especially highlight the difference to resize / rescale - maybe cross-reference downsample in those functions as well.
@ankit-maverick Your implementation is very elegant now, I really like it! I made some minor comments… let me know what you think. |
@ahojnnes Can you check the Travis log and check why I am getting the |
@ankit-maverick circular import? |
@sciunto Thanks for pointing out. But I still don't understand why the import chain doesn't stop at this line https://travis-ci.org/scikit-image/scikit-image/jobs/8729027#L2554 |
Even though you specifically told it to import from Sometimes this can be fixed by moving an import inside a function. Only the function |
I have some more smaller concerns, but I'll shortly address them in another PR. |
|
||
|
||
def resize(image, output_shape, order=1, mode='constant', cval=0.): | ||
"""Resize image to match a certain size. | ||
|
||
Resize performs interpolation to upsample or downsample 2D arrays. For | ||
downsampling any n-dimensional array by performing arithmetic sum or | ||
arithmetic mean, see measure._sum_blocks.sum_blocks and |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are we making public references to private functions here?
@stefanv There is already a new PR to fix the issues. |
Changes Unknown when pulling 971e7be on ankit-maverick:resample into * on scikit-image:master*. |
Just stumbled over #492 where it seems I had very similar requirements as @cdeil and developed https://github.com/CAB-LAB/gridtools, which are now in operational use for the production of a climate data cube. I use Numba for performance reasons. I'm happy to contribute one or the other method. |
@jni oh, sorry, I wasn't clear at all. I just wanted to inform anyone interested about some additional downsampling methods I've implemented in |
@forman - Thanks for pointing out https://github.com/CAB-LAB/gridtools I see you've released it under the GPL license. In case you're not aware: this means that many numerical Python people will not read or use or contribute to it. Numpy, Scipy, Numba, scikit-image, ... most numerical Python packages are under a liberal license like BSD or MIT. |
@cdeil you are right, I'll put it under a more liberal license for the next release. Thanks! |
@forman - Thank you! In this case ... I'll install it and check it out now. 😄 |
Done. |
Current api :