diff --git a/.gitignore b/.gitignore index cbe5b45..5857abe 100644 --- a/.gitignore +++ b/.gitignore @@ -86,3 +86,4 @@ matlab_runners/Demos/processed_features/ *.db exe/releases/OpenFace_0.3.0_win_x64/ exe/releases/OpenFace_0.3.0_win_x86/ +lib/3rdParty/CameraEnumerator/x64/ diff --git a/OpenFace.sln b/OpenFace.sln index ffe01dd..1fb61f1 100644 --- a/OpenFace.sln +++ b/OpenFace.sln @@ -41,6 +41,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HeadPoseLive", "gui\HeadPos EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Utilities", "lib\local\Utilities\Utilities.vcxproj", "{8E741EA2-9386-4CF2-815E-6F9B08991EAC}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CameraEnumerator", "lib\3rdParty\CameraEnumerator\CameraEnumerator.vcxproj", "{50B7D4BF-E33B-41D0-AA89-76BBA57BF5CC}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -73,6 +75,14 @@ Global {0E7FC556-0E80-45EA-A876-DDE4C2FEDCD7}.Release|Win32.Build.0 = Release|Win32 {0E7FC556-0E80-45EA-A876-DDE4C2FEDCD7}.Release|x64.ActiveCfg = Release|x64 {0E7FC556-0E80-45EA-A876-DDE4C2FEDCD7}.Release|x64.Build.0 = Release|x64 + {5F915541-F531-434F-9C81-79F5DB58012B}.Debug|Win32.ActiveCfg = Debug|Win32 + {5F915541-F531-434F-9C81-79F5DB58012B}.Debug|Win32.Build.0 = Debug|Win32 + {5F915541-F531-434F-9C81-79F5DB58012B}.Debug|x64.ActiveCfg = Debug|x64 + {5F915541-F531-434F-9C81-79F5DB58012B}.Debug|x64.Build.0 = Debug|x64 + {5F915541-F531-434F-9C81-79F5DB58012B}.Release|Win32.ActiveCfg = Release|Win32 + {5F915541-F531-434F-9C81-79F5DB58012B}.Release|Win32.Build.0 = Release|Win32 + {5F915541-F531-434F-9C81-79F5DB58012B}.Release|x64.ActiveCfg = Release|x64 + {5F915541-F531-434F-9C81-79F5DB58012B}.Release|x64.Build.0 = Release|x64 {8A23C00D-767D-422D-89A3-CF225E3DAB4B}.Debug|Win32.ActiveCfg = Debug|Win32 {8A23C00D-767D-422D-89A3-CF225E3DAB4B}.Debug|Win32.Build.0 = Debug|Win32 {8A23C00D-767D-422D-89A3-CF225E3DAB4B}.Debug|x64.ActiveCfg = Debug|x64 @@ -152,14 +162,6 @@ Global {F396362D-821E-4EA6-9BBF-1F6050844118}.Release|Win32.Build.0 = Release|x86 {F396362D-821E-4EA6-9BBF-1F6050844118}.Release|x64.ActiveCfg = Release|Any CPU {F396362D-821E-4EA6-9BBF-1F6050844118}.Release|x64.Build.0 = Release|Any CPU - {5F915541-F531-434F-9C81-79F5DB58012B}.Debug|Win32.ActiveCfg = Debug|Win32 - {5F915541-F531-434F-9C81-79F5DB58012B}.Debug|Win32.Build.0 = Debug|Win32 - {5F915541-F531-434F-9C81-79F5DB58012B}.Debug|x64.ActiveCfg = Debug|x64 - {5F915541-F531-434F-9C81-79F5DB58012B}.Debug|x64.Build.0 = Debug|x64 - {5F915541-F531-434F-9C81-79F5DB58012B}.Release|Win32.ActiveCfg = Release|Win32 - {5F915541-F531-434F-9C81-79F5DB58012B}.Release|Win32.Build.0 = Release|Win32 - {5F915541-F531-434F-9C81-79F5DB58012B}.Release|x64.ActiveCfg = Release|x64 - {5F915541-F531-434F-9C81-79F5DB58012B}.Release|x64.Build.0 = Release|x64 {8E741EA2-9386-4CF2-815E-6F9B08991EAC}.Debug|Win32.ActiveCfg = Debug|Win32 {8E741EA2-9386-4CF2-815E-6F9B08991EAC}.Debug|Win32.Build.0 = Debug|Win32 {8E741EA2-9386-4CF2-815E-6F9B08991EAC}.Debug|x64.ActiveCfg = Debug|x64 @@ -168,6 +170,14 @@ Global {8E741EA2-9386-4CF2-815E-6F9B08991EAC}.Release|Win32.Build.0 = Release|Win32 {8E741EA2-9386-4CF2-815E-6F9B08991EAC}.Release|x64.ActiveCfg = Release|x64 {8E741EA2-9386-4CF2-815E-6F9B08991EAC}.Release|x64.Build.0 = Release|x64 + {50B7D4BF-E33B-41D0-AA89-76BBA57BF5CC}.Debug|Win32.ActiveCfg = Debug|Win32 + {50B7D4BF-E33B-41D0-AA89-76BBA57BF5CC}.Debug|Win32.Build.0 = Debug|Win32 + {50B7D4BF-E33B-41D0-AA89-76BBA57BF5CC}.Debug|x64.ActiveCfg = Debug|x64 + {50B7D4BF-E33B-41D0-AA89-76BBA57BF5CC}.Debug|x64.Build.0 = Debug|x64 + {50B7D4BF-E33B-41D0-AA89-76BBA57BF5CC}.Release|Win32.ActiveCfg = Release|Win32 + {50B7D4BF-E33B-41D0-AA89-76BBA57BF5CC}.Release|Win32.Build.0 = Release|Win32 + {50B7D4BF-E33B-41D0-AA89-76BBA57BF5CC}.Release|x64.ActiveCfg = Release|x64 + {50B7D4BF-E33B-41D0-AA89-76BBA57BF5CC}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -176,6 +186,7 @@ Global {B47A5F12-2567-44E9-AE49-35763EC82149} = {D5F7B3E2-01FE-4F4A-8CE1-274D74D395D4} {BDC1D107-DE17-4705-8E7B-CDDE8BFB2BF8} = {99FEBA13-BDDF-4076-B57E-D8EF4076E20D} {0E7FC556-0E80-45EA-A876-DDE4C2FEDCD7} = {99FEBA13-BDDF-4076-B57E-D8EF4076E20D} + {5F915541-F531-434F-9C81-79F5DB58012B} = {99FEBA13-BDDF-4076-B57E-D8EF4076E20D} {8A23C00D-767D-422D-89A3-CF225E3DAB4B} = {9961DDAC-BE6E-4A6E-8EEF-FFC7D67BD631} {C3FAF36F-44BC-4454-87C2-C5106575FE50} = {9961DDAC-BE6E-4A6E-8EEF-FFC7D67BD631} {2D80FA0B-2DE8-4475-BA5A-C08A9E1EDAAC} = {9961DDAC-BE6E-4A6E-8EEF-FFC7D67BD631} @@ -186,7 +197,7 @@ Global {A4760F41-2B1F-4144-B7B2-62785AFFE79B} = {C9D8D0B0-11EC-41CB-8524-2DDB5BE94297} {E143A2AA-312E-4DFE-B61D-9A87CCBC8E90} = {C9D8D0B0-11EC-41CB-8524-2DDB5BE94297} {F396362D-821E-4EA6-9BBF-1F6050844118} = {C9D8D0B0-11EC-41CB-8524-2DDB5BE94297} - {5F915541-F531-434F-9C81-79F5DB58012B} = {99FEBA13-BDDF-4076-B57E-D8EF4076E20D} {8E741EA2-9386-4CF2-815E-6F9B08991EAC} = {99FEBA13-BDDF-4076-B57E-D8EF4076E20D} + {50B7D4BF-E33B-41D0-AA89-76BBA57BF5CC} = {D5F7B3E2-01FE-4F4A-8CE1-274D74D395D4} EndGlobalSection EndGlobal diff --git a/gui/OpenFaceOffline/MainWindow.xaml b/gui/OpenFaceOffline/MainWindow.xaml index e991830..1403b8d 100644 --- a/gui/OpenFaceOffline/MainWindow.xaml +++ b/gui/OpenFaceOffline/MainWindow.xaml @@ -31,6 +31,8 @@ + + diff --git a/gui/OpenFaceOffline/MainWindow.xaml.cs b/gui/OpenFaceOffline/MainWindow.xaml.cs index 2c4debf..0650774 100644 --- a/gui/OpenFaceOffline/MainWindow.xaml.cs +++ b/gui/OpenFaceOffline/MainWindow.xaml.cs @@ -96,6 +96,9 @@ namespace OpenFaceOffline FpsTracker processing_fps = new FpsTracker(); + // For selecting webcams + CameraSelection cam_sec; + // For tracking FaceDetector face_detector; FaceModelParameters face_model_params; @@ -753,6 +756,44 @@ namespace OpenFaceOffline } } + private void openWebcamClick(object sender, RoutedEventArgs e) + { + StopTracking(); + + Dispatcher.Invoke(DispatcherPriority.Render, new TimeSpan(0, 0, 0, 2, 0), (Action)(() => + { + + 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); + + 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; + +// processing_thread = new Thread(() => ProcessingLoop(cam_id, width, height)); +// processing_thread.Start(); + + } + })); + } + + // -------------------------------------------------------- // Button handling // -------------------------------------------------------- diff --git a/gui/OpenFaceOffline/OpenFaceOffline.csproj b/gui/OpenFaceOffline/OpenFaceOffline.csproj index b1e7bdc..779645d 100644 --- a/gui/OpenFaceOffline/OpenFaceOffline.csproj +++ b/gui/OpenFaceOffline/OpenFaceOffline.csproj @@ -97,6 +97,9 @@ CameraParametersEntry.xaml + + CameraSelection.xaml + MultiBarGraph.xaml @@ -136,6 +139,10 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + Designer MSBuild:Compile diff --git a/gui/OpenFaceOffline/UI_items/CameraSelection.xaml b/gui/OpenFaceOffline/UI_items/CameraSelection.xaml new file mode 100644 index 0000000..04375d6 --- /dev/null +++ b/gui/OpenFaceOffline/UI_items/CameraSelection.xaml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gui/OpenFaceOffline/UI_items/CameraSelection.xaml.cs b/gui/OpenFaceOffline/UI_items/CameraSelection.xaml.cs new file mode 100644 index 0000000..4a3f59f --- /dev/null +++ b/gui/OpenFaceOffline/UI_items/CameraSelection.xaml.cs @@ -0,0 +1,244 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Shapes; + +using CppInterop; +using System.Windows.Threading; +using System.Threading; + +namespace OpenFaceOffline +{ + /// + /// Interaction logic for CameraSelection.xaml + /// + public partial class CameraSelection : Window + { + + List sample_images; + List combo_boxes; + + // id, width, height + public Tuple selected_camera; + + List>> resolutions_all; + int selected_camera_idx = -1; + + // indicate if user clicked on camera + public bool camera_selected = false; + + public bool no_cameras_found = false; + + public List>, OpenCVWrappers.RawImage>> cams; + + public void PopulateCameraSelections() + { + this.KeyDown += new KeyEventHandler(CameraSelection_KeyDown); + + // Finding the cameras here + if (cams == null) + { + String root = AppDomain.CurrentDomain.BaseDirectory; + //cams = CameraInterop.Capture.GetCameras(root); + cams = UtilitiesOF.SequenceReader.GetCameras(root); + } + + int i = 0; + + sample_images = new List(); + + // Each cameras corresponding resolutions + resolutions_all = new List>>(); + combo_boxes = new List(); + + foreach (var s in cams) + { + + var b = s.Item4.CreateWriteableBitmap(); + s.Item4.UpdateWriteableBitmap(b); + b.Freeze(); + + Dispatcher.Invoke(() => + { + int idx = i; + Image img = new Image(); + img.Source = b; + img.Margin = new Thickness(5); + + ColumnDefinition col_def = new ColumnDefinition(); + ThumbnailPanel.ColumnDefinitions.Add(col_def); + + Border img_border = new Border(); + img_border.SetValue(Grid.ColumnProperty, i); + img_border.SetValue(Grid.RowProperty, 0); + img_border.CornerRadius = new CornerRadius(5); + + StackPanel img_panel = new StackPanel(); + + Label camera_name_label = new Label(); + camera_name_label.Content = s.Item2; + camera_name_label.HorizontalAlignment = System.Windows.HorizontalAlignment.Center; + img_panel.Children.Add(camera_name_label); + img.Height = 200; + img_panel.Children.Add(img); + img_border.Child = img_panel; + + sample_images.Add(img_border); + + ThumbnailPanel.Children.Add(img_border); + + ComboBox resolutions = new ComboBox(); + resolutions.Width = 80; + combo_boxes.Add(resolutions); + + resolutions_all.Add(new List>()); + + foreach (var r in s.Item3) + { + resolutions.Items.Add(r.Item1 + "x" + r.Item2); + resolutions_all[resolutions_all.Count - 1].Add(new Tuple(r.Item1, r.Item2)); + + } + + resolutions.SelectedIndex = 0; + for (int res = 0; res < s.Item3.Count; ++res) + { + if (s.Item3[res].Item1 >= 640 && s.Item3[res].Item2 >= 480) + { + resolutions.SelectedIndex = res; + break; + } + } + resolutions.SetValue(Grid.ColumnProperty, i); + resolutions.SetValue(Grid.RowProperty, 2); + ThumbnailPanel.Children.Add(resolutions); + + img_panel.MouseDown += (sender, e) => + { + ChooseCamera(idx); + }; + + resolutions.DropDownOpened += (sender, e) => + { + ChooseCamera(idx); + }; + + }); + + i++; + + } + if (cams.Count > 0) + { + no_cameras_found = false; + Dispatcher.Invoke(DispatcherPriority.Render, new TimeSpan(0, 0, 0, 0, 200), (Action)(() => + { + ChooseCamera(0); + })); + } + else + { + string messageBoxText = "No cameras detected, please connect a webcam"; + string caption = "Camera error!"; + MessageBoxButton button = MessageBoxButton.OK; + MessageBoxImage icon = MessageBoxImage.Warning; + MessageBox.Show(messageBoxText, caption, button, icon); + selected_camera_idx = -1; + no_cameras_found = true; + Dispatcher.Invoke(DispatcherPriority.Render, new TimeSpan(0, 0, 0, 0, 200), (Action)(() => + { + this.Close(); + })); + } + } + + public CameraSelection() + { + + InitializeComponent(); + + // We want to display the loading screen first + Thread load_cameras = new Thread(LoadCameras); + load_cameras.Start(); + } + + public void LoadCameras() + { + Thread.CurrentThread.IsBackground = true; + PopulateCameraSelections(); + + Dispatcher.Invoke(DispatcherPriority.Render, new TimeSpan(0, 0, 0, 0, 200), (Action)(() => + { + LoadingGrid.Visibility = System.Windows.Visibility.Hidden; + camerasPanel.Visibility = System.Windows.Visibility.Visible; + })); + } + + public CameraSelection(List>, OpenCVWrappers.RawImage>> cams) + { + InitializeComponent(); + this.cams = cams; + PopulateCameraSelections(); + + Dispatcher.Invoke(DispatcherPriority.Render, new TimeSpan(0, 0, 0, 0, 200), (Action)(() => + { + LoadingGrid.Visibility = System.Windows.Visibility.Hidden; + camerasPanel.Visibility = System.Windows.Visibility.Visible; + })); + } + + private void ChooseCamera(int idx) + { + selected_camera_idx = idx; + + foreach (var img in sample_images) + { + img.BorderThickness = new Thickness(1); + img.BorderBrush = Brushes.Gray; + } + sample_images[idx].BorderThickness = new Thickness(4); + sample_images[idx].BorderBrush = Brushes.Green; + + } + + private void Button_Click(object sender, RoutedEventArgs e) + { + Select(); + } + + private void CameraSelection_KeyDown(object sender, KeyEventArgs e) + { + if (e.Key == Key.Enter) + { + Select(); + } + } + + private void Select() + { + camera_selected = true; + + int selected_res = combo_boxes[selected_camera_idx].SelectedIndex; + Tuple resolution_selected = resolutions_all[selected_camera_idx][selected_res]; + + selected_camera = new Tuple(selected_camera_idx, resolution_selected.Item1, resolution_selected.Item2); + + this.Close(); + } + + // Do not close it as user might want to open it again + private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e) + { + } + + } +} diff --git a/lib/3rdParty/CameraEnumerator/CameraEnumerator.vcxproj b/lib/3rdParty/CameraEnumerator/CameraEnumerator.vcxproj index 3be56a7..7ec6dac 100644 --- a/lib/3rdParty/CameraEnumerator/CameraEnumerator.vcxproj +++ b/lib/3rdParty/CameraEnumerator/CameraEnumerator.vcxproj @@ -127,7 +127,11 @@ - + + + + + diff --git a/lib/3rdParty/CameraEnumerator/CameraEnumerator.vcxproj.filters b/lib/3rdParty/CameraEnumerator/CameraEnumerator.vcxproj.filters index 34c1b07..eccf711 100644 --- a/lib/3rdParty/CameraEnumerator/CameraEnumerator.vcxproj.filters +++ b/lib/3rdParty/CameraEnumerator/CameraEnumerator.vcxproj.filters @@ -15,6 +15,16 @@ - + + Header Files + + + + + Source Files + + + Source Files + \ No newline at end of file diff --git a/lib/3rdParty/CameraEnumerator/DeviceEnumerator.cpp b/lib/3rdParty/CameraEnumerator/DeviceEnumerator.cpp index 02f4776..efb8a3a 100644 --- a/lib/3rdParty/CameraEnumerator/DeviceEnumerator.cpp +++ b/lib/3rdParty/CameraEnumerator/DeviceEnumerator.cpp @@ -1,4 +1,5 @@ #include "DeviceEnumerator.h" +#include std::map DeviceEnumerator::getVideoDevicesMap() { return getDevicesMap(CLSID_VideoInputDeviceCategory); @@ -13,14 +14,15 @@ std::map DeviceEnumerator::getDevicesMap(const GUID deviceClass) { std::map deviceMap; - HRESULT hr = CoInitialize(nullptr); - if (FAILED(hr)) { - return deviceMap; // Empty deviceMap as an error - } + // TODO add back? Calling from C# seems to not need this + //HRESULT hr = CoInitialize(nullptr); + //if (FAILED(hr)) { + // return deviceMap; // Empty deviceMap as an error + //} // Create the System Device Enumerator ICreateDevEnum *pDevEnum; - hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pDevEnum)); + HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pDevEnum)); // If succeeded, create an enumerator for the category IEnumMoniker *pEnum = NULL; diff --git a/lib/local/CppInerop/CppInerop.vcxproj b/lib/local/CppInerop/CppInerop.vcxproj index f07cb0a..9e7ff4c 100644 --- a/lib/local/CppInerop/CppInerop.vcxproj +++ b/lib/local/CppInerop/CppInerop.vcxproj @@ -116,7 +116,7 @@ Level3 Disabled WIN32;_DEBUG;_WINDOWS;_USRDLL;CPPINEROP_EXPORTS;%(PreprocessorDefinitions) - ./;$(SolutionDir)lib\local\LandmarkDetector\include;$(SolutionDir)lib\local\FaceAnalyser\include;$(SolutionDir)lib\local\GazeAnalyser\include;$(SolutionDir)lib\local\Utilities\include;%(AdditionalIncludeDirectories) + ./;$(SolutionDir)lib\local\LandmarkDetector\include;$(SolutionDir)lib\local\FaceAnalyser\include;$(SolutionDir)lib\local\GazeAnalyser\include;$(SolutionDir)lib\local\Utilities\include;$(SolutionDir)lib\3rdParty\CameraEnumerator;%(AdditionalIncludeDirectories) Windows @@ -130,7 +130,7 @@ Level3 Disabled _DEBUG;_WINDOWS;_USRDLL;CPPINEROP_EXPORTS;%(PreprocessorDefinitions) - ./;$(SolutionDir)lib\local\LandmarkDetector\include;$(SolutionDir)lib\local\FaceAnalyser\include;$(SolutionDir)lib\local\GazeAnalyser\include;$(SolutionDir)lib\local\Utilities\include;%(AdditionalIncludeDirectories) + ./;$(SolutionDir)lib\local\LandmarkDetector\include;$(SolutionDir)lib\local\FaceAnalyser\include;$(SolutionDir)lib\local\GazeAnalyser\include;$(SolutionDir)lib\local\Utilities\include;$(SolutionDir)lib\3rdParty\CameraEnumerator;%(AdditionalIncludeDirectories) Windows @@ -146,7 +146,7 @@ true true WIN32;NDEBUG;_WINDOWS;_USRDLL;CPPINEROP_EXPORTS;%(PreprocessorDefinitions) - ./;$(SolutionDir)lib\local\LandmarkDetector\include;$(SolutionDir)lib\local\FaceAnalyser\include;$(SolutionDir)lib\local\GazeAnalyser\include;$(SolutionDir)lib\local\Utilities\include;%(AdditionalIncludeDirectories) + ./;$(SolutionDir)lib\local\LandmarkDetector\include;$(SolutionDir)lib\local\FaceAnalyser\include;$(SolutionDir)lib\local\GazeAnalyser\include;$(SolutionDir)lib\local\Utilities\include;$(SolutionDir)lib\3rdParty\CameraEnumerator;%(AdditionalIncludeDirectories) Windows @@ -164,7 +164,7 @@ true true NDEBUG;_WINDOWS;_USRDLL;CPPINEROP_EXPORTS;%(PreprocessorDefinitions) - ./;$(SolutionDir)lib\local\LandmarkDetector\include;$(SolutionDir)lib\local\FaceAnalyser\include;$(SolutionDir)lib\local\GazeAnalyser\include;$(SolutionDir)lib\local\Utilities\include;%(AdditionalIncludeDirectories) + ./;$(SolutionDir)lib\local\LandmarkDetector\include;$(SolutionDir)lib\local\FaceAnalyser\include;$(SolutionDir)lib\local\GazeAnalyser\include;$(SolutionDir)lib\local\Utilities\include;$(SolutionDir)lib\3rdParty\CameraEnumerator;%(AdditionalIncludeDirectories) Windows @@ -190,6 +190,9 @@ + + {50b7d4bf-e33b-41d0-aa89-76bba57bf5cc} + {b47a5f12-2567-44e9-ae49-35763ec82149} diff --git a/lib/local/CppInerop/SequenceReader.h b/lib/local/CppInerop/SequenceReader.h index 98fcdb7..38c4f61 100644 --- a/lib/local/CppInerop/SequenceReader.h +++ b/lib/local/CppInerop/SequenceReader.h @@ -211,181 +211,186 @@ namespace UtilitiesOF { { this->!SequenceReader(); } - }; - - static void split(const std::string &s, char delim, std::vector &elems) { - std::stringstream ss; - ss.str(s); - std::string item; - while (std::getline(ss, item, delim)) { - elems.push_back(item); - } - } - - // Camera listing is camera name and supported resolutions - static Dictionary^>^>^ GetListingFromFile(std::string filename) - { - // Check what cameras have been written (using OpenCVs XML packages) - cv::FileStorage fs_read(filename, cv::FileStorage::READ); - - auto managed_camera_list_initial = gcnew Dictionary^>^>(); - - cv::FileNode camera_node_list = fs_read["cameras"]; - - // iterate through a sequence using FileNodeIterator - for (size_t idx = 0; idx < camera_node_list.size(); idx++) - { - std::string camera_name = (std::string)camera_node_list[idx]["name"]; - - cv::FileNode resolution_list = camera_node_list[idx]["resolutions"]; - auto resolutions = gcnew System::Collections::Generic::List^>(); - for (size_t r_idx = 0; r_idx < resolution_list.size(); r_idx++) - { - string res = resolution_list[r_idx]["res"]; - - std::vector elems; - split(res, 'x', elems); - - int x = stoi(elems[0]); - int y = stoi(elems[1]); - resolutions->Add(gcnew System::Tuple(x, y)); + + private: + // Static methods for listing cameras and their resolutions + static void split(const std::string &s, char delim, std::vector &elems) { + std::stringstream ss; + ss.str(s); + std::string item; + while (std::getline(ss, item, delim)) { + elems.push_back(item); } - managed_camera_list_initial[gcnew System::String(camera_name.c_str())] = resolutions; } - fs_read.release(); - return managed_camera_list_initial; - } - static void WriteCameraListingToFile(System::Collections::Generic::Dictionary^>^>^ camera_list, std::string filename) - { - cv::FileStorage fs("camera_list.xml", cv::FileStorage::WRITE); - - fs << "cameras" << "["; - for each(System::String^ name_m in camera_list->Keys) + // Camera listing is camera name and supported resolutions + static Dictionary^>^>^ GetListingFromFile(std::string filename) { + // Check what cameras have been written (using OpenCVs XML packages) + cv::FileStorage fs_read(filename, cv::FileStorage::READ); - std::string name = msclr::interop::marshal_as(name_m); + auto managed_camera_list_initial = gcnew Dictionary^>^>(); - fs << "{:" << "name" << name; - fs << "resolutions" << "["; - auto resolutions = camera_list[name_m]; - for (int j = 0; j < resolutions->Count; j++) + cv::FileNode camera_node_list = fs_read["cameras"]; + + // iterate through a sequence using FileNodeIterator + for (size_t idx = 0; idx < camera_node_list.size(); idx++) { - stringstream ss; - ss << resolutions[j]->Item1 << "x" << resolutions[j]->Item2; + std::string camera_name = (std::string)camera_node_list[idx]["name"]; - fs << "{:" << "res" << ss.str(); + cv::FileNode resolution_list = camera_node_list[idx]["resolutions"]; + auto resolutions = gcnew System::Collections::Generic::List^>(); + for (size_t r_idx = 0; r_idx < resolution_list.size(); r_idx++) + { + string res = resolution_list[r_idx]["res"]; + + std::vector elems; + split(res, 'x', elems); + + int x = stoi(elems[0]); + int y = stoi(elems[1]); + resolutions->Add(gcnew System::Tuple(x, y)); + } + managed_camera_list_initial[gcnew System::String(camera_name.c_str())] = resolutions; + } + fs_read.release(); + return managed_camera_list_initial; + } + + static void WriteCameraListingToFile(System::Collections::Generic::Dictionary^>^>^ camera_list, std::string filename) + { + cv::FileStorage fs("camera_list.xml", cv::FileStorage::WRITE); + + fs << "cameras" << "["; + for each(System::String^ name_m in camera_list->Keys) + { + + std::string name = msclr::interop::marshal_as(name_m); + + fs << "{:" << "name" << name; + fs << "resolutions" << "["; + auto resolutions = camera_list[name_m]; + for (int j = 0; j < resolutions->Count; j++) + { + stringstream ss; + ss << resolutions[j]->Item1 << "x" << resolutions[j]->Item2; + + fs << "{:" << "res" << ss.str(); + fs << "}"; + } + fs << "]"; fs << "}"; } fs << "]"; - fs << "}"; - } - fs << "]"; - fs.release(); - } - - // A utility for listing the currently connected cameras together with their ID, name, subset of supported resolutions and a thumbnail - static List^>^, OpenCVWrappers::RawImage^>^>^ GetCameras(System::String^ root_directory_m) - { - auto managed_camera_list = gcnew List^>^, OpenCVWrappers::RawImage^>^>(); - - DeviceEnumerator de; - - // Get a listing of all connected video devices - std::map cameras = de.getVideoDevicesMap(); - - // Print information about the devices - for (auto const &device : cameras) { - std::cout << "== VIDEO DEVICE (id:" << device.first << ") ==" << std::endl; - std::cout << "Name: " << device.second.deviceName << std::endl; - std::cout << "Path: " << device.second.devicePath << std::endl; + fs.release(); } - size_t num_cameras = cameras.size(); - - // Pre-load supported camera resolutions if already computed - std::string root_directory = msclr::interop::marshal_as(root_directory_m); - auto camera_resolution_list = GetListingFromFile(root_directory + "camera_list.xml"); - - for (size_t i = 0; i < num_cameras; ++i) + // A utility for listing the currently connected cameras together with their ID, name, subset of supported resolutions and a thumbnail + public: + static List^>^, OpenCVWrappers::RawImage^>^>^ GetCameras(System::String^ root_directory_m) { - // Thumbnail to help with camera selection - cv::Mat sample_img; - OpenCVWrappers::RawImage^ sample_img_managed = gcnew OpenCVWrappers::RawImage(); + auto managed_camera_list = gcnew List^>^, OpenCVWrappers::RawImage^>^>(); - auto resolutions = gcnew List^>(); + DeviceEnumerator de; - // Before trying the resolutions, check if the resolutions have already been computed for the camera of interest - std::string device_name = cameras[i].deviceName; - System::String^ device_name_m = gcnew System::String(device_name.c_str()); - if (camera_resolution_list->ContainsKey(device_name_m)) + // Get a listing of all connected video devices + std::map cameras = de.getVideoDevicesMap(); + + //std::cout << "Number of cameras found: " << cameras.size() << std::endl; + //// Print information about the devices + //for (auto const &device : cameras) { + // std::cout << "== VIDEO DEVICE (id:" << device.first << ") ==" << std::endl; + // std::cout << "Name: " << device.second.deviceName << std::endl; + // std::cout << "Path: " << device.second.devicePath << std::endl; + //} + + size_t num_cameras = cameras.size(); + + // Pre-load supported camera resolutions if already computed + std::string root_directory = msclr::interop::marshal_as(root_directory_m); + auto camera_resolution_list = GetListingFromFile(root_directory + "camera_list.xml"); + + for (size_t i = 0; i < num_cameras; ++i) { - resolutions = camera_resolution_list[device_name_m]; + // Thumbnail to help with camera selection + cv::Mat sample_img; + OpenCVWrappers::RawImage^ sample_img_managed = gcnew OpenCVWrappers::RawImage(); - // Grab a thumbnail from mid resolution - cv::VideoCapture cap1(i); + auto resolutions = gcnew List^>(); - auto resolution = resolutions[(int)(resolutions->Count / 2)]; - cap1.set(CV_CAP_PROP_FRAME_WIDTH, resolution->Item1); - cap1.set(CV_CAP_PROP_FRAME_HEIGHT, resolution->Item2); - - // Read several frames, as the first one often is over-exposed - for (int k = 0; k < 2; ++k) - cap1.read(sample_img); - } - else - { - - // A common set of resolutions for webcams - 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(960, 720)); - common_resolutions.push_back(std::pair(1280, 720)); - common_resolutions.push_back(std::pair(1280, 960)); - common_resolutions.push_back(std::pair(1920, 1080)); - - // Grab some sample images and confirm the resolutions - cv::VideoCapture cap1(i); - - // Go through resolutions if they have not been identified - for (size_t i = 0; i < common_resolutions.size(); ++i) + // Before trying the resolutions, check if the resolutions have already been computed for the camera of interest + std::string device_name = cameras[i].deviceName; + System::String^ device_name_m = gcnew System::String(device_name.c_str()); + if (camera_resolution_list->ContainsKey(device_name_m)) { - auto resolution = gcnew System::Tuple(common_resolutions[i].first, common_resolutions[i].second); + resolutions = camera_resolution_list[device_name_m]; + // Grab a thumbnail from mid resolution + cv::VideoCapture cap1(i); + + auto resolution = resolutions[(int)(resolutions->Count / 2)]; cap1.set(CV_CAP_PROP_FRAME_WIDTH, resolution->Item1); cap1.set(CV_CAP_PROP_FRAME_HEIGHT, resolution->Item2); - // Add only valid resolutions as API sometimes provides wrong ones - int set_width = cap1.get(CV_CAP_PROP_FRAME_WIDTH); - int set_height = cap1.get(CV_CAP_PROP_FRAME_HEIGHT); - - // Grab a thumbnail from mid resolution - if(i == (int)common_resolutions.size()/2) - { - // Read several frames, as the first one often is over-exposed - for (int k = 0; k < 2; ++k) - cap1.read(sample_img); - } - - resolution = gcnew System::Tuple(set_width, set_height); - if (!resolutions->Contains(resolution)) - { - resolutions->Add(resolution); - } + // Read several frames, as the first one often is over-exposed + for (int k = 0; k < 2; ++k) + cap1.read(sample_img); } - cap1.~VideoCapture(); + else + { - // Ass the resolutions were not on the list, add them now - camera_resolution_list[device_name_m] = resolutions; - WriteCameraListingToFile(camera_resolution_list, root_directory + "camera_list.xml"); + // A common set of resolutions for webcams + 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(960, 720)); + common_resolutions.push_back(std::pair(1280, 720)); + common_resolutions.push_back(std::pair(1280, 960)); + common_resolutions.push_back(std::pair(1920, 1080)); + + // Grab some sample images and confirm the resolutions + cv::VideoCapture cap1(i); + + // Go through resolutions if they have not been identified + for (size_t i = 0; i < common_resolutions.size(); ++i) + { + auto resolution = gcnew System::Tuple(common_resolutions[i].first, common_resolutions[i].second); + + cap1.set(CV_CAP_PROP_FRAME_WIDTH, resolution->Item1); + cap1.set(CV_CAP_PROP_FRAME_HEIGHT, resolution->Item2); + + // Add only valid resolutions as API sometimes provides wrong ones + int set_width = cap1.get(CV_CAP_PROP_FRAME_WIDTH); + int set_height = cap1.get(CV_CAP_PROP_FRAME_HEIGHT); + + // Grab a thumbnail from mid resolution + if (i == (int)common_resolutions.size() / 2) + { + // Read several frames, as the first one often is over-exposed + for (int k = 0; k < 2; ++k) + cap1.read(sample_img); + } + + resolution = gcnew System::Tuple(set_width, set_height); + if (!resolutions->Contains(resolution)) + { + resolutions->Add(resolution); + } + } + cap1.~VideoCapture(); + + // Ass the resolutions were not on the list, add them now + camera_resolution_list[device_name_m] = resolutions; + WriteCameraListingToFile(camera_resolution_list, root_directory + "camera_list.xml"); + } + sample_img.copyTo(sample_img_managed->Mat); + + managed_camera_list->Add(gcnew System::Tuple^>^, OpenCVWrappers::RawImage^>(i, device_name_m, resolutions, sample_img_managed)); } - sample_img.copyTo(sample_img_managed->Mat); - managed_camera_list->Add(gcnew System::Tuple^>^, OpenCVWrappers::RawImage^>(i, device_name_m, resolutions, sample_img_managed)); + return managed_camera_list; } - return managed_camera_list; - } + }; }