USB免驅攝像頭採集圖像【VS2012+opencv+directShow(CcameraDS)實現】

在Opencv中文網站上有關於directShow和opencv結合採集圖像的教程,地址:http://wiki.opencv.org.cn/index.php/%e4%bd%bf%e7%94%a8DirectShow%e9%87%87%e9%9b%86%e5%9b%be%e5%83%8f
但是該配置比較老,本文講述如何基於該教程在 VS2012和opencv2.4.9上進行配置和修改,完成USB攝像頭的驅動。

博主的USB免驅攝像頭如下:
這裏寫圖片描述

文末有完整代碼的下載地址

1.環境配置

在Opencv中文網站上有關於directShow和opencv結合採集圖像的教程,地址:http://wiki.opencv.org.cn/index.php/%e4%bd%bf%e7%94%a8DirectShow%e9%87%87%e9%9b%86%e5%9b%be%e5%83%8f

但說明中的“本文檔介紹的CCameraDS類調用採集函數可直接返回IplImage,使用更方便,且集成了DirectShow,勿需安裝龐大的DirectX/Platform SDK”並不靠譜,DirectShow 似乎已經開始被微軟給淘汰了,最後存在是在多年前的 DirectX 9.0b 包裏。

注意這裏並不需要下載DirectX 9.0包,下面介紹在VS2012和opencv2.4.9下的配置過程。

1.1 配置VS2012和opencv環境

按照網上流行的配置即可,如http://www.sigvc.org/bbs/thread-529-1-1.html 。配置好之後嘗試運行一個打開圖片的小程序檢測opencv環境是否配置成功。

1.2 配置DirectX環境

新建工程,配置好Opencv環境,隨後將從Opencv中文網上下載的 CameraDS.h 和 CameraDS.cpp 文件分別添加到項目的頭文件和源文件中。

VS2012旗艦版是自帶了 SDK 的,在 C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Include。
打開建立的VS2012項目的屬性頁,找到“VC++目錄”,在“包含目錄”裏添加 (FrameworkSDKDir)Include (FrameworkSDKDir)Lib。

發現#include “qedit.h”報錯,原因是現在的版本已經沒有qedit.h這個頭文件了,從網址:http://download.csdn.net/download/bcj296050240/9651955 中下載該文件,添加到項目的頭文件中。

2. 運行

環境配置好之後,可以用 Opencv中文網 上下載的main.cpp運行,運行過程可能遇到const char* 無法轉換的問題,將此處的代碼去掉即可。

下面是本人編寫的main函數,提供了USB相機的打開、監視、圖像捕獲功能。

2.1 查看系統的所有攝像頭狀態(initAllCameras函數)

參數是 CCameraDS 類的對象。該函數獲取相機的數目並且顯示相機名稱。從輸出中我們可以找到USB相機的編號,一般情況下編號爲1。

//獲取當前可用的攝像頭並打開USB攝像頭
int initAllCameras(CCameraDS &m_CamDS){
    //僅僅獲取攝像頭數目
    int m_iCamCount = CCameraDS::CameraCount();
    printf("There are %d cameras.\n", m_iCamCount);

    if(m_iCamCount == 0)
    {
        return -1;
    }

    //獲取所有攝像頭的名稱
    for(int i = 0; i < m_iCamCount; i++)
    {
        char szCamName[1024];
        int retval = m_CamDS.CameraName(i, szCamName, sizeof(szCamName));
        if(retval >0)
        {
            printf("Camera #%d's Name is '%s'.\n", i, szCamName);
        }
        else
        {
            printf("Can not get Camera #%d's name.\n", i);
        }
    }
    return m_iCamCount;
}

運行結果如下所示:

There are 3 cameras.
Camera #0's Name is 'Lenovo EasyCamera'.
Camera #1's Name is '3D Camera'.
Camera #2's Name is 'Basler GenICam Source'.

從運行結果中可以看出,使用的3D相機的編號爲1。

2.2 打開USB相機(openUsbCam函數)

函數有四個參數,第一個參數爲CcameraDS類的對象,camNum設置爲1,表明現在要打開的USB相機,而不是電腦自帶相機。camWidth和camHeight根據自己所使用相機的情況進行設置,設置爲圖像的寬度和高度。

代碼如下:

// 打開 USB 相機  !! 在調用 camDisplay 和 camCapPic 之前必須調用該函數
// camNum = 1;       // 攝像頭編號爲1,表示當前要使用的是 USB 攝像頭
// camWidth = 2560;  // 圖片寬度
// camHeight = 720;  // 圖片高度
int openUsbCam(CCameraDS &m_CamDS, const int camNum=1, const int camWidth=2560, const int camHeight = 720){
    // 獲取當前可用的相機個數
    // 在所有的相機中,一般編號爲 0 的爲電腦自帶攝像頭,編號爲 1 的爲要使用的 USB 攝像頭
    int m_iCamCount = initAllCameras(m_CamDS);
    if(m_iCamCount == -1){
        cout<<"沒有可用的攝像頭! 退出.."<<endl;
        return -1;
    }

    Mat pFrame;
    // 打開相機並拍攝一幅圖片
    if((!m_CamDS.OpenCamera(camNum, false, camWidth, camHeight)) || (m_CamDS.QueryFrame() == NULL)){
        cout<<"# "<<camNum<<" 號相機無法打開,程序退出..";
        return -2;
    }
    return 1;
}

2.3 實時顯示(camDisplay函數)

函數有兩個參數,第一個參數是CcameraDS類的對象,第二個參數是時間,默認爲每隔20ms拍攝一幅圖片。
在顯示的過程中,按任意鍵可以退出。可以根據自己的要求進行修改,比如修改成按任意鍵保存當前圖片。

// 顯示相機視場的內容  每隔20毫秒顯示一幀
int camDisplay(CCameraDS &m_CamDS, const int t=20){
    Mat pFrame;
    while(1)
    {
        //獲取一幀
        pFrame = Mat(m_CamDS.QueryFrame());
        //顯示
        imshow("Camera", pFrame);
        //延遲,如果有鍵按下,退出
        if(cv::waitKey(t) != -1)
            break;
    }
    //m_CamDS.CloseCamera(); //可不調用此函數,CCameraDS析構時會自動關閉攝像頭
    cv::destroyAllWindows();
    return 0;
}

2.4 保存圖片(camCapPic函數)

實現獲取一幀圖片顯示並保存,保存路徑有filename設置。

// 抓取圖片 並保存到 filename 路徑中
int camCapPic(CCameraDS &m_CamDS, string filename="USBcam.jpg"){
    Mat pFrame;
    //獲取一幀
    pFrame = Mat(m_CamDS.QueryFrame());

    //顯示
    imshow("抓取圖片", pFrame);
    waitKey(1000);
    destroyAllWindows();

    //抓取圖片保存
    imwrite(filename, pFrame);

    //m_CamDS.CloseCamera(); //可不調用此函數,CCameraDS析構時會自動關閉攝像頭

    return 0;
}

2.5 主函數

調用順序爲,首先實例化對象,然後打開攝像頭(調用openUsbCam函數)。

打開攝像頭後,可以根據自己的需要調用不同的函數,如果要實時顯示,則調用camDisplay函數,如果要抓取圖像保存,則調用camCapPic函數。

注意在調用這些函數時,使用的是同一個CCameraDS的對象。

注意在函數中不要輕易調用CloseCamera()函數,該函數會釋放打開的USB攝像頭。如果釋放後要重新捕獲圖片,需要再次調用openUsbCam函數。

int main(){
    CCameraDS m_CamDS; 

    // 打開USB攝像頭
    openUsbCam(m_CamDS);

    // 1.0 顯示相機內容
    cout<<endl<<"顯示相機內容..."<<endl;
    camDisplay(m_CamDS);
    cout<<"顯示相機內容 退出..."<<endl<<endl;

    // 2.0 抓取圖片保存
    string filename = "USBcam.jpg";
    cout<<"抓取圖片保存..."<<endl;
    camCapPic(m_CamDS, filename);
    cout<<"抓取圖片保存 退出... 文件路徑 "<<filename<<endl;

    cout<<endl<<"結束..."<<endl;
    getchar();
    return 0;
}

完整代碼下載地址:

http://download.csdn.net/detail/bcj296050240/9652088

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章