private double getMin(ImageServiceBean bean) { if (bean.getMinimumCutBound() == null || bean.getMinimumCutBound().getBound() == null) { return bean.getMin().doubleValue(); } return Math.max( bean.getMin().doubleValue(), bean.getMinimumCutBound().getBound().doubleValue()); }
/** * Get the logged image value and cache the result. * * @param bean * @return a dataset that can be absolute, if complex, and also be logged according to bean * Package private for testing */ /* package */ Dataset getImageLoggedData(ImageServiceBean bean) { Dataset ret = DatasetUtils.convertToDataset(bean.getImageValue()); if (ret == null) { ret = getImageLoggedDataCalc(bean); bean.setImageValue(ret); } return ret; }
private void createMaxMin(ImageServiceBean bean) { double[] stats = null; if (bean.getMin() == null) { if (stats == null) stats = getFastStatistics(bean); // do not get unless have to bean.setMin(stats[0]); } if (bean.getMax() == null) { if (stats == null) stats = getFastStatistics(bean); // do not get unless have to bean.setMax(stats[1]); } }
/** * Get the logged image value. * * @param bean * @return a dataset that can be absolute, if complex, and also be logged according to bean * Package private for testing */ /* package */ Dataset getImageLoggedDataCalc(ImageServiceBean bean) { Dataset ret = DatasetUtils.convertToDataset(bean.getImage()); if (ret.isComplex()) { ret = Maths.abs(ret); } if (bean.isLogColorScale()) { double offset = bean.getLogOffset(); if (!Double.isNaN(offset) && !Double.isInfinite(offset)) { ret = Maths.subtract(ret, offset); } ret = Maths.log10(ret); } return ret; }
/** * getImageData(...) provides an image in a given palette data and origin. Faster than getting a * resolved image * * <p>This method should be thread safe. */ public ImageData getImageData(ImageServiceBean bean) { ImageOrigin origin = bean.getOrigin(); if (origin == null) origin = ImageOrigin.TOP_LEFT; // orientate the image Dataset oImage = DatasetUtils.rotate90(DatasetUtils.convertToDataset(bean.getImage()), origin.ordinal()); Dataset image = oImage; if (image instanceof RGBDataset) { return SWTImageUtils.createImageData( (RGBDataset) image, 0, 255, null, null, null, false, false, false); } createMaxMin(bean); double max = getMax(bean); double min = getMin(bean); double maxCut = getMaxCut(bean); double minCut = getMinCut(bean); // now deal with the log if needed if (bean.isLogColorScale()) { image = DatasetUtils.rotate90(getImageLoggedData(bean), origin.ordinal()); max = Math.log10(max); // note createMaxMin() -> getFastStatistics() -> getImageLogged() which ensures min >= 0 min = Math.log10(min); maxCut = Math.log10(maxCut); // no guarantees for minCut though minCut = minCut <= 0 ? Double.NEGATIVE_INFINITY : Math.log10(minCut); } if (oImage.isComplex()) { // handle complex datasets by creating RGB dataset Dataset hue = Maths.angle(oImage, true); Dataset value = DatasetUtils.rotate90(getImageLoggedData(bean), origin.ordinal()); double maxmax = Math.max(Math.abs(max), Math.abs(min)); if (max - min > Math.ulp(maxmax)) { value.isubtract(min); value.imultiply(1. / (max - min)); } else { value.imultiply(1. / maxmax); } image = RGBDataset.createFromHSV(hue, null, value); return SWTImageUtils.createImageData(image, 0, 255, null, null, null, false, false, false); } if (bean.getFunctionObject() != null && bean.getFunctionObject() instanceof FunctionContainer) { final FunctionContainer fc = (FunctionContainer) bean.getFunctionObject(); // TODO This does not support masking or cut bounds for zingers and dead pixels. return SWTImageUtils.createImageData( image, min, max, fc.getRedFunc(), fc.getGreenFunc(), fc.getBlueFunc(), fc.isInverseRed(), fc.isInverseGreen(), fc.isInverseBlue()); } return SWTImageUtils.createImageData(min, max, minCut, maxCut, image, bean); }
@Override public ImageServiceBean createBeanFromPreferences() { ImageServiceBean imageServiceBean = new ImageServiceBean(); if (Platform.getPreferencesService() != null) { // Normally IPreferenceStore store = new ScopedPreferenceStore(InstanceScope.INSTANCE, "org.dawnsci.plotting"); imageServiceBean.setOrigin( ImageOrigin.forLabel(store.getString(BasePlottingConstants.ORIGIN_PREF))); imageServiceBean.setHistogramType( HistoType.forLabel(store.getString(BasePlottingConstants.HISTO_PREF))); imageServiceBean.setMinimumCutBound( HistogramBound.fromString(store.getString(BasePlottingConstants.MIN_CUT))); imageServiceBean.setMaximumCutBound( HistogramBound.fromString(store.getString(BasePlottingConstants.MAX_CUT))); imageServiceBean.setNanBound( HistogramBound.fromString(store.getString(BasePlottingConstants.NAN_CUT))); imageServiceBean.setLo(store.getDouble(BasePlottingConstants.HISTO_LO)); imageServiceBean.setHi(store.getDouble(BasePlottingConstants.HISTO_HI)); try { IPaletteService pservice = ServiceLoader.getPaletteService(); if (pservice != null) { final String scheme = store.getString(BasePlottingConstants.COLOUR_SCHEME); if (store.getBoolean(BasePlottingConstants.USE_PALETTE_FUNCTIONS)) { FunctionContainer container = pservice.getFunctionContainer(scheme); if (container != null) { imageServiceBean.setFunctionObject(container); } else { imageServiceBean.setPalette(pservice.getDirectPaletteData(scheme)); } } else { // if 8-bit, set direct palette, otherwise set palette functions. PaletteData pd; try { pd = pservice.getDirectPaletteData(scheme); } catch (final IllegalArgumentException e) { // scheme does not exist final String defaultScheme = pservice.getColorSchemes().iterator().next(); pd = pservice.getDirectPaletteData(defaultScheme); store.setValue(BasePlottingConstants.COLOUR_SCHEME, defaultScheme); } imageServiceBean.setPalette(pd); } } } catch (Exception e) { // Ignored } } else { // Hard code something imageServiceBean.setOrigin(ImageOrigin.TOP_LEFT); imageServiceBean.setHistogramType(HistoType.OUTLIER_VALUES); imageServiceBean.setMinimumCutBound(HistogramBound.DEFAULT_MINIMUM); imageServiceBean.setMaximumCutBound(HistogramBound.DEFAULT_MAXIMUM); imageServiceBean.setNanBound(HistogramBound.DEFAULT_NAN); imageServiceBean.setLo(00.01); imageServiceBean.setHi(99.99); imageServiceBean.setPalette(makeJetPalette()); } return imageServiceBean; }
/** * Fast statistics as a rough guide - this is faster than Dataset.getMin() and getMax() which may * cache but slows the opening of images too much. The return array[2] was added in "Updated for * Diffraction Tool." commit, but no trace of such usage. However it should not be removed, * because it is useful as return array[3]. * * @param bean * @return [0] = min [1] = max(=mean*constant) [2] = mean [3] max */ public double[] getFastStatistics(ImageServiceBean bean) { Dataset image = getImageLoggedData(bean); if (bean.getHistogramType() == HistoType.OUTLIER_VALUES && !bean.isLogColorScale()) { double[] ret = null; try { double[] stats = Stats.outlierValues(image, bean.getLo(), bean.getHi(), -1); ret = new double[] {stats[0], stats[1], -1}; } catch (IllegalArgumentException iae) { bean.setLo(10); bean.setHi(90); double[] stats = Stats.outlierValues(image, bean.getLo(), bean.getHi(), -1); ret = new double[] {stats[0], stats[1], -1}; } if (bean.isLogColorScale() && ret != null) { ret = new double[] {Math.pow(10, ret[0]), Math.pow(10, ret[1]), -1}; } return ret; } double min = Double.MAX_VALUE; double max = -Double.MAX_VALUE; double sum = 0.0; int size = 0; BooleanDataset mask = bean.getMask() != null ? (BooleanDataset) DatasetUtils.cast(bean.getMask(), Dataset.BOOL) : null; // Big loop warning: final IndexIterator it = image.getIterator(); final IndexIterator mit = mask == null ? null : mask.getIterator(); while (it.hasNext()) { final double val = image.getElementDoubleAbs(it.index); if (mit != null && mit.hasNext()) { if (!mask.getElementBooleanAbs(mit.index)) { continue; // Masked! } } if (Double.isNaN(val)) continue; if (!bean.isInBounds(val)) continue; sum += val; if (val < min) min = val; if (val > max) max = val; size++; } double retMax = Double.NaN; double retExtra = Double.NaN; if (bean.getHistogramType() == HistoType.MEDIAN) { double median = Double.NaN; try { median = ((Number) Stats.median(image)).doubleValue(); // SLOW } catch (Exception ne) { median = ((Number) Stats.median(image.cast(Dataset.INT16))).doubleValue(); // SLOWER } retMax = 2 * median; retExtra = median; } else { // Use mean based histo double mean = sum / size; retMax = (Math.E) * mean; // Not statistical, E seems to be better than 3... retExtra = mean; } if (retMax > max) retMax = max; if (bean.isLogColorScale()) { return new double[] {Math.pow(10, min), Math.pow(10, retMax), Math.pow(10, retExtra)}; } return new double[] {min, retMax, retExtra, max}; }
private double getMinCut(ImageServiceBean bean) { if (bean.getMinimumCutBound() == null || bean.getMinimumCutBound().getBound() == null) { return Double.NEGATIVE_INFINITY; } return bean.getMinimumCutBound().getBound().doubleValue(); }