Skip to content

Commit

Permalink
Merge pull request #12 from JuliaImages/teh/indexing
Browse files Browse the repository at this point in the history
Extended indexing always returns an ImageMeta
  • Loading branch information
timholy authored Feb 11, 2017
2 parents aaa3508 + 198b79a commit 659b0e5
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 63 deletions.
12 changes: 4 additions & 8 deletions docs/src/intro.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,16 +77,12 @@ through Julia's type system. However, functions that receive an
in your own code it's fine to use properties to your advantage for
custom tasks.

### getindexim/viewim
### Vector indexing (region-of-interest selection)

As with the rest of julia, `img[i,j,...]` will return just the values
in an `ImageMeta`; the properties dictionary is "left behind." You can
ensure that the return is also an `ImageMeta` using `getindexim`
instead of `getindex` (`img[i,j]` gets converted into `getindex(img,
i, j)`, hence the name):
When indexing over an extended area, `img[i,j,...]` returns an `ImageMeta`:

```julia
julia> c = getindexim(img, 1:2, 1:2)
julia> c = img[1:2, 1:2]
RGB ImageMeta with:
data: 2×2 Array{ColorTypes.RGB{FixedPointNumbers.Normed{UInt8,8}},2}
properties:
Expand All @@ -97,7 +93,7 @@ RGB ImageMeta with:
This copies both the data (just the relevant portions) and the properties dictionary. In contrast,

```julia
julia> v = viewim(img, 1:2, 1:2)
julia> v = view(img, 1:2, 1:2)
RGB ImageMeta with:
data: 2×2 SubArray{ColorTypes.RGB{FixedPointNumbers.Normed{UInt8,8}},2,Array{ColorTypes.RGB{FixedPointNumbers.Normed{UInt8,8}},2},Tuple{UnitRange{Int64},UnitRange{Int64}},false}
properties:
Expand Down
39 changes: 7 additions & 32 deletions src/ImageMetadata.jl
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,9 @@ export
# functions
copyproperties,
data,
getindexim,
properties,
shareproperties,
spatialproperties,
viewim
spatialproperties

#### types and constructors ####

Expand Down Expand Up @@ -91,10 +89,10 @@ for AType in (ImageMeta, ImageMetaAxis)
end

@inline function Base.getindex(img::ImageMetaAxis, ax::Axis, I...)
img.data[ax, I...]
copyproperties(img, img.data[ax, I...])
end
@inline function Base.getindex(img::ImageMetaAxis, i::Union{Integer,AbstractVector,Colon}, I...)
img.data[i, I...]
copyproperties(img, img.data[i, I...])
end

@inline function Base.setindex!(img::ImageMetaAxis, val, ax::Axis, I...)
Expand All @@ -104,10 +102,10 @@ end
setindex!(img.data, val, i, I...)
end

Base.view(img::ImageMetaAxis, ax::Axis, I...) = view(img.data, ax, I...)
Base.view{T,N}(img::ImageMetaAxis{T,N}, I::Vararg{ViewIndex,N}) = view(img.data, I...)
Base.view(img::ImageMetaAxis, i::ViewIndex) = view(img.data, i)
Base.view{N}(img::ImageMetaAxis, I::Vararg{ViewIndex,N}) = view(img.data, I...)
Base.view(img::ImageMeta, ax::Axis, I...) = shareproperties(img, view(img.data, ax, I...))
Base.view{T,N}(img::ImageMeta{T,N}, I::Vararg{ViewIndex,N}) = shareproperties(img, view(img.data, I...))
Base.view(img::ImageMeta, i::ViewIndex) = shareproperties(img, view(img.data, i))
Base.view{N}(img::ImageMeta, I::Vararg{ViewIndex,N}) = shareproperties(img, view(img.data, I...))

Base.getindex(img::ImageMeta, propname::AbstractString) = img.properties[propname]

