Working towards proper camera selection.

This commit is contained in:
Tadas Baltrusaitis 2018-01-27 06:59:37 +00:00
parent 3b63728b9b
commit 20276a00b2
12 changed files with 539 additions and 166 deletions

1
.gitignore vendored
View file

@ -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/

View file

@ -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

View file

@ -31,6 +31,8 @@
</MenuItem>
<MenuItem Header="Open image directory" Click="individualImageDirectoryOpenClick">
</MenuItem>
<MenuItem Header="Open webcam" Click="openWebcamClick">
</MenuItem>
</MenuItem>
<MenuItem Name="RecordingMenu" Header="Record" >
<MenuItem IsCheckable="True" Header="Record AUs" IsChecked="{Binding RecordAUs}"/>

View file

@ -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
// --------------------------------------------------------

View file

@ -97,6 +97,9 @@
<Compile Include="UI_items\CameraParametersEntry.xaml.cs">
<DependentUpon>CameraParametersEntry.xaml</DependentUpon>
</Compile>
<Compile Include="UI_items\CameraSelection.xaml.cs">
<DependentUpon>CameraSelection.xaml</DependentUpon>
</Compile>
<Compile Include="UI_items\MultiBarGraph.xaml.cs">
<DependentUpon>MultiBarGraph.xaml</DependentUpon>
</Compile>
@ -136,6 +139,10 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="UI_items\CameraSelection.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="UI_items\MultiBarGraph.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>

View file

@ -0,0 +1,43 @@
<Window x:Class="OpenFaceOffline.CameraSelection"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:OpenFaceOffline"
mc:Ignorable="d"
Title="Camera selection" Height="460" Width="600" ResizeMode="NoResize" WindowStartupLocation="CenterScreen" Closing="Window_Closing">
<Grid>
<Grid Name="camerasPanel" Visibility="Hidden">
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="320" />
<RowDefinition Height="*" />
<RowDefinition Height="40" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.ColumnSpan="10" HorizontalContentAlignment="Center" FontSize="20">Choose Video Source</Label>
<Grid Grid.Row="1" Grid.Column="0" Name="ThumbnailPanel" HorizontalAlignment="Center">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="25" />
</Grid.RowDefinitions>
</Grid>
<!-- Click="OpenFile_Click" -->
<Button Width="150" Grid.Row="3" Height="35" Grid.ColumnSpan="10" FontSize="20" Click="Button_Click">Select camera</Button>
</Grid>
<Grid Name="LoadingGrid" Visibility="Visible">
<StackPanel Grid.Row="1" Name="ProgressBar" Margin="20">
<Label HorizontalAlignment="Center" FontSize="18">Loading Webcams</Label>
<ProgressBar Height="20" Minimum="0" Maximum="100" Name="pbStatus" IsIndeterminate="True" />
<Label HorizontalAlignment="Center" FontSize="18">Might take some time the first time</Label>
</StackPanel>
</Grid>
</Grid>
</Window>

View file

@ -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
{
/// <summary>
/// Interaction logic for CameraSelection.xaml
/// </summary>
public partial class CameraSelection : Window
{
List<Border> sample_images;
List<ComboBox> combo_boxes;
// id, width, height
public Tuple<int, int, int> selected_camera;
List<List<Tuple<int, int>>> 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<Tuple<int, String, List<Tuple<int, int>>, 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<Border>();
// Each cameras corresponding resolutions
resolutions_all = new List<List<Tuple<int, int>>>();
combo_boxes = new List<ComboBox>();
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<Tuple<int, int>>());
foreach (var r in s.Item3)
{
resolutions.Items.Add(r.Item1 + "x" + r.Item2);
resolutions_all[resolutions_all.Count - 1].Add(new Tuple<int, int>(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<Tuple<int, String, List<Tuple<int, int>>, 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<int, int> resolution_selected = resolutions_all[selected_camera_idx][selected_res];
selected_camera = new Tuple<int, int, int>(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)
{
}
}
}

View file

@ -127,7 +127,11 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<Text Include="ReadMe.txt" />
<ClInclude Include="DeviceEnumerator.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="DeviceEnumerator.cpp" />
<ClCompile Include="OpenCVDeviceEnumerator.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">

View file

@ -15,6 +15,16 @@
</Filter>
</ItemGroup>
<ItemGroup>
<Text Include="ReadMe.txt" />
<ClInclude Include="DeviceEnumerator.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="DeviceEnumerator.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="OpenCVDeviceEnumerator.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View file

@ -1,4 +1,5 @@
#include "DeviceEnumerator.h"
#include <iostream>
std::map<int, Device> DeviceEnumerator::getVideoDevicesMap() {
return getDevicesMap(CLSID_VideoInputDeviceCategory);
@ -13,14 +14,15 @@ std::map<int, Device> DeviceEnumerator::getDevicesMap(const GUID deviceClass)
{
std::map<int, Device> 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;

View file

@ -116,7 +116,7 @@
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;CPPINEROP_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>./;$(SolutionDir)lib\local\LandmarkDetector\include;$(SolutionDir)lib\local\FaceAnalyser\include;$(SolutionDir)lib\local\GazeAnalyser\include;$(SolutionDir)lib\local\Utilities\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<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)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
@ -130,7 +130,7 @@
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;_WINDOWS;_USRDLL;CPPINEROP_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>./;$(SolutionDir)lib\local\LandmarkDetector\include;$(SolutionDir)lib\local\FaceAnalyser\include;$(SolutionDir)lib\local\GazeAnalyser\include;$(SolutionDir)lib\local\Utilities\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<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)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
@ -146,7 +146,7 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;CPPINEROP_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>./;$(SolutionDir)lib\local\LandmarkDetector\include;$(SolutionDir)lib\local\FaceAnalyser\include;$(SolutionDir)lib\local\GazeAnalyser\include;$(SolutionDir)lib\local\Utilities\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<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)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
@ -164,7 +164,7 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>NDEBUG;_WINDOWS;_USRDLL;CPPINEROP_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>./;$(SolutionDir)lib\local\LandmarkDetector\include;$(SolutionDir)lib\local\FaceAnalyser\include;$(SolutionDir)lib\local\GazeAnalyser\include;$(SolutionDir)lib\local\Utilities\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<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)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
@ -190,6 +190,9 @@
<ClInclude Include="VisualizerInterop.h" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\3rdParty\CameraEnumerator\CameraEnumerator.vcxproj">
<Project>{50b7d4bf-e33b-41d0-aa89-76bba57bf5cc}</Project>
</ProjectReference>
<ProjectReference Include="..\..\3rdParty\dlib\dlib.vcxproj">
<Project>{b47a5f12-2567-44e9-ae49-35763ec82149}</Project>
</ProjectReference>

View file

@ -211,181 +211,186 @@ namespace UtilitiesOF {
{
this->!SequenceReader();
}
};
static void split(const std::string &s, char delim, std::vector<string> &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<System::String^, List<System::Tuple<int, int>^>^>^ 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<System::String^, List<System::Tuple<int, int>^>^>();
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<System::Tuple<int, int>^>();
for (size_t r_idx = 0; r_idx < resolution_list.size(); r_idx++)
{
string res = resolution_list[r_idx]["res"];
std::vector<std::string> elems;
split(res, 'x', elems);
int x = stoi(elems[0]);
int y = stoi(elems[1]);
resolutions->Add(gcnew System::Tuple<int, int>(x, y));
private:
// Static methods for listing cameras and their resolutions
static void split(const std::string &s, char delim, std::vector<string> &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<System::String^, System::Collections::Generic::List<System::Tuple<int, int>^>^>^ 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<System::String^, List<System::Tuple<int, int>^>^>^ 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<std::string>(name_m);
auto managed_camera_list_initial = gcnew Dictionary<System::String^, List<System::Tuple<int, int>^>^>();
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<System::Tuple<int, int>^>();
for (size_t r_idx = 0; r_idx < resolution_list.size(); r_idx++)
{
string res = resolution_list[r_idx]["res"];
std::vector<std::string> elems;
split(res, 'x', elems);
int x = stoi(elems[0]);
int y = stoi(elems[1]);
resolutions->Add(gcnew System::Tuple<int, int>(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<System::String^, System::Collections::Generic::List<System::Tuple<int, int>^>^>^ 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<std::string>(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<System::Tuple<int, System::String^, List<System::Tuple<int, int>^>^, OpenCVWrappers::RawImage^>^>^ GetCameras(System::String^ root_directory_m)
{
auto managed_camera_list = gcnew List<System::Tuple<int, System::String^, List<System::Tuple<int, int>^>^, OpenCVWrappers::RawImage^>^>();
DeviceEnumerator de;
// Get a listing of all connected video devices
std::map<int, Device> 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<std::string>(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<System::Tuple<int, System::String^, List<System::Tuple<int, int>^>^, 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<System::Tuple<int, System::String^, List<System::Tuple<int, int>^>^, OpenCVWrappers::RawImage^>^>();
auto resolutions = gcnew List<System::Tuple<int, int>^>();
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<int, Device> 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<std::string>(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<System::Tuple<int, int>^>();
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<std::pair<int, int>> common_resolutions;
common_resolutions.push_back(std::pair<int, int>(320, 240));
common_resolutions.push_back(std::pair<int, int>(640, 480));
common_resolutions.push_back(std::pair<int, int>(960, 720));
common_resolutions.push_back(std::pair<int, int>(1280, 720));
common_resolutions.push_back(std::pair<int, int>(1280, 960));
common_resolutions.push_back(std::pair<int, int>(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<int, int>(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<int, int>(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<std::pair<int, int>> common_resolutions;
common_resolutions.push_back(std::pair<int, int>(320, 240));
common_resolutions.push_back(std::pair<int, int>(640, 480));
common_resolutions.push_back(std::pair<int, int>(960, 720));
common_resolutions.push_back(std::pair<int, int>(1280, 720));
common_resolutions.push_back(std::pair<int, int>(1280, 960));
common_resolutions.push_back(std::pair<int, int>(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<int, int>(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<int, int>(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<int, System::String^, List<System::Tuple<int, int>^>^, OpenCVWrappers::RawImage^>(i, device_name_m, resolutions, sample_img_managed));
}
sample_img.copyTo(sample_img_managed->Mat);
managed_camera_list->Add(gcnew System::Tuple<int, System::String^, List<System::Tuple<int, int>^>^, OpenCVWrappers::RawImage^>(i, device_name_m, resolutions, sample_img_managed));
return managed_camera_list;
}
return managed_camera_list;
}
};
}