Package jjil.algorithm

Source Code of jjil.algorithm.Gray8DetectHaarMultiScale

package jjil.algorithm;
/*
* Gray8DetectHaarMultiScale.java
*
* Created on August 19, 2007, 7:33 PM
*
* To change this template, choose Tools | Template Manager
* and open the template in the editor.
*
* Copyright 2007 by Jon A. Webb
*     This program is free software: you can redistribute it and/or modify
*    it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
*
*    You should have received a copy of the Lesser GNU General Public License
*    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*
*/
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

import jjil.core.Error;
import jjil.core.Gray8Image;
import jjil.core.Gray8MaskedImage;
import jjil.core.Gray8OffsetImage;
import jjil.core.Image;
import jjil.core.PipelineStage;

/**
* DetectHaar applies a Haar cascade at multiple locations and multiple scales
* to an input Gray8Image. The result is a mask with the masked (non-Byte.MIN_VALUE)
* locations indicating the areas where the feature was detected.<br>
* The Haar cascade is applied at multiple scales, starting with the coarsest scale,
* and working down to the finest scale. At each scale, the cascade is applied to
* subimages spread across the image. If the cascade detects a feature, the area of
* the mask corresponding to that subimage is set to Byte.MAX_VALUE. When a subimage
* is to be tested, the mask is first examined to see if the central pixel in the
* mask area corresponding to that subimage is masked. If it is, the subimage is
* skipped. When transitioning to a finer scale, the mask is stretched to the new
* size. This results in areas where features have been detected at a coarser scale
* not being re-searched at a finer scale.<br>
* Gray8DetectHaarMultiScale is structured as a pipeline stage so push'ing an image
* results in a new mask being available on getFront. The mask can be further processed
* by doing connected component detection to determine the feature characteristics,
* or the mask can be displayed in an overlay on the original image to show the
* feature areas.
* @author webb
*/
public class Gray8DetectHaarMultiScale extends PipelineStage {
    private HaarClassifierCascade hcc;
    // maximum scale is the largest factor the image is divided by
    private int nMaxScale = 10;
    // minimum scale is the smallest factor the image is divided by
    private int nMinScale = 5;
    // scale change is the change in scale from one search to the next
    // times 256
    private int nScaleChange = 12 * 256 / 10;
      
    /**
     * Creates a new instance of Gray8DetectHaarMultiScale. The scale parameters correspond
     * to the size of a square area in the original input image that are averaged to
     * create a single pixel in the image used for detection. A scale factor of 1 would
     * do detection at full image resolution.
     * @param is Input stream containing the Haar cascade. This input stream is created
     * by the Haar2J2me program (run on a PC) from a Haar cascade that has been
     * trained using the OpenCV. See {http://sourceforge.net/projects/opencv} for
     * more information about the OpenCV. The Haar2J2me program should be available
     * wherever you got this code from.
     * @param nMinScale Minimum (finest) scale at which features will be detected.
     * @param nMaxScale Maximum (coarsest) scale at which features will be detected.
     * @throws jjil.core.Error if there is an error in the input file.
     * @throws java.io.IOException if there is an I/O error reading the input file.
     */
    public Gray8DetectHaarMultiScale(InputStream is, int nMinScale, int nMaxScale)
      throws jjil.core.Error, IOException
    {
        this.nMinScale = nMinScale;
        this.nMaxScale = nMaxScale;
        // load Haar classifier cascade
        InputStreamReader isr = new InputStreamReader(is);
        this.hcc = HaarClassifierCascade.fromStream(isr);
    }
   
    /**
     * Apply multi-scale Haar cascade and prepare a mask image showing where features
     * were detected.
     * @param image Input Gray8Image.
     * @throws jjil.core.Error if the input is not a Gray8Image or is too small.
     */
        
    public void push(Image image) throws jjil.core.Error
    {
        Gray8Image imGray;
        if (image instanceof Gray8Image) {
            imGray = (Gray8Image) image;
        } else {
            throw new Error(
                            Error.PACKAGE.ALGORITHM,
                            ErrorCodes.IMAGE_NOT_GRAY8IMAGE,
                            image.toString(),
                            null,
                            null);
        }
        if (image.getWidth() < this.hcc.getWidth() ||
            image.getHeight() < this.hcc.getHeight()) {
            throw new Error(
                            Error.PACKAGE.ALGORITHM,
                            ErrorCodes.IMAGE_TOO_SMALL,
                            image.toString(),
                            this.hcc.toString(),
                            null);
        }
        int nScale = Math.min(this.nMaxScale,
                Math.min(image.getWidth() / this.hcc.getWidth(),
                image.getHeight() / this.hcc.getHeight()));
        // Zero the mask
        Gray8Image imMask = new Gray8Image(1,1,Byte.MIN_VALUE);
        while (nScale >= this.nMinScale) {
            // shrink the input image
            int nTargetWidth = imGray.getWidth() / nScale;
            int nTargetHeight = imGray.getHeight() / nScale;
            Gray8Shrink gs = new Gray8Shrink(nTargetWidth, nTargetHeight);
            gs.push(imGray);
            Gray8Image imShrunk = (Gray8Image) gs.getFront();
            // scale the mask to the new size
            Gray8RectStretch grs = new Gray8RectStretch(nTargetWidth, nTargetHeight);
            grs.push(imMask);
            imMask = (Gray8Image) grs.getFront();
            // combine the image and mask to make a masked image
            Gray8MaskedImage gmi = new Gray8MaskedImage(imShrunk, imMask);
            // pass the masked image to a subimage generator
            MaskedGray8SubImgGen mgsi = new MaskedGray8SubImgGen(
                    this.hcc.getWidth(),
                    this.hcc.getHeight(),
                    Math.max(1, gmi.getWidth() / 30),
                    Math.max(1, gmi.getHeight() / 30));
            mgsi.push(gmi);
            // now run Haar detection on each scaled image
            int nxLastFound = -hcc.getWidth();
            int nyLastFound = -hcc.getHeight();
            while (!mgsi.isEmpty()) {
                Gray8OffsetImage imSub = (Gray8OffsetImage) mgsi.getFront();
                // if we've found a feature recently we skip forward until
                // we're outside the masked region. There's no point rerunning
                // the detector
                if (imSub.getXOffset() > nxLastFound + hcc.getWidth() &&
                    imSub.getYOffset() > nyLastFound + hcc.getHeight()) {
                    if (hcc.eval(imSub)) {
                        // Found something.
                        nxLastFound = imSub.getXOffset();
                        nyLastFound = imSub.getYOffset();
                        // assign Byte.MAX_VALUE to the feature area so we don't
                        // search it again
                        Gray8Rect gr = new Gray8Rect(nxLastFound,
                                nyLastFound,
                                this.hcc.getWidth(),
                                this.hcc.getHeight(),
                                Byte.MAX_VALUE);
                        gr.push(imMask);
                        imMask = (Gray8Image) gr.getFront();
                     }
                }
            }
            nScale = nScale * 256 / this.nScaleChange;
        }
        // Stretch imMask to original image size; this is the result
        Gray8RectStretch grs = new Gray8RectStretch(image.getWidth(), image.getHeight());
        grs.push(imMask);
        super.setOutput(grs.getFront());
    }
    
    /**
     * Set minimum and maximum scale.
     * @param nMinScale The finest scale -- a scale factor of 1 corresponds to the full image resolution.
     * @param nMaxScale The coarsest scale. A scale factor equal to the image width (for a square
     * image) would mean the entire image is reduced to a single pixel.<br>
     * <B>Note.</B> The maximum scale actually used is the maximum of this
     * number and the scale which would  reduce the image size to the smallest
     * size that the image used in the Haar cascade would fit inside.
     */
    public void setScale(int nMinScale, int nMaxScale) {
        this.nMinScale = nMinScale;
        this.nMaxScale = nMaxScale;
    }
}
TOP

Related Classes of jjil.algorithm.Gray8DetectHaarMultiScale

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.