Arrays: more advanced indexing

In addition to the handling of numbers and colors, one of the main ways that JuliaImages leverages Julia is through a number of more sophisticated indexing operations. These are perhaps best illustrated with examples.

Keeping track of location with unconventional indices

Consider the following pair of images:

imgrefimg
cameramancameraman

You might guess that the one on the right is a rotated version of the one on the left. But, what is the angle? Is there also a translation?

A "low tech" way to test this is to rotate and shift the image on the right until it seems aligned with the one on the left. We could overlay the two images (Using colorview to make color overlays) to see how well we're doing.

julia> using Images, CoordinateTransformations, Rotations

julia> tfm = recenter(RotMatrix(pi/8), center(img))
AffineMap([0.9238795325112867 -0.3826834323650898; 0.3826834323650898 0.9238795325112867], [88.77855462171088, -59.31993370357884])

julia> imgrot = warp(img, tfm);

julia> summary(img)
"386×386 Array{Gray{N0f8},2} with eltype Gray{N0f8}"

julia> summary(imgrot)
"506×506 OffsetArray(::Array{Gray{N0f8},2}, -59:446, -59:446) with eltype Gray{N0f8} with indices -59:446×-59:446"

While img has axes that start with the conventional 1, the summary of imgrot reports that it has axes (-59:446, -59:446). This means that the first element of imgrot is indexed with imgrot[-59,-59] and the last element with imgrot[446,446].

What is the meaning of these indices that extend beyond those of the original array in both directions? Displaying the rotated image–-especially when overlaid on the original–-reveals why:

julia> imgov = colorview(RGB, paddedviews(0, img, imgrot, zeroarray)...)

rot_overlay

The padding on all sides of the array leaves space for the fact that the rotated image (green) contains some pixels out of the region covered by the original image (red). The fact that Julia allows these indices to be negative means that we have no trouble adding appropriate "padding" to the original image: we just copy the original over to the padded array, using its original indices.

We can test whether imgrot aligns well with the original unrotated image imgref at the top of this page:

julia> imgov_ref = colorview(RGB, paddedviews(0, imgref, imgrot, zeroarray)...)

ref_overlay

The fact that the overlapping portion looks yellow–-the combination of red and green–-indicates that we have perfect alignment.

You can learn more about Julia's support for arbitrary indices in this blog post.

Keeping track of orientation with named axes

Suppose you are presented with a 3-dimensional grayscale image. Is this a movie (2d over time), or a 3d image (x, y, and z)? In such situations, one of the best ways to keep yourself oriented is by naming the axes. The TestImages package contains an example of a file that illustrates this:

julia> using Images, TestImages

julia> img = testimage("mri");

julia> println(summary(img))
3-dimensional AxisArray{Gray{N0f8},3,...} with axes:
    :P, 0:1:225
    :R, 0:1:185
    :S, 0:5:130
And data, a 226×186×27 Array{Gray{N0f8},3} with eltype Gray{N0f8}

TestImages uses the AxisArrays package to name the axes of this particular image in terms of the RAS coordinate system (Right, Anterior, Superior) as commonly used in magnetic resonance imaging. See the documentation for that package to learn more about how you can create your own AxisArray objects.

We can use this coordinate system to help with visualization. Let's look at a "horizontal slice," one perpendicular to the superior-inferior axis (i.e., a slice with constant S value):

Sslice

From the summary you can see that the slice has just the :A and :R axes remaining.

We could slice along the R and A axes too, although for this image (which is sampled very anisotropically) they are not as informative.

The ImageAxes and ImageMetadata packages add additional functionality to AxisArrays that may be useful when you need to encode more information about your image.