4.25 How to enumerate Video Input Devices to use in OpenCV VideoCapture?
Imagine that you have mulitple video input devices and you would like to select and use one of those devices.
In Windows, you can get all video input devices informatiion by using COM interfaces
of CLSID_SystemDeviceEnum, and CLSID_VideoInputDeviceCategory classes.
If you are familiar with COM interfaces, you can easily enumerate all video devices
by using those interfaces as shown below.
1 Create an interface of ICreateDevEnum by using CoCreateInstance.
ComPtr<ICreateDevEnum> pDevEnum;
CoCreateInstance(CLSID_SystemDeviceEnum, NULL,
CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pDevEnum));
2 Create an interface of IEnumMoniker by using CreateClassEnumerator from the ICreateDevEnum object.
ComPtr<IEnumMoniker> pEnum;
pDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnum, 0);
3 Get an IMoniker interface from the enumerator, and bind the moniker
to an IPropertyBag interface, and read "FriendlyName" from the bag.
IMoniker* pMoniker = NULL;
while (pEnum->Next(1, &pMoniker, NULL) == S_OK) {
ComPtr<IPropertyBag> pPropBag = NULL;
HRESULT hr = pMoniker->BindToStorage(0, 0, IID_PPV_ARGS(&pPropBag));
if (FAILED(hr)) {
pMoniker->Release();
continue;
}
VARIANT var;
VariantInit(&var);
//Read FriendlyName
hr = pPropBag->Read(L"FriendlyName", &var, 0;)
pMoniker->Release();
}
As you can easily see, we really would like to enumerate all FriendlyName properties of the CLSID_VideoInputDeviceCategory COM interface
through IMoniker and IPropertyBag interfaces. To simplify a story, however, we have implemented following two classes:
VideoInputDeviceEnumerator
LabeledVideoDeviceComboBox
In OpenCV VideoCapture applications of SOL9, you can use the LabeledVideoDeviceComboBox class to select a video device by name
from the ComboBox, and get a video device index which can be used as an argument of open method of cv::VideoCapture class.
The following VideoDeviceEnumerator program is a simple example to select a video device from LabeledVideoDeviceComboBox,
and start to read a video image from the device.
/*
* VideoDeviceEnumerator.cpp
* Copyright (c) 2017 Antillia.com TOSHIYUKI ARAI. ALL RIGHTS RESERVED.
*/
//2017/07/25
//This is a simple example to capture videoDevice, and to display the capturued frames
//to original imageview and blurred image view based on cv::boxFiter.
#define _CONSOLE_
//#define STRSAFE_LIB
#include <sol/com/ApartmentThreadedModel.h>
#include <sol/ModuleFileName.h>
#include <sol/LabeledTrackBar.h>
#include <sol/PushButton.h>
#include <sol/FileDialog.h>
#include <sol/directshow/LabeledVideoDeviceComboBox.h>
#include <sol/opencv/OpenCVVideoApplication.h>
#include <sol/opencv/OpenCVVideoCaptureView.h>
#include <sol/opencv/OpenCVNamedWindow.h>
namespace SOL {
class MainView :public OpenCVVideoCaptureView {
private:
////////////////////////////////////////////////////////////////////////////////////////
//Inner classes start.
class OriginalImageView :public OpenCVNamedWindow {
private:
cv::Mat originalImage;
public:
void display()
{
show(originalImage);
}
public:
OriginalImageView(View* parent, const char* name, Args& args)
:OpenCVNamedWindow(parent, name, args)
{
}
void setImage(cv::Mat& image)
{
originalImage = image;
}
};
//Inner classes end.
////////////////////////////////////////////////////////////////////////////////////////
SmartPtr<OriginalImageView> originalImage;
SmartPtr<LabeledVideoDeviceComboBox> videoDeviceComboBox;
SmartPtr<PushButton> startButton;
SmartPtr<PushButton> endButton;
static const int CONTROLPANE_WIDTH = 200;
void resize(int w, int h)
{
if (originalImage ) {
originalImage -> reshape(0, 0, w-CONTROLPANE_WIDTH-5, h);
videoDeviceComboBox -> reshape(w-CONTROLPANE_WIDTH+5, 0, 180, 40);
startButton -> reshape(w-CONTROLPANE_WIDTH+30, 60, 120, 30);
endButton -> reshape(w-CONTROLPANE_WIDTH+30, 100, 120, 30);
}
}
void confirm(Action& action)
{
int rc = MessageBox(NULL, "Are you sure to close this window?", "Confirmation",
MB_OKCANCEL|MB_ICONEXCLAMATION);
if (rc == IDOK) {
exit(action);
}
}
public:
MainView(OpenCVVideoApplication& applet, const char* name, Args& args)
:OpenCVVideoCaptureView(applet, name, args)
{
try {
Args ar;
originalImage = new OriginalImageView(this, "cvwindow1", ar);
ar.reset();
ar.reset();
ar.set(XmNstyle, CBS_DROPDOWNLIST);
videoDeviceComboBox = new LabeledVideoDeviceComboBox(this, "VideoDevice", ar);
videoDeviceComboBox->addCallback(XmNselChangeCallback, this,
(Callback)&MainView::selChangeCallback, NULL);
ar.reset();
startButton = new PushButton(this, "Start Caputure", ar);
startButton->addCallback(XmNactivateCallback, this,
(Callback)&MainView::startCapture, NULL);
startButton->disable();
ar.reset();
endButton = new PushButton(this, "End Capture", ar);
endButton -> addCallback(XmNactivateCallback, this,
(Callback)&MainView::endCapture, NULL);
endButton->disable();
addCallback(XmNmenuCallback, IDM_EXIT, this,
(Callback)&MainView::confirm, NULL);
} catch (Exception& ex) {
caught(ex);
}
}
~MainView()
{
}
void selChangeCallback(Action& action)
{
int deviceIndex = videoDeviceComboBox->getCurSel();
if (deviceIndex >=0) {
startButton->enable();
}
}
void startCapture(Action& action)
{
try {
int deviceIndex = videoDeviceComboBox->getCurSel();
if (deviceIndex >=0) {
String name;
videoDeviceComboBox->getString(deviceIndex, name);
char message[1024];
sprintf_s(message, CountOf(message),
"Are you sure to open device (%d):%s", deviceIndex,
(const char*)name);
if (MessageBoxA(NULL, message, "Device", MB_OKCANCEL) == IDOK) {
openDevice(deviceIndex);
endButton->enable();
}
}
} catch (SOL::Exception& ex) {
caught(ex);
}
}
void endCapture(Action& action)
{
stopCapture(action);
endButton->disable();
}
//This method will be called from the event loop OpenCVVideoCaptureApplition::run.
virtual void render()
{
cv::Mat frame;
if (readVideoFrame(frame)) {
if (!frame.empty() && originalImage) {
originalImage -> setImage(frame);
originalImage -> display();
}
}
}
};
}
void main(int argc, char** argv)
{
try {
ModuleFileName module(argv[0]);
//For VideoInputDeviceEnumerator class
ApartmentThreadedModel model;
const char* name = module.getAppName();
int delay = 40; //40 milliseconds
OpenCVVideoApplication applet(name, argc, argv, delay);
Args args;
args.set(XmNwidth, 700);
args.set(XmNheight, 420);
args.set(XmNvideoDeviceIndex, 0);
args.set(XmNcaptureAutoStart, false);
MainView view(applet, name, args);
view.realize();
applet.run(view);
} catch (SOL::Exception& ex) {
caught(ex);
}
}
Last modified: 18 Sep. 2017
Copyright (c) 2017 Antillia.com ALL RIGHTS RESERVED.