Closed timholy closed 7 years ago
Thanks! I updated the gist, now it should fetch automatically.
One thing I forgot to ask: do folks think that all the documentation should be moved to http://juliaimages.github.io/latest? (Meaning, should ImageCore, ImageFiltering, etc. continue to maintain their own documentation?) Either way, http://juliaimages.github.io/latest/conversions_views.html#Conversions-vs.-views-1 is largely redundant with https://juliaimages.github.io/ImageCore.jl/latest/views.html#Views-1. Any thoughts on this would be appreciated. Originally I intended to just link the page from ImageCore in to juliaimages.io, but there are technical difficulties with that, and once I thought about just copying I came to the conclusion that some of the groundwork laid on earlier pages led to me wanting to explain things slightly differently. So if you think we should have only one of them, concrete changes for suggestions about which to keep or how to merge them would be appreciated.
Personally I think the following would make sense:
colorview
vs ColorView
, the note on arithmetic overflow etc. All the information that makes the interested and potential contributors understand how the packages work.The principle seems sound. But sometimes the dividing line between the two is unclear, perhaps especially to me (given that I spent so much time thinking about the technical details). To pick just one example: is http://juliaimages.github.io/latest/conversions_views.html#Sharing-memory:-an-introduction-to-views-1, pointing out the differences between a copy and and view, a "detail" or "necessary"?
My favored approach would be for others to cut/paste the docs and move them appropriately, since others have a better "outsider" perspective, but I'm happy to do it particularly if folks give me sufficiently detailed instructions.
My vote (not that I have one to cast) would be to have to docs all in one place and dedicate a page to each package to explain how it fits into the ecosystem and any peculiars one would need to know if they were to use it in isolation. Then you could link directly to that page from the respective repo.
On Tuesday, October 18, 2016, Tim Holy notifications@github.com wrote:
The principle seems sound. But sometimes the dividing line between the two is unclear, perhaps especially to me (given that I spent so much time thinking about the technical details). To pick just one example: is http://juliaimages.github.io/latest/conversions_views.html# Sharing-memory:-an-introduction-to-views-1, pointing out the differences between a copy and and view, a "detail" or "necessary"?
My favored approach would be for others to cut/paste the docs and move them appropriately, since others have a better "outsider" perspective, but I'm happy to do it particularly if folks give me sufficiently detailed instructions.
— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/timholy/Images.jl/issues/542#issuecomment-254451693, or mute the thread https://github.com/notifications/unsubscribe-auth/AA492jT0L3eXLo4jNzlND2djWtXJGlM7ks5q1I3fgaJpZM4Jjs9f .
You definitely have a vote to cast! EDIT: I think this idea too has merit. "local" vs "global" may be determined in part by how easy/difficult it is to explain one piece in isolation from any other piece.
:)
Also... I could throw together a meta spec (for MetaPkg) for the transition if you want, to avoid making users copy/paste that long gist to setup. I want to help, but weary of pushing it on anyone considering the tension over package management.
On Tuesday, October 18, 2016, Tim Holy notifications@github.com wrote:
You definitely have a vote to cast!
— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/timholy/Images.jl/issues/542#issuecomment-254465529, or mute the thread https://github.com/notifications/unsubscribe-auth/AA492k1vK_YdhOxMga_ls3DHXRsHLT8Mks5q1JvIgaJpZM4Jjs9f .
I haven't played with MetaPkg yet. Very cool, and seems like a systematic solution to precisely the problem my gist was designed to address. I'd be thrilled!
Exactly. My needs were for managing the many packages of JuliaPlots, JuliaML, and the GLVisualize universe, many of them not registered.
On Tuesday, October 18, 2016, Tim Holy notifications@github.com wrote:
I haven't played with MetaPkg yet. Very cool, and seems like a systematic solution to precisely the problem my gist was designed to address. I'd be thrilled!
— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/timholy/Images.jl/issues/542#issuecomment-254469409, or mute the thread https://github.com/notifications/unsubscribe-auth/AA492hAJTKYDUvZns_P485Lwk-vL5-D6ks5q1KAlgaJpZM4Jjs9f .
would be nice to have more info in each package's README. i code in a terminal and it's nice when packages contain at least a list of exports therein so that one can just say ?JLD
, for example, for a quick jog of the memory.
it's also very important to make the "description" (eg for ImagesCore it is currently "Julia types for representing images") informative. because, this and the name of the package are all that's listed at http://pkg.julialang.org. in such a constrained space, i think the word "Julia" is not useful.
I agree with @tbreloff here. One centralized place for documentation would be better. That way you don't have jump back and forth between different sets of docs. I would imagine that the less users are exposed to separate Image packages the better.
I took the liberty of adding a JuliaImages
meta spec in MetaPkg. I tested it on my mac laptop, and everything seemed to work, but you should verify yourself (make sure all your work is pushed up because purge will do Pkg.rm
and also delete cache/lib/trash files that are left around).
Instead of using that gist linked to above, you should be able to update with the commands:
using MetaPkg
MetaPkg.purge("JuliaImages")
meta_add("JuliaImages")
Then you should be all set up on the "release" path of the gist.
If you want to do the "fixed-renaming" branch:
meta_checkout("JuliaImages", "fixed-renaming")
and if you want to go back to the "release" afterwards:
meta_free("JuliaImages")
I didn't do the "images-next" path yet.. figured I'd get your input first. I made a gist with the full expected output from the REPL.
This looks awesome.
I have a bunch of not-pushed branches in quite a few of those packages, and I'm hopping on a plane this morning, so it might take me a bit of time to prepare the groundwork for testing this. But I really like how this looks as a way of managing an interwoven set of packages!
I am a little late on this show, but would like to ask where all the metadata handling has gone (pixelspacing
and so on) This was a very prominent feature in the stable branch of Images and in our internal codebase almost anything is an image object for exactly that reason. We also attach quite some additional metadata in image objects.
Tim, would you mind opening an issue over on QuartzImageIO with some guidance on what needs to be updated? I haven't had a chance to try this out yet, but I hope to do so soon. Thanks.
@tknopp, it's now called ImageMeta
. See ImageMetadata.jl. However, things like pixelspacing
are no longer encoded in the dictionary; you should use AxisArrays (with a bit of extra functionality provided by ImageAxes). All these packages are loaded when you say using Images
, however. I'm especially interested in transitions like the one you're describing, so if you have more than a little difficulty with the transition please let me know: the whole point of this beta period is to find out the pain points, and I can help smooth the pain.
@rsrock, will do.
Ok, thanks. Not sure when we get to this but we will try. I ping my colleague @hofmannmartin to be aware of the Images transition. Since we also set the pixelspacing using im[:pixelspacing]
it seems that we will need some transitioning.
The safer thing has always been to say pixelspacing(im)
, but perhaps this wasn't emphasized strongly enough. EDIT: and that will still work just fine (and without a deprecation warning), if you're using an AxisArray
or ImageMeta
that wraps one.
@timholy I see you that you might move the Overlay
stuff out. Would that be the recommended way of handling multichannel images or should something else be used instead?
That certainly has been emphasized. There are these annoying people not carefully reading the documentation... Sorry my workflow is sometimes a little exploratory.
@tlnagy, that's in fact already done, see http://juliaimages.github.io/latest/conversions_views.html#Using-colorview-to-make-color-overlays-1 and redundantly described in https://juliaimages.github.io/ImageCore.jl/latest/views.html#View-types-defined-in-ImageCore-1. That allows you to easily fill in channels for red, green, and blue (and you can do magenta/green with colorview(RGB, m, g, m)
). If that's not flexible enough, I suspect that better than the old approach would be to define a custom color type, e.g., the 2-channel color
immutable GFPtdTomato{T} <: Color{T, 2}
gfp::T
tdTomato::T
end
along with a function that can convert such "colors" to RGB
.
@tknopp, now I also see you said "set the pixelspacing". Yes, it might be a little more work, sorry---if you find it too annoying then let's talk about a convenience function, e.g.
im = imageaxes(buf, pixelspacing=(1mm, 1mm))
or something.
As consolation for any pain, among the benefits of having it be more "structured" now is that it won't be lost when you index like im[5:100, 40:80]
; formerly that lost both the pixel spacing and the orientation, which was just evil.
Thanks! The ImageCore documentation is quite thorough. It does mention StackedView
on several occasions, but I can't seem to find any docs on that.
The balance of advice above was to centralize the docs at JuliaImages, so the final product may look more like what's there than the ImageCore docs.
StackedView
is kinda internal; if you use colorview(RGB, r, g, b)
then you don't need to touch it. Briefly, StackedView
takes m×n
arrays a
, b
, c
and creates a 3×m×n
view of them.
Is there some documentation how to combine ImageMeta
objects with AxisArrays
? I would like to start with an object that is a close to the current Image
object and start from there.
Sure, they're completely orthogonal: just use an AxisArray
for the array argument of ImageMeta
. There's already some special-purpose code in place to look for this case, e.g., https://github.com/JuliaImages/ImageMetadata.jl/blob/b8e5c162b71babe457b56669e4cb8530964407f3/src/ImageMetadata.jl#L71-L73.
So, a typical usage of Images.jl was
What is your advice to handle this in the future. I will try playing around with this myself, but maybe it would be good to have this particular case discussed in the documentation somewhere.
And whats about the other image loader, are the already ported to the new Image infrastructure?
In case you haven't seen it, https://juliaimages.github.io/ImageAxes.jl/latest/ might help.
Simple (ignoring pixel spacing): ImageMeta(AxisArray(colorview(Gray, ni.raw), :x, :y, :z, :time))
There isn't quite as simple an approach for handling the pixel spacing (this is exactly the kind of feedback I'm looking for), but it is more flexible:
ImageMeta(AxisArray(colorview(Gray, ni.raw), Axis{:x}(rngx), Axis{:y}(rngy), Axis{:z}(rngz), Axis{:time}(rngt)))
where rng[xyzt]
is a range that describes the positions of the different coordinates, e.g., 0:2:284
if the pixels are 2mm and go from 0mm to 284mm. (If you want to attach real units, currently Julia's ranges are kinda problematic, but see Unitful.jl, Ranges.jl and https://github.com/JuliaLang/julia/pull/18777.)
Do you need an easier way to specify pixel spacing? The default AxisArray
behavior is very flexible (it lets you specify the origin) but maybe somewhat verbose.
Note you don't really need the ImageMeta
here, everything is encoded by the AxisArray
...one of the main points of the redesign was to encode everything having to do with orientation in the type system so that A[:, 5, :]
can preserve the names of the correct axes without hammering performance.
Hm, this is of course flexible but also pretty complicated.
The pixelspacing is one of the most important things since in our (tomographic) imaging method we have anisotropic voxels. Furthermore I use two custom fields "offset" and "rotation" within the image object that allow to define the precise coordinate system in space. With this I can take two Image
objects measured with two different tomographs and overlay them doing the appropriate registration/regridding/image fusion. The rotation field is necessary since MRI scans can be arbitrarily angulated.
So if I see it correctly I will have to but the offset
into the ranges, but the rotation
will remain an ImageMeta
field.
Well, offset
is exactly what you can encode in the AxisArray
ranges. Might want a simpler approach, how about
A = AxisImage(data, (:x, :y, :z, :time), (dx, dy, dz, dt), [(x0, y0, z0, t0)])
?
As for rotation goes...that would either have to be in the metadata, or possibly you could use a TransformedArray
from AffineTransforms.jl
. That package will be deprecated by CoordinateTransforms.jl
, however, but I can't remember the current status.
Yes, such a syntax would be definitely a nice convenience constructor, so thumbs up.
Oh, and to answer an earlier question, yes, all the IO packages have been updated too if you check things out as described in https://github.com/timholy/Images.jl/issues/542#issuecomment-254059092. That gist has been updated several times, so you may want a fresh copy.
Ok thanks.
Its quite interesting to see how this restructuring will change the workflow. Before, all parameters such as pixelspacing
where just metadata and I extracted the underlaying array before giving it to a hot loop. Maybe this won't be necessary anymore if the type stability is preserved.
Yes, the idea is you just pass an AbstractArray
to whatever you do. That way you never have to make choices between performance and "self-documentation." It should be just as fast as an Array
.
Could you open an issue on ImageAxes with https://github.com/timholy/Images.jl/issues/542#issuecomment-270742133, so I don't forget?
Added to AxisArrays
(need to be running master).
Closed by #577
There have been justifiable questions about "what exactly is happening?" so let me post my TODO list here (including completed items, with an explanation of purpose):
Range
(even one with physical units) for each axis, which thus incorporates thepixelspacing
. All this information is exposed to the type system (rather than through fields of the properties dict). What that means is that indexing operations become type-predictable: for example, if you slice at a particular spot in time, the new array doesn't have a time axis anymore. In the old Images.jl we had to check for this and set thetimedim
property to 0 at runtime, and because that's slow we were constantly throwing away the dictionary for performance and therefore losing track of orientation. Now everything should Just Work.imfilter
implementations. Everything will be type-stable, efficient algorithms will be chosen automatically based on the kernel size, and a platform will be in place for more efficient operations with separable kernels. Also options for performing the computation on the GPU, etc. This package will also likely be the first place to test another experimental direction: the ability (at the user's choice) to dispatch to algorithms in other libraries like OpenCV. (Currently this package is well underway but still needs work, and has been the occasion for me making changes to julia and a half dozen other packages. It won't be runnable by anyone else until julia-0.5-rc3 at the earliest.)MapInfo
machinery with something based on functions. This will probably go in ImageCore.?pkg
give an API summary@rexport
. Get the old tests passing:Things that could be done before or after:
as well as thesrc/map.jl
functionality. (For now I don't really plan on touching that, so that file could probably be copied verbatim.)Longer-term future: implement lots of missing functions. Other BSD-licensed projects should be used as important inspiration.