Skip to content

ImageAccessor

Wilhelm Burger edited this page May 12, 2023 · 20 revisions

Purpose

An image accessor is a wrapper around some ImageProcessor object that provides unified (read and write) access to its pixels values. This abstract class defines uniform access to all 4 types of images available in ImageJ:

  • ByteProcessor (8-bit unsigned integer, scalar-valued),
  • ShortProcessor (16-bit signed integer, scalar-valued),
  • FloatProcessor (32-bit float, scalar-valued),
  • ColorProcessor (3x8-bit unsigned integer, vector-valued).

ImageAccessor transfers pixel data for all read and write operations as values of type float[], either containing a single element (on scalar-valued images) or 3 elements (on color images). An ImageAccessor is always linked to a particular image and duplicates no pixel data. Upon instantiation, each ImageAccessor is also assigned a specific OutOfBoundsStrategy and InterpolationMethod.

Class Hierarchy

  • ImageAccessor (abstract)
    • ScalarAccessor (abstract)
      • ByteAccessor
      • ShortAccessor
      • FloatAccessor
    • VectorAccessor (abstract)
      • RgbAccessor

Creation And Usage

A generic ImageAccessor is created, e.g., using the static method

ImageAccessor create(ImageProcessor ip)

which, depending upon the concrete type of ip, returns an instance of ByteAccessor, ShortAccessor, FloatAccessor or RgbAccessor, respectively. In this case, the default OutOfBoundsStrategy and InterpolationMethod are used. Both can be specified explicitly using method

ImageAccessor create(ImageProcessor ip,  OutOfBoundsStrategy obs, InterpolationMethod ipm)

Reading Pixels

Independent of the underlying image type, ImageAccessor can read pixels using method

float[] getPix(int u, int v)

The returned float[] contains a single element for scalar-valued images and multiple elements for vector-valued images. There is no restriction on the coordinates u and v; pixels outside the image are handled according to the specified OutOfBoundsStrategy.

Reading pixels is not constrained to integer coordinates. Method

float[] getPix(double x, double y)

returns the interpolated pixel value for the continuous position x and y, using the InterpolationMethod specified at creation.

Writing Pixels

Pixel values can be modified using method

void setPix(int u, int v, float[] val)

The supplied float array val must contain a single element for scalar-valued images or 3 elements for color images. Pixel values are automatically clamped to the permissible range. Writing to coordinates outside the image has no effect and also does not raise an error.

Scalar Accessors

ScalarAccessor is the abstract superclass to all accessors for scalar-valued images (i.e., ByteAccessor, ShortAccessor, FloatAccessor, see Class Hierarchy). It defines the static creator method

ScalarAccessor create(ImageProcessor ip, OutOfBoundsStrategy obs, InterpolationMethod ipm)

where ip must be of type ByteProcessor, ShortProcessor, or FloatProcessor (otherwise an exception is thrown). ScalarAccessor also defines the following additional access methods:

  • float getVal(int u, int v),
  • float getVal(double x, double y),
  • void setVal(int u, int v, float)

to read and write pixels passing single float values.

Vector Accessors

VectorAccessor is the abstract superclass to vector-valued images (currently RgbAccessoronly, see Class Hierarchy). VectorAccessor itself cannot be instatiated, but its (single) subclass RgbAccessor can using the static method

RgbAccessor create(ColorProcessor ip, OutOfBoundsStrategy obs, InterpolationMethod ipm)

VectorAccessor also defines the following additional access methods:

  • float getVal(int u, int v, int k),
  • float getVal(double x, double y, int k),
  • void setVal(int u, int v, int k, float val)

to read and write the k-th component of pixel vectors passing single float values.

Example

This is the run() method of ImageJ plugin Pixel_Interpolation_Demo (package Ch22_Pixel_Interpolation), which translates the input image by some continuous distance (dx/dy) and performs interpolation on any type of image:

import ij.ImagePlus;
import ij.process.ImageProcessor;
import imagingbook.common.image.OutOfBoundsStrategy;
import imagingbook.common.image.access.ImageAccessor;
import imagingbook.common.image.interpolation.InterpolationMethod;


    public void run(ImageProcessor source) {

	double dx = 10.50;	// translation parameters
	double dy = -3.25;

        InterpolationMethod IPM = InterpolationMethod.Bicubic;
	OutOfBoundsStrategy OBS = OutOfBoundsStrategy.DefaultValue;
    	    	
    	final int w = source.getWidth();
    	final int h = source.getHeight();
    	
    	// create the target image (same type as source):
    	ImageProcessor target = source.createProcessor(w, h);
    	
    	// create ImageAccessor's for the source and target  image:
    	ImageAccessor sa = ImageAccessor.create(source, OBS, IPM);
    	ImageAccessor ta = ImageAccessor.create(target);
    	
    	// iterate over all pixels of the target image:
    	for (int u = 0; u < w; u++) {	// discrete target position (u,v)
    		for (int v = 0; v < h; v++) {
    			double x = u + dx;	// continuous source position (x,y)
    			double y = v + dy;
    			float[] val = sa.getPix(x, y);
    			ta.setPix(u, v, val);	// update target pixel
    		}
    	}
    	
    	// display the target image:
    	new ImagePlus("Result", target).show();
    }

See Also

  • A related concept for providing unified access to images is PixelPack, which copies all pixel data to internal float arrays. In contrast to PixelPack, ImageAccessor does not duplicate any data but reads and writes the original ImageProcessor pixel data directly.
  • GridIndexer2D
  • OutOfBoundsStrategy
  • InterpolationMethod