/*
* Copyright (c) 2012 European Synchrotron Radiation Facility,
* Diamond Light Source Ltd.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package fable.imageviewer.internal;
import java.util.Vector;
import jep.JepException;
import org.dawb.fabio.FabioFile;
//import org.dawb.fabio.FableJep;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.slf4j.Logger;
import fable.framework.logging.FableLogger;
import fable.framework.navigator.controller.SampleController;
import fable.framework.navigator.views.SampleNavigatorView;
import fable.framework.toolbox.EclipseUtils;
import fable.framework.toolbox.FableUtils;
import fable.imageviewer.component.ImageComponent;
import fable.imageviewer.editor.ImageEditor;
import fable.imageviewer.views.ImageView;
import fable.python.Sample;
/**
* ImageUtils is a class of utilities used mainly by the ImageView class. It
* consists of static methods for doing a number of useful image related jobs.
*
* @author Andy Gotz
*
*/
public class ImageUtils {
/**
* Make and display a 2d image by taking a 1d slice across all images
* currently selected in the sample navigator.
*
* This action runs as a job because it can take a lot time to read all the
* images.
*
* @param y1
* - line start x
* @param z1
* - line start y
* @param y2
* - line end x
* @param z2
* - line end y
* @param width
* - line width
*/
public static void Slice2DLine(int _y1, int _z1, int _y2, int _z2,
int _width) {
final int y1 = _y1, z1 = _z1, y2 = _y2, z2 = _z2, width = _width;
Job job = new Job("Make 1D Slice") {
protected IStatus run(IProgressMonitor monitor) {
final Sample sample = SampleController.getController()
.getCurrentsample();
Vector<FabioFile> fabioFiles = sample.getFilteredfiles();
Vector<Integer> selectedFiles = SampleNavigatorView.view
.getSelectedFilesIndex();
monitor.beginTask("Make 1D Slice", selectedFiles.size());
// FableJep fableJep;
try {
// fableJep = FableJep.getFableJep();
final int imageWidth = selectedFiles.size();
final int imageHeight;
int lineZLength = Math.abs(z2 - z1);
int lineYLength = Math.abs(y2 - y1);
if (lineZLength > lineYLength) {
imageHeight = lineZLength;
} else {
imageHeight = lineYLength;
}
float sliceImage[] = new float[imageWidth * imageHeight];
for (int i = 0; i < selectedFiles.size(); i++) {
float line[];
if (monitor.isCanceled())
return Status.CANCEL_STATUS;
try {
line = SelectLine(fabioFiles.elementAt(
selectedFiles.elementAt(i))
.getImageAsFloat(), fabioFiles
.elementAt(selectedFiles.elementAt(i))
.getWidth(), fabioFiles.elementAt(
selectedFiles.elementAt(i)).getHeight(),
y1, z1, y2, z2, width);
for (int j = 0; j < imageHeight; j++) {
sliceImage[j * imageWidth + i] = line[j];
}
} catch (JepException ex) {
FableUtils.excNoTraceMsg(this, "Error using Jep",
ex);
}
monitor.worked(1);
}
// fableJep.close();
final float[] _sliceImage = sliceImage;
Display.getDefault().asyncExec(new Runnable() {
public void run() {
try {
ImageView slice2DImageView;
slice2DImageView = (ImageView) PlatformUI
.getWorkbench()
.getActiveWorkbenchWindow()
.getActivePage().showView(ImageView.ID,
ImageComponent.SECONDARY_ID_SLICE2D,
IWorkbenchPage.VIEW_ACTIVATE);
slice2DImageView.getImage().changeImageRect(
new Rectangle(0, 0, imageWidth,
imageHeight), _sliceImage,
sample.getDirectoryName(), null);
slice2DImageView.setPartName(slice2DImageView
.getSecondaryId()
+ " " + sample.getDirectoryName());
} catch (PartInitException ex) {
FableUtils.excMsg(this,
"Error opening Slice2DImageView", ex);
}
}
});
} catch (Throwable ex) {
FableUtils.excNoTraceMsg(this, "Error using Jep", ex);
}
monitor.done();
return Status.OK_STATUS;
}
};
job.setUser(true);
job.schedule();
}
/**
* Make and display a 2d image by taking a 2d slice across all images
* currently selected in sample navigator.
*
* This action runs as a job because it can take a lot time to read all the
* images.
*
* @param _y1
* - area to slice starts at [y1,z1]
* @param _z1
* - area to slice starts at [y1,z1]
* @param _y2
* - area to slice ends at [y2,z2]
* @param _z2
* - area to slice ends at [y2,z2]
*/
public static void Slice2DArea(int _y1, int _z1, int _y2, int _z2) {
final int y1 = _y1, z1 = _z1, y2 = _y2, z2 = _z2;
Job job = new Job("Make 2D Slice of Selected Area") {
protected IStatus run(IProgressMonitor monitor) {
final Sample sample = SampleController.getController()
.getCurrentsample();
Vector<FabioFile> fabioFiles = sample.getFilteredfiles();
Vector<Integer> selectedFiles = SampleNavigatorView.view
.getSelectedFilesIndex();
monitor.beginTask("Read " + selectedFiles.size()
+ " files and select area [" + y1 + "," + z1 + "] to ["
+ y2 + "," + z2 + "] ...", selectedFiles.size());
// FableJep fableJep;
Logger logger = FableLogger
.getLogger((Class<?>) ImageUtils.class);
try {
// fableJep = FableJep.getFableJep();
int selectedWidth, selectedHeight;
selectedWidth = Math.abs(y2 - y1);
selectedHeight = Math.abs(z2 - z1);
logger.debug("selected width " + selectedWidth + " height "
+ selectedHeight);
final int imageWidth = selectedFiles.size() * selectedWidth;
final int imageHeight = selectedHeight;
float sliceImage[] = new float[imageWidth * imageHeight];
logger.debug("image width " + imageWidth + " height "
+ imageHeight);
for (int i = 0; i < selectedFiles.size(); i++) {
float area[];
if (monitor.isCanceled())
return Status.CANCEL_STATUS;
try {
monitor.subTask("Reading file "
+ i
+ " "
+ fabioFiles.elementAt(
selectedFiles.elementAt(i))
.getFileName() + " ...");
area = SelectArea(fabioFiles.elementAt(
selectedFiles.elementAt(i))
.getImageAsFloat(), fabioFiles
.elementAt(selectedFiles.elementAt(i))
.getWidth(), fabioFiles.elementAt(
selectedFiles.elementAt(i)).getHeight(),
y1, z1, y2, z2);
for (int j = 0; j < selectedWidth; j++) {
for (int k = 0; k < selectedHeight; k++) {
float intensity;
intensity = area[k * selectedWidth + j];
sliceImage[k * imageWidth + i
* selectedWidth + j] = intensity;
}
}
} catch (JepException ex) {
FableUtils.excNoTraceMsg(this, "Error using Jep",
ex);
}
monitor.worked(1);
}
// fableJep.close();
final float[] _sliceImage = sliceImage;
Display.getDefault().asyncExec(new Runnable() {
public void run() {
try {
ImageView slice2DImageView;
slice2DImageView = (ImageView) PlatformUI
.getWorkbench()
.getActiveWorkbenchWindow()
.getActivePage().showView(ImageView.ID,
ImageComponent.SECONDARY_ID_SLICE2D,
IWorkbenchPage.VIEW_ACTIVATE);
slice2DImageView.getImage().changeImageRect(
new Rectangle(0, 0, imageWidth,
imageHeight), _sliceImage,
sample.getDirectoryName(), null);
slice2DImageView.setPartName(slice2DImageView
.getSecondaryId()
+ " " + sample.getDirectoryName());
} catch (PartInitException ex) {
FableUtils.excMsg(this,
"Error opening Slice2DImageView", ex);
}
}
});
} catch (Throwable ex) {
FableUtils.excNoTraceMsg(this, "Error using Jep", ex);
}
monitor.done();
return Status.OK_STATUS;
}
};
job.setUser(true);
job.schedule();
}
/**
* Select an area over the requested range from the image array with the
* given dimensions. Returns an array with the pixel intensities of the
* corresponding area in the image.
*
* @param imageAsFloat
* - image data
* @param imageWidth
* - image width
* @param imageHeight
* - image height
* @param y1
* - area begins at [y1,z1]
* @param z1
* - area begins at [y1,z1]
* @param y2
* - area ends at [y2,z2]
* @param z2
* - area ends at [y2,z2]
* @return - float array containing the intensities of the pixels in the
* selected area
*/
private static float[] SelectArea(float[] imageAsFloat, int imageWidth,
int imageHeight, int y1, int z1, int y2, int z2) {
float[] zoomAreaAsFloat = null;
if (y1 > y2) {
int temp = y1;
y1 = y2;
y2 = temp;
}
if (z1 > z2) {
int temp = z1;
z1 = z2;
z2 = temp;
}
if (y1 < 0)
y1 = 0;
if (y1 >= imageWidth)
y1 = imageWidth - 1;
if (y2 <= y1)
y2 = y1 + 1;
if (y2 >= imageWidth)
y2 = imageWidth - 1;
if (z1 < 0)
z1 = 0;
if (z1 >= imageHeight)
z1 = imageHeight - 1;
if (z2 <= z1)
z2 = z1 + 1;
if (z2 >= imageHeight)
z2 = imageHeight - 1;
int zoomWidth = y2 - y1;
int zoomHeight = z2 - z1;
zoomAreaAsFloat = new float[zoomWidth * zoomHeight];
float areaMinimum = Float.MAX_VALUE;
float areaMaximum = Float.MIN_VALUE;
// float areaMean = 0.0f;
float areaSum = 0.0f;
for (int i = 0; i < zoomWidth; i++) {
for (int j = 0; j < zoomHeight; j++) {
zoomAreaAsFloat[i + j * zoomWidth] = imageAsFloat[y1 + i
+ (z1 + j) * imageWidth];
if (zoomAreaAsFloat[i + j * zoomWidth] < areaMinimum)
areaMinimum = zoomAreaAsFloat[i + j * zoomWidth];
if (zoomAreaAsFloat[i + j * zoomWidth] > areaMaximum)
areaMaximum = zoomAreaAsFloat[i + j * zoomWidth];
areaSum += zoomAreaAsFloat[i + j * zoomWidth];
}
// areaMean = areaSum / (zoomWidth * zoomHeight);
}
return zoomAreaAsFloat;
}
/**
* Select a line over the requested range from the image array with the
* given dimensions. Returns an array with the intensities averaged along
* the longest axis.
*
* @param imageAsFloat
* - image data
* @param imageWidth
* - image width
* @param imageHeight
* - image height
* @param y1
* - line begins at [y1,z1]
* @param z1
* - line begins at [y1,z1]
* @param y2
* - line ends at [y2,z2]
* @param z2
* - line ends at [y2,z2]
* @param lineWidth
* - line width to average over (in pixels)
* @return - float array containing the intensities averaged along the line
*/
private static float[] SelectLine(float[] imageAsFloat, int imageWidth,
int imageHeight, int y1, int z1, int y2, int z2, int lineWidth) {
float line[];
if (Math.abs(y2 - y1) > Math.abs(z2 - z1)) {
if (y1 > y2) {
// swap y1,y2 and z1,z2
int temp = y1;
y1 = y2;
y2 = temp;
temp = z1;
z1 = z2;
z2 = temp;
}
} else {
if (z1 > z2) {
// swap y1,y2 and z1,z2
int temp = y1;
y1 = y2;
y2 = temp;
temp = z1;
z1 = z2;
z2 = temp;
}
}
if (y1 < 0)
y1 = 0;
if (y2 < 0)
y2 = 0;
if (y1 >= imageWidth)
y1 = imageWidth - 1;
if (y2 >= imageWidth)
y2 = imageWidth - 1;
if (z1 < 0)
z1 = 0;
if (z2 < 0)
z2 = 0;
if (z1 >= imageHeight)
z1 = imageHeight - 1;
if (z2 >= imageHeight)
z2 = imageHeight - 1;
float slope = 0;
if ((y2 - y1) > (z2 - z1)) {
line = new float[y2 - y1];
if ((y2 - y1) != 0)
slope = (float) (z2 - z1) / (float) (y2 - y1);
for (int i = 0; i < (y2 - y1); i++) {
// KE: Note that allocating inside a loop is inefficient since
// it drives the GC crazy
int x, y;
y = (int) ((float) z1 + (slope * (float) (i)));
x = y1 + i;
/* integrate over linePeakWidth pixels along the line */
int jMin = y - (int) (lineWidth / 2.);
if (jMin < 0)
jMin = 0;
int jMax = y + (int) (lineWidth / 2.) + 1;
if (jMax > imageHeight)
jMax = imageHeight;
float jWidth = jMax - jMin;
for (int j = jMin; j < jMax; j++) {
line[i] += imageAsFloat[x + (j) * imageWidth];
}
line[i] = line[i] / (jWidth);
}
} else {
line = new float[z2 - z1];
if ((z2 - z1) != 0)
slope = (float) (y2 - y1) / (float) (z2 - z1);
for (int i = 0; i < (z2 - z1); i++) {
int x, y;
/*
* x = (int)((float)y1 + (slope(float)(i))); y = z1+i;
*/
y = (int) ((float) y1 + (slope * (float) (i)));
x = z1 + i;
/* integrate over linePeakWidth pixels along the line */
int jMin = y - (int) (lineWidth / 2.);
if (jMin < 0)
jMin = 0;
int jMax = y + (int) (lineWidth / 2.) + 1;
if (jMax > imageWidth)
jMax = imageWidth;
float jWidth = jMax - jMin;
for (int j = jMin; j < jMax; j++) {
line[i] += imageAsFloat[j + (x) * imageWidth];
}
line[i] = line[i] / (jWidth);
}
}
return line;
}
public static ImageComponent getComponentFromPartSelected() {
final IEditorPart sel = EclipseUtils.getActiveEditor();
if (sel!=null && sel instanceof ImageEditor) {
return ((ImageEditor)sel).getImageComponent();
}
final ImageView iv = (ImageView) PlatformUI.getWorkbench()
.getActiveWorkbenchWindow().getActivePage()
.findViewReference(ImageView.ID,
ImageComponent.SECONDARY_ID_SLICE2D).getView(
true);
if (iv!=null) return iv.getImageComponent();
return null;
}
}