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

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

There is a newer version: 0.0.11
Show newest version
/*
 * MaskedGray32SubImgGen.java
 *
 * Given a target image size and a horizontal and vertical offset
 * generates a series of subimages within the input image,
 * each subimage offset by an integral multiple of the 
 * offset with size equal to the target size and lying 
 * entirely within the original image. The offset of the
 * subimage in the input image is given in the subimage class.
 * In this masked version only subimages whose center is not a masked
 * point (mask image value = 0) will be generated.
 *
 * Created on July 1, 2007, 1:51 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 .
 *
 */

package com.github.ojil.algorithm;
import com.github.ojil.core.Error;
import com.github.ojil.core.Gray32MaskedImage;
import com.github.ojil.core.Gray32OffsetImage;
import com.github.ojil.core.Gray8OffsetImage;
import com.github.ojil.core.Image;
import com.github.ojil.core.PipelineStage;

/**
 * Generates subimages from a source Gray32Image, using a mask. In a normal
 * subimage generator subimages are generated evenly spaced across the input
 * image. Here, the subimage is generated only if is center point is not masked.
 * This can increase processing speed in hierarchical detection operations since features
 * detected at coarser resolution don't have to be redetected at finer resolution.
 * @author webb
 */
public class MaskedGray32SubImgGen extends PipelineStage {
    Gray32MaskedImage imageInput;  // input image
    boolean oSubImageReady; // true if sub image position is OK
    int nHeight;            // target height
    int nHorizLimit = 0;    // number of subimages generated horizontally
    int nVertLimit = 0;     // number of subimages generated vertically
    int nHorizIndex = 0;    // current subimiage index, horizontal
    int nVertIndex = 0;     // current subimage index, vertical
    int nWidth;             // target width
    int nXOffset;           // x offset multiple for subimages
    int nYOffset;           // y offset multiple for subimages
    
    /**
     * Creates a new instance of MaskedGray32SubImgGen.
     * @param nWidth the width of the generated subimage.
     * @param nHeight the height of the generated subimage.
     * @param nXOffset the horizontal offset between subimages.
     * @param nYOffset the vertical offset between subimages.
     */
    public MaskedGray32SubImgGen(int nWidth, int nHeight, int nXOffset, int nYOffset) {
        this.nWidth = nWidth;
        this.nHeight = nHeight;
        this.nXOffset = nXOffset;
        this.nYOffset = nYOffset;
        this.oSubImageReady = false;
        // create an output image. We'll reuse this
        // image, changing the contents and offset,
        // for every Gray8OffsetImage we output.
        super.imageOutput = new Gray8OffsetImage( 
            this.nWidth, 
            this.nHeight, 
            0, 
            0);
    }
    
    /** advanceToNextSubImage advances to the next position for generating
     * a subimage. It returns true iff there is a non-masked position within
     * the image where a subimage can be generated.
     */
    private boolean advanceToNextSubImage() {
        if (oSubImageReady) {
            return this.nVertIndex <= this.nVertLimit;
        }
        // advance to next subimage position
        this.nHorizIndex ++;
        if (this.nHorizIndex > this.nHorizLimit) {
            this.nVertIndex ++;
            this.nHorizIndex = 0;
        }
        // nPos is the byte address that we will test in the mask image
        // to see if it is OK to generate a subimage. It is the midpoint
        // of the subimage.
        int nPos = (this.nHeight / 2 + 
                this.nVertIndex * this.nYOffset) * this.imageInput.getWidth() +
                this.nWidth / 2 + this.nHorizIndex * this.nXOffset;
        // starting at the current position, search forward for a position
        // that is not masked.
        while (this.nVertIndex <= this.nVertLimit) {
            while (this.nHorizIndex <= this.nHorizLimit) {
                if (this.imageInput.getMaskData()[nPos] == Byte.MIN_VALUE) {
                    // found it
                    oSubImageReady = true;
                    return true;
                }
                this.nHorizIndex ++;
                nPos += this.nWidth;
            }
            this.nHorizIndex = 0;
            this.nVertIndex ++;
            // reset nPos for next row of subimages
            nPos = (this.nHeight / 2 + 
                this.nVertIndex * this.nYOffset) * this.imageInput.getWidth() +
                this.nWidth / 2;
        }
        this.oSubImageReady = true;
        return false;
    }
    
    // We are done producing images when the advance returns no more images
    /**
     * Returns true iff there is another image available from getFront().
     * Note that the existence of another image from
     * MaskedGray32SubImgGen depends on the mask image so there's no way to guarantee
     * there will be even one subimage generated for a particular input. You must
     * always call isEmpty().
     * @return true iff there is another image available from getFront().
     */
    public boolean isEmpty() {
        return !advanceToNextSubImage();
     }
    
    // Return the next subimage and increment the indices
    /**
     * Returns the next subimage generated. The subimage will have its offset
     * set to indicate where it was generated in the input image.
     * @return a MaskedGray8SubImage that is the next subimage in the input Gray8Image to
     * be processed.
     * @throws com.github.ojil.core.Error if no subimage is available (you have to call isEmpty() to determine if
     * a subimage is available. As few as 0 subimage can be generated for a
     * given input if the entire image is masked.) Also throws if the output
     * image (stored in the superclass) has been changed in type.
     */
     public Image getFront() throws com.github.ojil.core.Error
    {
        // reuse output image
        // check to make sure nobody damaged it somehow
        if (!(super.imageOutput instanceof Gray32OffsetImage)) {
            throw new Error(
                            Error.PACKAGE.ALGORITHM,
                            ErrorCodes.OBJECT_NOT_EXPECTED_TYPE,
                            super.imageOutput.toString(),
                            "Gray32SubImage",
                            null);
        }
        if (!advanceToNextSubImage()) {
            throw new Error(
                            Error.PACKAGE.ALGORITHM,
                            ErrorCodes.SUBIMAGE_NO_IMAGE_AVAILABLE,
                            this.toString(),
                            null,
                            null);
        }
        
        Integer[] dataIn = this.imageInput.getData();
        // offset of first pixel of the subimage within the
        // larget image.
        int nHOffset = this.nXOffset * this.nHorizIndex;
        int nVOffset = this.nYOffset * this.nVertIndex;
        Gray32OffsetImage imageResult = (Gray32OffsetImage) super.imageOutput;
        imageResult.setXOffset(nHOffset);
        imageResult.setYOffset(nVOffset);
        Integer[] dataOut = imageResult.getData();
        // don't access outside the image
        int nLimitY = Math.min(this.imageInput.getHeight() - nVOffset, this.nHeight);
        int nLimitX = Math.min(this.imageInput.getWidth() - nHOffset, this.nWidth);
        for (int i=0; i




© 2015 - 2024 Weber Informatics LLC | Privacy Policy