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

org.jgrasstools.gears.modules.r.labeler.OmsLabeler Maven / Gradle / Ivy

The newest version!
/*
 * This file is part of JGrasstools (http://www.jgrasstools.org)
 * 
 * JGrasstools 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 org.jgrasstools.gears.modules.r.labeler;

import static org.jgrasstools.gears.libs.modules.JGTConstants.isNovalue;

import java.awt.image.RenderedImage;
import java.awt.image.WritableRaster;
import java.util.HashMap;

import javax.media.jai.iterator.RandomIter;
import javax.media.jai.iterator.RandomIterFactory;

import oms3.annotations.Author;
import oms3.annotations.Description;
import oms3.annotations.Execute;
import oms3.annotations.In;
import oms3.annotations.Keywords;
import oms3.annotations.Label;
import oms3.annotations.License;
import oms3.annotations.Name;
import oms3.annotations.Out;
import oms3.annotations.Status;

import org.geotools.coverage.grid.GridCoverage2D;
import org.jgrasstools.gears.libs.modules.JGTConstants;
import org.jgrasstools.gears.libs.modules.JGTModel;
import org.jgrasstools.gears.modules.utils.BinaryFast;
import org.jgrasstools.gears.utils.coverage.CoverageUtilities;

@Description("Connected components labeling operation")
@Author(name = "Simon Horne, Andrea Antonello", contact = "http://homepages.inf.ed.ac.uk/rbf/HIPR2/, www.hydrologis.com")
@Keywords("Labeling, Raster")
@Label(JGTConstants.RASTERPROCESSING)
@Name("omslabeler")
@Status(Status.DRAFT)
@License("http://www.gnu.org/licenses/gpl-3.0.html")
public class OmsLabeler extends JGTModel {

    @Description("The map to label.")
    @In
    public GridCoverage2D inMap = null;

    @Description("The resulting map.")
    @Out
    public GridCoverage2D outMap = null;

    @Execute
    public void process() throws Exception {
        if (!concatOr(outMap == null, doReset)) {
            return;
        }

        final RenderedImage renderedImage = inMap.getRenderedImage();
        int width = renderedImage.getWidth();
        int height = renderedImage.getHeight();
        int[] data = new int[width * height];
        RandomIter iter = RandomIterFactory.create(renderedImage, null);
        int index = 0;
        for( int r = 0; r < height; r++ ) {
            for( int c = 0; c < width; c++ ) {
                double value = iter.getSampleDouble(c, r, 0);
                if (isNovalue(value)) {
                    data[index] = BinaryFast.BACKGROUND;
                } else {
                    data[index] = BinaryFast.FOREGROUND;
                }
                index++;
            }
        }

        int[] labelsArray = doLabel(data, width, height);

        WritableRaster dataWR = CoverageUtilities.createWritableRasterFromArray(width, height, labelsArray);
        HashMap regionMap = CoverageUtilities.getRegionParamsFromGridCoverage(inMap);
        outMap = CoverageUtilities.buildCoverage("labeled", dataWR, regionMap, inMap.getCoordinateReferenceSystem()); //$NON-NLS-1$
    }

    /**
     * Applies the Labeling algorithm plus offset and scaling
     * 
     * 

The input image is expected to be 8-bit mono 0=black everything else=white * * @param data The input pixel array * @param width width of the destination image in pixels * @param height height of the destination image in pixels * @return A pixel array containing the labelled image */ private int[] doLabel( int[] data, int width, int height ) { int nextlabel = 1; int nbs[] = new int[4]; int nbls[] = new int[4]; // Get size of image and make 1d_arrays int d_w = width; int d_h = height; int[] dest_1d = new int[d_w * d_h]; // the most labels there can be is 1/2 of the points // in checkerboard int[] labels = new int[d_w * d_h / 2]; int result = 0; // labelsValid = false; // only set to true once we've complete the task // initialise labels for( int i = 0; i < labels.length; i++ ) labels[i] = i; int count; // now Label the image for( int i = 0; i < data.length; i++ ) { int src1rgb = data[i] & 0x000000ff; if (src1rgb == 0) { result = 0; // nothing here } else { // The 4 visited neighbours nbs[0] = getNeighbours(data, i, -1, 0, d_w, d_h); nbs[1] = getNeighbours(data, i, 0, -1, d_w, d_h); nbs[2] = getNeighbours(data, i, -1, -1, d_w, d_h); nbs[3] = getNeighbours(data, i, 1, -1, d_w, d_h); // Their corresponding labels nbls[0] = getNeighbourd(dest_1d, i, -1, 0, d_w, d_h); nbls[1] = getNeighbourd(dest_1d, i, 0, -1, d_w, d_h); nbls[2] = getNeighbourd(dest_1d, i, -1, -1, d_w, d_h); nbls[3] = getNeighbourd(dest_1d, i, 1, -1, d_w, d_h); // label the point if ((nbs[0] == nbs[1]) && (nbs[1] == nbs[2]) && (nbs[2] == nbs[3]) && (nbs[0] == 0)) { // all neighbours are 0 so gives this point a new label result = nextlabel; nextlabel++; } else { // one or more neighbours have already got labels count = 0; int found = -1; for( int j = 0; j < 4; j++ ) { if (nbs[j] != 0) { count += 1; found = j; } } if (count == 1) { // only one neighbour has a label, so assign the same label to this. result = nbls[found]; } else { // more than 1 neighbour has a label result = nbls[found]; // Equivalence the connected points for( int j = 0; j < 4; j++ ) { if ((nbls[j] != 0) && (nbls[j] != result)) { associate(nbls[j], result, labels); } } } } } dest_1d[i] = result; } // reduce labels ie 76=23=22=3 -> 76=3 // done in reverse order to preserve sorting for( int i = labels.length - 1; i > 0; i-- ) { labels[i] = reduce(i, labels); } /*now labels will look something like 1=1 2=2 3=2 4=2 5=5.. 76=5 77=5 this needs to be condensed down again, so that there is no wasted space eg in the above, the labels 3 and 4 are not used instead it jumps to 5. */ int condensed[] = new int[nextlabel]; // cant be more than nextlabel labels count = 0; for( int i = 0; i < nextlabel; i++ ) { if (i == labels[i]) condensed[i] = count++; } // Record the number of labels int numberOfLabels = count - 1; // now run back through our preliminary results, replacing the raw label // with the reduced and condensed one, and do the scaling and offsets too // Now generate an array of colours which will be used to label the image int[] labelColors = new int[numberOfLabels + 1]; // Variable used to check if the color generated is acceptable // boolean acceptColor = false; for( int i = 0; i < labelColors.length; i++ ) { // acceptColor = false; // while( !acceptColor ) { // double tmp = Math.random(); // labelColors[i] = (int) (tmp * 16777215); // if (((labelColors[i] & 0x000000ff) < 200) && (((labelColors[i] & 0x0000ff00) >> 8) < // 64) && (((labelColors[i] & 0x00ff0000) >> 16) < 64)) { // // Color to be rejected so don't set acceptColor // } else { // acceptColor = true; // } // } // if (i == 0) // labelColors[i] = 0; labelColors[i] = i; } for( int i = 0; i < data.length; i++ ) { result = condensed[labels[dest_1d[i]]]; // result = (int) ( scale * (float) result + oset ); // truncate if necessary // if( result > 255 ) result = 255; // if( result < 0 ) result = 0; // produce grayscale // dest_1d[i] = 0xff000000 | (result + (result << 16) + (result << 8)); dest_1d[i] = labelColors[result];// + 0xff000000; } // labelsValid = true; // only set to true now we've complete the task return dest_1d; } /** * getNeighbours will get the pixel value of i's neighbour that's ox and oy * away from i, if the point is outside the image, then 0 is returned. * This version gets from source image. * @param d_w * @param d_h */ private int getNeighbours( int[] src1d, int i, int ox, int oy, int d_w, int d_h ) { int x, y, result; x = (i % d_w) + ox; // d_w and d_h are assumed to be set to the y = (i / d_w) + oy; // width and height of scr1d if ((x < 0) || (x >= d_w) || (y < 0) || (y >= d_h)) { result = 0; } else { result = src1d[y * d_w + x] & 0x000000ff; } return result; } /** * getNeighbourd will get the pixel value of i's neighbour that's ox and oy * away from i, if the point is outside the image, then 0 is returned. * This version gets from destination image. * @param d_w * @param d_h */ private int getNeighbourd( int[] src1d, int i, int ox, int oy, int d_w, int d_h ) { int x, y, result; x = (i % d_w) + ox; // d_w and d_h are assumed to be set to the y = (i / d_w) + oy; // width and height of scr1d if ((x < 0) || (x >= d_w) || (y < 0) || (y >= d_h)) { result = 0; } else { result = src1d[y * d_w + x]; } return result; } /** * Associate(equivalence) a with b. * a should be less than b to give some ordering (sorting) * if b is already associated with some other value, then propagate * down the list. * @param labels */ private void associate( int a, int b, int[] labels ) { if (a > b) { associate(b, a, labels); return; } if ((a == b) || (labels[b] == a)) return; if (labels[b] == b) { labels[b] = a; } else { associate(labels[b], a, labels); if (labels[b] > a) { // ***rbf new labels[b] = a; } } } /** * Reduces the number of labels. * @param labels */ private int reduce( int a, int[] labels ) { if (labels[a] == a) { return a; } else { return reduce(labels[a], labels); } } // /** // *getColours // *@return the number of unique, non zero colours. -1 if not valid // */ // private int getColours() { // // if (labelsValid) { // // return numberOfLabels; // } else { // return -1; // } // } // // /** // * Returns the number of labels. // */ // private int getNumberOfLabels() { // return numberOfLabels; // } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy