Imports System
Imports System.Collections.Generic
Imports System.Linq
Imports System.Windows
Imports System.Windows.Controls
Imports Microsoft.Kinect
Imports Emgu.CV
Imports Emgu.CV.VideoSurveillance
Imports Emgu.CV.Structure
imports system.Drawing
imports system.ComponentModel
Imports ProximityCamera.ImageManipulationExtensionMethods

''' <summary>
''' Interaction logic for MainWindow.xaml
''' </summary>
Class MainWindow
    Private _kinectSensor As KinectSensor
    Private _motionHistory As MotionHistory
    Private _forgroundDetector As IBGFGDetector(Of Bgr)
    Private _isTracking As Boolean = False

    Public Sub New()

        ' この呼び出しはデザイナーで必要です。
        InitializeComponent()

        ' InitializeComponent() 呼び出しの後で初期化を追加します。
        AddHandler Me.Unloaded, Sub()
                                    _kinectSensor.ColorStream.Disable()
                                End Sub

        AddHandler Me.Loaded, Sub()
                                  _motionHistory = New MotionHistory(
                                      1.0,
                                      0.05,
                                      0.5)

                                  _kinectSensor = KinectSensor.KinectSensors(0)

                                  _kinectSensor.ColorStream.Enable()
                                  _kinectSensor.Start()

                                  Dim bw As New BackgroundWorker()
                                  AddHandler bw.DoWork, Sub(a, b)
                                                            Pulse()
                                                        End Sub
                                  AddHandler bw.RunWorkerCompleted, Sub(c, d)
                                                                        bw.RunWorkerAsync()
                                                                    End Sub
                                  bw.RunWorkerAsync()
                              End Sub
    End Sub

    Private Sub Pulse()
        Using imageFrame As ColorImageFrame = _kinectSensor.ColorStream.OpenNextFrame(200)
            If (imageFrame Is Nothing) Then
                Exit Sub
            End If

            Using _image As Image(Of Bgr, Byte) = imageFrame.ToOpenCVImage(Of Bgr, Byte)()
                Using storage As New MemStorage() 'create storage for motion components
                    If (_forgroundDetector Is Nothing) Then
                        _forgroundDetector = New BGStatModel(Of Bgr)(_image,
                                                                     Emgu.CV.CvEnum.BG_STAT_TYPE.GAUSSIAN_BG_MODEL)
                    End If

                    _forgroundDetector.Update(_image)

                    'update the motion history
                    _motionHistory.Update(_forgroundDetector.ForgroundMask)

                    'get a copy of the motion mask and enhance its color
                    Dim minValues() As Double, maxValues() As Double
                    Dim minLoc() As System.Drawing.Point, maxLoc() As System.Drawing.Point
                    _motionHistory.Mask.MinMax(minValues,
                                               maxValues,
                                               minLoc,
                                               maxLoc)
                    Dim motionMask As Image(Of Gray, Byte) = _motionHistory.Mask.Mul(255.0 / maxValues(0))

                    'create the motion image 
                    Dim motionImage As New Image(Of Bgr, Byte)(motionMask.Size)
                    motionImage(0) = motionMask

                    'Threshold to define a motion area
                    'reduce the value to detect smaller motion
                    Const minArea As Integer = 100

                    storage.Clear() 'clear the storage
                    Dim motionComponents As Seq(Of MCvConnectedComp) = _motionHistory.GetMotionComponents(storage)
                    Dim isMotionDetected As Boolean = False
                    'iterate through each of the motion component
                    For c As Integer = 0 To motionComponents.Count() - 1
                        Dim comp As MCvConnectedComp = motionComponents(c)
                        'reject the components that have small area
                        If (comp.area < minArea) Then
                            Continue For
                        End If

                        OnDetection()
                        isMotionDetected = True
                        Exit For
                    Next
                    If (isMotionDetected = False) Then
                        OnDetectionStopped()
                        Me.Dispatcher.Invoke(New Action(Sub()
                                                            rgbImage.Source = Nothing
                                                        End Sub))
                        StopRecording()
                        Exit Sub
                    End If

                    Me.Dispatcher.Invoke(
                        New Action(Sub()
                                       rgbImage.Source = imageFrame.ToBitmapSource()
                                   End Sub))
                    Record(imageFrame)
                End Using
            End Using
        End Using
    End Sub

    Private _lastTracked As DateTime = DateTime.Now
    Private Sub OnDetection()
        _lastTracked = DateTime.Now
        If (Not _isTracking) Then
            _isTracking = True
        End If
    End Sub

    Private Sub OnDetectionStopped()
        Const waitTime As Double = 2
        If (DateTime.Now.Subtract(_lastTracked) > TimeSpan.FromSeconds(waitTime)) Then
            _isTracking = False
        End If
    End Sub

    Private _isRecording As Boolean = False
    Private _baseDirectory As String = System.IO.Path.GetDirectoryName(
                                    System.Reflection.Assembly.GetEntryAssembly().Location)
    Private _fileName As String
    Private _videoArray As New List(Of Image(Of Rgb, Byte))()

    Sub Record(_image As ColorImageFrame)
        If (Not _isRecording) Then
            _fileName = String.Format("{0}{1}{2}", _baseDirectory, DateTime.Now.ToString("MMddyyyyHmmss"), ".avi")
            _isRecording = True
        End If
        _videoArray.Add(_image.ToOpenCVImage(Of Rgb, Byte)())
    End Sub


    Sub StopRecording()
        If (Not _isRecording) Then
            Exit Sub
        End If

        'CvInvoke.CV_FOURCC('P','I','M','1')    = MPEG-1 codec
        'CvInvoke.CV_FOURCC('M','J','P','G')    = motion-jpeg codec (does not work well)
        'CvInvoke.CV_FOURCC('M', 'P', '4', '2') = MPEG-4.2 codec
        'CvInvoke.CV_FOURCC('D', 'I', 'V', '3') = MPEG-4.3 codec
        'CvInvoke.CV_FOURCC('D', 'I', 'V', 'X') = MPEG-4 codec
        'CvInvoke.CV_FOURCC('U', '2', '6', '3') = H263 codec
        'CvInvoke.CV_FOURCC('I', '2', '6', '3') = H263I codec
        'CvInvoke.CV_FOURCC('F', 'L', 'V', '1') = FLV1 codec

        Using vw As New VideoWriter(_fileName, 0, 30, 640, 480, True)
            For i As Integer = 0 To _videoArray.Count - 1
                vw.WriteFrame(Of Rgb, Byte)(_videoArray(i))
            Next
        End Using
        _fileName = String.Empty
        _videoArray.Clear()
        _isRecording = False

    End Sub
End Class
