-
-
Notifications
You must be signed in to change notification settings - Fork 44
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
Added NAFE #24
Added NAFE #24
Conversation
Hello @MinaSGorgy! Thanks for updating this PR. We checked the lines you've touched for PEP 8 issues, and found:
Comment last updated at 2019-05-04 01:12:18 UTC |
Thanks for the pull request @MinaSGorgy! Everything looks great! |
Thanks for this, I will have a proper review later on but any chance you can change your image to focus on the edges of the Sun? I'd like to see the output on a patch of loop structures nearer the edge. |
That region works, are you doing any extra normalization to plot the image? |
sunkit_image/nafe.py
Outdated
return new_margin[0] + (new_margin[1] - new_margin[0]) * (((old_value - old_margin[0]) / (old_margin[1] - old_margin[0])) ** (1.0 / power)) | ||
|
||
|
||
class _Nafe(): |
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 am not sure I am in favour of having a class here, is it not possible to avoid this?
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.
Probably yes. Will apply or report if it's not.
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 am curious why would a class not be preferred. I come from a C++ background so that's why it seemed the way to go for me.
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 guess I don't understand why we need a class here.
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.
Basically used for keeping reference of the shared variables across the processes pool. Just making the code more readable and the mapping function cleaner.
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.
This: pool.imap(nafe_instance.transform, indices), total=map_data.size)
is what I mean. I need to use imap because the order of the results matter since they are pixels values. AFAIK the only other way to pass the arguments to imap would be creating an iterable whose elements will mainly be in the form (row, col, some constant arguments). I thought since they are constant arguments this seemed a typical case for using a class.
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.
Well if it's the best way to do it, it can stay.
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.
Will keep for now then.
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'm ok with the class, but why not having it all as one? I mean to include the nafe
function as to execute it?
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 have no preference but current implementation doesn't require a class anymore.
sunkit_image/nafe.py
Outdated
axes[0].set_title('Original Image') | ||
axes[1].imshow(nafe_image, cmap='gray') | ||
axes[1].set_title('Enhanced Image') | ||
plt.show() |
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.
This can all go. We don't want to be able to call the function like this. All those arser.add_argument(
should the parameters in the corresponding doc strings.
This could be turned into a seperate gallery example.
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.
It's basically for debugging purposes but will apply for final PR.
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.
Though I agree with @nabobalis and probably this wouldn't be the place. I imagine sunkit-image could have some command line programs that run some of these functions. This would need, however some extra additions to the setup.py
.
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.
Will remove from file for now and investigate where to migrate after finishing testing.
sunkit_image/nafe.py
Outdated
def nafe(input_map, imargin=None, gamma=None, omargin=None, nafe=False, | ||
nafe_weight=None, roi_p=None, roi_f=None, nproc=None, hbins=None, | ||
nrs=15, gb=0.3, lb=0.7, gw=0.3, lw=0.7, n=129, | ||
c=[1 for _ in range(12)]): |
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.
This just creates a list of 1 that is 12 long?
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.
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 wouldn't put a loop as part of the arguments. Rather None and then check it later and create the ones. Then, maybe this is more readable:
c = np.ones(12)
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.
Will apply the ones one.
sunkit_image/nafe.py
Outdated
---------- | ||
input_map : `~sunpy.map.sources.sdo.AIAMap` | ||
The original input image to be enhanced. | ||
|
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.
You should remove these line breaks between parameters.
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.
Will apply.
sunkit_image/nafe.py
Outdated
input_map : `~sunpy.map.sources.sdo.AIAMap` | ||
The original input image to be enhanced. | ||
|
||
imargin: `~tuple` |
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.
The ~
shorterns the name in the sphinx build, you only want it for long import. For the basic python types, you don't need them.
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.
Will apply.
sunkit_image/nafe.py
Outdated
|
||
Parameters | ||
---------- | ||
input_map : `~sunpy.map.sources.sdo.AIAMap` |
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.
This will only work on AIAMap
and not any Map
?
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.
For current implementation: anything with .meta["wavelnth"]
and .data
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.
Should I change this to take a numpy array instead and an optional wavelength argument? The original program uses the wavelength to calculate the optimal values for some other parameters. I can assign the default values for these parameters instead if not given a wavelength.
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.
That would be a good idea.
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.
Will apply.
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 think I prefer a map instead of a numpy array as an input, as it would be the most used. If I have a numpy array, then I can create a map instead to run it through here.
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 thought it would be easier to pass the map.data rather than possibly having to create a map from a numpy array. Again I have no preference. If a map would be sent I will check if its header contains info about the wavelength else I will use default value.
Thanks @nabobalis for your review and feedback. Regarding extra normalization, nothing not mentioned in the algorithm. |
In one of the examples in the SunPy Gallery, we apply just a log scale to the intensity. Any chance for the second example, you apply that to both images? |
Can you do a comparison with the other Python version? Also with the original version, are any of the examples got a timestamp we can trace? If so, we could download the original data and do a more "direct" comparison. |
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.
Great work @MinaSGorgy
This still needs tests!
sunkit_image/nafe.py
Outdated
def nafe(input_map, imargin=None, gamma=None, omargin=None, nafe=False, | ||
nafe_weight=None, roi_p=None, roi_f=None, nproc=None, hbins=None, | ||
nrs=15, gb=0.3, lb=0.7, gw=0.3, lw=0.7, n=129, | ||
c=[1 for _ in range(12)]): |
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 wouldn't put a loop as part of the arguments. Rather None and then check it later and create the ones. Then, maybe this is more readable:
c = np.ones(12)
sunkit_image/nafe.py
Outdated
|
||
def nafe(input_map, imargin=None, gamma=None, omargin=None, nafe=False, | ||
nafe_weight=None, roi_p=None, roi_f=None, nproc=None, hbins=None, | ||
nrs=15, gb=0.3, lb=0.7, gw=0.3, lw=0.7, n=129, |
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 dislike very short variable names. nrs
, gb
, ...? I like to look at the options and know what these parameters are, if I don't need to read the documentation, then the better, that means is self-explanatory.
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.
Ideally the user would never change these parameters values. Some of them even aren't mentioned in the paper but I adopted them from the original software implemented by the paper's author. In this software they are even read from a file containing fine tuned default values. The author exposes changing them through changing the file, so I thought I would rather expose them as functions arguments. I totally agree with having self-explanatory variables as I normally go for but I took these as named in the mentioned file. Of course I can change if you find it better to.
sunkit_image/nafe.py
Outdated
return new_margin[0] + (new_margin[1] - new_margin[0]) * (((old_value - old_margin[0]) / (old_margin[1] - old_margin[0])) ** (1.0 / power)) | ||
|
||
|
||
class _Nafe(): |
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'm ok with the class, but why not having it all as one? I mean to include the nafe
function as to execute it?
sunkit_image/nafe.py
Outdated
axes[0].set_title('Original Image') | ||
axes[1].imshow(nafe_image, cmap='gray') | ||
axes[1].set_title('Enhanced Image') | ||
plt.show() |
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.
Though I agree with @nabobalis and probably this wouldn't be the place. I imagine sunkit-image could have some command line programs that run some of these functions. This would need, however some extra additions to the setup.py
.
Thanks for the review @dpshelio |
Thanks @dpshelio for your review 😄 I think we mainly need to decide on using a map or numpy array as input. Meanwhile I am working on testing. Will reopen a PR once all changes are applied and testing is complete. |
No need to re-open the PR, you can add to this, bit by bit. I've just labelled as WIP as you did on the title. |
3b0edb7
to
3d8de26
Compare
Sorry for late reply, last two weeks have been TOO hectic. Applied all changes requested mainly:
[1] Ideally nafe should support ROI but it's removed for now since some information is currently missing. TODO:
Finally for comparing results, the only maps I currently have that are accepted by the original software are 4k*4k which would take quite some time to process. Cropping them with SunPy produces rejected maps for some reason. |
Thanks for the update. I will have to review it in more detail later on. Just a few comments tho: I don't see why adding pytest would break any of the CI. I think ROI would be nice but not really important. People should probably pass in submaps if they want a smaller area. I did try to load in some data I downloaded and NAFE would not accept it, I don't know why tho. Can you not crop a region within the NAFE windows program? Should hopefully crop the 4k image down a bit. I have to reiterate tho, if the before and after images are the same after we apply some normalization, has the code worked correctly? |
Welcome @nabobalis . Take your time. Regarding CI break: I thought I saw something suggesting that in the error log but seems there isn't. Will investigate this. Any hints though? Regarding the ROI: the thing is the original software most probably doesn't discard the out of ROI pixels. ie it doesn't really crop the image but just calculates new values for the ROI pixels including in the calculations the out of ROI neighbor pixels. It even does this with a ratio which we can change in the ini file but I am not 100% sure it's linear. Hence only full size images would provide reasonable comparison. Regarding before and after images: if I am getting it correctly that you are even questioning the benefit of the filter itself against simpler normalization filters, this I can test using original software. |
I'm not sure what to hint about, the CI has all passed bar the install one. That is a known fault and I need to fix it separately. Yes I guess I'm questing the need for this filter if it's just the same as normalizing it with a simple function. Which makes me suspect that if the original method is "correct", then there is a mistake somewhere in the version here. |
97f6b59
to
9a7ce1e
Compare
Description
This is a complete working implementation of the NAFE filter. Only missing feature is setting default values for input and output margins according to image contrast which is provided by original version. Otherwise, it supports all features including default parameters for different wavelengths. Original code is not open-sourced, hence can't compare it code-wise and thorough testing against original code results is still in progress. Differences between this implementation and other available open-source version are mainly implementation-wise. The only non-trivial difference is using constant noise removal sigma.
An output sample: (400x400) in ~10 mins
Creating this PR for feedback. @nabobalis @dpshelio
Fixes #6