From da458f1ab67280f0d8eff271c6f2b052074762ea Mon Sep 17 00:00:00 2001 From: Tadas Baltrusaitis Date: Sat, 27 Jan 2018 07:46:21 +0000 Subject: [PATCH] Cleaning up reading from a webcam. --- gui/OpenFaceOffline/MainWindow.xaml.cs | 64 ++++++++++--------- lib/local/CppInerop/SequenceReader.h | 9 ++- lib/local/Utilities/include/SequenceCapture.h | 2 + lib/local/Utilities/src/SequenceCapture.cpp | 6 ++ 4 files changed, 50 insertions(+), 31 deletions(-) diff --git a/gui/OpenFaceOffline/MainWindow.xaml.cs b/gui/OpenFaceOffline/MainWindow.xaml.cs index 0650774..a381f7c 100644 --- a/gui/OpenFaceOffline/MainWindow.xaml.cs +++ b/gui/OpenFaceOffline/MainWindow.xaml.cs @@ -116,7 +116,7 @@ namespace OpenFaceOffline 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 - public bool RecordTracked { get; set; } = false; // Recording tracked videos or images + public bool RecordTracked { get; set; } = true; // Recording tracked videos or images // Visualisation options public bool ShowTrackedVideo { get; set; } = true; // Showing the actual tracking @@ -166,7 +166,7 @@ namespace OpenFaceOffline ProcessSequence(reader); // Before continuing to next video make sure the user did not stop the processing - if(!thread_running) + if (!thread_running) { break; } @@ -248,9 +248,15 @@ namespace OpenFaceOffline processing_fps.AddFrame(); } + // Finalize the recording and flush to disk + recorder.Close(); + // Post-process the AU recordings face_analyser.PostProcessOutputFile(recorder.GetCSVFile()); + // Close the open video/webcam + reader.Close(); + EndMode(); } @@ -342,6 +348,7 @@ namespace OpenFaceOffline lastFrameTime = CurrentTime; processing_fps.AddFrame(); + // TODO how to report errors from the reader here? exceptions? logging? Problem for future versions? } @@ -676,13 +683,12 @@ namespace OpenFaceOffline using (var fbd = new FolderBrowserDialog()) { DialogResult result = fbd.ShowDialog(); - if (result == System.Windows.Forms.DialogResult.OK && !string.IsNullOrWhiteSpace(fbd.SelectedPath)) + if (result == System.Windows.Forms.DialogResult.OK) { to_return = fbd.SelectedPath; } - else + else if(!string.IsNullOrWhiteSpace(fbd.SelectedPath)) { - // TODO warning message here string messageBoxText = "Could not open the directory."; string caption = "Invalid directory"; MessageBoxButton button = MessageBoxButton.OK; @@ -760,37 +766,37 @@ namespace OpenFaceOffline { StopTracking(); - Dispatcher.Invoke(DispatcherPriority.Render, new TimeSpan(0, 0, 0, 2, 0), (Action)(() => + // 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 + { + cam_sec = new CameraSelection(cam_sec.cams); + cam_sec.Visibility = System.Windows.Visibility.Visible; + } - if (cam_sec == null) - { - cam_sec = new CameraSelection(); - } - else - { - cam_sec = new CameraSelection(cam_sec.cams); - cam_sec.Visibility = System.Windows.Visibility.Visible; - } + // Set the icon + Uri iconUri = new Uri("logo1.ico", UriKind.RelativeOrAbsolute); + cam_sec.Icon = BitmapFrame.Create(iconUri); - // Set the icon - Uri iconUri = new Uri("logo1.ico", UriKind.RelativeOrAbsolute); - cam_sec.Icon = BitmapFrame.Create(iconUri); + if (!cam_sec.no_cameras_found) + cam_sec.ShowDialog(); - if (!cam_sec.no_cameras_found) - cam_sec.ShowDialog(); + 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; - 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; + SequenceReader reader = new SequenceReader(cam_id, width, height); -// processing_thread = new Thread(() => ProcessingLoop(cam_id, width, height)); -// processing_thread.Start(); + processing_thread = new Thread(() => ProcessSequence(reader)); + processing_thread.Name = "Webcam processing"; + processing_thread.Start(); - } - })); + } } diff --git a/lib/local/CppInerop/SequenceReader.h b/lib/local/CppInerop/SequenceReader.h index 38c4f61..19d054f 100644 --- a/lib/local/CppInerop/SequenceReader.h +++ b/lib/local/CppInerop/SequenceReader.h @@ -98,11 +98,11 @@ namespace UtilitiesOF { } // Can provide a webcam id - SequenceReader(int webcam_id) + SequenceReader(int webcam_id, int width, int height) { m_sequence_capture = new Utilities::SequenceCapture(); - bool success = m_sequence_capture->OpenWebcam(webcam_id); + bool success = m_sequence_capture->OpenWebcam(webcam_id, width, height); if (!success) { @@ -184,6 +184,10 @@ namespace UtilitiesOF { return m_gray_frame; } + void Close() { + m_sequence_capture->Close(); + } + // Finalizer. Definitely called before Garbage Collection, // but not automatically called on explicit Dispose(). // May be called multiple times. @@ -343,6 +347,7 @@ namespace UtilitiesOF { std::vector> common_resolutions; common_resolutions.push_back(std::pair(320, 240)); common_resolutions.push_back(std::pair(640, 480)); + common_resolutions.push_back(std::pair(800, 600)); common_resolutions.push_back(std::pair(960, 720)); common_resolutions.push_back(std::pair(1280, 720)); common_resolutions.push_back(std::pair(1280, 960)); diff --git a/lib/local/Utilities/include/SequenceCapture.h b/lib/local/Utilities/include/SequenceCapture.h index 97f7629..422faff 100644 --- a/lib/local/Utilities/include/SequenceCapture.h +++ b/lib/local/Utilities/include/SequenceCapture.h @@ -87,6 +87,8 @@ namespace Utilities bool IsOpened(); + void Close(); + int frame_width; int frame_height; diff --git a/lib/local/Utilities/src/SequenceCapture.cpp b/lib/local/Utilities/src/SequenceCapture.cpp index 9bec750..4ee6e94 100644 --- a/lib/local/Utilities/src/SequenceCapture.cpp +++ b/lib/local/Utilities/src/SequenceCapture.cpp @@ -256,6 +256,12 @@ bool SequenceCapture::OpenWebcam(int device, int image_width, int image_height, } +void SequenceCapture::Close() +{ + if (capture.isOpened()) + capture.release(); +} + // Destructor that releases the capture SequenceCapture::~SequenceCapture() {