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

com.github.ojil.algorithm.RgbSplit Maven / Gradle / Ivy

There is a newer version: 0.0.11
Show newest version
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package com.github.ojil.algorithm;

import java.util.Enumeration;
import java.util.Random;
import java.util.Vector;

import com.github.ojil.core.Error;
import com.github.ojil.core.Image;
import com.github.ojil.core.PipelineStage;
import com.github.ojil.core.Rect;
import com.github.ojil.core.RgbImage;
import com.github.ojil.core.RgbRegion;
import com.github.ojil.core.RgbVal;
import com.github.ojil.core.RgbRegion.MeanVar;

/**
 * Uses region splitting to break the input image down into rectangular areas
 * of similar color. The region granularity can be controlled by setting a 
 * maximum standard deviation in each color channel.
 * @author webb
 */
public class RgbSplit extends PipelineStage {
    int nRVar, nGVar, nBVar;
    Random random = new Random();
    RgbImage rgbInput;
    Vector vecROk = null;  // vector of RgbRegions
    
    /**
     * Construct the class, setting the maximum standard deviation in each
     * color channel.
     * @param rStdDev maximum red standard deviation
     * @param gStdDev maximum green standard deviation
     * @param bStdDev maximum blue standard deviation.
     */
    public RgbSplit(int rStdDev, int gStdDev, int bStdDev) {
        this.nRVar = rStdDev;
        this.nGVar = gStdDev;
        this.nBVar = bStdDev;
        this.nRVar *= this.nRVar;
        this.nGVar *= this.nGVar;
        this.nBVar *= this.nBVar;
    }
    
