Starting to add support for proper webcam listing.
This commit is contained in:
parent
f9608aa758
commit
3b63728b9b
7 changed files with 527 additions and 42 deletions
135
lib/3rdParty/CameraEnumerator/CameraEnumerator.vcxproj
vendored
Normal file
135
lib/3rdParty/CameraEnumerator/CameraEnumerator.vcxproj
vendored
Normal file
|
@ -0,0 +1,135 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{50B7D4BF-E33B-41D0-AA89-76BBA57BF5CC}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>CameraEnumerator</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup />
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<Text Include="ReadMe.txt" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
20
lib/3rdParty/CameraEnumerator/CameraEnumerator.vcxproj.filters
vendored
Normal file
20
lib/3rdParty/CameraEnumerator/CameraEnumerator.vcxproj.filters
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Text Include="ReadMe.txt" />
|
||||
</ItemGroup>
|
||||
</Project>
|
121
lib/3rdParty/CameraEnumerator/DeviceEnumerator.cpp
vendored
Normal file
121
lib/3rdParty/CameraEnumerator/DeviceEnumerator.cpp
vendored
Normal file
|
@ -0,0 +1,121 @@
|
|||
#include "DeviceEnumerator.h"
|
||||
|
||||
std::map<int, Device> DeviceEnumerator::getVideoDevicesMap() {
|
||||
return getDevicesMap(CLSID_VideoInputDeviceCategory);
|
||||
}
|
||||
|
||||
std::map<int, Device> DeviceEnumerator::getAudioDevicesMap() {
|
||||
return getDevicesMap(CLSID_AudioInputDeviceCategory);
|
||||
}
|
||||
|
||||
// Returns a map of id and devices that can be used
|
||||
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
|
||||
}
|
||||
|
||||
// Create the System Device Enumerator
|
||||
ICreateDevEnum *pDevEnum;
|
||||
hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pDevEnum));
|
||||
|
||||
// If succeeded, create an enumerator for the category
|
||||
IEnumMoniker *pEnum = NULL;
|
||||
if (SUCCEEDED(hr)) {
|
||||
hr = pDevEnum->CreateClassEnumerator(deviceClass, &pEnum, 0);
|
||||
if (hr == S_FALSE) {
|
||||
hr = VFW_E_NOT_FOUND;
|
||||
}
|
||||
pDevEnum->Release();
|
||||
}
|
||||
|
||||
// Now we check if the enumerator creation succeeded
|
||||
int deviceId = -1;
|
||||
if (SUCCEEDED(hr)) {
|
||||
// Fill the map with id and friendly device name
|
||||
IMoniker *pMoniker = NULL;
|
||||
while (pEnum->Next(1, &pMoniker, NULL) == S_OK) {
|
||||
|
||||
IPropertyBag *pPropBag;
|
||||
HRESULT hr = pMoniker->BindToStorage(0, 0, IID_PPV_ARGS(&pPropBag));
|
||||
if (FAILED(hr)) {
|
||||
pMoniker->Release();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Create variant to hold data
|
||||
VARIANT var;
|
||||
VariantInit(&var);
|
||||
|
||||
std::string deviceName;
|
||||
std::string devicePath;
|
||||
|
||||
// Read FriendlyName or Description
|
||||
hr = pPropBag->Read(L"Description", &var, 0); // Read description
|
||||
if (FAILED(hr)) {
|
||||
// If description fails, try with the friendly name
|
||||
hr = pPropBag->Read(L"FriendlyName", &var, 0);
|
||||
}
|
||||
// If still fails, continue with next device
|
||||
if (FAILED(hr)) {
|
||||
VariantClear(&var);
|
||||
continue;
|
||||
}
|
||||
// Convert to string
|
||||
else {
|
||||
deviceName = ConvertBSTRToMBS(var.bstrVal);
|
||||
}
|
||||
|
||||
VariantClear(&var); // We clean the variable in order to read the next value
|
||||
|
||||
// We try to read the DevicePath
|
||||
hr = pPropBag->Read(L"DevicePath", &var, 0);
|
||||
if (FAILED(hr)) {
|
||||
VariantClear(&var);
|
||||
continue; // If it fails we continue with next device
|
||||
}
|
||||
else {
|
||||
devicePath = ConvertBSTRToMBS(var.bstrVal);
|
||||
}
|
||||
|
||||
// We populate the map
|
||||
deviceId++;
|
||||
Device currentDevice;
|
||||
currentDevice.id = deviceId;
|
||||
currentDevice.deviceName = deviceName;
|
||||
currentDevice.devicePath = devicePath;
|
||||
deviceMap[deviceId] = currentDevice;
|
||||
|
||||
}
|
||||
pEnum->Release();
|
||||
}
|
||||
CoUninitialize();
|
||||
return deviceMap;
|
||||
}
|
||||
|
||||
/*
|
||||
This two methods were taken from
|
||||
https://stackoverflow.com/questions/6284524/bstr-to-stdstring-stdwstring-and-vice-versa
|
||||
*/
|
||||
|
||||
std::string DeviceEnumerator::ConvertBSTRToMBS(BSTR bstr)
|
||||
{
|
||||
int wslen = ::SysStringLen(bstr);
|
||||
return ConvertWCSToMBS((wchar_t*)bstr, wslen);
|
||||
}
|
||||
|
||||
std::string DeviceEnumerator::ConvertWCSToMBS(const wchar_t* pstr, long wslen)
|
||||
{
|
||||
int len = ::WideCharToMultiByte(CP_ACP, 0, pstr, wslen, NULL, 0, NULL, NULL);
|
||||
|
||||
std::string dblstr(len, '\0');
|
||||
len = ::WideCharToMultiByte(CP_ACP, 0 /* no flags */,
|
||||
pstr, wslen /* not necessary NULL-terminated */,
|
||||
&dblstr[0], len,
|
||||
NULL, NULL /* no default char */);
|
||||
|
||||
return dblstr;
|
||||
}
|
31
lib/3rdParty/CameraEnumerator/DeviceEnumerator.h
vendored
Normal file
31
lib/3rdParty/CameraEnumerator/DeviceEnumerator.h
vendored
Normal file
|
@ -0,0 +1,31 @@
|
|||
#pragma once
|
||||
|
||||
#include <Windows.h>
|
||||
#include <dshow.h>
|
||||
|
||||
#pragma comment(lib, "strmiids")
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
struct Device {
|
||||
int id; // This can be used to open the device in OpenCV
|
||||
std::string devicePath;
|
||||
std::string deviceName; // This can be used to show the devices to the user
|
||||
};
|
||||
|
||||
class DeviceEnumerator {
|
||||
|
||||
public:
|
||||
|
||||
DeviceEnumerator() = default;
|
||||
std::map<int, Device> getDevicesMap(const GUID deviceClass);
|
||||
std::map<int, Device> getVideoDevicesMap();
|
||||
std::map<int, Device> getAudioDevicesMap();
|
||||
|
||||
private:
|
||||
|
||||
std::string ConvertBSTRToMBS(BSTR bstr);
|
||||
std::string ConvertWCSToMBS(const wchar_t* pstr, long wslen);
|
||||
|
||||
};
|
36
lib/3rdParty/CameraEnumerator/OpenCVDeviceEnumerator.cpp
vendored
Normal file
36
lib/3rdParty/CameraEnumerator/OpenCVDeviceEnumerator.cpp
vendored
Normal file
|
@ -0,0 +1,36 @@
|
|||
#include <map>
|
||||
#include <iostream>
|
||||
|
||||
#include "DeviceEnumerator.h"
|
||||
|
||||
int main()
|
||||
{
|
||||
|
||||
/*
|
||||
The id field of the Device struct can be used with an OpenCV VideoCapture object
|
||||
*/
|
||||
|
||||
DeviceEnumerator de;
|
||||
|
||||
// Audio Devices
|
||||
std::map<int, Device> devices = de.getAudioDevicesMap();
|
||||
|
||||
// Print information about the devices
|
||||
for (auto const &device : devices) {
|
||||
std::cout << "== AUDIO DEVICE (id:" << device.first << ") ==" << std::endl;
|
||||
std::cout << "Name: " << device.second.deviceName << std::endl;
|
||||
std::cout << "Path: " << device.second.devicePath << std::endl;
|
||||
}
|
||||
|
||||
// Video Devices
|
||||
devices = de.getVideoDevicesMap();
|
||||
|
||||
// Print information about the devices
|
||||
for (auto const &device : devices) {
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
32
lib/3rdParty/CameraEnumerator/readme.md
vendored
Normal file
32
lib/3rdParty/CameraEnumerator/readme.md
vendored
Normal file
|
@ -0,0 +1,32 @@
|
|||
# Device Enumerator for OpenCV
|
||||
|
||||
This project contains a *C++* class that allows the enumeration of devices using DirectShow in Windows, in order to select and obtain the ID that needs to be used with OpenCV when creating, for example, a VideoCapture object to grab frames from a camera. I decided to put this up as "How to get the ID of a device to use inside OpenCV?" is a question that pops up continuously.
|
||||
|
||||
## Contents
|
||||
|
||||
The project contains the class itself (DeviceEnumerator.h and DeviceEnumerator.cpp) and also an example of how to use the class (OpenCVDeviceEnumerator.cpp)
|
||||
|
||||
## License
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018 David Gil de Gómez Pérez (Studiosi)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
|
@ -49,6 +49,8 @@
|
|||
#include <OpenCVWrappers.h>
|
||||
#include <ImageReader.h>
|
||||
|
||||
#include "DeviceEnumerator.h"
|
||||
|
||||
#include "SequenceCapture.h"
|
||||
|
||||
#pragma managed
|
||||
|
@ -211,68 +213,176 @@ namespace UtilitiesOF {
|
|||
}
|
||||
};
|
||||
|
||||
// A utility for listing the currently connected cameras together with their ID, subset of supported resolutions and a thumbnail
|
||||
static List<System::Tuple<int, List<System::Tuple<int, int>^>^, OpenCVWrappers::RawImage^>^>^ GetCameras()
|
||||
{
|
||||
auto managed_camera_list = gcnew List<System::Tuple<int, List<System::Tuple<int, int>^>^, OpenCVWrappers::RawImage^>^>();
|
||||
|
||||
// Go through camera id's untill no new cameras are found
|
||||
int num_cameras = 0;
|
||||
while (true)
|
||||
{
|
||||
cv::VideoCapture cap(num_cameras);
|
||||
if (cap.isOpened())
|
||||
num_cameras++;
|
||||
else
|
||||
break;
|
||||
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));
|
||||
}
|
||||
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.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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
//std::string name = cameras[i].name();
|
||||
//System::String^ name_managed = gcnew System::String(name.c_str());
|
||||
|
||||
auto resolutions = gcnew List<System::Tuple<int, int>^>();
|
||||
|
||||
// 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>(1280, 960));
|
||||
|
||||
// Grab some sample images and confirm the resolutions
|
||||
cv::VideoCapture cap1(i);
|
||||
|
||||
// Thumbnail to help with camera selection
|
||||
cv::Mat sample_img;
|
||||
OpenCVWrappers::RawImage^ sample_img_managed = gcnew OpenCVWrappers::RawImage();
|
||||
|
||||
// Go through resolutions if they have not been identified
|
||||
for (auto beg = common_resolutions.begin(); beg != common_resolutions.end(); ++beg)
|
||||
{
|
||||
auto resolution = gcnew System::Tuple<int, int>(beg->first, beg->first);
|
||||
auto resolutions = gcnew List<System::Tuple<int, int>^>();
|
||||
|
||||
// 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))
|
||||
{
|
||||
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);
|
||||
|
||||
// Read several frames, as the first one often is over-exposed
|
||||
for (int k = 0; k < 2; ++k)
|
||||
cap1.read(sample_img);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
resolution = gcnew System::Tuple<int, int>(set_width, set_height);
|
||||
if (!resolutions->Contains(resolution))
|
||||
// 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)
|
||||
{
|
||||
resolutions->Add(resolution);
|
||||
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);
|
||||
|
||||
cap1.~VideoCapture();
|
||||
|
||||
managed_camera_list->Add(gcnew System::Tuple<int, List<System::Tuple<int, int>^>^, OpenCVWrappers::RawImage^>(i, resolutions, sample_img_managed));
|
||||
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;
|
||||
|
|
Loading…
Reference in a new issue