All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.actelion.research.orbit.imageAnalysis.features.TissueFeaturesOld Maven / Gradle / Ivy

Go to download

Orbit, a versatile image analysis software for biological image-based quantification

There is a newer version: 3.15
Show newest version
/*
 *     Orbit, a versatile image analysis software for biological image-based quantification.
 *     Copyright (C) 2009 - 2018 Idorsia Pharmaceuticals Ltd., Hegenheimermattweg 91, CH-4123 Allschwil, Switzerland.
 *
 *     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.
 *
 *     This program is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU General Public License for more details.
 *
 *     You should have received a copy of the GNU General Public License
 *     along with this program.  If not, see .
 *
 */

package com.actelion.research.orbit.imageAnalysis.features;

import com.actelion.research.orbit.exceptions.OrbitImageServletException;
import com.actelion.research.orbit.imageAnalysis.models.FeatureDescription;
import com.actelion.research.orbit.imageAnalysis.utils.TiledImagePainter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.awt.*;
import java.awt.image.Raster;

/**
 * Old version (for backward compatibility)
 * Attention: This class is not thread-safe!!!
* Channel usage (useRed,useGreen,useBlue) is treated in feats[] assignment loop - all samples are calculated! */ public class TissueFeaturesOld { private final static Logger logger = LoggerFactory.getLogger(TissueFeaturesOld.class); private static double EPSILON = 0.00000001d; private int featuresPerSample = 6; private int samples = 3; private int windowSize = 4; private int[] buf = null; private double[] pix = null; private double[] mean = null; private double[] min = null; private double[] max = null; private double[] sd = null; private double[] edge = null; // edge intensity per sample private TiledImagePainter bimg = null; private int[] p = new int[4]; // buffer of one pixel up to 4 samples private int featureSet = FeatureDescription.FEATURE_SET_PIX_MEAN_MIN_MAX_SD_EDGE; private FeatureDescription featureDescription = null; /** * bimg can be null (then raster r in buildFeatures cannot be null) */ public TissueFeaturesOld(final FeatureDescription featureDescription, final TiledImagePainter bimg) { this.samples = featureDescription.getSampleSize(); this.windowSize = featureDescription.getWindowSize(); this.featureSet = featureDescription.getFeatureSet(); this.featureDescription = featureDescription; this.bimg = bimg; buf = new int[(windowSize * 2 + 1) * (windowSize * 2 + 1) * samples]; pix = new double[samples]; mean = new double[samples]; min = new double[samples]; max = new double[samples]; sd = new double[samples]; edge = new double[samples]; if (featureSet == FeatureDescription.FEATURE_SET_INTENS) featuresPerSample = 1; else if (featureSet == FeatureDescription.FEATURE_SET_PIX_MEAN_MIN_MAX_SD) featuresPerSample = 5; else featuresPerSample = 6; // with edge } /** * Initializes a double array of a sufficient size given the feature description. * * @return */ public double[] prepareDoubleArray() { return new double[(windowSize * 2 + 1) * (windowSize * 2 + 1) * samples + 1]; // +1 for contextclassification??? } /** * computes tissue features (mean,min,max,sd of each sample (r,g,b or grey)).
* Not thread-safe!!! * * @param r can be null (then bimg cannot be null in the constructor) * @param x * @param y * @param classVal (set to Double.NaN for classification) * @return * @throws OrbitImageServletException */ public double[] buildFeatures(final Raster r, final int x, final int y, final double classVal) throws OrbitImageServletException { if (featureSet == FeatureDescription.FEATURE_SET_INTENS) return buildIntensFeatures(r, x, y, classVal); // init for (int i = 0; i < samples; i++) { mean[i] = 0d; min[i] = Double.NaN; max[i] = Double.NaN; sd[i] = 0d; } if (r != null) // faster if raster is pre-assigned (e.g. the shape fits into memory) { buf = r.getPixels(x - windowSize, y - windowSize, (windowSize * 2) + 1, (windowSize * 2) + 1, buf); p = r.getPixel(x, y, p); // mid-pixel } else { // slower, but works for very large shapes Raster r2 = bimg.getData(new Rectangle(x - windowSize, y - windowSize, (windowSize * 2) + 1, (windowSize * 2) + 1), featureDescription); if (r2 == null) System.out.println("r2 is null!!"); buf = r2.getPixels(x - windowSize, y - windowSize, (windowSize * 2) + 1, (windowSize * 2) + 1, buf); p = r2.getPixel(x, y, p); } // middle pixel for (int i = 0; i < samples; i++) pix[i] = p[i]; // Remark: System.arraycopy() does not work here because pix is double[] and p is int[]! //int[] p = new int[4]; // r,g,b,alpha (if available) int cnt = 0; // BUG: should be 1 int bufPos = 0; //try { //for (int px=x-windowSize; px<=x+windowSize; px++) // for (int py=y-windowSize; py<=y+windowSize; py++) while (bufPos < buf.length - samples) { //if (r!=null) //p = r.getPixel(px, py, p); // better use getPixels()... //else p = bimg.getPixels(px, py, windowSize, p); //int d = Math.max(Math.abs(px-x), Math.abs(py-y)); // use it as weights for (int i = 0; i < samples; i++) { // BUG: correct would be only one bufPos++ in this for loop. Fixed in // new TissueFeatures but kept here for backward compatibility mean[i] += buf[bufPos]; bufPos++; if (Double.isNaN(min[i]) || (min[i] > buf[bufPos])) min[i] = buf[bufPos]; bufPos++; if (Double.isNaN(max[i]) || (max[i] < buf[bufPos])) max[i] = buf[bufPos]; bufPos++; } cnt++; } //} catch (Exception e) {e.printStackTrace(); } if (cnt > 0) for (int i = 0; i < samples; i++) { if (mean[i] > 0) mean[i] /= (double) cnt; } // sd and edge cnt = 0; bufPos = 0; //for (int px=x-windowSize; px<=x+windowSize; px++) // for (int py=y-windowSize; py<=y+windowSize; py++) while (bufPos < buf.length) { //p = r.getPixel(px, py, p); // better use getPixels()... //int d = Math.max(Math.abs(px-x), Math.abs(py-y)); // use it as weights for (int i = 0; i < samples; i++) { //sd[i] += (mean[i]-p[i]) * (mean[i]-p[i]); sd[i] += (mean[i] - buf[bufPos]) * (mean[i] - buf[bufPos]); //bufPos++; edge[i] += (pix[i] - buf[bufPos]) * (pix[i] - buf[bufPos]); bufPos++; } cnt++; } for (int i = 0; i < samples; i++) { if (cnt > 1) { sd[i] /= (double) (cnt - 1); if (sd[i] > EPSILON) { sd[i] = Math.sqrt(sd[i]); } else sd[i] = Double.NaN; edge[i] /= (double) (cnt - 1); if (edge[i] > EPSILON) { edge[i] = Math.sqrt(edge[i]); } else edge[i] = Double.NaN; } else { sd[i] = Double.NaN; edge[i] = Double.NaN; } } // store features double[] feats = new double[featuresPerSample * samples + 1]; for (int i = 0; i < samples; i++) { if ((i == 0) && (featureDescription.isSkipRed())) continue; if ((i == 1) && (featureDescription.isSkipGreen())) continue; if ((i == 2) && (featureDescription.isSkipBlue())) continue; feats[(samples * 0) + i] = pix[i]; feats[(samples * 1) + i] = mean[i]; feats[(samples * 2) + i] = min[i]; feats[(samples * 3) + i] = max[i]; feats[(samples * 4) + i] = sd[i]; if (featureSet >= FeatureDescription.FEATURE_SET_PIX_MEAN_MIN_MAX_SD_EDGE) feats[(samples * 5) + i] = edge[i]; } feats[feats.length - 1] = classVal; //logger.trace(feats.toString()); return feats; } private double[] buildIntensFeatures(final Raster r, final int x, final int y, final double classVal) throws OrbitImageServletException { // init for (int i = 0; i < samples; i++) { mean[i] = 0d; } if (r != null) // faster if raster is pre-assigned (e.g. the shape fits into memory) { buf = r.getPixels(x - windowSize, y - windowSize, (windowSize * 2) + 1, (windowSize * 2) + 1, buf); p = r.getPixel(x, y, p); // mid-pixel } else { // slower, but works for very large shapes Raster r2 = bimg.getData(new Rectangle(x - windowSize, y - windowSize, (windowSize * 2) + 1, (windowSize * 2) + 1), featureDescription); if (r2 == null) System.out.println("r2 is null!!"); buf = r2.getPixels(x - windowSize, y - windowSize, (windowSize * 2) + 1, (windowSize * 2) + 1, buf); p = r2.getPixel(x, y, p); } for (int i = 0; i < samples; i++) { mean[0] += p[i]; } mean[0] /= (double) samples; double[] feats = new double[featuresPerSample * samples + 1]; for (int i = 0; i < samples; i++) { if ((i == 0) && (featureDescription.isSkipRed())) continue; if ((i == 1) && (featureDescription.isSkipGreen())) continue; if ((i == 2) && (featureDescription.isSkipBlue())) continue; feats[(samples * 0) + i] = mean[i]; } feats[feats.length - 1] = classVal; //logger.trace(Arrays.toString(feats)); return feats; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy