I’ve been blogging recently about some of my experiments with the Kinect for Windows v2 developer preview. Most of my experiments have been based on the supplied samples, with a lot of copy and paste action. I’ve pulled some of the repeated code into some re-usable classes.
Here’s some code that I’ve moved out of the samples into a reusable component that measures frames-per-second and the amount of time taken per frame. The code provided here is based on the original samples, modified slightly. Free as in beer, though I doubt any of you will buy me beer so let’s just say “free”.
Example how to use:
public class MainWindow : Window, INotifyPropertyChanged
{
    private FrameCounter _frameCounter;
    private KinectSensor _sensor;
    private DepthFrameReader _reader;
    public MainWindow()
    {
        InitializeComponent();
        _frameCounter = new FrameCounter();
        _frameCounter.PropertyChanged += (o,e) =>
            StatusText = String.Format("FPS = {0:N1} / CPU = {1:N6}",
                            _frameCounter.FramesPerSecond,
                            _frameCounter.CpuTimePerFrame);
        _sensor = KinectSensor.Default;
        _sensor.Open();
        _reader = sensor.DepthFrameSource.OpenReader();
        _reader.FrameArrived += FrameArrived;
        this.DataContext = this;
    }
    private void FrameArrived(object sender, DepthFrameArrivedEventArgs e)
    {
        var reference = e.FrameReference;
        DepthFrame depthFrame = null;
        try
        {
            // increment the frame counter
            using (_frameCounter.Increment())
            {
                depthFrame = reference.AcquireFrame();
                
                // do work with depth data...
            } // disposing the frame counter will calculate CPU time for this block
        }
        catch
        {
        }
        finally
        {
            if (depthFrame != null)
                depthFrame.Dispose();
        }
    }
}
Expand the block below for code goodness.
public class FrameCounter : INotifyPropertyChanged
{
    private Stopwatch _stopWatch;
    private uint _framesSinceUpdate = 0;
    private DateTime _nextStatusUpdate = DateTime.MinValue;
    private CpuCounter _cpuCounter;
    private double _fps;
    private double _cpuTime;
    public FrameCounter()
    {
        _stopWatch = new Stopwatch();
        _cpuCounter = new CpuCounter(this);
    }
    public double FramesPerSecond
    {
        get { return _fps; }
        protected set
        {
            if (_fps != value)
            {
                _fps = value;
                NotifyPropertyChanged("FramesPerSecond");
            }
        }
    }
    public double CpuTimePerFrame
    {
        get { return _cpuTime; }
        protected set
        {
            if (_cpuTime != value)
            {
                _cpuTime = value;
                NotifyPropertyChanged("CpuTimePerFrame");
            }
        }
    }
    public event PropertyChangedEventHandler PropertyChanged;
    public void DeferFrameCount(TimeSpan timeToWait)
    {
        this._nextStatusUpdate = DateTime.Now + timeToWait;
    }
    public IDisposable Increment()
    {
        this._framesSinceUpdate++;
        if (DateTime.Now >= this._nextStatusUpdate)
        {
            double fps = 0.0;
            double cpuTime = 0.0;
            if (this._stopWatch.IsRunning)
            {
                this._stopWatch.Stop();
                fps = this._framesSinceUpdate / this._stopWatch.Elapsed.TotalSeconds;
                cpuTime = this._cpuTime / fps;
                this._stopWatch.Reset();
            }
            this._nextStatusUpdate = DateTime.Now + TimeSpan.FromSeconds(1);
            this.FramesPerSecond = fps;
            this.CpuTimePerFrame = cpuTime;
        }
        if (!this._stopWatch.IsRunning)
        {
            this._framesSinceUpdate = 0;
            this._cpuTime = 0;
            this._stopWatch.Start();
        }
        _cpuCounter.Reset();
        return _cpuCounter;
    }
    internal void IncrementCpuTime(double amount)
    {
        _cpuTime += amount;
    }
    public void Reset()
    {
        _nextStatusUpdate = DateTime.MinValue;
        _framesSinceUpdate = 0;
        FramesPerSecond = 0;
        CpuTimePerFrame = 0;
    }
    protected void NotifyPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    public class CpuCounter : IDisposable
    {
        FrameCounter _parent;
        Stopwatch _stopWatch;
        internal CpuCounter(FrameCounter parent)
        {
            _parent = parent;
            _stopWatch = new Stopwatch();
        }
        public TimeSpan Elapsed
        {
            get
            {
                return _stopWatch.Elapsed;
            }
        }
        public void Reset()
        {
            _stopWatch.Reset();
            if (!_stopWatch.IsRunning)
            {
                _stopWatch.Start();
            }
            
        }
        public void Dispose()
        {
            _stopWatch.Stop();
            _parent.IncrementCpuTime(_stopWatch.Elapsed.TotalMilliseconds);
        }
    }
}
Happy coding.
0 comments:
Post a Comment