/*- * Copyright 2016 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 uk.ac.diamond.scisoft.analysis.image; import java.util.ArrayList; import java.util.List; import org.eclipse.dawnsci.analysis.dataset.impl.function.Centroid; import org.eclipse.january.dataset.Dataset; import org.eclipse.january.dataset.DatasetFactory; import org.eclipse.january.dataset.DoubleDataset; import org.eclipse.january.dataset.IndexIterator; import org.eclipse.january.dataset.SliceND; public class ImageUtils { /** * Find peaks in data that are defined by being within the threshold values * and are the maximum in each window * @param data * @param window size of window * @param low lower threshold value for centre of peak * @param high upper threshold value for centre of peak * @return list of their sum and centroids (as coordinates in N x rank dataset) */ public static List<Dataset> findWindowedPeaks(Dataset data, int window, double low, double high) { int[] shape = data.getShapeRef(); int rank = shape.length; List<Double> sum = new ArrayList<Double>(); List<Double> centroid = new ArrayList<Double>(); IndexIterator it = data.getIterator(true); int half = window/2; int[] ub = new int[rank]; for (int i = 0; i < rank; i++) { ub[i] = shape[i] - window; } Dataset base = DatasetFactory.createRange(DoubleDataset.class, window); base.iadd(0.5); // shift to centre of pixel Dataset[] bases = new Dataset[rank]; for (int i = 0; i < rank; i++) { bases[i] = base; } Centroid centroidFn = new Centroid(bases); int[] centre = new int[rank]; int[] pos = it.getPos(); SliceND slice = new SliceND(shape); while (it.hasNext()) { if (windowIsInsideVolume(ub, pos)) { for (int i = 0; i < rank; i++) { centre[i] = pos[i] + half; } double v = data.getDouble(centre); if (v > low && v < high) { for (int i = 0; i < rank; i++) { int p = pos[i]; slice.setSlice(i, p, p + window, 1); } Dataset sliced = data.getSliceView(slice); if (sliced.max().doubleValue() <= v) { // this does not check if other non-central pixels are equal to v sum.add(((Number) sliced.sum()).doubleValue()); List<Double> c = centroidFn.value(sliced); for (int i = 0; i < rank; i++) { centroid.add(pos[i] + c.get(i)); } } } } } List<Dataset> list = new ArrayList<>(); if (sum.size() == 0) { list.add(DatasetFactory.zeros(0)); list.add(DatasetFactory.zeros(0, rank)); } else { list.add(DatasetFactory.createFromList(sum)); list.add(DatasetFactory.createFromList(centroid).reshape(sum.size(), rank)); } return list; } /** * Check if window is entirely within volume * @param ub upper bound on position * @param pos window position * @return true if window does not overlap boundary of volume */ private static boolean windowIsInsideVolume(int[] ub, int[] pos) { for (int i = 0; i < ub.length; i++) { if (pos[i] > ub[i]) { return false; } } return true; } }