Doing Simple Stuff with imglib2

by 8/19/2014 02:57:00 PM 0 comments
imglib2 is a library that I keep coming back to for image manipulation. It's very powerful but way, Way, WAY over abstracted. The documentation for it is just terrible; figuring out how to do simple things is much, much harder than it really needs to be. So, I'm adding a few notes for how to do the simple things. For the examples below I used Scala and SBT. If you use Java the code is very similar and you can use Maven with the same dependencies. You will need the following dependencies in your project:
    "net.imglib2" % "imglib2" % "2.0.0-beta-26",
    "net.imglib2" % "imglib2-ij" % "2.0.0-beta-26",
    "io.scif" % "scifio" % "0.16.2-SNAPSHOT"

Reading images

The correct way(s) to read images with imglib2 seems to change every time I revisit the library. I think the correct way is to use SCIFIO to read images as ImgPlus objects. You can do this like so:
import io.scif.img.IO
import scala.collection.JavaConverters._

...

// Open the image as ImgPlus
val imgs = IO.openImgs(myImagePath).asScala  // openImgs returns a java list, convert to scala
val imgPlus = imgs.head                      // Only 1 item in list so take it.

Getting the Image size

First step is to get the number of dimensions in the image.
val img = imgPlus.getImg                     // imgPlus wraps An Img object which contains the data
val dims = img.numDimensions                 // Returns dimensions
If myImagePath pointed to a typically PNG or JPEG then img will be an ArrayImg object with 3 dimensions in the order of HEIGHT, WIDTH, # COLOR CHANNELS (i.e. 3 for RGB). So to get the size of the image, I iterate over each dimension asking for it's size. In Scala, this is done like so:
// My example RGB image was 2448 pixels wide by 3264 pixels tall. So size
// here would be in the order of (height, width, colorChannels) or (3264, 2448, 3)
val size = for (i <- 0 until dims) yield img.dimension(i)

Navigating over the pixels

imglib2 provides cursors for iterating over the pixels. While this is very fast, the order of iteration is unknown to the programmer. I often want to access a specific pixel in a specific order. The way to do this is to grab a reference to some random access type pointing to the image data and use that to navigate to pixels.
val cursor = img.randomAcess()

// Here we'll walk over all the pixels in the first color channel (which 
// I assume is Red, as in RGB, but I haven't verified that yet)

for {
  w <- 0 until img.dimension(1).toInt // dimensions return longs not ints
  h <- 0 until img.dimension(0).toInt
} {
  val idx = Array(h, w, c)
  cursor.setPosition(idx) // Navigate to desired pixel
  val v = cursor.get      // read pixel value

}

Brian Schlining

Developer

Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor.

0 comments: