001/**
002 * Copyright (c) 2011, The University of Southampton and the individual contributors.
003 * All rights reserved.
004 *
005 * Redistribution and use in source and binary forms, with or without modification,
006 * are permitted provided that the following conditions are met:
007 *
008 *   *  Redistributions of source code must retain the above copyright notice,
009 *      this list of conditions and the following disclaimer.
010 *
011 *   *  Redistributions in binary form must reproduce the above copyright notice,
012 *      this list of conditions and the following disclaimer in the documentation
013 *      and/or other materials provided with the distribution.
014 *
015 *   *  Neither the name of the University of Southampton nor the names of its
016 *      contributors may be used to endorse or promote products derived from this
017 *      software without specific prior written permission.
018 *
019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
020 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
021 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
022 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
023 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
026 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
028 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029 */
030/**
031 *
032 */
033package org.openimaj.video.processing.motion;
034
035import java.util.LinkedList;
036import java.util.Map;
037import java.util.Queue;
038
039import org.openimaj.image.FImage;
040import org.openimaj.math.geometry.point.Point2d;
041import org.openimaj.video.Video;
042import org.openimaj.video.VideoFrame;
043import org.openimaj.video.analyser.VideoAnalyser;
044import org.openimaj.video.timecode.HrsMinSecFrameTimecode;
045
046
047/**
048 *      A motion estimator will estimate the motion of parts of a video frame.
049 *      This class includes a set of algorithms for calculating the motion estimation.
050 *      <p>
051 *      This class deals with the buffering of frames from the video which to pass
052 *      to the motion estimation. The class is abstract and the method
053 *      {@link #estimateMotionField(MotionEstimatorAlgorithm, VideoFrame, VideoFrame[])}
054 *      must be overridden by an implementing class to provide the field over which
055 *      the motion estimation will take place. This field may, for example, be a grid
056 *      or an overlapping grid. This overridden method must also determine the appropriate
057 *      way to call the motion estimation algorithm while returning a map which maps
058 *      a point to a displacement vector.
059 *
060 *      @author David Dupplaw (dpd@ecs.soton.ac.uk)
061 *  @created 1 Mar 2012
062 *
063 */
064@SuppressWarnings( "javadoc" )
065public abstract class MotionEstimator extends VideoAnalyser<FImage>
066{
067        /** The estimator to use */
068        private MotionEstimatorAlgorithm estimator = null;
069
070        /** The old frame stack. It's a queue so the oldest frame is popped off */
071        private Queue<VideoFrame<FImage>> oldFrames = null;
072
073        /** The estimated motion vectors for the last analysed frame */
074        public Map<Point2d,Point2d> motionVectors = null;
075
076        /**
077         *      Constructor a new motion estimator using the given algorithm.
078         *      @param alg The algorithm to use to estimate motion.
079         */
080        public MotionEstimator( MotionEstimatorAlgorithm alg )
081        {
082                this.estimator = alg;
083                oldFrames = new LinkedList<VideoFrame<FImage>>();
084        }
085
086        /**
087         *      Create a chainable motion estimator.
088         *      @param v The video to chain to
089         *      @param alg The algorithm to use to estimate motion
090         */
091        public MotionEstimator( Video<FImage> v, MotionEstimatorAlgorithm alg )
092        {
093                super(v);
094                this.estimator = alg;
095                oldFrames = new LinkedList<VideoFrame<FImage>>();
096        }
097
098        /**
099         *      {@inheritDoc}
100         *      @see org.openimaj.video.analyser.VideoAnalyser#analyseFrame(org.openimaj.image.Image)
101         */
102        @SuppressWarnings( "unchecked" )
103        @Override
104        public void analyseFrame( FImage frame )
105        {
106                VideoFrame<FImage> vf = new VideoFrame<FImage>( frame,
107                                new HrsMinSecFrameTimecode( getTimeStamp(), getFPS() ) );
108
109                motionVectors = estimateMotionField( estimator, vf,
110                                oldFrames.toArray( new VideoFrame[0] ) );
111
112                oldFrames.offer( vf );
113
114                // Make sure there's never too many frames in the queue
115                if( oldFrames.size() > estimator.requiredNumberOfFrames() )
116                        oldFrames.poll();
117        }
118
119        /**
120         *      Return the estimated motion vectors for the last processed frame.
121         *      @return The estimated motion vectors
122         */
123        public Map<Point2d,Point2d> getMotionVectors()
124        {
125                return motionVectors;
126        }
127
128        /**
129         *      This method needs to be overridden for specific layouts of motion
130         *      field within the image.
131         *
132         *      @param frame The current frame
133         *      @param array The list of previous frames (based on the estimator)
134         *      @return The motion field
135         */
136        protected abstract Map<Point2d, Point2d> estimateMotionField(
137                        MotionEstimatorAlgorithm estimator, VideoFrame<FImage> frame,
138                        VideoFrame<FImage>[] array );
139}