001/**
002 * This source code file is part of a direct port of Stan Birchfield's implementation
003 * of a Kanade-Lucas-Tomasi feature tracker. The original implementation can be found
004 * here: http://www.ces.clemson.edu/~stb/klt/
005 *
006 * As per the original code, the source code is in the public domain, available
007 * for both commercial and non-commercial use.
008 */
009package org.openimaj.video.tracking.klt;
010
011import org.openimaj.image.FImage;
012import org.openimaj.image.processing.convolution.FGaussianConvolve;
013
014/**
015 * A simple Gaussian pyramid
016 * 
017 * @author Stan Birchfield
018 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk)
019 */
020public class Pyramid {
021        int subsampling;
022        int nLevels;
023        FImage [] img;
024        int [] ncols, nrows;
025
026        /**
027         * @param ncols
028         * @param nrows
029         * @param subsampling
030         * @param nlevels
031         */
032        public Pyramid(int ncols, int nrows, int subsampling, int nlevels) {
033                if (subsampling != 2 && subsampling != 4 && 
034                                subsampling != 8 && subsampling != 16 && subsampling != 32)
035                        throw new RuntimeException("(_KLTCreatePyramid)  Pyramid's subsampling must be either 2, 4, 8, 16, or 32");
036
037                img = new FImage[nlevels];
038                this.ncols = new int[nlevels];
039                this.nrows = new int[nlevels];
040
041                /* Set parameters */
042                this.subsampling = subsampling;
043                this.nLevels = nlevels;
044
045                /* Allocate memory for each level of pyramid and assign pointers */
046                for (int i = 0 ; i < nlevels ; i++) {
047                        this.img[i] =  new FImage(ncols, nrows);
048                        this.ncols[i] = ncols;  
049                        this.nrows[i] = nrows;
050                        ncols /= subsampling;  
051                        nrows /= subsampling;
052                }
053        }
054
055        /*********************************************************************
056         * 
057         */
058        void computePyramid(FImage img, float sigma_fact) {
059                FImage currimg, tmpimg;
060                int ncols = img.width, nrows = img.height;
061                int subsampling = this.subsampling;
062                int subhalf = subsampling / 2;
063                float sigma = subsampling * sigma_fact;  /* empirically determined */
064                int i, x, y;
065
066                if (subsampling != 2 && subsampling != 4 && 
067                                subsampling != 8 && subsampling != 16 && subsampling != 32)
068                        throw new RuntimeException("(_KLTComputePyramid)  Pyramid's subsampling must be either 2, 4, 8, 16, or 32");
069
070                /* Copy original image to level 0 of pyramid */
071                this.img[0] = img.clone();
072
073                currimg = img;
074                for (i = 1 ; i < this.nLevels ; i++)  {
075                        //tmpimg = FImage(nrows, ncols);
076                        //_KLTComputeSmoothedImage(currimg, sigma, tmpimg);
077                        tmpimg = currimg.process(new FGaussianConvolve(sigma));
078
079                        /* Subsample */
080                        ncols /= subsampling;  nrows /= subsampling;
081                        for (y = 0 ; y < nrows ; y++)
082                                for (x = 0 ; x < ncols ; x++)
083                                        this.img[i].pixels[y][x] = tmpimg.pixels[(subsampling*y+subhalf)][(subsampling*x+subhalf)];
084
085                        /* Reassign current image */
086                        currimg = this.img[i];
087                }
088        }
089}