【问题标题】:OpenCV: Get camera resolutions C++OpenCV:获取相机分辨率 C++
【发布时间】:2013-08-22 01:13:51
【问题描述】:

OpenCV 中有没有办法获取相机分辨率列表?

【问题讨论】:

    标签: c++ opencv resolutions


    【解决方案1】:

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

    【讨论】:

    • 链接器添加:Strmiids.lib
    • 对不起,这与 OpenCV 有什么关系?
    • 它可以解决(对于windows)opencv中缺乏这样的功能。
    【解决方案2】:

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

    【讨论】:

    • 是的,我知道,但我的意思是如何获得所有可能的分辨率? (哪个相机支持)
    【解决方案3】:

    这是一个使用 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);
    }
    

    【讨论】:

      【解决方案4】:

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

      https://github.com/kcwongjoe/directshow_camera

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-09-12
        • 1970-01-01
        • 2010-09-06
        • 1970-01-01
        • 2014-01-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多