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

io.github.mianalysis.mia.object.Obj Maven / Gradle / Ivy

Go to download

ModularImageAnalysis (MIA) is an ImageJ plugin which provides a modular framework for assembling image and object analysis workflows. Detected objects can be transformed, filtered, measured and related. Analysis workflows are batch-enabled by default, allowing easy processing of high-content datasets.

There is a newer version: 1.6.12
Show newest version
package io.github.mianalysis.mia.object;

import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.Shape;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;

import ij.IJ;
import ij.ImagePlus;
import ij.gui.Roi;
import io.github.mianalysis.mia.object.coordinates.Point;
import io.github.mianalysis.mia.object.coordinates.volume.PointOutOfRangeException;
import io.github.mianalysis.mia.object.coordinates.volume.Volume;
import io.github.mianalysis.mia.object.coordinates.volume.VolumeType;
import io.github.mianalysis.mia.object.image.Image;
import io.github.mianalysis.mia.object.image.ImageFactory;
import io.github.mianalysis.mia.object.units.SpatialUnit;
import io.github.mianalysis.mia.object.units.TemporalUnit;
import io.github.mianalysis.mia.process.exceptions.IntegerOverflowException;
import net.imagej.ImgPlus;
import net.imglib2.type.NativeType;
import net.imglib2.type.numeric.RealType;

/**
 * Created by Stephen on 30/04/2017.
 */
public class Obj extends Volume {
    /**
     * Unique instance ID for this object
     */
    private int ID;

    private int T;

    private Objs objCollection;

    private LinkedHashMap parents = new LinkedHashMap<>();
    private LinkedHashMap children = new LinkedHashMap<>();
    private LinkedHashMap partners = new LinkedHashMap<>();
    private LinkedHashMap measurements = new LinkedHashMap<>();
    private LinkedHashMap metadata = new LinkedHashMap<>();
    private HashMap rois = new HashMap<>();

    // CONSTRUCTORS

    public Obj(Objs objCollection, VolumeType volumeType, int ID) {
        super(volumeType, objCollection.getSpatialCalibration());

        this.objCollection = objCollection;
        this.ID = ID;

    }

    public Obj(Objs objCollection, int ID, Volume exampleVolume) {
        super(exampleVolume.getVolumeType(), exampleVolume.getSpatialCalibration());

        this.objCollection = objCollection;
        this.ID = ID;

    }

    public Obj(Objs objCollection, int ID, Obj exampleObj) {
        super(exampleObj.getVolumeType(), exampleObj.getSpatialCalibration());

        this.objCollection = objCollection;
        this.ID = ID;

    }

    public Obj(Objs objCollection, VolumeType volumeType, int ID, Volume exampleVolume) {
        super(volumeType, exampleVolume.getSpatialCalibration());

        this.objCollection = objCollection;
        this.ID = ID;

    }

    public Obj(Objs objCollection, VolumeType volumeType, int ID, Obj exampleObj) {
        super(volumeType, exampleObj.getSpatialCalibration());

        this.objCollection = objCollection;
        this.ID = ID;

    }

    // PUBLIC METHODS

    public void addMeasurement(Measurement measurement) {
        if (measurement == null)
            return;
        measurements.put(measurement.getName(), measurement);

    }

    public Measurement getMeasurement(String name) {
        if (measurements.get(name) == null)
            return null;

        name = SpatialUnit.replace(name);
        name = TemporalUnit.replace(name);

        return measurements.get(name);

    }

    public void removeMeasurement(String name) {
        name = SpatialUnit.replace(name);
        name = TemporalUnit.replace(name);

        measurements.remove(name);

    }

    public void addMetadataItem(ObjMetadata metadataItem) {
        if (metadataItem == null)
            return;
        metadata.put(metadataItem.getName(), metadataItem);

    }

    public ObjMetadata getMetadataItem(String name) {
        if (metadata.get(name) == null)
            return null;

        name = SpatialUnit.replace(name);
        name = TemporalUnit.replace(name);

        return metadata.get(name);

    }

    public void removeMetadataItem(String name) {
        name = SpatialUnit.replace(name);
        name = TemporalUnit.replace(name);

        metadata.remove(name);

    }

    public Objs getObjectCollection() {
        return objCollection;
    }

    public void setObjectCollection(Objs objCollection) {
        this.objCollection = objCollection;
    }

    public String getName() {
        return objCollection.getName();
    }

    public int getID() {
        return ID;
    }

    public Obj setID(int ID) {
        this.ID = ID;
        return this;
    }

    public int getT() {
        return T;
    }

    public Obj setT(int t) {
        this.T = t;
        return this;
    }

    public LinkedHashMap getParents(boolean useFullHierarchy) {
        if (!useFullHierarchy)
            return parents;

        // Adding each parent and then the parent of that
        LinkedHashMap parentHierarchy = new LinkedHashMap<>(parents);

        // Going through each parent, adding the parents of that.
        for (Obj parent : parents.values()) {
            if (parent == null)
                continue;

            LinkedHashMap currentParents = parent.getParents(true);
            if (currentParents == null)
                continue;

            parentHierarchy.putAll(currentParents);

        }

        return parentHierarchy;

    }

    public void setParents(LinkedHashMap parents) {
        this.parents = parents;
    }

    public Obj getParent(String name) {
        // Split name down by " // " tokenizer
        String[] elements = name.split(" // ");

        // Getting the first parent
        Obj parent = parents.get(elements[0]);

        // If the first parent was the only one listed, returning this
        if (elements.length == 1)
            return parent;

        // If there are additional parents listed, re-constructing the string and
        // running this method on the parent
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 1; i < elements.length; i++) {
            stringBuilder.append(elements[i]);
            if (i != elements.length - 1)
                stringBuilder.append(" // ");
        }

        if (parent == null)
            return null;

        return parent.getParent(stringBuilder.toString());

    }

    public void addParent(Obj parent) {
        parents.put(parent.getName(), parent);
    }

    public void addParent(String name, Obj parent) {
        parents.put(name, parent);
    }

    public void removeParent(String name) {
        parents.remove(name);
    }

    public void removeParent(Obj parent) {
        parents.remove(parent.getName());
    }

    public LinkedHashMap getChildren() {
        return children;
    }

    public Objs getChildren(String name) {
        // Split name down by " // " tokenizer
        String[] elements = name.split(" // ");

        // Getting the first set of children
        Objs allChildren = children.get(elements[0]);
        if (allChildren == null)
            return new Objs(elements[0], objCollection);

        // If the first set of children was the only one listed, returning this
        if (elements.length == 1)
            return allChildren;

        // If there are additional parents listed, re-constructing the string and
        // running this method on the parent
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 1; i < elements.length; i++) {
            stringBuilder.append(elements[i]);
            if (i != elements.length - 1)
                stringBuilder.append(" // ");
        }

        // Going through each child in the current set, then adding all their children
        // to the output set
        Objs outputChildren = new Objs(name, allChildren);
        for (Obj child : allChildren.values()) {
            Objs currentChildren = child.getChildren(stringBuilder.toString());
            for (Obj currentChild : currentChildren.values())
                outputChildren.add(currentChild);
        }

        return outputChildren;

    }

    public void setChildren(LinkedHashMap children) {
        this.children = children;
    }

    public void addChildren(Objs childSet) {
        children.put(childSet.getName(), childSet);
    }

    public void removeChildren(String name) {
        children.remove(name);
    }

    public void addChild(Obj child) {
        String childName = child.getName();

        children.computeIfAbsent(childName, k -> new Objs(childName, child.getObjectCollection()));
        children.get(childName).add(child);

    }

    public void removeChild(Obj child) {
        String childName = child.getName();
        children.get(childName).values().remove(child);

    }

    public LinkedHashMap getPartners() {
        return partners;
    }

    public Objs getPartners(String name) {
        return partners.get(name);
    }

    public void setPartners(LinkedHashMap partners) {
        this.partners = partners;
    }

    public void addPartners(Objs partnerSet) {
        partners.put(partnerSet.getName(), partnerSet);
    }

    public void removePartners(String name) {
        partners.remove(name);
    }

    public void addPartner(Obj partner) {
        String partnerName = partner.getName();

        partners.computeIfAbsent(partnerName, k -> new Objs(partnerName, partner.getObjectCollection()));
        partners.get(partnerName).add(partner);
    }

    public void removePartner(Obj partner) {
        String partnerName = partner.getName();
        partners.get(partnerName).values().remove(partner);

    }

    public void removePartner(String name) {
        partners.remove(name);
    }

    /**
     * Returns any partners that happened in previous frames
     */
    public Objs getPreviousPartners(String name) {
        Objs allPartners = getPartners(name);

        if (allPartners == null)
            return new Objs(name, objCollection);

        Objs previousPartners = new Objs(name, allPartners);
        for (Obj partner : allPartners.values())
            if (partner.getT() < T)
                previousPartners.add(partner);

        return previousPartners;

    }

    /**
     * Returns any partners that happen in following frames
     */
    public Objs getSimultaneousPartners(String name) {
        Objs allPartners = getPartners(name);

        if (allPartners == null)
            return new Objs(name, objCollection);

        Objs simultaneousPartners = new Objs(name, allPartners);
        for (Obj partner : allPartners.values())
            if (partner.getT() == T)
                simultaneousPartners.add(partner);

        return simultaneousPartners;

    }

    /**
     * Returns any partners that happen in following frames
     */
    public Objs getNextPartners(String name) {
        Objs allPartners = getPartners(name);

        if (allPartners == null)
            return new Objs(name, objCollection);

        Objs nextPartners = new Objs(name, allPartners);
        for (Obj partner : allPartners.values())
            if (partner.getT() > T)
                nextPartners.add(partner);

        return nextPartners;

    }

    /**
     * Removes itself from any other objects as a parent or child.
     */
    public void removeRelationships() {
        // Removing itself as a child from its parent
        if (parents != null) {
            for (Obj parent : parents.values()) {
                if (parent != null)
                    parent.removeChild(this);
            }
        }

        // Removing itself as a parent from any children
        if (children != null) {
            for (Objs childSet : children.values()) {
                for (Obj child : childSet.values()) {
                    if (child.getParent(getName()) == this) {
                        child.removeParent(getName());
                    }
                }
            }
        }

        // Removing itself as a partner from any partners
        if (partners != null) {
            for (Objs partnerSet : partners.values()) {
                for (Obj partner : partnerSet.values()) {
                    partner.removePartner(this);
                }
            }
        }

        // Clearing children and parents
        children = new LinkedHashMap<>();
        parents = new LinkedHashMap<>();
        partners = new LinkedHashMap<>();

    }

    public LinkedHashMap getMeasurements() {
        return measurements;
    }

    public void setMeasurements(LinkedHashMap measurements) {
        this.measurements = measurements;

    }

    public LinkedHashMap getMetadata() {
        return metadata;
    }

    public void setMetadata(LinkedHashMap metadata) {
        this.metadata = metadata;

    }

    @Override
    public Roi getRoi(int slice) {
        if (rois.containsKey(slice))
            return (Roi) rois.get(slice).clone();

        Roi roi = super.getRoi(slice);

        if (roi == null)
            return null;

        rois.put(slice, roi);

        return (Roi) roi.clone();

    }

    /**
     * Accesses and generates all ROIs for the object
     * 
     * @return HashMap containing each ROI. Keys are integers with zero-based
     *         numbering, specifying Z-axis slice.
     */
    public HashMap getRois() {
        // This will access and generate all ROIs for this object
        double[][] extents = getExtents(true, false);
        int minZ = (int) Math.round(extents[2][0]);
        int maxZ = (int) Math.round(extents[2][1]);
        for (int z = minZ; z <= maxZ; z++)
            getRoi(z);

        // For the sake of not wasting memory, this will output the original list of
        // ROIs
        return rois;

    }

    public void addPointsFromRoi(Roi roi, int z) throws IntegerOverflowException {
        for (java.awt.Point point : roi.getContainedPoints()) {
            try {
                add((int) point.getX(), (int) point.getY(), z);
            } catch (PointOutOfRangeException e) {
            }
        }
    }

    public void addPointsFromPolygon(Polygon polygon, int z) throws PointOutOfRangeException {
        addPointsFromShape(polygon, z);
    }

    public void addPointsFromShape(Shape polygon, int z) throws PointOutOfRangeException {
        // Determining xy limits
        // int minX = Arrays.stream(polygon.xpoints).min().getAsInt();
        // int maxX = Arrays.stream(polygon.xpoints).max().getAsInt();
        // int minY = Arrays.stream(polygon.ypoints).min().getAsInt();
        // int maxY = Arrays.stream(polygon.ypoints).max().getAsInt();

        Rectangle bounds = polygon.getBounds();
        int minX = bounds.x;
        int maxX = minX + bounds.width;
        int minY = bounds.y;
        int maxY = minY + bounds.height;

        // Iterating over all possible points, checking if they're inside the polygon
        for (int x = minX; x <= maxX; x++) {
            for (int y = minY; y <= maxY; y++) {
                if (polygon.contains(x, y))
                    add(x, y, z);
            }
        }
    }

    public Image getAsImage(String imageName, boolean singleTimepoint) {
        if (singleTimepoint)
            return getAsImage(imageName, 0, 1);
        else
            return getAsImage(imageName, getT(), objCollection.getNFrames());
    }

    public Image getCentroidAsImage(String imageName, boolean singleTimepoint) {
        int nFrames = singleTimepoint ? 1 : objCollection.getNFrames();
        int t = singleTimepoint ? 0 : getT();

        ImagePlus ipl = IJ.createHyperStack(imageName, spatCal.width, spatCal.height, 1, spatCal.nSlices, nFrames, 8);
        spatCal.applyImageCalibration(ipl);

        Point centroid = getMeanCentroid(true, false);
        int x = (int) Math.round(centroid.getX());
        int y = (int) Math.round(centroid.getY());
        int z = (int) Math.round(centroid.getZ());

        int idx = ipl.getStackIndex(1, z + 1, t + 1);
        ipl.getStack().getProcessor(idx).set(x, y, 255);

        return ImageFactory.createImage(imageName, ipl);

    }

    public void addToImage(Image image, float hue) {
        ImagePlus ipl = image.getImagePlus();
        int bitDepth = ipl.getBitDepth();

        int tPos = getT();
        for (Point point : getCoordinateSet()) {
            int xPos = point.x;
            int yPos = point.y;
            int zPos = point.z;

            ipl.setPosition(1, zPos + 1, tPos + 1);

            switch (bitDepth) {
                case 8:
                case 16:
                    ipl.getProcessor().putPixel(xPos, yPos, Math.round(hue * 255));
                    break;
                case 32:
                    ipl.getProcessor().putPixelValue(xPos, yPos, hue);
                    break;
            }
        }
    }

    public void addCentroidToImage(Image image, float hue) {
        ImagePlus ipl = image.getImagePlus();
        int bitDepth = ipl.getBitDepth();

        int tPos = getT();
        int xPos = (int) Math.round(getXMean(true));
        int yPos = (int) Math.round(getYMean(true));
        int zPos = (int) Math.round(getZMean(true, false));

        ipl.setPosition(1, zPos + 1, tPos + 1);

        switch (bitDepth) {
            case 8:
            case 16:
                ipl.getProcessor().putPixel(xPos, yPos, Math.round(hue * 255));
                break;
            case 32:
                ipl.getProcessor().putPixelValue(xPos, yPos, hue);
                break;
        }
    }

    public void removeOutOfBoundsCoords() {
        int width = spatCal.getWidth();
        int height = spatCal.getHeight();
        int nSlices = spatCal.getNSlices();

        getCoordinateSet().removeIf(point -> point.getX() < 0 || point.getX() >= width || point.getY() < 0
                || point.getY() >= height || point.getZ() < 0 || point.getZ() >= nSlices);

    }

    public  & NativeType> Iterator getImgPlusCoordinateIterator(
            ImgPlus imgPlus, int c) {
        return new ImgPlusCoordinateIterator<>(getCoordinateIterator(), imgPlus, c, T);
    }

    public void clearROIs() {
        rois = new HashMap<>();

    }

    @Override
    public void clearAllCoordinates() {
        super.clearAllCoordinates();
        rois = new HashMap<>();
    }

    public Obj duplicate(Objs newCollection, boolean duplicateRelationships, boolean duplicateMeasurement,
            boolean duplicateMetadata) {
        Obj newObj = new Obj(newCollection, getID(), this);

        // Duplicating coordinates
        newObj.setCoordinateSet(getCoordinateSet().duplicate());

        // Setting timepoint
        newObj.setT(getT());

        // Duplicating relationships
        if (duplicateRelationships) {
            for (Obj parent : parents.values()) {
                newObj.addParent(parent);
                parent.addChild(this);
            }

            for (Objs currChildren : children.values())
                for (Obj child : currChildren.values()) {
                    newObj.addChild(child);
                    child.addParent(newObj);
                }

            for (Objs currPartners : partners.values())
                for (Obj partner : currPartners.values()) {
                    newObj.addPartner(partner);
                    partner.addPartner(newObj);
                }
        }

        // Duplicating measurements
        if (duplicateMeasurement)
            for (Measurement measurement : measurements.values())
                newObj.addMeasurement(measurement.duplicate());

        // Duplicating metadata
        if (duplicateMetadata)
            for (ObjMetadata metadataItem : metadata.values())
                newObj.addMetadataItem(metadataItem.duplicate());

        return newObj;

    }

    @Override
    public int hashCode() {
        // Updating the hash for time-point. Measurements and relationships aren't
        // included; only spatial location.
        return super.hashCode() * 31 + getID() * 31 + getT() * 31 + getName().hashCode();
    }

    @Override
    public boolean equals(Object obj) {
        int T = getT();

        if (!super.equals(obj))
            return false;

        if (obj == this)
            return true;
        if (!(obj instanceof Obj))
            return false;

        if (ID != ((Obj) obj).getID())
            return false;

        if (T != ((Obj) obj).getT())
            return false;

        return (getName().equals(((Obj) obj).getName()));

    }

    public boolean equalsIgnoreNameAndID(Object obj) {
        int T = getT();

        if (!super.equals(obj))
            return false;

        if (obj == this)
            return true;
        if (!(obj instanceof Obj))
            return false;

        return (T == ((Obj) obj).getT());

    }

    @Override
    public String toString() {
        return "Object \"" + getName() + "\", ID = " + ID + ", frame = " + getT();
    }

    public static String getNameWithoutRelationship(String name) {
        if (name.contains("//"))
            name = name.substring(name.lastIndexOf("//") + 3);

        return name;

    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy