001package org.openimaj.demos.sandbox.tldcpp.detector;
002
003import org.openimaj.image.FImage;
004
005/**
006 * The variance filter forms the first step of the {@link DetectorCascade#detect(FImage)}.
007 * For each window in the {@link DetectorCascade} a variance is calculated using {@link IntegralImage} 
008 * for speed.
009 * 
010 * Windows are filtered by whether they contain more variance than minVar which is the variance of 
011 * the original bounding box being tracked
012 * @author Sina Samangooei (ss@ecs.soton.ac.uk)
013 *
014 */
015public class VarianceFilter {
016
017        private IntegralImage integralImg;
018        private IntegralImage integralImg_squared;
019
020        /**
021         * whether the variance filter is enabled
022         */
023        public boolean enabled;
024        int[][] windowOffsets;
025
026        /**
027         * the results of the variance check are saved to this results instance
028         */
029        public DetectionResult detectionResult;
030
031        /**
032         * the minimum variance (variance of the original bounding box)
033         */
034        public float minVar;
035
036        /**
037         * enabled with a 0 minvar (most permissive)
038         */
039        public VarianceFilter() {
040                enabled = true;
041                minVar = 0;
042                integralImg = null;
043                integralImg_squared = null;
044        }
045
046        private double calcVariance(int winIndex) {
047                int offIndex = DetectorCascade.TLD_WINDOW_OFFSET_SIZE * winIndex;
048                double[][] ii1 = integralImg.data;
049                double[][] ii2 = integralImg_squared.data;
050                int[][] off = this.windowOffsets;
051                int[] tlXY = off[offIndex + 0];
052                int[] blXY = off[offIndex + 1];
053                int[] trXY = off[offIndex + 2];
054                int[] brXY = off[offIndex + 3];
055                int[] area = off[offIndex + 5];
056                double mX  = (ii1[brXY[1]][brXY[0]] - ii1[trXY[1]][trXY[0]] - ii1[blXY[1]][blXY[0]] + ii1[tlXY[1]][tlXY[0]]) / (float) area[0]; //Sum of Area divided by area
057                double mX2 = (
058                        ii2[brXY[1]][brXY[0]] - 
059                        ii2[trXY[1]][trXY[0]] - 
060                        ii2[blXY[1]][blXY[0]] + 
061                        ii2[tlXY[1]][tlXY[0]]
062                ) / (float) area[0];
063                return mX2 - mX*mX;
064        }
065
066        /**
067         * calculates the integralImage and the integral(image*image) (these are used to calculate variance)
068         * @param img
069         */
070        public void nextIteration(FImage img) {
071                if(!enabled) return;
072                integralImg = new IntegralImage();
073                integralImg.calcIntImg(img,false);
074
075                integralImg_squared = new IntegralImage();
076                integralImg_squared.calcIntImg(img, true);
077        }
078
079        
080
081        /**
082         * @param windowIndex
083         * @return whether the ith window has a variance higher than minvar 
084         */
085        public boolean filter(int windowIndex) {
086                if(!enabled) return true;
087
088                float bboxvar = (float) calcVariance(windowIndex);
089
090                detectionResult.variances[windowIndex] = bboxvar;
091
092                if(bboxvar < minVar) {
093                        return false;
094                }
095
096                return true;
097        }
098}