Using OpenCV APIs to capture video from a camera is convenient. However, OpenCV does not provide an API for listing all available devices. If you have multiple cameras connected to your PC, you have no idea how to choose the right one. To get device information on Windows, you need to invoke DirectShow APIs. In this post, I will share how to create a Python extension that lists camera devices for OpenCV-Python on Windows.
Bridging DirectShow APIs to OpenCV-Python
How to run DirectShow sample
To use DirectShow APIs, read the Microsoft’s tutorial – Selecting a Capture Device, which shares how to list video and audio devices in C++.
To run the sample, create an empty Win32 Console Application in Visual Studio: File > New > Project > Templates > Visual C++ > Win32.
Create main.cpp, and copy all codes snippets from the tutorial page to the C++ file.
Build and run the project.
How to wrap up DirectShow C++ code
Define Python module and change main() function to a Python method:
static PyObject * getDeviceList(PyObject *self, PyObject *args) { PyObject* pyList = NULL; HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); if (SUCCEEDED(hr)) { IEnumMoniker *pEnum; hr = EnumerateDevices(CLSID_VideoInputDeviceCategory, &pEnum); if (SUCCEEDED(hr)) { pyList = DisplayDeviceInformation(pEnum); pEnum->Release(); } CoUninitialize(); } return pyList; } static PyMethodDef Methods[] = { {"getDeviceList", getDeviceList, METH_VARARGS, NULL}, {NULL, NULL, 0, NULL} }; PyMODINIT_FUNC initdevice(void) { (void) Py_InitModule("device", Methods); }
Create Python list to save device information:
PyObject* pyList = PyList_New(0); Char *pValue = _com_util::ConvertBSTRToString(var.bstrVal); HRESULT hr = PyList_Append(pyList, Py_BuildValue("s", pValue));
Note: you have to convert BSTR to string. To use ConvertBSTRToString, we need a header file #include <comutil.h>, and the corresponding library #pragma comment(lib, “comsuppw.lib”).
How to build and use Python extension
Create setup.py:
from distutils.core import setup, Extension module_device = Extension('device', sources = ['device.cpp'], library_dirs=['G:\Program Files\Microsoft SDKs\Windows\v6.1\Lib'] ) setup (name = 'WindowsDevices', version = '1.0', description = 'Get device list with DirectShow', ext_modules = [module_device])
Build and install the extension:
python setup.py build install
If you see the error ‘Unable to find vcvarsall.bat’, set Visual Studio environment:
- Visual Studio 2010 (VS10): SET VS90COMNTOOLS=%VS100COMNTOOLS%
- Visual Studio 2012 (VS11): SET VS90COMNTOOLS=%VS110COMNTOOLS%
- Visual Studio 2013 (VS12): SET VS90COMNTOOLS=%VS120COMNTOOLS%
- Visual Studio 2015 (VS14): SET VS90COMNTOOLS=%VS140COMNTOOLS%
Create test.py to use the extension for OpenCV-Python:
import device import cv2 def select_camera(last_index): number = 0 hint = "Select a camera (0 to " + str(last_index) + "): " try: number = int(input(hint)) # select = int(select) except Exception ,e: print("It's not a number!") return select_camera(last_index) if number > last_index: print("Invalid number! Retry!") return select_camera(last_index) return number def open_camera(index): cap = cv2.VideoCapture(index) return cap def main(): # print OpenCV version print("OpenCV version: " + cv2.__version__) # Get camera list device_list = device.getDeviceList() index = 0 for name in device_list: print(str(index) + ': ' + name) index += 1 last_index = index - 1 if last_index < 0: print("No device is connected") return # Select a camera camera_number = select_camera(last_index) # Open camera cap = open_camera(camera_number) if cap.isOpened(): width = cap.get(3) # Frame Width height = cap.get(4) # Frame Height print('Default width: ' + str(width) + ', height: ' + str(height)) while True: ret, frame = cap.read(); cv2.imshow("frame", frame) # key: 'ESC' key = cv2.waitKey(20) if key == 27: break cap.release() cv2.destroyAllWindows() if __name__ == "__main__": main()
Source Code
https://github.com/yushulx/python-capture-device-list
The post Listing Multiple Cameras for OpenCV-Python on Windows appeared first on Code Pool.