2016-05-20 16:48:43 -04:00
///////////////////////////////////////////////////////////////////////////////
2017-05-15 14:55:18 -04:00
// Copyright (C) 2017, Carnegie Mellon University and University of Cambridge,
2016-05-20 16:48:43 -04:00
// all rights reserved.
//
2017-05-15 14:55:18 -04:00
// ACADEMIC OR NON-PROFIT ORGANIZATION NONCOMMERCIAL RESEARCH USE ONLY
2016-05-20 16:48:43 -04:00
//
2017-05-15 14:55:18 -04:00
// BY USING OR DOWNLOADING THE SOFTWARE, YOU ARE AGREEING TO THE TERMS OF THIS LICENSE AGREEMENT.
// IF YOU DO NOT AGREE WITH THESE TERMS, YOU MAY NOT USE OR DOWNLOAD THE SOFTWARE.
//
// License can be found in OpenFace-license.txt
2016-05-20 16:48:43 -04:00
// * Any publications arising from the use of this software, including but
// not limited to academic journal and conference publications, technical
// reports and manuals, must cite at least one of the following works:
//
2018-05-29 18:03:26 +01:00
// OpenFace 2.0: Facial Behavior Analysis Toolkit
// Tadas Baltrušaitis, Amir Zadeh, Yao Chong Lim, and Louis-Philippe Morency
// in IEEE International Conference on Automatic Face and Gesture Recognition, 2018
//
// Convolutional experts constrained local model for facial landmark detection.
// A. Zadeh, T. Baltrušaitis, and Louis-Philippe Morency,
// in Computer Vision and Pattern Recognition Workshops, 2017.
2016-05-20 16:48:43 -04:00
//
// Rendering of Eyes for Eye-Shape Registration and Gaze Estimation
// Erroll Wood, Tadas Baltrušaitis, Xucong Zhang, Yusuke Sugano, Peter Robinson, and Andreas Bulling
// in IEEE International. Conference on Computer Vision (ICCV), 2015
//
2018-05-29 18:03:26 +01:00
// Cross-dataset learning and person-specific normalisation for automatic Action Unit detection
2016-05-20 16:48:43 -04:00
// Tadas Baltrušaitis, Marwa Mahmoud, and Peter Robinson
// in Facial Expression Recognition and Analysis Challenge,
// IEEE International Conference on Automatic Face and Gesture Recognition, 2015
//
///////////////////////////////////////////////////////////////////////////////
using System ;
using System.Collections.Generic ;
using System.Diagnostics ;
using System.Threading ;
using System.Windows ;
using System.Windows.Threading ;
using System.Windows.Media.Imaging ;
2018-05-06 08:19:09 +01:00
using System.Windows.Controls ;
using Microsoft.WindowsAPICodePack.Dialogs ;
2016-05-20 16:48:43 -04:00
// Internal libraries
using OpenCVWrappers ;
using CppInterop.LandmarkDetector ;
using FaceAnalyser_Interop ;
2017-05-18 17:04:38 -04:00
using GazeAnalyser_Interop ;
2018-01-09 17:08:39 +00:00
using FaceDetectorInterop ;
2018-01-18 08:08:29 +00:00
using UtilitiesOF ;
2016-05-20 16:48:43 -04:00
namespace OpenFaceOffline
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
// Timing for measuring FPS
#region High - Resolution Timing
static DateTime startTime ;
static Stopwatch sw = new Stopwatch ( ) ;
static MainWindow ( )
{
startTime = DateTime . Now ;
sw . Start ( ) ;
}
public static DateTime CurrentTime
{
get { return startTime + sw . Elapsed ; }
}
#endregion
// -----------------------------------------------------------------
// Members
// -----------------------------------------------------------------
Thread processing_thread ;
// Some members for displaying the results
private WriteableBitmap latest_img ;
private WriteableBitmap latest_aligned_face ;
private WriteableBitmap latest_HOG_descriptor ;
// Managing the running of the analysis system
private volatile bool thread_running ;
private volatile bool thread_paused = false ;
// Allows for going forward in time step by step
// Useful for visualising things
private volatile int skip_frames = 0 ;
FpsTracker processing_fps = new FpsTracker ( ) ;
2018-01-27 06:59:37 +00:00
// For selecting webcams
CameraSelection cam_sec ;
2016-05-20 16:48:43 -04:00
// For tracking
2018-01-24 08:02:04 +00:00
FaceDetector face_detector ;
2017-05-15 14:55:18 -04:00
FaceModelParameters face_model_params ;
2018-01-25 08:13:02 +00:00
CLNF landmark_detector ;
2018-01-09 18:14:15 +00:00
// For face analysis
2018-01-10 08:27:16 +00:00
FaceAnalyserManaged face_analyser ;
2017-05-18 17:04:38 -04:00
GazeAnalyserManaged gaze_analyser ;
2016-05-20 16:48:43 -04:00
2017-01-05 17:48:14 -05:00
public bool RecordAligned { get ; set ; } = false ; // Aligned face images
public bool RecordHOG { get ; set ; } = false ; // HOG features extracted from face images
public bool Record2DLandmarks { get ; set ; } = true ; // 2D locations of facial landmarks (in pixels)
public bool Record3DLandmarks { get ; set ; } = true ; // 3D locations of facial landmarks (in pixels)
public bool RecordModelParameters { get ; set ; } = true ; // Facial shape parameters (rigid and non-rigid geometry)
public bool RecordPose { get ; set ; } = true ; // Head pose (position and orientation)
public bool RecordAUs { get ; set ; } = true ; // Facial action units
public bool RecordGaze { get ; set ; } = true ; // Eye gaze
2018-01-27 07:46:21 +00:00
public bool RecordTracked { get ; set ; } = true ; // Recording tracked videos or images
2016-05-20 17:38:03 -04:00
2016-05-20 16:48:43 -04:00
// Visualisation options
2017-01-05 17:48:14 -05:00
public bool ShowTrackedVideo { get ; set ; } = true ; // Showing the actual tracking
public bool ShowAppearance { get ; set ; } = true ; // Showing appeaance features like HOG
public bool ShowGeometry { get ; set ; } = true ; // Showing geometry features, pose, gaze, and non-rigid
public bool ShowAUs { get ; set ; } = true ; // Showing Facial Action Units
2016-12-05 17:28:39 -05:00
int image_output_size = 112 ;
2018-02-08 16:28:00 +00:00
public bool MaskAligned { get ; set ; } = true ; // Should the aligned images be masked
2017-01-05 17:48:14 -05:00
// Where the recording is done (by default in a record directory, from where the application executed)
2018-01-18 08:08:29 +00:00
String record_root = "./processed" ;
2017-01-05 17:48:14 -05:00
2018-05-06 08:19:09 +01:00
// Selecting which face detector will be used
public bool DetectorHaar { get ; set ; } = false ;
public bool DetectorHOG { get ; set ; } = false ;
public bool DetectorCNN { get ; set ; } = true ;
// Selecting which landmark detector will be used
public bool LandmarkDetectorCLM { get ; set ; } = false ;
public bool LandmarkDetectorCLNF { get ; set ; } = false ;
public bool LandmarkDetectorCECLM { get ; set ; } = true ;
2017-01-05 17:48:14 -05:00
// For AU prediction, if videos are long dynamic models should be used
public bool DynamicAUModels { get ; set ; } = true ;
2016-12-05 17:28:39 -05:00
2017-01-06 16:43:55 -05:00
// Camera calibration parameters
2018-01-21 10:08:24 +00:00
public float fx = - 1 , fy = - 1 , cx = - 1 , cy = - 1 ;
2017-01-06 16:43:55 -05:00
2016-05-20 16:48:43 -04:00
public MainWindow ( )
{
InitializeComponent ( ) ;
2016-12-08 16:14:06 -05:00
this . DataContext = this ; // For WPF data binding
2016-05-20 16:48:43 -04:00
// Set the icon
Uri iconUri = new Uri ( "logo1.ico" , UriKind . RelativeOrAbsolute ) ;
this . Icon = BitmapFrame . Create ( iconUri ) ;
2018-05-06 08:19:09 +01:00
2016-05-20 16:48:43 -04:00
String root = AppDomain . CurrentDomain . BaseDirectory ;
2018-05-06 08:19:09 +01:00
face_model_params = new FaceModelParameters ( root , LandmarkDetectorCECLM , LandmarkDetectorCLNF , LandmarkDetectorCLM ) ;
// Initialize the face detector
face_detector = new FaceDetector ( face_model_params . GetHaarLocation ( ) , face_model_params . GetMTCNNLocation ( ) ) ;
// If MTCNN model not available, use HOG
if ( ! face_detector . IsMTCNNLoaded ( ) )
{
FaceDetCNN . IsEnabled = false ;
DetectorCNN = false ;
DetectorHOG = true ;
}
face_model_params . SetFaceDetector ( DetectorHaar , DetectorHOG , DetectorCNN ) ;
2016-05-20 16:48:43 -04:00
2018-01-25 08:13:02 +00:00
landmark_detector = new CLNF ( face_model_params ) ;
2016-05-20 16:48:43 -04:00
2017-05-18 17:04:38 -04:00
gaze_analyser = new GazeAnalyserManaged ( ) ;
2018-01-09 17:08:39 +00:00
2016-05-20 16:48:43 -04:00
}
// ----------------------------------------------------------
// Actual work gets done here
2018-01-22 17:43:05 +00:00
// Wrapper for processing multiple sequences
private void ProcessSequences ( List < String > filenames )
{
for ( int i = 0 ; i < filenames . Count ; + + i )
{
2018-01-27 12:12:36 +00:00
SequenceReader reader = new SequenceReader ( filenames [ i ] , false , fx , fy , cx , cy ) ;
2018-01-22 17:43:05 +00:00
ProcessSequence ( reader ) ;
2018-01-24 18:58:12 +00:00
// Before continuing to next video make sure the user did not stop the processing
2018-01-27 07:46:21 +00:00
if ( ! thread_running )
2018-01-24 18:58:12 +00:00
{
break ;
}
2018-01-22 17:43:05 +00:00
}
}
// The main function call for processing sequences
private void ProcessSequence ( SequenceReader reader )
2016-05-20 16:48:43 -04:00
{
2018-01-24 08:02:04 +00:00
Thread . CurrentThread . Priority = ThreadPriority . Highest ;
2017-01-05 17:48:14 -05:00
SetupFeatureExtractionMode ( ) ;
2016-05-20 16:48:43 -04:00
thread_running = true ;
2018-05-06 08:19:09 +01:00
// Reload the face landmark detector if needed
ReloadLandmarkDetector ( ) ;
if ( ! landmark_detector . isLoaded ( ) )
{
DetectorNotFoundWarning ( ) ;
EndMode ( ) ;
thread_running = false ;
return ;
}
// Set the face detector
face_model_params . SetFaceDetector ( DetectorHaar , DetectorHOG , DetectorCNN ) ;
2018-01-22 17:43:05 +00:00
face_model_params . optimiseForVideo ( ) ;
2016-05-20 16:48:43 -04:00
2018-01-22 17:43:05 +00:00
// Setup the visualization
2018-03-24 10:30:30 +00:00
Visualizer visualizer_of = new Visualizer ( ShowTrackedVideo | | RecordTracked , ShowAppearance , ShowAppearance , false ) ;
2016-05-20 16:48:43 -04:00
2018-01-22 17:43:05 +00:00
// Initialize the face analyser
2018-02-08 16:28:00 +00:00
face_analyser = new FaceAnalyserManaged ( AppDomain . CurrentDomain . BaseDirectory , DynamicAUModels , image_output_size , MaskAligned ) ;
2016-12-05 17:28:39 -05:00
2018-01-22 17:43:05 +00:00
// Reset the tracker
2018-01-25 08:13:02 +00:00
landmark_detector . Reset ( ) ;
2016-05-20 16:48:43 -04:00
2018-01-22 17:43:05 +00:00
// Loading an image file
2018-08-03 11:06:40 +01:00
var frame = reader . GetNextImage ( ) ;
var gray_frame = reader . GetCurrentFrameGray ( ) ;
2016-05-20 16:48:43 -04:00
2018-01-22 17:43:05 +00:00
// Setup recording
RecorderOpenFaceParameters rec_params = new RecorderOpenFaceParameters ( true , reader . IsWebcam ( ) ,
Record2DLandmarks , Record3DLandmarks , RecordModelParameters , RecordPose , RecordAUs ,
2018-05-26 11:06:45 +01:00
RecordGaze , RecordHOG , RecordTracked , RecordAligned , false ,
2018-01-22 17:43:05 +00:00
reader . GetFx ( ) , reader . GetFy ( ) , reader . GetCx ( ) , reader . GetCy ( ) , reader . GetFPS ( ) ) ;
RecorderOpenFace recorder = new RecorderOpenFace ( reader . GetName ( ) , rec_params , record_root ) ;
// For FPS tracking
DateTime ? startTime = CurrentTime ;
var lastFrameTime = CurrentTime ;
2018-01-24 08:02:04 +00:00
// Empty image would indicate that the stream is over
2018-05-06 08:19:09 +01:00
while ( ! gray_frame . IsEmpty )
2018-01-22 17:43:05 +00:00
{
2018-05-06 08:19:09 +01:00
2018-01-22 17:43:05 +00:00
if ( ! thread_running )
2016-05-20 16:48:43 -04:00
{
2018-01-24 18:58:12 +00:00
break ;
2018-01-22 17:43:05 +00:00
}
2016-05-20 16:48:43 -04:00
2018-01-22 17:43:05 +00:00
double progress = reader . GetProgress ( ) ;
2018-05-06 08:19:09 +01:00
bool detection_succeeding = landmark_detector . DetectLandmarksInVideo ( frame , face_model_params , gray_frame ) ;
2016-05-20 16:48:43 -04:00
2018-01-22 17:43:05 +00:00
// The face analysis step (for AUs and eye gaze)
2018-01-25 08:13:02 +00:00
face_analyser . AddNextFrame ( frame , landmark_detector . CalculateAllLandmarks ( ) , detection_succeeding , false ) ;
2018-05-06 08:19:09 +01:00
2018-01-27 09:00:18 +00:00
gaze_analyser . AddNextFrame ( landmark_detector , detection_succeeding , reader . GetFx ( ) , reader . GetFy ( ) , reader . GetCx ( ) , reader . GetCy ( ) ) ;
2016-05-20 16:48:43 -04:00
2018-01-22 17:43:05 +00:00
// Only the final face will contain the details
2018-05-06 08:19:09 +01:00
VisualizeFeatures ( frame , visualizer_of , landmark_detector . CalculateAllLandmarks ( ) , landmark_detector . GetVisibilities ( ) , detection_succeeding , true , false , reader . GetFx ( ) , reader . GetFy ( ) , reader . GetCx ( ) , reader . GetCy ( ) , progress ) ;
2018-01-22 17:43:05 +00:00
// Record an observation
2018-05-06 08:19:09 +01:00
RecordObservation ( recorder , visualizer_of . GetVisImage ( ) , 0 , detection_succeeding , reader . GetFx ( ) , reader . GetFy ( ) , reader . GetCx ( ) , reader . GetCy ( ) , reader . GetTimestamp ( ) , reader . GetFrameNumber ( ) ) ;
2018-01-22 17:43:05 +00:00
2018-05-17 11:57:07 +08:00
if ( RecordTracked )
{
recorder . WriteObservationTracked ( ) ;
}
2018-01-22 17:43:05 +00:00
while ( thread_running & thread_paused & & skip_frames = = 0 )
{
Thread . Sleep ( 10 ) ;
2016-05-20 16:48:43 -04:00
}
2018-01-22 17:43:05 +00:00
if ( skip_frames > 0 )
skip_frames - - ;
2018-08-03 11:06:40 +01:00
frame = reader . GetNextImage ( ) ;
gray_frame = reader . GetCurrentFrameGray ( ) ;
2018-01-24 08:02:04 +00:00
lastFrameTime = CurrentTime ;
processing_fps . AddFrame ( ) ;
2016-05-20 16:48:43 -04:00
}
2018-01-27 07:46:21 +00:00
// Finalize the recording and flush to disk
recorder . Close ( ) ;
2018-01-24 18:58:12 +00:00
// Post-process the AU recordings
2018-01-29 17:26:35 +00:00
if ( RecordAUs )
{
face_analyser . PostProcessOutputFile ( recorder . GetCSVFile ( ) ) ;
}
2018-01-22 17:43:05 +00:00
2018-01-27 07:46:21 +00:00
// Close the open video/webcam
reader . Close ( ) ;
2017-01-05 18:13:49 -05:00
EndMode ( ) ;
2016-05-20 16:48:43 -04:00
}
2018-01-18 08:08:29 +00:00
private void ProcessIndividualImages ( ImageReader reader )
2018-01-09 17:08:39 +00:00
{
// Make sure the GUI is setup appropriately
SetupFeatureExtractionMode ( ) ;
// Indicate we will start running the thread
thread_running = true ;
2018-05-06 08:19:09 +01:00
// Reload the face landmark detector if needed
ReloadLandmarkDetector ( ) ;
if ( ! landmark_detector . isLoaded ( ) )
{
DetectorNotFoundWarning ( ) ;
EndMode ( ) ;
thread_running = false ;
return ;
}
2018-01-09 17:08:39 +00:00
// Setup the parameters optimized for working on individual images rather than sequences
face_model_params . optimiseForImages ( ) ;
2018-01-19 16:17:22 +00:00
// Setup the visualization
2018-03-24 10:30:30 +00:00
Visualizer visualizer_of = new Visualizer ( ShowTrackedVideo | | RecordTracked , ShowAppearance , ShowAppearance , false ) ;
2018-01-19 16:17:22 +00:00
2018-01-09 17:08:39 +00:00
// Initialize the face detector if it has not been initialized yet
2018-01-19 16:17:22 +00:00
if ( face_detector = = null )
2018-01-09 17:08:39 +00:00
{
2018-05-06 08:19:09 +01:00
face_detector = new FaceDetector ( face_model_params . GetHaarLocation ( ) , face_model_params . GetMTCNNLocation ( ) ) ;
2018-01-09 17:08:39 +00:00
}
2018-01-10 08:27:16 +00:00
// Initialize the face analyser
2018-02-08 16:28:00 +00:00
face_analyser = new FaceAnalyserManaged ( AppDomain . CurrentDomain . BaseDirectory , false , image_output_size , MaskAligned ) ;
2018-01-10 08:27:16 +00:00
2018-01-13 16:34:03 +00:00
// Loading an image file
2018-08-03 11:06:40 +01:00
var frame = reader . GetNextImage ( ) ;
var gray_frame = reader . GetCurrentFrameGray ( ) ;
2018-01-13 16:34:03 +00:00
2018-01-24 08:02:04 +00:00
// For FPS tracking
DateTime ? startTime = CurrentTime ;
var lastFrameTime = CurrentTime ;
2018-01-13 16:34:03 +00:00
// This will be false when the image is not available
2018-01-09 17:08:39 +00:00
while ( reader . isOpened ( ) )
{
if ( ! thread_running )
{
2018-01-24 18:58:12 +00:00
break ;
2018-01-09 17:08:39 +00:00
}
2018-01-18 08:08:29 +00:00
// Setup recording
RecorderOpenFaceParameters rec_params = new RecorderOpenFaceParameters ( false , false ,
Record2DLandmarks , Record3DLandmarks , RecordModelParameters , RecordPose , RecordAUs ,
2018-05-26 11:06:45 +01:00
RecordGaze , RecordHOG , RecordTracked , RecordAligned , true ,
2018-01-18 08:08:29 +00:00
reader . GetFx ( ) , reader . GetFy ( ) , reader . GetCx ( ) , reader . GetCy ( ) , 0 ) ;
2018-01-09 17:08:39 +00:00
2018-01-18 08:08:29 +00:00
RecorderOpenFace recorder = new RecorderOpenFace ( reader . GetName ( ) , rec_params , record_root ) ;
2018-01-09 17:08:39 +00:00
2018-08-03 10:20:56 +01:00
visualizer_of . SetImage ( frame , reader . GetFx ( ) , reader . GetFy ( ) , reader . GetCx ( ) , reader . GetCy ( ) ) ;
2018-01-09 17:08:39 +00:00
// Detect faces here and return bounding boxes
List < Rect > face_detections = new List < Rect > ( ) ;
2018-05-06 08:19:09 +01:00
List < float > confidences = new List < float > ( ) ;
if ( DetectorHOG )
{
face_detector . DetectFacesHOG ( face_detections , gray_frame , confidences ) ;
}
else if ( DetectorCNN )
{
face_detector . DetectFacesMTCNN ( face_detections , frame , confidences ) ;
}
else if ( DetectorHaar )
{
face_detector . DetectFacesHaar ( face_detections , gray_frame , confidences ) ;
}
2018-01-18 08:08:29 +00:00
// For visualization
double progress = reader . GetProgress ( ) ;
2018-01-09 17:08:39 +00:00
2018-01-09 18:14:15 +00:00
for ( int i = 0 ; i < face_detections . Count ; + + i )
2018-01-09 17:08:39 +00:00
{
2018-05-06 08:19:09 +01:00
bool detection_succeeding = landmark_detector . DetectFaceLandmarksInImage ( frame , face_detections [ i ] , face_model_params , gray_frame ) ;
2018-01-09 18:14:15 +00:00
2018-01-25 08:13:02 +00:00
var landmarks = landmark_detector . CalculateAllLandmarks ( ) ;
2018-01-10 08:27:16 +00:00
2018-01-09 17:08:39 +00:00
// Predict action units
2018-01-20 09:09:59 +00:00
var au_preds = face_analyser . PredictStaticAUsAndComputeFeatures ( frame , landmarks ) ;
2018-01-09 18:14:15 +00:00
// Predic eye gaze
2018-01-25 08:13:02 +00:00
gaze_analyser . AddNextFrame ( landmark_detector , detection_succeeding , reader . GetFx ( ) , reader . GetFy ( ) , reader . GetCx ( ) , reader . GetCy ( ) ) ;
2018-01-18 08:08:29 +00:00
2018-01-19 08:58:37 +00:00
// Only the final face will contain the details
2018-05-06 08:19:09 +01:00
VisualizeFeatures ( frame , visualizer_of , landmarks , landmark_detector . GetVisibilities ( ) , detection_succeeding , i = = 0 , true , reader . GetFx ( ) , reader . GetFy ( ) , reader . GetCx ( ) , reader . GetCy ( ) , progress ) ;
2018-01-19 08:58:37 +00:00
2018-01-18 08:08:29 +00:00
// Record an observation
2018-05-06 08:19:09 +01:00
RecordObservation ( recorder , visualizer_of . GetVisImage ( ) , i , detection_succeeding , reader . GetFx ( ) , reader . GetFy ( ) , reader . GetCx ( ) , reader . GetCy ( ) , 0 , 0 ) ;
2018-01-09 18:14:15 +00:00
2018-01-09 17:08:39 +00:00
}
2018-08-03 10:20:56 +01:00
recorder . SetObservationVisualization ( visualizer_of . GetVisImage ( ) ) ;
2018-08-03 11:06:40 +01:00
frame = reader . GetNextImage ( ) ;
gray_frame = reader . GetCurrentFrameGray ( ) ;
2018-01-18 08:08:29 +00:00
2018-05-17 11:57:07 +08:00
// Write out the tracked image
if ( RecordTracked )
{
recorder . WriteObservationTracked ( ) ;
}
2018-01-18 08:08:29 +00:00
// Do not cary state accross images
2018-01-25 08:13:02 +00:00
landmark_detector . Reset ( ) ;
2018-01-18 08:08:29 +00:00
face_analyser . Reset ( ) ;
2018-01-18 17:19:44 +00:00
recorder . Close ( ) ;
2018-01-18 08:08:29 +00:00
2018-01-24 08:02:04 +00:00
lastFrameTime = CurrentTime ;
processing_fps . AddFrame ( ) ;
2018-01-27 07:46:21 +00:00
2018-01-09 17:08:39 +00:00
// TODO how to report errors from the reader here? exceptions? logging? Problem for future versions?
}
EndMode ( ) ;
}
2018-05-06 08:19:09 +01:00
// If the landmark detector model changed need to reload it
private void ReloadLandmarkDetector ( )
{
bool reload = false ;
if ( face_model_params . IsCECLM ( ) & & ! LandmarkDetectorCECLM )
{
reload = true ;
}
else if ( face_model_params . IsCLNF ( ) & & ! LandmarkDetectorCLNF )
{
reload = true ;
}
else if ( face_model_params . IsCLM ( ) & & ! LandmarkDetectorCLM )
{
reload = true ;
}
if ( reload )
{
String root = AppDomain . CurrentDomain . BaseDirectory ;
face_model_params = new FaceModelParameters ( root , LandmarkDetectorCECLM , LandmarkDetectorCLNF , LandmarkDetectorCLM ) ;
landmark_detector = new CLNF ( face_model_params ) ;
}
}
private void DetectorNotFoundWarning ( )
{
string messageBoxText = "Could not open the landmark detector model file. For instructions of how to download them, see https://github.com/TadasBaltrusaitis/OpenFace/wiki/Model-download" ;
string caption = "Model file not found or corrupt" ;
MessageBoxButton button = MessageBoxButton . OK ;
MessageBoxImage icon = MessageBoxImage . Warning ;
// Display message box
System . Windows . MessageBox . Show ( messageBoxText , caption , button , icon ) ;
}
private void RecordObservation ( RecorderOpenFace recorder , RawImage vis_image , int face_id , bool success , float fx , float fy , float cx , float cy , double timestamp , int frame_number )
2018-01-18 08:08:29 +00:00
{
2018-01-28 10:16:20 +00:00
recorder . SetObservationTimestamp ( timestamp ) ;
2018-01-25 08:13:02 +00:00
double confidence = landmark_detector . GetConfidence ( ) ;
2018-01-18 08:08:29 +00:00
2018-05-06 08:19:09 +01:00
List < float > pose = new List < float > ( ) ;
2018-01-25 08:13:02 +00:00
landmark_detector . GetPose ( pose , fx , fy , cx , cy ) ;
2018-01-18 08:08:29 +00:00
recorder . SetObservationPose ( pose ) ;
2018-05-06 08:19:09 +01:00
List < Tuple < float , float > > landmarks_2D = landmark_detector . CalculateAllLandmarks ( ) ;
List < Tuple < float , float , float > > landmarks_3D = landmark_detector . Calculate3DLandmarks ( fx , fy , cx , cy ) ;
List < float > global_params = landmark_detector . GetRigidParams ( ) ;
List < float > local_params = landmark_detector . GetNonRigidParams ( ) ;
2018-01-18 08:08:29 +00:00
recorder . SetObservationLandmarks ( landmarks_2D , landmarks_3D , global_params , local_params , confidence , success ) ;
var gaze = gaze_analyser . GetGazeCamera ( ) ;
var gaze_angle = gaze_analyser . GetGazeAngle ( ) ;
2018-01-25 08:13:02 +00:00
var landmarks_2d_eyes = landmark_detector . CalculateAllEyeLandmarks ( ) ;
var landmarks_3d_eyes = landmark_detector . CalculateAllEyeLandmarks3D ( fx , fy , cx , cy ) ;
2018-01-18 08:08:29 +00:00
recorder . SetObservationGaze ( gaze . Item1 , gaze . Item2 , gaze_angle , landmarks_2d_eyes , landmarks_3d_eyes ) ;
2018-01-18 15:47:58 +00:00
var au_regs = face_analyser . GetCurrentAUsReg ( ) ;
var au_classes = face_analyser . GetCurrentAUsClass ( ) ;
recorder . SetObservationActionUnits ( au_regs , au_classes ) ;
2018-01-18 08:08:29 +00:00
2018-05-06 08:19:09 +01:00
recorder . SetObservationFaceID ( face_id ) ;
recorder . SetObservationFrameNumber ( frame_number ) ;
2018-01-18 16:34:31 +00:00
recorder . SetObservationFaceAlign ( face_analyser . GetLatestAlignedFace ( ) ) ;
2018-01-19 08:10:34 +00:00
2018-01-18 21:55:15 +00:00
var hog_feature = face_analyser . GetLatestHOGFeature ( ) ;
2018-01-19 08:10:34 +00:00
recorder . SetObservationHOG ( success , hog_feature , face_analyser . GetHOGRows ( ) , face_analyser . GetHOGCols ( ) , face_analyser . GetHOGChannels ( ) ) ;
2018-01-19 21:11:58 +00:00
recorder . SetObservationVisualization ( vis_image ) ;
2018-01-18 16:34:31 +00:00
recorder . WriteObservation ( ) ;
2018-01-18 08:08:29 +00:00
}
2018-05-06 08:19:09 +01:00
private void VisualizeFeatures ( RawImage frame , Visualizer visualizer , List < Tuple < float , float > > landmarks , List < bool > visibilities , bool detection_succeeding ,
bool new_image , bool multi_face , float fx , float fy , float cx , float cy , double progress )
2016-12-22 16:08:07 -05:00
{
2018-01-19 08:58:37 +00:00
2016-12-22 16:08:07 -05:00
List < Tuple < Point , Point > > lines = null ;
2018-05-06 08:19:09 +01:00
List < Tuple < float , float > > eye_landmarks = null ;
2016-12-22 16:08:07 -05:00
List < Tuple < Point , Point > > gaze_lines = null ;
2018-05-06 08:19:09 +01:00
Tuple < float , float > gaze_angle = new Tuple < float , float > ( 0 , 0 ) ;
2016-12-22 16:08:07 -05:00
2018-05-06 08:19:09 +01:00
List < float > pose = new List < float > ( ) ;
2018-01-25 08:13:02 +00:00
landmark_detector . GetPose ( pose , fx , fy , cx , cy ) ;
2018-05-06 08:19:09 +01:00
List < float > non_rigid_params = landmark_detector . GetNonRigidParams ( ) ;
2016-12-22 16:08:07 -05:00
2018-01-25 08:13:02 +00:00
double confidence = landmark_detector . GetConfidence ( ) ;
2016-12-22 16:08:07 -05:00
if ( confidence < 0 )
confidence = 0 ;
else if ( confidence > 1 )
confidence = 1 ;
2018-01-31 08:23:48 +00:00
double scale = landmark_detector . GetRigidParams ( ) [ 0 ] ;
2017-01-09 16:11:19 -05:00
2018-01-19 08:58:37 +00:00
// Helps with recording and showing the visualizations
2018-01-31 08:23:48 +00:00
if ( new_image )
2018-01-21 10:08:24 +00:00
{
visualizer . SetImage ( frame , fx , fy , cx , cy ) ;
}
2018-01-19 16:17:22 +00:00
visualizer . SetObservationHOG ( face_analyser . GetLatestHOGFeature ( ) , face_analyser . GetHOGRows ( ) , face_analyser . GetHOGCols ( ) ) ;
2018-01-31 08:23:48 +00:00
visualizer . SetObservationLandmarks ( landmarks , confidence , visibilities ) ;
2018-01-19 16:17:22 +00:00
visualizer . SetObservationPose ( pose , confidence ) ;
2018-01-25 08:13:02 +00:00
visualizer . SetObservationGaze ( gaze_analyser . GetGazeCamera ( ) . Item1 , gaze_analyser . GetGazeCamera ( ) . Item2 , landmark_detector . CalculateAllEyeLandmarks ( ) , landmark_detector . CalculateAllEyeLandmarks3D ( fx , fy , cx , cy ) , confidence ) ;
2018-01-19 08:58:37 +00:00
2018-05-06 08:19:09 +01:00
eye_landmarks = landmark_detector . CalculateVisibleEyeLandmarks ( ) ;
lines = landmark_detector . CalculateBox ( fx , fy , cx , cy ) ;
2016-12-22 16:08:07 -05:00
2018-05-06 08:19:09 +01:00
gaze_lines = gaze_analyser . CalculateGazeLines ( fx , fy , cx , cy ) ;
gaze_angle = gaze_analyser . GetGazeAngle ( ) ;
2016-12-22 16:08:07 -05:00
// Visualisation (as a separate function)
Dispatcher . Invoke ( DispatcherPriority . Render , new TimeSpan ( 0 , 0 , 0 , 0 , 200 ) , ( Action ) ( ( ) = >
{
if ( ShowAUs )
{
var au_classes = face_analyser . GetCurrentAUsClass ( ) ;
var au_regs = face_analyser . GetCurrentAUsReg ( ) ;
auClassGraph . Update ( au_classes ) ;
var au_regs_scaled = new Dictionary < String , double > ( ) ;
foreach ( var au_reg in au_regs )
{
au_regs_scaled [ au_reg . Key ] = au_reg . Value / 5.0 ;
if ( au_regs_scaled [ au_reg . Key ] < 0 )
au_regs_scaled [ au_reg . Key ] = 0 ;
if ( au_regs_scaled [ au_reg . Key ] > 1 )
au_regs_scaled [ au_reg . Key ] = 1 ;
}
auRegGraph . Update ( au_regs_scaled ) ;
}
if ( ShowGeometry )
{
int yaw = ( int ) ( pose [ 4 ] * 180 / Math . PI + 0.5 ) ;
int roll = ( int ) ( pose [ 5 ] * 180 / Math . PI + 0.5 ) ;
int pitch = ( int ) ( pose [ 3 ] * 180 / Math . PI + 0.5 ) ;
YawLabel . Content = yaw + "°" ;
RollLabel . Content = roll + "°" ;
PitchLabel . Content = pitch + "°" ;
XPoseLabel . Content = ( int ) pose [ 0 ] + " mm" ;
YPoseLabel . Content = ( int ) pose [ 1 ] + " mm" ;
ZPoseLabel . Content = ( int ) pose [ 2 ] + " mm" ;
nonRigidGraph . Update ( non_rigid_params ) ;
// Update eye gaze
String x_angle = String . Format ( "{0:F0}°" , gaze_angle . Item1 * ( 180.0 / Math . PI ) ) ;
String y_angle = String . Format ( "{0:F0}°" , gaze_angle . Item2 * ( 180.0 / Math . PI ) ) ;
GazeXLabel . Content = x_angle ;
GazeYLabel . Content = y_angle ;
}
if ( ShowTrackedVideo )
{
2018-01-31 08:23:48 +00:00
if ( new_image )
2016-12-22 16:08:07 -05:00
{
latest_img = frame . CreateWriteableBitmap ( ) ;
2018-05-06 08:19:09 +01:00
overlay_image . Clear ( ) ;
2016-12-22 16:08:07 -05:00
}
2018-05-06 08:19:09 +01:00
2016-12-22 16:08:07 -05:00
frame . UpdateWriteableBitmap ( latest_img ) ;
2018-01-31 08:23:48 +00:00
2018-05-06 08:19:09 +01:00
// Clear results from previous image
2018-01-31 08:23:48 +00:00
overlay_image . Source = latest_img ;
2018-05-06 08:19:09 +01:00
overlay_image . Confidence . Add ( confidence ) ;
2018-01-31 08:23:48 +00:00
overlay_image . FPS = processing_fps . GetFPS ( ) ;
overlay_image . Progress = progress ;
2018-05-06 08:19:09 +01:00
overlay_image . FaceScale . Add ( scale ) ;
2016-12-22 16:08:07 -05:00
2018-05-06 08:19:09 +01:00
// Update results even if it is not succeeding when in multi-face mode
if ( detection_succeeding | | multi_face )
2016-12-22 16:08:07 -05:00
{
List < Point > landmark_points = new List < Point > ( ) ;
foreach ( var p in landmarks )
{
landmark_points . Add ( new Point ( p . Item1 , p . Item2 ) ) ;
}
List < Point > eye_landmark_points = new List < Point > ( ) ;
foreach ( var p in eye_landmarks )
{
eye_landmark_points . Add ( new Point ( p . Item1 , p . Item2 ) ) ;
}
2018-05-06 08:19:09 +01:00
overlay_image . OverlayLines . Add ( lines ) ;
overlay_image . OverlayPoints . Add ( landmark_points ) ;
overlay_image . OverlayPointsVisibility . Add ( visibilities ) ;
overlay_image . OverlayEyePoints . Add ( eye_landmark_points ) ;
overlay_image . GazeLines . Add ( gaze_lines ) ;
2016-12-22 16:08:07 -05:00
}
}
if ( ShowAppearance )
{
RawImage aligned_face = face_analyser . GetLatestAlignedFace ( ) ;
2018-01-19 16:33:17 +00:00
RawImage hog_face = visualizer . GetHOGVis ( ) ;
2016-12-22 16:08:07 -05:00
if ( latest_aligned_face = = null )
{
latest_aligned_face = aligned_face . CreateWriteableBitmap ( ) ;
latest_HOG_descriptor = hog_face . CreateWriteableBitmap ( ) ;
}
aligned_face . UpdateWriteableBitmap ( latest_aligned_face ) ;
hog_face . UpdateWriteableBitmap ( latest_HOG_descriptor ) ;
AlignedFace . Source = latest_aligned_face ;
AlignedHOG . Source = latest_HOG_descriptor ;
}
} ) ) ;
}
2016-05-20 16:48:43 -04:00
private void StopTracking ( )
{
// First complete the running of the thread
if ( processing_thread ! = null )
{
// Tell the other thread to finish
thread_running = false ;
processing_thread . Join ( ) ;
}
}
// ----------------------------------------------------------
// Mode handling (image, video)
// ----------------------------------------------------------
2017-01-05 17:48:14 -05:00
// Disable GUI components that should not be active during processing
private void SetupFeatureExtractionMode ( )
{
Dispatcher . Invoke ( ( Action ) ( ( ) = >
{
SettingsMenu . IsEnabled = false ;
RecordingMenu . IsEnabled = false ;
AUSetting . IsEnabled = false ;
2018-05-06 08:19:09 +01:00
FaceDetectorMenu . IsEnabled = false ;
LandmarkDetectorMenu . IsEnabled = false ;
2017-01-05 17:48:14 -05:00
PauseButton . IsEnabled = true ;
StopButton . IsEnabled = true ;
NextFiveFramesButton . IsEnabled = false ;
NextFrameButton . IsEnabled = false ;
} ) ) ;
}
// When the processing is done re-enable the components
2017-01-05 18:13:49 -05:00
private void EndMode ( )
2017-01-05 17:48:14 -05:00
{
2018-01-22 17:43:05 +00:00
latest_img = null ;
skip_frames = 0 ;
// Unpause if it's paused
if ( thread_paused )
{
Dispatcher . Invoke ( DispatcherPriority . Render , new TimeSpan ( 0 , 0 , 0 , 0 , 200 ) , ( Action ) ( ( ) = >
{
PauseButton_Click ( null , null ) ;
} ) ) ;
}
2017-01-05 18:13:49 -05:00
Dispatcher . Invoke ( DispatcherPriority . Render , new TimeSpan ( 0 , 0 , 0 , 1 , 0 ) , ( Action ) ( ( ) = >
2017-01-05 17:48:14 -05:00
{
2017-01-05 18:13:49 -05:00
2017-01-05 17:48:14 -05:00
SettingsMenu . IsEnabled = true ;
RecordingMenu . IsEnabled = true ;
AUSetting . IsEnabled = true ;
2018-05-06 08:19:09 +01:00
FaceDetectorMenu . IsEnabled = true ;
LandmarkDetectorMenu . IsEnabled = true ;
2017-01-05 17:48:14 -05:00
PauseButton . IsEnabled = false ;
StopButton . IsEnabled = false ;
NextFiveFramesButton . IsEnabled = false ;
NextFrameButton . IsEnabled = false ;
2017-01-05 18:13:49 -05:00
// Clean up the interface itself
2018-01-31 08:23:48 +00:00
overlay_image . Source = null ;
2017-01-05 18:13:49 -05:00
auClassGraph . Update ( new Dictionary < string , double > ( ) ) ;
auRegGraph . Update ( new Dictionary < string , double > ( ) ) ;
YawLabel . Content = "0°" ;
RollLabel . Content = "0°" ;
PitchLabel . Content = "0°" ;
XPoseLabel . Content = "0 mm" ;
YPoseLabel . Content = "0 mm" ;
ZPoseLabel . Content = "0 mm" ;
2018-05-06 08:19:09 +01:00
nonRigidGraph . Update ( new List < float > ( ) ) ;
2017-01-05 18:13:49 -05:00
GazeXLabel . Content = "0°" ;
GazeYLabel . Content = "0°" ;
AlignedFace . Source = null ;
AlignedHOG . Source = null ;
2017-01-05 17:48:14 -05:00
} ) ) ;
}
2016-05-20 16:48:43 -04:00
// ----------------------------------------------------------
// Opening Videos/Images
// ----------------------------------------------------------
2018-01-09 17:08:39 +00:00
// Some utilities for opening images/videos and directories
2018-01-22 17:43:05 +00:00
private List < string > openMediaDialog ( bool images )
2018-01-09 17:08:39 +00:00
{
string [ ] image_files = new string [ 0 ] ;
Dispatcher . Invoke ( DispatcherPriority . Render , new TimeSpan ( 0 , 0 , 0 , 2 , 0 ) , ( Action ) ( ( ) = >
{
2018-01-16 07:29:30 +00:00
var d = new Microsoft . Win32 . OpenFileDialog ( ) ;
2018-01-09 17:08:39 +00:00
d . Multiselect = true ;
2018-01-22 17:43:05 +00:00
if ( images )
{
2018-01-09 17:08:39 +00:00
d . Filter = "Image files|*.jpg;*.jpeg;*.bmp;*.png;*.gif" ;
}
else
{
2018-06-29 09:57:45 +01:00
d . Filter = "Video files|*.avi;*.webm;*.wmv;*.mov;*.mpg;*.mpeg;*.mp4" ;
2018-01-09 17:08:39 +00:00
}
if ( d . ShowDialog ( this ) = = true )
{
2016-05-20 16:48:43 -04:00
2018-01-09 17:08:39 +00:00
image_files = d . FileNames ;
}
} ) ) ;
List < string > img_files_list = new List < string > ( image_files ) ;
2018-01-22 17:43:05 +00:00
return img_files_list ;
2018-01-09 17:08:39 +00:00
}
2018-01-22 17:43:05 +00:00
2018-01-16 07:29:30 +00:00
private string openDirectory ( )
{
string to_return = "" ;
2018-05-06 08:19:09 +01:00
using ( var fbd = new System . Windows . Forms . FolderBrowserDialog ( ) )
2018-01-16 07:29:30 +00:00
{
2018-05-06 08:19:09 +01:00
System . Windows . Forms . DialogResult result = fbd . ShowDialog ( ) ;
2018-01-27 07:46:21 +00:00
if ( result = = System . Windows . Forms . DialogResult . OK )
2018-01-16 07:29:30 +00:00
{
to_return = fbd . SelectedPath ;
}
2018-01-27 07:46:21 +00:00
else if ( ! string . IsNullOrWhiteSpace ( fbd . SelectedPath ) )
2018-01-16 07:29:30 +00:00
{
string messageBoxText = "Could not open the directory." ;
string caption = "Invalid directory" ;
MessageBoxButton button = MessageBoxButton . OK ;
MessageBoxImage icon = MessageBoxImage . Warning ;
// Display message box
System . Windows . MessageBox . Show ( messageBoxText , caption , button , icon ) ;
2018-01-09 17:08:39 +00:00
2018-01-16 07:29:30 +00:00
}
}
return to_return ;
}
2018-01-22 17:43:05 +00:00
private void imageSequenceFileOpenClick ( object sender , RoutedEventArgs e )
{
// First clean up existing tracking
StopTracking ( ) ;
string directory = openDirectory ( ) ;
if ( ! string . IsNullOrWhiteSpace ( directory ) )
{
2018-01-27 12:12:36 +00:00
SequenceReader reader = new SequenceReader ( directory , true , fx , fy , cx , cy ) ;
2018-01-22 17:43:05 +00:00
processing_thread = new Thread ( ( ) = > ProcessSequence ( reader ) ) ;
2018-01-24 18:58:12 +00:00
processing_thread . Name = "Image sequence processing" ;
2018-01-22 17:43:05 +00:00
processing_thread . Start ( ) ;
}
}
private void videoFileOpenClick ( object sender , RoutedEventArgs e )
{
// First clean up existing tracking
StopTracking ( ) ;
var video_files = openMediaDialog ( false ) ;
processing_thread = new Thread ( ( ) = > ProcessSequences ( video_files ) ) ;
2018-01-24 18:58:12 +00:00
processing_thread . Name = "Video processing" ;
2018-01-22 17:43:05 +00:00
processing_thread . Start ( ) ;
}
2018-01-16 07:29:30 +00:00
// Selecting one or more images in a directory
2018-01-09 17:08:39 +00:00
private void individualImageFilesOpenClick ( object sender , RoutedEventArgs e )
{
// First clean up existing tracking
StopTracking ( ) ;
2018-01-22 17:43:05 +00:00
var image_files = openMediaDialog ( true ) ;
2018-01-09 17:08:39 +00:00
2018-05-06 08:19:09 +01:00
if ( image_files . Count > 0 )
{
ImageReader reader = new ImageReader ( image_files , fx , fy , cx , cy ) ;
2018-01-09 17:08:39 +00:00
2018-05-06 08:19:09 +01:00
processing_thread = new Thread ( ( ) = > ProcessIndividualImages ( reader ) ) ;
processing_thread . Start ( ) ;
}
2018-01-09 17:08:39 +00:00
}
2018-01-16 07:29:30 +00:00
// Selecting a directory containing images
2018-01-09 17:08:39 +00:00
private void individualImageDirectoryOpenClick ( object sender , RoutedEventArgs e )
2016-05-20 16:48:43 -04:00
{
2018-01-09 17:08:39 +00:00
2018-01-16 07:29:30 +00:00
// First clean up existing tracking
2016-05-20 16:48:43 -04:00
StopTracking ( ) ;
2018-01-16 07:29:30 +00:00
string directory = openDirectory ( ) ;
if ( ! string . IsNullOrWhiteSpace ( directory ) )
{
2018-01-31 21:08:54 +00:00
ImageReader reader = new ImageReader ( directory , fx , fy , cx , cy ) ;
2016-05-20 16:48:43 -04:00
2018-01-16 07:29:30 +00:00
processing_thread = new Thread ( ( ) = > ProcessIndividualImages ( reader ) ) ;
processing_thread . Start ( ) ;
}
2016-05-20 16:48:43 -04:00
}
2018-01-27 06:59:37 +00:00
private void openWebcamClick ( object sender , RoutedEventArgs e )
{
StopTracking ( ) ;
2018-01-27 07:46:21 +00:00
// If camera selection has already been done, no need to re-populate the list as it is quite slow
if ( cam_sec = = null )
{
cam_sec = new CameraSelection ( ) ;
}
else
2018-01-27 06:59:37 +00:00
{
2018-01-27 07:46:21 +00:00
cam_sec = new CameraSelection ( cam_sec . cams ) ;
cam_sec . Visibility = System . Windows . Visibility . Visible ;
}
2018-01-27 06:59:37 +00:00
2018-01-27 07:46:21 +00:00
// Set the icon
Uri iconUri = new Uri ( "logo1.ico" , UriKind . RelativeOrAbsolute ) ;
cam_sec . Icon = BitmapFrame . Create ( iconUri ) ;
2018-01-27 06:59:37 +00:00
2018-01-27 07:46:21 +00:00
if ( ! cam_sec . no_cameras_found )
cam_sec . ShowDialog ( ) ;
2018-01-27 06:59:37 +00:00
2018-01-27 07:46:21 +00:00
if ( cam_sec . camera_selected )
{
int cam_id = cam_sec . selected_camera . Item1 ;
int width = cam_sec . selected_camera . Item2 ;
int height = cam_sec . selected_camera . Item3 ;
2018-01-27 06:59:37 +00:00
2018-01-27 12:12:36 +00:00
SequenceReader reader = new SequenceReader ( cam_id , width , height , fx , fy , cx , cy ) ;
2018-01-27 06:59:37 +00:00
2018-01-27 07:46:21 +00:00
processing_thread = new Thread ( ( ) = > ProcessSequence ( reader ) ) ;
processing_thread . Name = "Webcam processing" ;
processing_thread . Start ( ) ;
2018-01-27 06:59:37 +00:00
2018-01-27 07:46:21 +00:00
}
2018-01-27 06:59:37 +00:00
}
2016-05-20 16:48:43 -04:00
// --------------------------------------------------------
// Button handling
// --------------------------------------------------------
// Cleanup stuff when closing the window
private void Window_Closing ( object sender , System . ComponentModel . CancelEventArgs e )
{
if ( processing_thread ! = null )
{
// Stop capture and tracking
thread_running = false ;
processing_thread . Join ( ) ;
}
}
// Stopping the tracking
private void StopButton_Click ( object sender , RoutedEventArgs e )
{
if ( processing_thread ! = null )
{
// Stop capture and tracking
thread_paused = false ;
thread_running = false ;
2017-01-05 18:13:49 -05:00
// Let the processing thread finish
2016-05-20 16:48:43 -04:00
processing_thread . Join ( ) ;
2017-01-05 18:13:49 -05:00
// Clean up the interface
EndMode ( ) ;
2016-05-20 16:48:43 -04:00
}
}
private void PauseButton_Click ( object sender , RoutedEventArgs e )
{
if ( processing_thread ! = null )
{
// Stop capture and tracking
thread_paused = ! thread_paused ;
NextFrameButton . IsEnabled = thread_paused ;
NextFiveFramesButton . IsEnabled = thread_paused ;
if ( thread_paused )
{
PauseButton . Content = "Resume" ;
}
else
{
PauseButton . Content = "Pause" ;
}
}
}
private void SkipButton_Click ( object sender , RoutedEventArgs e )
{
if ( sender . Equals ( NextFrameButton ) )
{
skip_frames + = 1 ;
}
else if ( sender . Equals ( NextFiveFramesButton ) )
{
skip_frames + = 5 ;
}
}
2016-12-08 16:14:06 -05:00
private void VisualisationChange ( object sender , RoutedEventArgs e )
2016-05-20 16:48:43 -04:00
{
// Collapsing or restoring the windows here
2016-12-08 16:14:06 -05:00
if ( ! ShowTrackedVideo )
2016-05-20 16:48:43 -04:00
{
VideoBorder . Visibility = System . Windows . Visibility . Collapsed ;
MainGrid . ColumnDefinitions [ 0 ] . Width = new GridLength ( 0 , GridUnitType . Star ) ;
}
else
{
VideoBorder . Visibility = System . Windows . Visibility . Visible ;
MainGrid . ColumnDefinitions [ 0 ] . Width = new GridLength ( 2.1 , GridUnitType . Star ) ;
}
2016-12-08 16:14:06 -05:00
if ( ! ShowAppearance )
2016-05-20 16:48:43 -04:00
{
AppearanceBorder . Visibility = System . Windows . Visibility . Collapsed ;
MainGrid . ColumnDefinitions [ 1 ] . Width = new GridLength ( 0 , GridUnitType . Star ) ;
}
else
{
AppearanceBorder . Visibility = System . Windows . Visibility . Visible ;
MainGrid . ColumnDefinitions [ 1 ] . Width = new GridLength ( 0.8 , GridUnitType . Star ) ;
}
// Collapsing or restoring the windows here
2016-12-08 16:14:06 -05:00
if ( ! ShowGeometry )
2016-05-20 16:48:43 -04:00
{
GeometryBorder . Visibility = System . Windows . Visibility . Collapsed ;
MainGrid . ColumnDefinitions [ 2 ] . Width = new GridLength ( 0 , GridUnitType . Star ) ;
}
else
{
GeometryBorder . Visibility = System . Windows . Visibility . Visible ;
MainGrid . ColumnDefinitions [ 2 ] . Width = new GridLength ( 1.0 , GridUnitType . Star ) ;
}
// Collapsing or restoring the windows here
2016-12-08 16:14:06 -05:00
if ( ! ShowAUs )
2016-05-20 16:48:43 -04:00
{
ActionUnitBorder . Visibility = System . Windows . Visibility . Collapsed ;
MainGrid . ColumnDefinitions [ 3 ] . Width = new GridLength ( 0 , GridUnitType . Star ) ;
}
else
{
ActionUnitBorder . Visibility = System . Windows . Visibility . Visible ;
MainGrid . ColumnDefinitions [ 3 ] . Width = new GridLength ( 1.6 , GridUnitType . Star ) ;
}
}
2018-01-10 08:27:16 +00:00
2016-12-05 17:28:39 -05:00
private void setOutputImageSize_Click ( object sender , RoutedEventArgs e )
{
2017-01-06 16:43:55 -05:00
NumberEntryWindow number_entry_window = new NumberEntryWindow ( image_output_size ) ;
2016-12-05 17:28:39 -05:00
number_entry_window . Icon = this . Icon ;
number_entry_window . WindowStartupLocation = WindowStartupLocation . CenterScreen ;
if ( number_entry_window . ShowDialog ( ) = = true )
{
image_output_size = number_entry_window . OutputInt ;
}
}
2016-12-06 10:03:04 -05:00
2018-05-06 08:19:09 +01:00
private void ExclusiveMenuItem_Click ( object sender , RoutedEventArgs e )
{
// Disable all other items but this one
MenuItem parent = ( MenuItem ) ( ( MenuItem ) sender ) . Parent ;
foreach ( var me in parent . Items )
{
( ( MenuItem ) me ) . IsChecked = false ;
}
( ( MenuItem ) sender ) . IsChecked = true ;
}
2017-01-06 16:43:55 -05:00
private void setCameraParameters_Click ( object sender , RoutedEventArgs e )
{
CameraParametersEntry camera_params_entry_window = new CameraParametersEntry ( fx , fy , cx , cy ) ;
camera_params_entry_window . Icon = this . Icon ;
camera_params_entry_window . WindowStartupLocation = WindowStartupLocation . CenterScreen ;
if ( camera_params_entry_window . ShowDialog ( ) = = true )
{
fx = camera_params_entry_window . Fx ;
fy = camera_params_entry_window . Fy ;
cx = camera_params_entry_window . Cx ;
cy = camera_params_entry_window . Cy ;
}
}
2018-05-06 08:19:09 +01:00
// Making sure only one radio button is selected
private void MenuItemWithRadioButtons_Click ( object sender , System . Windows . RoutedEventArgs e )
{
MenuItem mi = sender as MenuItem ;
if ( mi ! = null )
{
RadioButton rb = mi . Icon as RadioButton ;
if ( rb ! = null )
{
rb . IsChecked = true ;
}
}
}
2016-12-06 10:03:04 -05:00
private void OutputLocationItem_Click ( object sender , RoutedEventArgs e )
{
var dlg = new CommonOpenFileDialog ( ) ;
dlg . Title = "Select output directory" ;
dlg . IsFolderPicker = true ;
dlg . AllowNonFileSystemItems = false ;
dlg . EnsureFileExists = true ;
dlg . EnsurePathExists = true ;
dlg . EnsureReadOnly = false ;
dlg . EnsureValidNames = true ;
dlg . Multiselect = false ;
dlg . ShowPlacesList = true ;
if ( dlg . ShowDialog ( ) = = CommonFileDialogResult . Ok )
{
var folder = dlg . FileName ;
record_root = folder ;
}
}
2017-01-06 16:43:55 -05:00
2016-05-20 16:48:43 -04:00
}
2018-05-06 08:19:09 +01:00
2016-05-20 16:48:43 -04:00
}