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 */ 030package org.openimaj.demos.sandbox.video; 031 032import java.io.IOException; 033 034import org.openimaj.image.MBFImage; 035import org.openimaj.image.colour.RGBColour; 036import org.openimaj.image.processing.face.tracking.clm.CLMFaceTracker; 037import org.openimaj.image.typography.hershey.HersheyFont; 038import org.openimaj.video.Video; 039import org.openimaj.video.VideoDisplay; 040import org.openimaj.video.VideoDisplayListener; 041import org.openimaj.video.capture.VideoCapture; 042import org.openimaj.video.processing.shotdetector.HistogramVideoShotDetector; 043 044/** 045 * Tracks faces in video using the CLM Tracker. 046 * 047 * @author David Dupplaw (dpd@ecs.soton.ac.uk) 048 * @version $Author$, $Revision$, $Date$ 049 * @created 4 Jul 2012 050 */ 051public class VideoFaceTracker implements VideoDisplayListener<MBFImage> 052{ 053 /** The shot detector to use */ 054 private HistogramVideoShotDetector shotDetector = null; 055 056 /** The face tracker we're going to use */ 057 private final CLMFaceTracker tracker = new CLMFaceTracker(); 058 059 /** Frame counter for FPS display */ 060 private int fnum = 0; 061 062 /** Cache for the FPS text generated every 10 frames */ 063 private String fpsText = ""; 064 065 /** Timers for the FPS calculation */ 066 private long t1, t0 = System.currentTimeMillis(); 067 068 /** Whether to show the FPS on the view */ 069 private final boolean showFPS = true; 070 071 /** Whether to draw triangles on the video */ 072 private final boolean drawTriangles = false; 073 074 /** Whether to draw connection on the video */ 075 private final boolean drawConnections = true; 076 077 /** Whether to draw points on the video */ 078 private final boolean drawPoints = true; 079 080 /** Whether to draw the face bounds */ 081 private final boolean drawBounds = true; 082 083 /** Whether to draw the template match search area */ 084 private final boolean drawSearchArea = true; 085 086 /** 087 * Default constructor 088 * @param v The video to track faces in 089 * @throws IOException 090 */ 091 public VideoFaceTracker( final Video<MBFImage> v ) throws IOException 092 { 093 final VideoDisplay<MBFImage> vd = VideoDisplay.createVideoDisplay( v ); 094 vd.addVideoListener( this ); 095 this.shotDetector = new HistogramVideoShotDetector( v.getFPS() ); 096// shotDetector.setThreshold( 500 ); 097 } 098 099 /** 100 * {@inheritDoc} 101 * @see org.openimaj.video.VideoDisplayListener#beforeUpdate(org.openimaj.image.Image) 102 */ 103 @Override 104 public void beforeUpdate( final MBFImage frame ) 105 { 106 if( frame == null ) return; 107 108 // Process the frame. 109 this.shotDetector.processFrame( frame ); 110 if( this.shotDetector.wasLastFrameBoundary() ) 111 { 112 System.out.println( "Shot detected. Forcing redetect on face tracker."); 113 this.tracker.reset(); 114 } 115 116 // Track faces in the image 117 this.tracker.track( frame ); 118 119 // Draw the tracked model to the image 120 this.tracker.drawModel( frame, this.drawTriangles, this.drawConnections, this.drawPoints, 121 this.drawSearchArea, this.drawBounds ); 122 123 // Whether to show FPS 124 if( this.showFPS ) 125 { 126 // Draw framerate on display image (average of 10 frames) 127 if( this.fnum >= 9 ) 128 { 129 this.t1 = System.currentTimeMillis(); 130 final double fps = 10 / ((this.t1 - this.t0) / 1000.0); 131 this.t0 = this.t1; 132 this.fnum = 0; 133 this.fpsText = String.format( "%d frames/sec", (int)Math.round( fps ) ); 134 } 135 else 136 { 137 this.fnum++; 138 } 139 140 frame.drawText( this.fpsText, 10, 20, HersheyFont.ROMAN_SIMPLEX, 20, 141 RGBColour.GREEN ); 142 } 143 } 144 145 /** 146 * {@inheritDoc} 147 * @see org.openimaj.video.VideoDisplayListener#afterUpdate(org.openimaj.video.VideoDisplay) 148 */ 149 @Override 150 public void afterUpdate( final VideoDisplay<MBFImage> display ) 151 { 152 // No implementation 153 } 154 155 /** 156 * @param args 157 * @throws Exception 158 */ 159 public static void main( final String[] args ) throws Exception 160 { 161 new VideoFaceTracker( new VideoCapture(320,240) );// new XuggleVideo( "rt20111114.mp4" ) ); 162 } 163}