/*
* Copyright (c) 2012 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.roi;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.dawnsci.analysis.dataset.impl.function.DatasetToDatasetFunction;
import org.eclipse.dawnsci.analysis.dataset.impl.function.LineSample;
import org.eclipse.dawnsci.analysis.dataset.roi.LinearROI;
import org.eclipse.dawnsci.analysis.dataset.roi.RectangularROI;
import org.eclipse.dawnsci.analysis.dataset.roi.SectorROI;
import org.eclipse.january.dataset.BooleanDataset;
import org.eclipse.january.dataset.Dataset;
import org.eclipse.january.dataset.DatasetFactory;
import org.eclipse.january.dataset.DatasetUtils;
import org.eclipse.january.dataset.FloatDataset;
import org.eclipse.january.dataset.IDataset;
import org.eclipse.january.dataset.IndexIterator;
import org.eclipse.january.dataset.Maths;
import uk.ac.diamond.scisoft.analysis.dataset.function.Integrate2D;
import uk.ac.diamond.scisoft.analysis.dataset.function.MapToPolarAndIntegrate;
import uk.ac.diamond.scisoft.analysis.dataset.function.MapToRotatedCartesianAndIntegrate;
import uk.ac.diamond.scisoft.analysis.diffraction.QSpace;
import uk.ac.diamond.scisoft.analysis.roi.XAxis;
/**
* Utility methods for calculating region of interest profiles.
*/
public class ROIProfile {
// public enum XAxis {
// ANGLE,
// PIXEL,
// RESOLUTION,
// Q;
// }
/**
* @param data
* @param lroi
* @param step
* size
* @return line profile
*/
public static Dataset[] line(Dataset data, LinearROI lroi, double step) {
return ROIProfile.line(data, null, lroi, step, false);
}
public static Dataset[] line(Dataset data, Dataset mask, LinearROI lroi, double step, boolean maskWithNans) {
double[] spt = lroi.getPoint();
double[] ept = lroi.getEndPoint();
Dataset[] profiles = new Dataset[] { null, null };
LineSample ls = new LineSample(spt[0], spt[1], ept[0], ept[1], step);
if (mask != null && data != null) {
if (data.isCompatibleWith(mask)) {
// TODO both multiply and nanalize create copies of the whole data passed in
if (!maskWithNans || !(mask instanceof BooleanDataset)) {
data = Maths.multiply(data, mask);
} else {
// Masks values to NaN, also changes dtype to Float
data = nanalize(data, (BooleanDataset)mask);
}
}
}
List<? extends Dataset> dsets = ls.value(data);
if (dsets == null)
return null;
profiles[0] = dsets.get(0);
if (lroi.isCrossHair()) {
spt = lroi.getPerpendicularBisectorPoint(0.0);
ept = lroi.getPerpendicularBisectorPoint(1.0);
LineSample bls = new LineSample(spt[0], spt[1], ept[0], ept[1], step);
dsets = bls.value(data);
if (dsets != null)
profiles[1] = dsets.get(0);
}
return profiles;
}
private static void clippingCompensate(IDataset data, IDataset mask, Dataset[] profiles,
DatasetToDatasetFunction map) {
// normalise plot for case when region is clipped to size of image
// and/or when a mask is specified
if (mask == null) {
mask = DatasetFactory.ones(data.getShape(), Dataset.BOOL);
}
List<? extends IDataset> dsets = map.value(mask);
IDataset nintx = dsets.get(1);
IDataset ninty = dsets.get(0);
// calculate fraction in each element that was not clipped
nintx = Maths.dividez(nintx, dsets.get(3));
ninty = Maths.dividez(ninty, dsets.get(2));
profiles[0] = Maths.dividez(profiles[0], nintx);
profiles[1] = Maths.dividez(profiles[1], ninty);
}
/**
* @param data
* @param rroi
* @return box profile
*/
public static Dataset[] box(Dataset data, RectangularROI rroi) {
return box(data, null, rroi);
}
/**
* @param data
* @param mask
* used for clipping compensation (can be null)
* @param rroi
* @return box profile
*/
public static Dataset[] box(Dataset data, Dataset mask, RectangularROI rroi) {
return box(data, mask, rroi, false);
}
/**
* @param data
* @param mask
* used for clipping compensation (can be null)
* @param rroi
* @param maskWithNans - normally masked pixels will use a multiply with 0 to mask. The plotting
* deals with NaNs however, in this case we can set maskWithNans true and masked
* pixels are NaN instead of 0.
* @return box profile
*/
public static Dataset[] box(Dataset data, Dataset mask, RectangularROI rroi, boolean maskWithNans) {
int[] spt = rroi.getIntPoint();
int[] len = rroi.getIntLengths();
double ang = rroi.getAngle();
boolean clip = rroi.isClippingCompensation();
Dataset[] profiles = new Dataset[] { null, null };
if (len[0] == 0)
len[0] = 1;
if (len[1] == 0)
len[1] = 1;
if (ang == 0.0) {
final int xstart = Math.max(0, spt[0]);
final int xend = Math.min(spt[0] + len[0], data.getShape()[1]);
final int ystart = Math.max(0, spt[1]);
final int yend = Math.min(spt[1] + len[1], data.getShape()[0]);
// We slice down data to reduce the work the masking and the integrate needs to do.
// TODO Does this always work? This makes large images profile better...
Dataset slicedData = null;
try {
slicedData = data.getSlice(new int[]{ystart, xstart},
new int[]{yend, xend},
new int[]{1,1});
} catch (Exception ne) {
// We cannot process the profiles for a region totally outside the image!
return null;
}
final Dataset slicedMask = mask!=null
? mask.getSlice(new int[]{ystart, xstart},
new int[]{yend, xend},
new int[]{1,1})
: null;
if (slicedMask != null && slicedData != null) {
if (slicedData.isCompatibleWith(slicedMask)) {
clip = true;
if (!maskWithNans || !(slicedMask instanceof BooleanDataset)) {
slicedData = Maths.multiply(slicedData, slicedMask);
} else {
// Masks values to NaN, also changes dtype to Float
slicedData = nanalize(slicedData, (BooleanDataset)slicedMask);
}
}
}
if (slicedData==null){
slicedData = data;
}
Integrate2D int2d = new Integrate2D(0, 0, Math.min(len[0], data.getShape()[1]), Math.min(len[1], data.getShape()[0]));
List<? extends Dataset> dsets = int2d.value(slicedData);
if (dsets == null) return null;
profiles[0] = maskWithNans
? processColumnNans(dsets.get(1), slicedData)
: dsets.get(1);
profiles[1] = maskWithNans
? processRowNans(dsets.get(0), slicedData)
: dsets.get(0);
} else {
if (mask != null && data != null) {
if (data.isCompatibleWith(mask)) {
clip = true;
// TODO both multiply and nanalize create copies of the whole data passed in
if (!maskWithNans || !(mask instanceof BooleanDataset)) {
data = Maths.multiply(data, mask);
} else {
// Masks values to NaN, also changes dtype to Float
data = nanalize(data, (BooleanDataset)mask);
}
}
}
MapToRotatedCartesianAndIntegrate rcmapint = new MapToRotatedCartesianAndIntegrate(spt[0], spt[1], len[0],
len[1], ang, false);
List<? extends Dataset> dsets = rcmapint.value(data);
if (dsets == null)
return null;
profiles[0] = dsets.get(1);
profiles[1] = dsets.get(0);
if (clip) {
clippingCompensate(data, mask, profiles, rcmapint);
}
}
return profiles;
}
/**
* Returns the mean of the dataset given a RectangularROI
* @param data
* @param mask
* used for clipping compensation (can be null)
* @param rroi
* @param maskWithNans - normally masked pixels will use a multiply with 0 to mask. The plotting
* deals with NaNs however, in this case we can set maskWithNans true and masked
* pixels are NaN instead of 0.
* @return box profile
*/
public static Dataset[] boxMean(Dataset data, Dataset mask, RectangularROI rroi, boolean maskWithNans) {
if(data == null) return null;
double[] spoint = rroi.getPoint();
double[] leng = rroi.getLengths();
int[] spt = new int[] { (int) Math.round(spoint[0]), (int) Math.round(spoint[1]) };
int[] len = new int[] { (int) Math.round(leng[0]), (int) Math.round(leng[1]) };
double ang = rroi.getAngle();
boolean clip = rroi.isClippingCompensation();
Dataset[] profiles = new Dataset[] { null, null };
if (len[0] == 0)
len[0] = 1;
if (len[1] == 0)
len[1] = 1;
if (ang == 0.0) {
final int xtart = Math.max(0, spt[1]);
final int xend = Math.min(spt[1] + len[1], data.getShape()[0]);
final int ystart = Math.max(0, spt[0]);
final int yend = Math.min(spt[0] + len[0], data.getShape()[1]);
// We slice down data to reduce the work the masking and the integrate needs to do.
// TODO Does this always work? This makes large images profile better...
Dataset slicedData = null;
try {
slicedData = data.getSlice(new int[]{xtart, ystart},
new int[]{xend, yend},
new int[]{1,1});
} catch (Exception ne) {
// We cannot process the profiles for a region totally outside the image!
return null;
}
final Dataset slicedMask = mask!=null
? mask.getSlice(new int[]{xtart, ystart},
new int[]{xend, yend},
new int[]{1,1})
: null;
if (slicedMask != null && slicedData != null) {
if (slicedData.isCompatibleWith(slicedMask)) {
clip = true;
if (!maskWithNans || !(slicedMask instanceof BooleanDataset)) {
} else {
// Masks values to NaN, also changes dtype to Float
slicedData = nanalize(slicedData, (BooleanDataset)slicedMask);
}
}
}
if (slicedData==null){
slicedData = data;
}
Integrate2D int2d = new Integrate2D(0, 0, Math.min(len[0], data.getShape()[1]), Math.min(len[1], data.getShape()[0]));
List<? extends Dataset> dsets = int2d.value(slicedData);
if (dsets == null) return null;
profiles[0] = slicedData.mean(0);
profiles[1] = slicedData.mean(1);
} else {
if (mask != null) {
if (data.isCompatibleWith(mask)) {
clip = true;
// TODO both multiply and nanalize create copies of the whole data passed in
if (!maskWithNans || !(mask instanceof BooleanDataset)) {
} else {
// Masks values to NaN, also changes dtype to Float
data = nanalize(data, (BooleanDataset)mask);
}
}
}
MapToRotatedCartesianAndIntegrate rcmapint = new MapToRotatedCartesianAndIntegrate(spt[0], spt[1], len[0],
len[1], ang, false);
List<? extends Dataset> dsets = rcmapint.value(data);
if (dsets == null)
return null;
profiles[0] = dsets.get(1).mean(0);
profiles[1] = dsets.get(0).mean(1);
if (clip) {
clippingCompensate(data, mask, profiles, rcmapint);
}
}
return profiles;
}
/**
* @param data
* @param mask
* used for clipping compensation (can be null)
* @param rroi
* @return max in box profile
*/
public static Dataset[] maxInBox(Dataset data, Dataset mask, RectangularROI rroi) {
return maxInBox(data, mask, rroi, false);
}
/**
* @param data
* @param mask
* used for clipping compensation (can be null)
* @param rroi
* @param maskWithNans - normally masked pixels will use a multiply with 0 to mask. The plotting
* deals with NaNs however, in this case we can set maskWithNans true and masked
* pixels are NaN instead of 0.
* @return max in box profile
*/
public static Dataset[] maxInBox(Dataset data, Dataset mask, RectangularROI rroi, boolean maskWithNans) {
int[] spt = rroi.getIntPoint();
int[] len = rroi.getIntLengths();
double ang = rroi.getAngle();
boolean clip = rroi.isClippingCompensation();
Dataset[] profiles = new Dataset[] { null, null };
if (len[0] == 0)
len[0] = 1;
if (len[1] == 0)
len[1] = 1;
if (ang == 0.0) {
final int xtart = Math.max(0, spt[1]);
final int xend = Math.min(spt[1] + len[1], data.getShape()[0]);
final int ystart = Math.max(0, spt[0]);
final int yend = Math.min(spt[0] + len[0], data.getShape()[1]);
// We slice down data to reduce the work the masking and the integrate needs to do.
// TODO Does this always work? This makes large images profile better...
Dataset slicedData = null;
try {
slicedData = data.getSlice(new int[]{xtart, ystart},
new int[]{xend, yend},
new int[]{1,1});
} catch (Exception ne) {
// We cannot process the profiles for a region totally outside the image!
return null;
}
final Dataset slicedMask = mask!=null
? mask.getSlice(new int[]{xtart, ystart},
new int[]{xend, yend},
new int[]{1,1})
: null;
if (slicedMask != null && slicedData != null) {
if (slicedData.isCompatibleWith(slicedMask)) {
clip = true;
if (!maskWithNans || !(slicedMask instanceof BooleanDataset)) {
slicedData = Maths.multiply(slicedData, slicedMask);
} else {
// Masks values to NaN, also changes dtype to Float
slicedData = nanalize(slicedData, (BooleanDataset)slicedMask);
}
}
}
if (slicedData==null){
slicedData = data;
}
List<Dataset> dsets = new ArrayList<Dataset>();
dsets.add(DatasetUtils.convertToDataset(slicedData.max(1)));
dsets.add(DatasetUtils.convertToDataset(slicedData.max(0)));
profiles[0] = maskWithNans
? processColumnNans(dsets.get(1), slicedData)
: dsets.get(1);
profiles[1] = maskWithNans
? processRowNans(dsets.get(0), slicedData)
: dsets.get(0);
} else {
if (mask != null && data != null) {
if (data.isCompatibleWith(mask)) {
clip = true;
// TODO both multiply and nanalize create copies of the whole data passed in
if (!maskWithNans || !(mask instanceof BooleanDataset)) {
data = Maths.multiply(data, mask);
} else {
// Masks values to NaN, also changes dtype to Float
data = nanalize(data, (BooleanDataset)mask);
}
}
}
MapToRotatedCartesianAndIntegrate rcmapint = new MapToRotatedCartesianAndIntegrate(spt[0], spt[1], len[0],
len[1], ang, false);
List<? extends Dataset> dsets = rcmapint.maxValue(data);
if (dsets == null)
return null;
profiles[0] = dsets.get(1);
profiles[1] = dsets.get(0);
if (clip) {
clippingCompensate(data, mask, profiles, rcmapint);
}
}
return profiles;
}
/**
* @param data
* @param mask
* used for clipping compensation (can be null)
* @param rroi
* @param maskWithNans - normally masked pixels will use a multiply with 0 to mask. The plotting
* deals with NaNs however, in this case we can set maskWithNans true and masked
* pixels are NaN instead of 0.
* @param isVertical
* @return box line profiles
*/
public static Dataset[] boxLine(Dataset data, Dataset mask, RectangularROI rroi, boolean maskWithNans, boolean isVertical) {
double[] startpt = rroi.getPoint();
double[] endpt = rroi.getEndPoint();
Dataset[] profiles = new Dataset[] { null, null };
// get the left and right side line profile of the rectangle
double[] righttoppt = { new Double(endpt[0]), new Double(startpt[1]) };
double[] leftbottompt = { new Double(startpt[0]), new Double(endpt[1]) };
LinearROI line1 = null, line2 = null;
if (isVertical) {
line1 = new LinearROI(startpt, leftbottompt);
line2 = new LinearROI(righttoppt, endpt);
} else {
line1 = new LinearROI(startpt, righttoppt);
line2 = new LinearROI(leftbottompt, endpt);
}
Dataset[] lineProfiles = ROIProfile.line(data, mask, line1, 1d, maskWithNans);
profiles[0] = lineProfiles != null ? lineProfiles[0] : null;
if(profiles[0] == null) return null;
lineProfiles = ROIProfile.line(data, mask, line2, 1d, maskWithNans);
profiles[1] = lineProfiles != null ? lineProfiles[0] : null;
if(profiles[1] == null) return null;
return profiles;
}
/**
* This method will nanalize any data which the mask has set to false. NOTE
* the data and the mask must be precisely the same in size and value order.
*
* No compatibility test is done for speed reasons, instead a failure will occur
* during the nanalise operation.
*
* It always returns a FloatDataset for speed and size reasons, this being the
* smallest Dtype which allows NaNs.
*
*
* @param data
* @param mask
* @return clone of dataset with NaNs at the appropriate place.
*/
public static FloatDataset nanalize(Dataset data, BooleanDataset mask) {
FloatDataset nanalized = DatasetFactory.zeros(FloatDataset.class, data.getShape());
float[] buffer = nanalized.getData();
IndexIterator it = data.getIterator();
for (int i = 0; it.hasNext(); i++) {
buffer[i] = mask.getElementBooleanAbs(i) // assumes mask is not a view
? (float) data.getElementDoubleAbs(it.index) // NOTE: Do not round, just lose precision.
: Float.NaN;
}
return nanalized;
}
private static Dataset processColumnNans(Dataset cols, Dataset data) {
MAIN_LOOP: for (int i = 0; i < cols.getSize(); i++) {
for (int j = 0, jmax = data.getShape()[0]; j < jmax; j++) {
if (!Float.isNaN(data.getFloat(j, i))) continue MAIN_LOOP;
}
cols.set(Float.NaN, i);
}
return cols;
}
private static Dataset processRowNans(Dataset rows, Dataset data) {
MAIN_LOOP: for (int i = 0; i < rows.getSize(); i++) {
for (int j = 0, jmax = data.getShape()[1]; j < jmax; j++) {
if (!Float.isNaN(data.getFloat(i, j))) continue MAIN_LOOP;
}
rows.set(Float.NaN, i);
}
return rows;
}
/**
* @param data
* @param sroi
* @return box profile
*/
public static Dataset[] sector(Dataset data, SectorROI sroi) {
return sector(data, null, sroi, null);
}
/**
* @param data
* @param sroi
* @return box profile
*/
public static Dataset[] sector(Dataset data, Dataset mask, SectorROI sroi) {
return sector(data, mask, sroi, true, true, false, null, null, false);
}
/**
* @param data
* @param sroi
* @return box profile
*/
public static Dataset[] sector(Dataset data, Dataset mask, SectorROI sroi, QSpace qSpace) {
return sector(data, mask, sroi, true, true, false, qSpace, null, false);
}
/**
* @param data
* @param mask
* used for clipping compensation (can be null)
* @param sroi
* @param useInterpolateFJ
* uses interpolation and fork/join which might make things faster
* @return sector profile
*/
public static Dataset[] sector(Dataset data, Dataset mask, SectorROI sroi, boolean doRadial, boolean doAzimuthal, boolean useInterpolateFJ) {
return sector(data, mask, sroi, doRadial, doAzimuthal, useInterpolateFJ, null, null, false);
}
/**
*
* @param data
* @param mask
* used for clipping compensation (can be null)
* @param sroi
*
* @param doRadial
* @param doAzimuthal
* @param useInterpolateFJ
* uses interpolation and fork/join which might make things faster
* @param qSpace
* @param axisType
* @param doErrors
* @return
* the profile
*/
public static Dataset[] sector(Dataset data, Dataset mask, SectorROI sroi, boolean doRadial, boolean doAzimuthal, boolean useInterpolateFJ, QSpace qSpace, XAxis axisType, boolean doErrors) {
final double[] spt = sroi.getPointRef();
final double[] rad = sroi.getRadii();
final double[] ang = sroi.getAngles();
int symmetry = sroi.getSymmetry();
boolean clip = sroi.isClippingCompensation();
boolean aver = sroi.isAverageArea();
double dpp = sroi.getDpp();
Dataset[] profiles = new Dataset[8];
Dataset[] errors = new Dataset[8];
if (Math.abs(rad[0] - rad[1]) < 1) {
return null;
}
if (symmetry == SectorROI.FULL) {
MapToPolarAndIntegrate pmapfint = new MapToPolarAndIntegrate(spt[0], spt[1], rad[0], ang[0], rad[1], ang[0]
+ 2 * Math.PI, dpp, false);
if (mask != null && mask.isCompatibleWith(data)) {
pmapfint.setMask(mask);
}
pmapfint.setClip(clip);
pmapfint.setInterpolate(!useInterpolateFJ);
pmapfint.setDoRadial(doRadial);
pmapfint.setDoAzimuthal(doAzimuthal);
pmapfint.setQSpace(qSpace, axisType);
pmapfint.setDoErrors(doErrors);
List<? extends Dataset> dsetsf = pmapfint.value(data);
if (dsetsf == null) {
return null;
}
if (aver) {
final SectorROI areaSector = sroi.copy();
areaSector.setAverageArea(false);
Dataset[] areas = sector(mask != null ? mask : DatasetFactory.ones(data), null,
areaSector, doRadial, doAzimuthal, useInterpolateFJ, qSpace, axisType, false);
profiles[0] = Maths.dividez(dsetsf.get(1), areas[0]);
profiles[1] = Maths.dividez(dsetsf.get(0), areas[1]);
if (doErrors) {
errors[0] = Maths.dividez(dsetsf.get(1).getErrorBuffer(), areas[0].ipower(2));
errors[1] = Maths.dividez(dsetsf.get(0).getErrorBuffer(), areas[1].ipower(2));
profiles[0].setErrorBuffer(errors[0]);
profiles[1].setErrorBuffer(errors[1]);
}
} else {
profiles[0] = dsetsf.get(1);
profiles[1] = dsetsf.get(0);
}
if (dsetsf.size() >= 6) {
profiles[4] = dsetsf.get(5);
profiles[5] = dsetsf.get(4);
}
return profiles;
}
if (Math.abs(ang[0] - ang[1]) < 1e-2) {
return null;
}
MapToPolarAndIntegrate pmapint = new MapToPolarAndIntegrate(spt[0], spt[1], rad[0], ang[0], rad[1], ang[1],
dpp, false);
if (mask != null && data != null && mask.isCompatibleWith(data)) {
pmapint.setMask(mask);
}
pmapint.setClip(clip);
pmapint.setInterpolate(!useInterpolateFJ);
pmapint.setDoRadial(doRadial);
pmapint.setDoAzimuthal(doAzimuthal);
pmapint.setQSpace(qSpace, axisType);
pmapint.setDoErrors(doErrors);
List<? extends Dataset> dsets = pmapint.value(data);
if (dsets == null) {
return null;
}
profiles[0] = dsets.get(1);
profiles[1] = dsets.get(0);
if (doErrors) { // TODO check if errors are datasets
errors[0] = profiles[0].getErrorBuffer();
errors[1] = profiles[1].getErrorBuffer();
}
if (dsets.size() >= 6) {
profiles[4] = dsets.get(5);
profiles[5] = dsets.get(4);
}
if (symmetry != SectorROI.NONE) {
double[] nang = sroi.getSymmetryAngles();
MapToPolarAndIntegrate pmapsint = new MapToPolarAndIntegrate(spt[0], spt[1], rad[0], nang[0], rad[1],
nang[1], dpp, false);
if (mask != null && data != null && mask.isCompatibleWith(data)) {
pmapsint.setMask(mask);
}
pmapsint.setClip(clip);
pmapsint.setInterpolate(!useInterpolateFJ);
pmapsint.setDoRadial(doRadial);
pmapsint.setDoAzimuthal(doAzimuthal);
pmapsint.setQSpace(qSpace, axisType);
pmapsint.setDoErrors(doErrors);
List<? extends Dataset> dsetss = pmapsint.value(data);
if (dsetss != null) {
if (sroi.isCombineSymmetry()) {
profiles[0] = Maths.add(profiles[0], dsetss.get(1));
profiles[1] = Maths.add(profiles[1], dsetss.get(0));
if (doErrors) {
errors[0] = Maths.add(errors[0], dsetss.get(1).getErrorBuffer());
errors[1] = Maths.add(errors[1], dsetss.get(0).getErrorBuffer());
}
} else {
profiles[2] = dsetss.get(1);
profiles[3] = dsetss.get(0);
if (doErrors) { // TODO check if errors are datasets
errors[2] = profiles[2].getErrorBuffer();
errors[3] = profiles[3].getErrorBuffer();
}
if (dsetss.size() >= 6) {
profiles[6] = dsetss.get(5);
profiles[7] = dsetss.get(4);
}
}
}
}
if (aver) {
final SectorROI areaSector = sroi.copy();
areaSector.setAverageArea(false);
Dataset[] areas = sector(mask != null ? mask : DatasetFactory.ones(data), null,
areaSector, doRadial, doAzimuthal, useInterpolateFJ, qSpace, axisType, false);
for (int i = 0; i < 4; i++) {
if (profiles[i] != null && areas[i] != null) {
Maths.dividez(profiles[i], areas[i], profiles[i]);
if (doErrors) {
Maths.dividez(errors[i], areas[i].ipower(2), errors[i]);
profiles[i].setErrorBuffer(errors[i]);
}
}
}
}
return profiles;
}
/**
* Calculate area values of the selected sector region in pixels.
*
* @param shape
* image dimensions
* @param sroi
* @return sector profile
*/
public static Dataset[] area(int[] shape, int dtype, SectorROI sroi) {
return area(shape, dtype, null, sroi);
}
/**
* Calculate area values of the selected sector region in pixels.
*
* @param shape
* image dimensions
* @param mask
* used for clipping compensation (can be null)
* @param sroi
* @return sector profile
*/
public static Dataset[] area(int[] shape, int dtype, Dataset mask, SectorROI sroi) {
return area(shape, dtype, mask, sroi, true, true, false);
}
/**
* Calculate area values of the selected sector region in pixels.
*
* @param shape
* image dimensions
* @param mask
* used for clipping compensation (can be null)
* @param sroi
* @return sector profile
*/
public static Dataset[] area(int[] shape, int dtype, Dataset mask, SectorROI sroi, boolean doRadial, boolean doAzimuthal, boolean fast) {
//TODO: This method only works on pixel axis. It can't be use for normalising data on non-pixel axes (e.g q-space, d-spacing).
final SectorROI areaSector = sroi.copy();
areaSector.setAverageArea(false);
return sector(mask != null ? mask : DatasetFactory.ones(shape, dtype), null, areaSector, doRadial, doAzimuthal, fast);
}
}