-
Notifications
You must be signed in to change notification settings - Fork 12
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
Write ndarray to nifti #21
Conversation
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.
Nice work! We're going to need a few more iterations before merging. I also didn't make a full assessment of the ndarray writing routine yet.
Besides the suggestions inline, it might also be worth checking whether we can build a function for writing just an .img[.gz]
file.
src/writer.rs
Outdated
} | ||
} | ||
|
||
fn read_2d_image<P: AsRef<::std::path::Path>>(path: P) -> Array2<f32> { |
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.
My convention is to use where
clauses for all traits (except ?Sized
and lifetime constraints):
fn read_2d_image<P: AsRef<::std::path::Path>>(path: P) -> Array2<f32> { | |
fn read_2d_image<P>(path: P) -> Array2<f32> | |
where | |
P: AsRef<::std::path::Path>, | |
{ |
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 probably concluded that you put them 'in' when I checked extension.rs
by "chance"
pub fn from_stream<S: Read>(mut source: S) -> Result<Self> {
There are some other examples in your code, but I won't touch them because they are not related at all to this PR. I'll change mine.
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.
Hmm yeah, that code was written before I left my wicked ways. 😊
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.
Hahaha, sorry, I just need to add another example that I just found
fn from_file_2<P: AsRef<Path>, S>(path: P, mut stream: S) -> Result<InMemNiftiObject>
where
S: Read,
Ok, I'll see myself out ^^
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.
Hah, I figured there'd be more. This one here is worse though, as it clearly shows how adding the type constraints at the beginning makes a long-cat long function prototype. If we ever consider a full restyle, this one ought to go first.
pub fn from_stream<B: ByteOrder, S: Read>(
extender: Extender,
mut source: S,
len: usize,
) -> Result<Self> {
src/writer.rs
Outdated
@@ -230,7 +232,9 @@ pub mod tests { | |||
} | |||
} | |||
|
|||
fn read_2d_image<P: AsRef<::std::path::Path>>(path: P) -> Array2<f32> { | |||
fn read_2d_image<P>(path: P) -> Array2<f32> | |||
where P: AsRef<Path> |
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.
Is that how rustfmt
put 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.
My bad, sorry. I'm not used to run rustfmt
! Will do.
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 good to go! 🎉 In the near future, we can make a public function for writing header files.
As explained in #19, here's our code to write a
ndarray
to a nifti file. I kept it simple, it's all in the same file, you simply need to callwrite_nifti
with anArray
or anArrayView
, inc
orf
ordering. When you want to create a new image with the same header (same position, spacing, etc.), simply call the function with the optionalNiftiHeader
.In a generic context, you will need to use the trait
TypeTool
. I'm not a fan of it, but I don't know how to avoid it, and it's not too bad, maybe it simply needs to be hidden :)Some problems that I can see with my code:
if slope != 1.0 || header.scl_inter != 0.0 {
condition is not required. Maybe we shouldn't care about some substraction and divisions...TypeTool
. The name is bad, I know. But I do think it's a good trait usage.dim
anddatatype
currently win over the same fields in the header. That may or may not be what the user wants. I know that nibabel prefers the header, so it casts the data. I personally don't like automatic hidden casts, I prefer converting my ndarray myself.scl_slope
andscl_inter
on writing. They are simply set to 1.0 or 0.0. I never ignore them. This is sadly as "automatic" as the casts...By the way, do not hesitate to be critical! I won't cry over it. It's the best way to learn.