Expand Down Expand Up @@ -160,29 +158,6 @@ shareproperties(img::ImageMeta, data::AbstractArray) = ImageMeta(data, img.prope
# Delete a property!
Base.delete!(img::ImageMeta, propname::AbstractString) = delete!(img.properties, propname)

"""
getindexim(img::ImageMeta, I...) -> newimg
Like `img[I...]`, except that the returned `newimg` is another
ImageMeta. Like the data component, the properties dictionary of `img`
is copied, so `newimg` is not linked in any way to `img`.
See also: [`viewim`](@ref).
"""
getindexim(img::ImageMeta, I...) = copyproperties(img, img.data[I...])

"""
viewim(img::ImageMeta, I...) -> newimg
Like `view(img, I...)`, except that the returned `newimg` is another
ImageMeta. Like the data component, the properties dictionary of `img`
is shared with `img`, so that changes to either the data or the
properties apply to both.
See also: [`getindexim`](@ref).
"""
viewim(img::ImageMeta, I...) = shareproperties(img, view(img.data, I...))

# Iteration
# Defer to the array object in case it has special iteration defined
Base.start(img::ImageMeta) = start(data(img))
Expand Down
17 changes: 6 additions & 11 deletions src/deprecated.jl
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ Base.@deprecate_binding AbstractImageIndexed ImageMetaIndirect
@deprecate ImageCmap(data, cmap; kwargs...) ImageMeta(IndirectArray(data, cmap); kwargs...)
@deprecate ImageCmap(data, cmap, properties) ImageMeta(IndirectArray(data, cmap), properties)

Base.@deprecate_binding sliceim viewim
Base.@deprecate_binding sliceim view

function subim(img::Union{AxisArray,ImageMeta}, args...)
newargs = _subim_indexes(args)
newargstr = join(map(string, newargs), ", ")
Base.depwarn("subim is deprecated, call viewim(img, $newargstr) instead", :subim)
viewim(img, newargs...)
Base.depwarn("subim is deprecated, call view(img, $newargstr) instead", :subim)
view(img, newargs...)
end
export subim

Expand All @@ -46,12 +46,6 @@ end
using ImageAxes: getaxes

function Base.view(img::ImageMetaAxis, dimname::AbstractString, ind::Base.ViewIndex, args...)
axs = getaxes(dimname, ind, args...)
Base.depwarn("indexing with strings is deprecated, use view(img, $(axs...)) instead", :view!)
view(img.data, axs...)
end

function viewim(img::ImageMetaAxis, dimname::AbstractString, ind::Base.ViewIndex, args...)
axs = getaxes(dimname, ind, args...)
Base.depwarn("indexing with strings is deprecated, use view(img, $(axs...)) instead", :view!)
shareproperties(img, view(img.data, axs...))
Expand All @@ -60,8 +54,6 @@ end
@deprecate copyproperties(img::AbstractArray, data::AbstractArray) data
@deprecate shareproperties(img::AbstractArray, data::AbstractArray) data

@deprecate getindexim(img::AbstractArray, I...) img[I...]
@deprecate viewim(img::AbstractArray, I...) view(img, I...)

#### Properties ####

Expand Down Expand Up @@ -152,3 +144,6 @@ import ImageAxes.storageorder
@deprecate real(img::ImageMeta) shareproperties(img,real.(data(img)))
@deprecate imag(img::ImageMeta) shareproperties(img,imag.(data(img)))
@deprecate abs(img::ImageMeta) shareproperties(img,abs.(data(img)))

@deprecate getindexim getindex
@deprecate viewim view
35 changes: 23 additions & 12 deletions test/core.jl
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ using Base.Test
@test size(img) == (3,)
@test data(img) === A
for i = 1:3
@test img[i] === A[i]
@test @inferred(img[i]) === A[i]
end
for I in eachindex(img)
@test img[I] === A[I]
@test @inferred(img[I]) === A[I]
end
k = 0
for a in img
Expand Down Expand Up @@ -49,13 +49,13 @@ using Base.Test
@test size(img) == (3,5)
@test data(img) === A
for j = 1:5, i = 1:3
@test img[i,j] === A[i,j]
@test @inferred(img[i,j]) === A[i,j]
end
for k = 1:15
@test img[k] === A[k]
@test @inferred(img[k]) === A[k]
end
for I in eachindex(img)
@test img[I] === A[I]
@test @inferred(img[I]) === A[I]
end
k = 0
for a in img
Expand All @@ -74,6 +74,17 @@ using Base.Test
@test img["prop2"] == [1,2,3]
img["prop1"] = -1
@test img["prop1"] == -1
# vector-indexing
@test isa(@inferred(img[:,:]), ImageMeta) && img[:,:] == img
@test isa(@inferred(img[:]), ImageMeta) && img[:] == A[:]
@test isa(@inferred(img[1:2,1:2]), ImageMeta) && img[1:2,1:2] == A[1:2,1:2]
@test isa(@inferred(img[1:2,:]), ImageMeta) && img[1:2,:] == A[1:2,:]
@test isa(@inferred(img[:,1:2]), ImageMeta) && img[:,1:2] == A[:,1:2]
@test isa(@inferred(view(img,:,:)), ImageMeta) && view(img,:,:) == img
@test isa(@inferred(view(img,:)), ImageMeta) && view(img,:) == A[:]
@test isa(@inferred(view(img,1:2,1:2)), ImageMeta) && view(img,1:2,1:2) == A[1:2,1:2]
@test isa(@inferred(view(img,1:2,:)), ImageMeta) && view(img,1:2,:) == A[1:2,:]
@test isa(@inferred(view(img,:,1:2)), ImageMeta) && view(img,:,1:2) == A[:,1:2]
end
# Test bounds-checking removal by @inbounds
if Base.JLOptions().check_bounds != 1 && Base.JLOptions().can_inline == 1
Expand All @@ -90,12 +101,12 @@ using Base.Test
A = AxisArray(rand(3,5), :y, :x)
B = ImageMeta(A, info="blah")
Broi = B[2:3, 2:3]
@test isa(Broi, AxisArray)
@test isa(Broi, ImageMeta)
@test axisnames(Broi) == (:y, :x)
A1, B1 = A[2:7], B[2:7]
@test typeof(A1) == typeof(B1) && A1 == B1
@test isa(B1, ImageMeta) && A1 == B1
Broi = view(B, 2:3, 2:3)
@test isa(Broi, AxisArray)
@test isa(Broi, ImageMeta)
@test axisnames(Broi) == (:y, :x)
end

Expand Down Expand Up @@ -164,8 +175,8 @@ end
@testset "copy/shareproperties/viewim" begin
img = ImageMeta(rand(3,5); prop1 = 1, prop2 = [1,2,3])
@test !isempty(properties(img))
v = viewim(img, 1:2, 1:2)
c = getindexim(img, 1:2, 1:2)
v = view(img, 1:2, 1:2)
c = img[1:2, 1:2]
@test v["prop1"] == 1
@test c["prop1"] == 1
img2 = copyproperties(img, reshape(1:15, 5, 3))
Expand Down Expand Up @@ -194,8 +205,8 @@ end
Axis{:y}(1:5),
Axis{:time}(0.1:0.1:0.8));
prop1 = 1, prop2 = [1,2,3])
v = viewim(img, Axis{:time}(0.25..0.5))
c = getindexim(img, Axis{:time}(0.25..0.5))
v = view(img, Axis{:time}(0.25..0.5))
c = img[Axis{:time}(0.25..0.5)]
@test v["prop1"] == 1
@test c["prop1"] == 1
end
Expand Down
7 changes: 7 additions & 0 deletions test/deprecated.jl
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,13 @@ msg_contains(pass, msg) = contains(pass.value.msg, msg) || error(pass.value.msg,
msg_contains(result, "data, :boo, :rah")
end
end

@testset "getindexim/viewim" begin
img = ImageMeta(rand(3,5); prop1 = 1, prop2 = [1,2,3])
@test !isempty(properties(img))
@test isa(viewim(img, 1:2, 1:2), ImageMeta)
@test isa(getindexim(img, 1:2, 1:2), ImageMeta)
end
end

nothing

0 comments on commit 659b0e5

Please sign in to comment.