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 <OpenCVWrappers.h>
|
||||||
#include <ImageReader.h>
|
#include <ImageReader.h>
|
||||||
|
|
||||||
|
#include "DeviceEnumerator.h"
|
||||||
|
|
||||||
#include "SequenceCapture.h"
|
#include "SequenceCapture.h"
|
||||||
|
|
||||||
#pragma managed
|
#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 void split(const std::string &s, char delim, std::vector<string> &elems) {
|
||||||
static List<System::Tuple<int, List<System::Tuple<int, int>^>^, OpenCVWrappers::RawImage^>^>^ GetCameras()
|
std::stringstream ss;
|
||||||
{
|
ss.str(s);
|
||||||
auto managed_camera_list = gcnew List<System::Tuple<int, List<System::Tuple<int, int>^>^, OpenCVWrappers::RawImage^>^>();
|
std::string item;
|
||||||
|
while (std::getline(ss, item, delim)) {
|
||||||
// Go through camera id's untill no new cameras are found
|
elems.push_back(item);
|
||||||
int num_cameras = 0;
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
cv::VideoCapture cap(num_cameras);
|
|
||||||
if (cap.isOpened())
|
|
||||||
num_cameras++;
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)
|
for (size_t i = 0; i < num_cameras; ++i)
|
||||||
{
|
{
|
||||||
//std::string name = cameras[i].name();
|
// Thumbnail to help with camera selection
|
||||||
//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);
|
|
||||||
|
|
||||||
cv::Mat sample_img;
|
cv::Mat sample_img;
|
||||||
OpenCVWrappers::RawImage^ sample_img_managed = gcnew OpenCVWrappers::RawImage();
|
OpenCVWrappers::RawImage^ sample_img_managed = gcnew OpenCVWrappers::RawImage();
|
||||||
|
|
||||||
// Go through resolutions if they have not been identified
|
auto resolutions = gcnew List<System::Tuple<int, int>^>();
|
||||||
for (auto beg = common_resolutions.begin(); beg != common_resolutions.end(); ++beg)
|
|
||||||
{
|
|
||||||
auto resolution = gcnew System::Tuple<int, int>(beg->first, beg->first);
|
|
||||||
|
|
||||||
|
// 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_WIDTH, resolution->Item1);
|
||||||
cap1.set(CV_CAP_PROP_FRAME_HEIGHT, resolution->Item2);
|
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
|
// Read several frames, as the first one often is over-exposed
|
||||||
for (int k = 0; k < 2; ++k)
|
for (int k = 0; k < 2; ++k)
|
||||||
cap1.read(sample_img);
|
cap1.read(sample_img);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
resolution = gcnew System::Tuple<int, int>(set_width, set_height);
|
// A common set of resolutions for webcams
|
||||||
if (!resolutions->Contains(resolution))
|
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);
|
sample_img.copyTo(sample_img_managed->Mat);
|
||||||
|
|
||||||
cap1.~VideoCapture();
|
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));
|
||||||
|
|
||||||
managed_camera_list->Add(gcnew System::Tuple<int, List<System::Tuple<int, int>^>^, OpenCVWrappers::RawImage^>(i, resolutions, sample_img_managed));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return managed_camera_list;
|
return managed_camera_list;
|
||||||
|
|
Loading…
Reference in a new issue