package gdsc.smlm.ij.utils;
/*-----------------------------------------------------------------------------
* GDSC SMLM Software
*
* Copyright (C) 2013 Alex Herbert
* Genome Damage and Stability Centre
* University of Sussex, UK
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*---------------------------------------------------------------------------*/
import ij.process.ColorProcessor;
import ij.process.FloatProcessor;
import ij.process.ImageProcessor;
import java.awt.Rectangle;
/**
* Contains methods for converting an image to float data
*/
public class ImageConverter
{
/**
* Get the data from the image processor as a float array (include cropping to the ROI)
*
* @param ip
* @return The float array data
*/
public static float[] getData(ImageProcessor ip)
{
return getData(ip, null);
}
/**
* Get the data from the image processor as a float array (include cropping to the ROI). Data is duplicated if the
* InputImage is a FloatProcessor.
* <p>
* Allows reuse of an existing buffer if provided. This will not be truncated if it is larger than the
* ImageProcessor ROI bounds. If smaller then a new buffer will be created.
*
* @param ip
* @param buffer
* @return The float array data
*/
public static float[] getData(ImageProcessor ip, float[] buffer)
{
if (ip == null)
return null;
return getData(ip.getPixels(), ip.getWidth(), ip.getHeight(), ip.getRoi(), buffer);
}
/**
* Get the data from the image as a float array (include cropping to the ROI). Data is duplicated if the
* input already a float array.
* <p>
* Allows reuse of an existing buffer if provided. This will not be truncated if it is larger than the
* ImageProcessor ROI bounds. If smaller then a new buffer will be created.
*
* @param oPixels
* @param width
* @param height
* @param bounds
* @param buffer
* @return The float array data
*/
public static float[] getData(final Object oPixels, final int width, final int height, final Rectangle bounds,
float[] buffer)
{
if (oPixels == null)
return null;
// Ignore the bounds if they specify the entire image size
if (oPixels instanceof float[])
{
float[] pixels = (float[]) oPixels;
if (bounds != null && (bounds.x != 0 || bounds.y != 0 || bounds.width != width || bounds.height != height))
{
float[] pixels2 = allocate(buffer, bounds.width * bounds.height);
for (int ys = bounds.y; ys < bounds.y + bounds.height; ys++)
{
int offset1 = (ys - bounds.y) * bounds.width;
int offset2 = ys * width + bounds.x;
for (int xs = 0; xs < bounds.width; xs++)
pixels2[offset1++] = pixels[offset2++];
}
return pixels2;
}
else
{
float[] pixels2 = allocate(buffer, pixels.length);
System.arraycopy(pixels, 0, pixels2, 0, pixels.length);
return pixels2;
}
}
else if (oPixels instanceof short[])
{
short[] pixels = (short[]) oPixels;
if (bounds != null && (bounds.x != 0 || bounds.y != 0 || bounds.width != width || bounds.height != height))
{
float[] pixels2 = allocate(buffer, bounds.width * bounds.height);
for (int ys = bounds.y; ys < bounds.y + bounds.height; ys++)
{
int offset1 = (ys - bounds.y) * bounds.width;
int offset2 = ys * width + bounds.x;
for (int xs = 0; xs < bounds.width; xs++)
pixels2[offset1++] = pixels[offset2++] & 0xffff;
}
return pixels2;
}
else
{
float[] pixels2 = allocate(buffer, pixels.length);
for (int i = 0; i < pixels.length; i++)
pixels2[i] = pixels[i] & 0xffff;
return pixels2;
}
}
else if (oPixels instanceof byte[])
{
byte[] pixels = (byte[]) oPixels;
if (bounds != null && (bounds.x != 0 || bounds.y != 0 || bounds.width != width || bounds.height != height))
{
float[] pixels2 = allocate(buffer, bounds.width * bounds.height);
for (int ys = bounds.y; ys < bounds.y + bounds.height; ys++)
{
int offset1 = (ys - bounds.y) * bounds.width;
int offset2 = ys * width + bounds.x;
for (int xs = 0; xs < bounds.width; xs++)
pixels2[offset1++] = pixels[offset2++] & 0xff;
}
return pixels2;
}
else
{
float[] pixels2 = allocate(buffer, pixels.length);
for (int i = 0; i < pixels.length; i++)
pixels2[i] = pixels[i] & 0xff;
return pixels2;
}
}
else if (oPixels instanceof int[])
{
// The default processing
ImageProcessor ip = new ColorProcessor(width, height, (int[]) oPixels);
ip.setRoi(bounds);
FloatProcessor fp = ip.crop().toFloat(0, null);
return (float[]) fp.getPixels();
}
return null;
}
private static float[] allocate(float[] buffer, int size)
{
if (buffer == null || buffer.length < size)
buffer = new float[size];
return buffer;
}
/**
* Get the data from the image processor as a double array (include cropping to the ROI). Data is duplicated if the
* InputImage is a FloatProcessor.
* <p>
* Allows reuse of an existing buffer if provided. This will not be truncated if it is larger than the
* ImageProcessor ROI bounds. If smaller then a new buffer will be created.
*
* @param ip
* @param buffer
* @return The double array data
*/
public static double[] getDoubleData(ImageProcessor ip, double[] buffer)
{
if (ip == null)
return null;
return getDoubleData(ip.getPixels(), ip.getWidth(), ip.getHeight(), ip.getRoi(), buffer);
}
/**
* Get the data from the image as a double array (include cropping to the ROI). Data is duplicated if the
* input already a double array.
* <p>
* Allows reuse of an existing buffer if provided. This will not be truncated if it is larger than the
* ImageProcessor ROI bounds. If smaller then a new buffer will be created.
*
* @param oPixels
* @param width
* @param height
* @param bounds
* @param buffer
* @return The double array data
*/
public static double[] getDoubleData(final Object oPixels, final int width, final int height,
final Rectangle bounds, double[] buffer)
{
if (oPixels == null)
return null;
// Ignore the bounds if they specify the entire image size
if (oPixels instanceof float[])
{
float[] pixels = (float[]) oPixels;
if (bounds != null && (bounds.x != 0 || bounds.y != 0 || bounds.width != width || bounds.height != height))
{
double[] pixels2 = allocate(buffer, bounds.width * bounds.height);
for (int ys = bounds.y; ys < bounds.y + bounds.height; ys++)
{
int offset1 = (ys - bounds.y) * bounds.width;
int offset2 = ys * width + bounds.x;
for (int xs = 0; xs < bounds.width; xs++)
pixels2[offset1++] = pixels[offset2++];
}
return pixels2;
}
else
{
double[] pixels2 = allocate(buffer, pixels.length);
for (int i = 0; i < pixels.length; i++)
pixels2[i] = pixels[i];
return pixels2;
}
}
else if (oPixels instanceof short[])
{
short[] pixels = (short[]) oPixels;
if (bounds != null && (bounds.x != 0 || bounds.y != 0 || bounds.width != width || bounds.height != height))
{
double[] pixels2 = allocate(buffer, bounds.width * bounds.height);
for (int ys = bounds.y; ys < bounds.y + bounds.height; ys++)
{
int offset1 = (ys - bounds.y) * bounds.width;
int offset2 = ys * width + bounds.x;
for (int xs = 0; xs < bounds.width; xs++)
pixels2[offset1++] = pixels[offset2++] & 0xffff;
}
return pixels2;
}
else
{
double[] pixels2 = allocate(buffer, pixels.length);
for (int i = 0; i < pixels.length; i++)
pixels2[i] = pixels[i] & 0xffff;
return pixels2;
}
}
else if (oPixels instanceof byte[])
{
byte[] pixels = (byte[]) oPixels;
if (bounds != null && (bounds.x != 0 || bounds.y != 0 || bounds.width != width || bounds.height != height))
{
double[] pixels2 = allocate(buffer, bounds.width * bounds.height);
for (int ys = bounds.y; ys < bounds.y + bounds.height; ys++)
{
int offset1 = (ys - bounds.y) * bounds.width;
int offset2 = ys * width + bounds.x;
for (int xs = 0; xs < bounds.width; xs++)
pixels2[offset1++] = pixels[offset2++] & 0xff;
}
return pixels2;
}
else
{
double[] pixels2 = allocate(buffer, pixels.length);
for (int i = 0; i < pixels.length; i++)
pixels2[i] = pixels[i] & 0xff;
return pixels2;
}
}
else if (oPixels instanceof int[])
{
// The default processing
ImageProcessor ip = new ColorProcessor(width, height, (int[]) oPixels);
ip.setRoi(bounds);
FloatProcessor fp = ip.crop().toFloat(0, null);
return (double[]) fp.getPixels();
}
return null;
}
private static double[] allocate(double[] buffer, int size)
{
if (buffer == null || buffer.length < size)
buffer = new double[size];
return buffer;
}
}