5

OpenCV中有什么方法可以获取相机分辨率列表吗?

4

4 回答 4

4

对于 Windows,您可以使用以下代码枚举所有相机和分辨率:

#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;
}
于 2013-08-24T15:29:13.717 回答
1

您可以使用VideoCapture::get(int propId)函数。在该函数中,您可以获得两个属性来获取视频分辨率。CV_CAP_PROP_FRAME_WIDTHCV_CAP_PROP_FRAME_HEIGHT分别为您提供视频流的 with 和 height 。

于 2013-08-22T07:05:25.060 回答
1

这是 OpenCV 的解决方案。但它非常慢,对于大多数应用程序来说可能无用。无论如何,下面的代码显示了支持的分辨率。这个想法是逐步测试分辨率,并在每次检查实际分辨率。只需使用指向您的 cv::VideoCapture 的指针调用 query_resolutions()。

// 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);
}
于 2017-09-20T14:32:26.320 回答
0

我也遇到了这个问题。OpenCV 隐藏了一些与分辨率和属性相关的功能。所以我所做的是在directshow(基于窗口)中构建一个相机库并输出cv::Mat。你可以使用我的代码。

https://github.com/kcwongjoe/directshow_camera

于 2021-03-15T06:04:31.033 回答