    /**
     * Compute variance of a rectangle in the input image.
     * @param r the Rect outlining the region to compute
     * @return a MeanVar object containing the mean and variance of the region.
     */
    private MeanVar computeVariance(Rect r) {
        Integer[] nData = rgbInput.getData();
        int nSumR = 0, nSumG = 0, nSumB = 0;
        int nSumRSq = 0, nSumGSq = 0, nSumBSq = 0;
        for (int i=r.getTop(); i vecRNotOk = new Vector<>();
        this.vecROk = new Vector<>();
        vecRNotOk.addElement(new Rect(
                0,
                0,
                this.rgbInput.getWidth(),
                this.rgbInput.getHeight()));
        while (!vecRNotOk.isEmpty()) {
            Rect r = (Rect) vecRNotOk.elementAt(0);
            vecRNotOk.removeElementAt(0);
            if (r.getHeight() >= 2 && r.getWidth() >= 2) {
                MeanVar nVar = computeVariance(r);
                if (nVar.getRVar()>this.nRVar ||
                        nVar.getGVar()>this.nGVar ||
                        nVar.getB()>this.nBVar) {
                    // split horizontally or vertically, whichever
                    // is longer
                    if (r.getWidth() >= r.getHeight()) {
                        // split horizontally
                        int nHalfWidth = r.getWidth()/2;
                        Rect rNew = 
                                new Rect(r.getLeft(), 
                                r.getTop(), 
                                nHalfWidth, 
                                r.getHeight());
                        vecRNotOk.addElement(rNew);
                        rNew = new Rect(r.getLeft()+nHalfWidth, 
                                r.getTop(),
                                r.getWidth() - nHalfWidth,
                                r.getHeight());
                        vecRNotOk.addElement(rNew);
                    } else {
                        // split vertically
                        int nHalfHeight = r.getHeight()/2;
                        Rect rNew = new Rect(r.getLeft(), 
                                r.getTop(),
                                r.getWidth(),
                                nHalfHeight);
                        vecRNotOk.addElement(rNew);
                        rNew = new Rect(r.getLeft(), 
                                r.getTop()+nHalfHeight,
                                r.getWidth(),
                                r.getHeight() - nHalfHeight);
                        vecRNotOk.addElement(rNew);
                    }
                } else {
                    RgbRegion reg = new RgbRegion(r, nVar);
                    this.vecROk.addElement(reg);
                }
            } else {
                // region too small, stop splitting
                MeanVar nVar = computeVariance(r);
                    RgbRegion reg = new RgbRegion(r, nVar);
                    this.vecROk.addElement(reg);                
            }
        }
    }
    
    /**
     * Returns a color image with colors randomly assigned to regions. This
     * is used during debugging to see how the image has been split so that
     * the threshold can be adjusted.
     * @return RgbImage with colors randomly assigned to regions.
     * @throws com.github.ojil.core.Error if push() hasn't been called yet
     */
    public RgbImage getRandomizedRgbImage() throws com.github.ojil.core.Error {
        if (this.vecROk == null) {
            throw new com.github.ojil.core.Error(
                            com.github.ojil.core.Error.PACKAGE.CORE,
                            com.github.ojil.core.ErrorCodes.NO_RESULT_AVAILABLE,
                            null,
                            null,
                            null);
        }
        RgbImage rgbImage = new RgbImage(
                this.rgbInput.getWidth(),
                this.rgbInput.getHeight());
        for (Enumeration e = this.vecROk.elements(); e.hasMoreElements();) {
            RgbRegion r = (RgbRegion) e.nextElement();
            int nRgb = RgbVal.toRgb(
                    (byte)((this.random.nextInt()&0xff)+Byte.MIN_VALUE), 
                    (byte)((this.random.nextInt()&0xff)+Byte.MIN_VALUE), 
                    (byte)((this.random.nextInt()&0xff)+Byte.MIN_VALUE));
            Rect rect = r.getRect();
            rgbImage = rgbImage.fill(rect, nRgb);
        }
        return rgbImage;
        
    }
    
    /**
     * Return the region list.
     * @return an Enumeration on RgbRegion objects.
     * @throws com.github.ojil.core.Error if push() hasn't been called yet
     */
    public Enumeration getRegions() throws com.github.ojil.core.Error {
        if (this.vecROk == null) {
            throw new com.github.ojil.core.Error(
                            com.github.ojil.core.Error.PACKAGE.CORE,
                            com.github.ojil.core.ErrorCodes.NO_RESULT_AVAILABLE,
                            null,
                            null,
                            null);
        }
        return this.vecROk.elements();
    }
    
    /**
     * Return an RgbImage with the mean color of each region assigned. This
     * should be an approximation of the original input image, except more 
     * blocky, depending on the thresholds set.
     * @return RgbImage with the mean color of each region assigned to the
     * region.
     * @throws com.github.ojil.core.Error if push() hasn't been called yet
     */
    public RgbImage getRgbImage() throws com.github.ojil.core.Error {
        if (this.vecROk == null) {
            throw new com.github.ojil.core.Error(
                            com.github.ojil.core.Error.PACKAGE.CORE,
                            com.github.ojil.core.ErrorCodes.NO_RESULT_AVAILABLE,
                            null,
                            null,
                            null);
        }
        RgbImage rgbImage = new RgbImage(
                this.rgbInput.getWidth(),
                this.rgbInput.getHeight());
        for (Enumeration e = this.vecROk.elements(); e.hasMoreElements();) {
            RgbRegion r = (RgbRegion) e.nextElement();
            int nRgb = r.getColor();
            Rect rect = r.getRect();
            rgbImage = rgbImage.fill(rect, nRgb);
        }
        return rgbImage;
    }
    
    /**
     * Implement toString
     * @return a string giving the name of this class, the parameters, and
     * the vector result if push has been called.
     */
    public String toString() {
        String szResult = super.toString() + "(" + new Integer(this.nRVar).toString() +
                "," + new Integer(this.nGVar).toString() + 
                "," + new Integer(this.nBVar).toString();
        if (this.vecROk != null) {
            szResult += "," + this.vecROk.toString();
        }
        return szResult + ")";
    }

    public void push(Image imageInput) throws Error {
        if (!(imageInput instanceof RgbImage)) {
            throw new Error(
                            Error.PACKAGE.ALGORITHM,
                            ErrorCodes.IMAGE_NOT_RGBIMAGE,
                            imageInput.toString(),
                            null,
                            null);
        }
        this.split((RgbImage)imageInput);
        super.setOutput(this.getRgbImage());
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy