org.knime.knip.core.features.ObjectCalcAndCache.java Source code

Java tutorial

Introduction

Here is the source code for org.knime.knip.core.features.ObjectCalcAndCache.java

Source

/*
 * ------------------------------------------------------------------------
 *
 *  Copyright (C) 2003 - 2013
 *  University of Konstanz, Germany and
 *  KNIME GmbH, Konstanz, Germany
 *  Website: http://www.knime.org; Email: contact@knime.org
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License, Version 3, as
 *  published by the Free Software Foundation.
 *
 *  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 <http://www.gnu.org/licenses>.
 *
 *  Additional permission under GNU GPL version 3 section 7:
 *
 *  KNIME interoperates with ECLIPSE solely via ECLIPSE's plug-in APIs.
 *  Hence, KNIME and ECLIPSE are both independent programs and are not
 *  derived from each other. Should, however, the interpretation of the
 *  GNU GPL Version 3 ("License") under any applicable laws result in
 *  KNIME and ECLIPSE being a combined program, KNIME GMBH herewith grants
 *  you the additional permission to use and propagate KNIME together with
 *  ECLIPSE with only the license terms in place for ECLIPSE applying to
 *  ECLIPSE and the GNU GPL Version 3 applying for KNIME, provided the
 *  license terms of ECLIPSE themselves allow for the respective use and
 *  propagation of ECLIPSE together with KNIME.
 *
 *  Additional permission relating to nodes for KNIME that extend the Node
 *  Extension (and in particular that are based on subclasses of NodeModel,
 *  NodeDialog, and NodeView) and that only interoperate with KNIME through
 *  standard APIs ("Nodes"):
 *  Nodes are deemed to be separate and independent programs and to not be
 *  covered works.  Notwithstanding anything to the contrary in the
 *  License, the License does not apply to Nodes, you are not required to
 *  license Nodes under the License, and you are granted a license to
 *  prepare and propagate Nodes, in each case even if such Nodes are
 *  propagated with or for interoperation with KNIME.  The owner of a Node
 *  may freely choose the license terms applicable to such Node, including
 *  when such Node is propagated with or for interoperation with KNIME.
 * --------------------------------------------------------------------- *
 *
 */
package org.knime.knip.core.features;

import java.awt.Polygon;
import java.util.BitSet;

import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics;
import org.knime.knip.core.data.labeling.Signature;
import org.knime.knip.core.util.PolygonTools;

import net.imglib2.Cursor;
import net.imglib2.FinalInterval;
import net.imglib2.IterableInterval;
import net.imglib2.RandomAccess;
import net.imglib2.img.Img;
import net.imglib2.img.ImgView;
import net.imglib2.img.array.ArrayImgFactory;
import net.imglib2.ops.data.CooccurrenceMatrix;
import net.imglib2.ops.data.CooccurrenceMatrix.MatrixOrientation;
import net.imglib2.ops.operation.SubsetOperations;
import net.imglib2.ops.operation.iterableinterval.unary.MakeCooccurrenceMatrix;
import net.imglib2.type.logic.BitType;
import net.imglib2.type.numeric.RealType;

/**
 *
 * Utility class which calculates "caches" commonly used objects, i.e. as soon as one of the methods is called, the
 * demanded object is created and returned. On the second call the already created object is returned, if the parameter
 * object equals (object equality) the parameter object of the previous call.
 *
 * @author <a href="mailto:dietzc85@googlemail.com">Christian Dietz</a>
 * @author <a href="mailto:horn_martin@gmx.de">Martin Horn</a>
 * @author <a href="mailto:michael.zinsmaier@googlemail.com">Michael Zinsmaier</a>
 */
public class ObjectCalcAndCache {

    private CooccurrenceMatrix m_coocMatrix;

    private IterableInterval<? extends RealType<?>> m_coocII;

    private int m_coocDist;

    private int m_coocGrayLevels;

    private MatrixOrientation m_coocOrientation;

    private BitSet m_coocBitSet;

    private Img<BitType> m_binaryMask;

    private IterableInterval<BitType> m_bmIterableInterval;

    public ObjectCalcAndCache() {
    }

    public Img<BitType> binaryMask(final IterableInterval<BitType> ii) {
        if (m_bmIterableInterval != ii) {
            m_bmIterableInterval = ii;
            m_binaryMask = new ArrayImgFactory<BitType>().create(ii, new BitType());
            final RandomAccess<BitType> maskRA = m_binaryMask.randomAccess();

            final Cursor<BitType> cur = ii.localizingCursor();
            while (cur.hasNext()) {
                cur.fwd();
                for (int d = 0; d < cur.numDimensions(); d++) {
                    maskRA.setPosition(cur.getLongPosition(d) - ii.min(d), d);
                }
                maskRA.get().set(true);

            }
        }
        return m_binaryMask;

    }

    private Img<BitType> m_binaryMask2D;

    private IterableInterval<BitType> m_bm2dIterableInterval;

    public Img<BitType> binaryMask2D(final IterableInterval<BitType> ii) {
        if (m_bm2dIterableInterval != ii) {
            m_bm2dIterableInterval = ii;
            final long[] dims = new long[ii.numDimensions()];
            ii.dimensions(dims);
            for (int i = 0; i < 2; i++) {
                dims[i] += 2;
            }
            final Img<BitType> mask = new ArrayImgFactory<BitType>().create(dims, new BitType());
            final RandomAccess<BitType> maskRA = mask.randomAccess();
            final Cursor<BitType> cur = ii.localizingCursor();
            while (cur.hasNext()) {
                cur.fwd();
                for (int d = 0; d < 2; d++) {
                    maskRA.setPosition((cur.getLongPosition(d) - ii.min(d)) + 1, d);
                }
                maskRA.get().set(true);
            }
            m_binaryMask2D = new ImgView<BitType>(SubsetOperations.subsetview(mask, new FinalInterval(dims)),
                    mask.factory());
        }
        return m_binaryMask2D;
    }

    private DescriptiveStatistics m_descriptiveStatistics = new DescriptiveStatistics();

    private IterableInterval<? extends RealType<?>> m_dsIterableInterval;

    public <T extends RealType<T>> DescriptiveStatistics descriptiveStatistics(final IterableInterval<T> ii) {

        if (m_dsIterableInterval != ii) {
            m_dsIterableInterval = ii;
            m_descriptiveStatistics.clear();
            final Cursor<T> c = ii.cursor();

            while (c.hasNext()) {
                c.fwd();

                m_descriptiveStatistics.addValue(c.get().getRealDouble());
            }
        }
        return m_descriptiveStatistics;

    }

    private double[] m_centroid;

    private IterableInterval<? extends RealType<?>> m_cIterableInterval;

    public <T extends RealType<T>> double[] centroid(final IterableInterval<T> ii) {
        if (m_cIterableInterval != ii) {
            m_cIterableInterval = ii;
            final Cursor<T> c = ii.cursor();
            m_centroid = new double[ii.numDimensions()];

            long count = 0;
            while (c.hasNext()) {
                c.fwd();
                for (int i = 0; i < m_centroid.length; i++) {
                    m_centroid[i] += c.getDoublePosition(i);
                }
                count++;
            }

            for (int i = 0; i < m_centroid.length; i++) {
                m_centroid[i] /= count;
            }
        }
        return m_centroid;
    }

    private double[] m_weightedCentroid;

    private IterableInterval<? extends RealType<?>> m_wcIterableInterval;

    public <T extends RealType<T>> double[] weightedCentroid(final IterableInterval<T> ii,
            final DescriptiveStatistics ds, int massDisplacement) {

        if (m_wcIterableInterval != ii) {
            m_wcIterableInterval = ii;
            m_weightedCentroid = new double[ii.numDimensions()];
            final double[] centroid = new double[ii.numDimensions()];

            final double sum = ds.getSum();
            final Cursor<T> c = ii.localizingCursor();

            final long[] pos = new long[c.numDimensions()];
            while (c.hasNext()) {
                c.fwd();
                c.localize(pos);

                final double val = c.get().getRealDouble();

                for (int d = 0; d < ii.numDimensions(); d++) {
                    m_weightedCentroid[d] += pos[d] * (val / sum);
                    centroid[d] += pos[d];
                }
            }

            massDisplacement = 0;
            for (int d = 0; d < ii.numDimensions(); d++) {
                centroid[d] /= ii.size();
                massDisplacement += Math.pow(m_weightedCentroid[d] - centroid[d], 2);
            }

        }
        return m_weightedCentroid;

    }

    private IterableInterval<BitType> m_sIterableInterval;

    private Signature m_signature;

    public Signature signature(final IterableInterval<BitType> ii, final int samplingRate) {

        if (m_sIterableInterval != ii) {
            m_sIterableInterval = ii;

            final double[] centroid = centroid(ii);
            final long[] pos = new long[centroid.length];
            for (int i = 0; i < pos.length; i++) {
                pos[i] = Math.round(centroid[i]);
            }

            m_signature = new Signature(binaryMask(ii), pos, samplingRate);
        }

        return m_signature;

    }

    private IterableInterval<BitType> m_tIterableInterval;

    private Polygon m_polygon;

    private int[] m_offset = new int[2];

    public Polygon traceContour(final IterableInterval<BitType> ii) {

        if (m_sIterableInterval != ii) {
            m_sIterableInterval = ii;

            m_polygon = PolygonTools.extractPolygon(binaryMask(ii), m_offset);

        }
        return m_polygon;

    }

    public <T extends RealType<T>> CooccurrenceMatrix cooccurenceMatrix(final IterableInterval<T> ii,
            final int dimX, final int dimY, final int distance, final int nrGrayLevels,
            final MatrixOrientation matrixOrientation, final BitSet features) {
        if ((m_coocII != ii) || (m_coocDist != distance) || (m_coocGrayLevels != nrGrayLevels)
                || (m_coocOrientation != matrixOrientation) || !features.equals(m_coocBitSet)) {
            final MakeCooccurrenceMatrix<T> matrixOp = new MakeCooccurrenceMatrix<T>(dimX, dimY, distance,
                    nrGrayLevels, matrixOrientation, features);
            if ((m_coocMatrix == null) || (m_coocGrayLevels != nrGrayLevels)) {
                // matrix still null or size must change
                m_coocMatrix = new CooccurrenceMatrix(nrGrayLevels);
            }
            matrixOp.compute(ii, m_coocMatrix);
            m_coocII = ii;
            m_coocDist = distance;
            m_coocGrayLevels = nrGrayLevels;
            m_coocOrientation = matrixOrientation;
            m_coocBitSet = features;
        }
        return m_coocMatrix;
    }

    /**
     *
     */
    public void cleanUp() {
        m_binaryMask = null;
        m_binaryMask2D = null;
        m_bm2dIterableInterval = null;
        m_bmIterableInterval = null;
        m_centroid = null;
        m_cIterableInterval = null;
        m_coocBitSet = null;
        m_coocMatrix = null;
        m_coocII = null;
        m_descriptiveStatistics = null;
        m_polygon = null;
        m_dsIterableInterval = null;
        m_sIterableInterval = null;
        m_signature = null;
        m_wcIterableInterval = null;
        m_tIterableInterval = null;

    }

}