Question

Is there any way in OpenCV to get the list of camera's resolutions?

Was it helpful?

Solution

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;
}

OTHER TIPS

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.

https://github.com/kcwongjoe/directshow_camera

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top