Is there any way in OpenCV to get the list of camera's resolutions?
For windows you can enumerate all cameras and resolutions using this code:
#include <dshow.h>
#include <locale>
#include <vector>
using namespace std;
#define BLUE 0x0001
#define GREEN 0x0002
#define RED 0x0004
#define GRAY 0x0007
static void setcolor(unsigned int color)
{
HANDLE hCon = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(hCon,color|FOREGROUND_INTENSITY);
}
void _FreeMediaType(AM_MEDIA_TYPE& mt)
{
if (mt.cbFormat != 0)
{
CoTaskMemFree((PVOID)mt.pbFormat);
mt.cbFormat = 0;
mt.pbFormat = NULL;
}
if (mt.pUnk != NULL)
{
// pUnk should not be used.
mt.pUnk->Release();
mt.pUnk = NULL;
}
}
HRESULT CamCaps(IBaseFilter *pBaseFilter)
{
HRESULT hr = 0;
vector<IPin*> pins;
IEnumPins *EnumPins;
pBaseFilter->EnumPins(&EnumPins);
pins.clear();
for(;;)
{
IPin *pin;
hr=EnumPins->Next(1,&pin,NULL);
if(hr!=S_OK){break;}
pins.push_back(pin);
pin->Release();
}
EnumPins->Release();
printf("Device pins number: %d\n",pins.size());
PIN_INFO pInfo;
for(int i=0;i<pins.size();i++)
{
pins[i]->QueryPinInfo(&pInfo);
setcolor(RED);
if(pInfo.dir==0)
{
wprintf(L"Pin name: %s (Ввод)\n",pInfo.achName);
}
if(pInfo.dir==1)
{
wprintf(L"Pin name: %s (Выход)\n",pInfo.achName);
}
IEnumMediaTypes *emt=NULL;
pins[i]->EnumMediaTypes(&emt);
AM_MEDIA_TYPE *pmt;
vector<SIZE> modes;
setcolor(GRAY);
wprintf(L"Avialable resolutions.\n",pInfo.achName);
for(;;)
{
hr=emt->Next(1,&pmt,NULL);
if(hr!=S_OK){break;}
if ( (pmt->formattype == FORMAT_VideoInfo) &&
//(pmt->subtype == MEDIASUBTYPE_RGB24) &&
(pmt->cbFormat >= sizeof(VIDEOINFOHEADER)) &&
(pmt->pbFormat != NULL) )
{
VIDEOINFOHEADER *pVIH = (VIDEOINFOHEADER*)pmt->pbFormat;
SIZE s;
// Get frame size
s.cy=pVIH->bmiHeader.biHeight;
s.cx=pVIH->bmiHeader.biWidth;
// Битрейт
unsigned int bitrate=pVIH->dwBitRate;
modes.push_back(s);
// Bits per pixel
unsigned int bitcount=pVIH->bmiHeader.biBitCount;
REFERENCE_TIME t=pVIH->AvgTimePerFrame; // blocks (100ns) per frame
int FPS=floor(10000000.0/static_cast<double>(t));
printf("Size: x=%d\ty=%d\tFPS: %d\t bitrate: %ld\tbit/pixel:%ld\n",s.cx,s.cy,FPS,bitrate,bitcount);
}
_FreeMediaType(*pmt);
}
//----------------------------------------------------
//
//
//
//----------------------------------------------------
modes.clear();
emt->Release();
}
pins.clear();
return S_OK;
}
/*
* Do something with the filter. In this sample we just test the pan/tilt properties.
*/
void process_filter(IBaseFilter *pBaseFilter)
{
CamCaps(pBaseFilter);
}
/*
* Enumerate all video devices
*
* See also:
*
* Using the System Device Enumerator:
* http://msdn2.microsoft.com/en-us/library/ms787871.aspx
*/
int enum_devices()
{
HRESULT hr;
setcolor(GRAY);
printf("Enumeraring videoinput devices ...\n");
// Create the System Device Enumerator.
ICreateDevEnum *pSysDevEnum = NULL;
hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
IID_ICreateDevEnum, (void **)&pSysDevEnum);
if(FAILED(hr))
{
fprintf(stderr, "Error. Can't create enumerator.\n");
return hr;
}
// Obtain a class enumerator for the video input device category.
IEnumMoniker *pEnumCat = NULL;
hr = pSysDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnumCat, 0);
if(hr == S_OK)
{
// Enumerate the monikers.
IMoniker *pMoniker = NULL;
ULONG cFetched;
while(pEnumCat->Next(1, &pMoniker, &cFetched) == S_OK)
{
IPropertyBag *pPropBag;
hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag,
(void **)&pPropBag);
if(SUCCEEDED(hr))
{
// To retrieve the filter's friendly name, do the following:
VARIANT varName;
VariantInit(&varName);
hr = pPropBag->Read(L"FriendlyName", &varName, 0);
if (SUCCEEDED(hr))
{
// Display the name in your UI somehow.
setcolor(GREEN);
wprintf(L"------------------> %s <------------------\n", varName.bstrVal);
}
VariantClear(&varName);
// To create an instance of the filter, do the following:
IBaseFilter *pFilter;
hr = pMoniker->BindToObject(NULL, NULL, IID_IBaseFilter,
(void**)&pFilter);
process_filter(pFilter);
//Remember to release pFilter later.
pPropBag->Release();
}
pMoniker->Release();
}
pEnumCat->Release();
}
pSysDevEnum->Release();
return 0;
}
int wmain(int argc, wchar_t* argv[])
{
setlocale(LC_ALL, "Russian");
int result;
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
result = enum_devices();
CoUninitialize();
getchar();
return result;
}
You can use VideoCapture::get(int propId) function. Within that function you can get two properties to get the video resolution. CV_CAP_PROP_FRAME_WIDTH
and CV_CAP_PROP_FRAME_HEIGHT
which give you the with and height of the video stream respectively.
Here's a solution with OpenCV. But it's very slow and then, probably useless for most applications. Anyway, the code below displays supported resolutions. The idea is to test resolutions decreasingly, and check the actual resolution at each time. Just call query_resolutions() with pointer to your cv::VideoCapture.
// return true if the actual resolution has changed
bool test_resolution(cv::VideoCapture* camera, int width, int height, int &actualWidth, int &actualHeight)
{
camera->set(CV_CAP_PROP_FRAME_WIDTH, width);
camera->set(CV_CAP_PROP_FRAME_HEIGHT, height);
width = static_cast<int>(camera->get(CV_CAP_PROP_FRAME_WIDTH));
height = static_cast<int>(camera->get(CV_CAP_PROP_FRAME_HEIGHT));
if (width != actualWidth || height != actualHeight)
{
actualWidth = width;
actualHeight = height;
return true;
}
else
{
return false;
}
}
void query_resolutions(cv::VideoCapture* camera)
{
// Save current resolution
const int current_width = static_cast<int>(camera->get(CV_CAP_PROP_FRAME_WIDTH));
const int current_height = static_cast<int>(camera->get(CV_CAP_PROP_FRAME_HEIGHT));
int actualWidth = 10000;
int actualHeight = 10000;
int delta = 0;
do
{
// first, test to decrease width only
bool resoChanged = test_resolution(camera, actualWidth - delta, actualHeight, actualWidth, actualHeight);
if (!resoChanged)
{
// then, try to decrease height only
resoChanged = test_resolution(camera, actualWidth, actualHeight - delta, actualWidth, actualHeight);
}
if (!resoChanged)
{
// finally, try to decrease width and height
resoChanged = test_resolution(camera, actualWidth - delta, actualHeight - delta, actualWidth, actualHeight);
}
if (resoChanged)
{
delta = 100;
std::cout << actualWidth << "x" << actualHeight << std::endl;
}
else
{
// if these tries don't change the resolution, let's increase delta
delta += 100;
}
}
while (actualWidth > delta && actualHeight > delta);
// Restore resolution
camera->set(CV_CAP_PROP_FRAME_WIDTH, current_width);
camera->set(CV_CAP_PROP_FRAME_HEIGHT, current_height);
}
I also encountered this problem. OpenCV has hidden some functions related to the resolutions and properties. So what I did is to build a camera library in directshow (Window-based) and output cv::Mat. You can use my code.
© 2022 - 2024 — McMap. All rights reserved.