2008年6月17日 星期二

GUI介面的製作-視訊,AVI檔案儲存,多視訊裝置

視訊GUI介面程式設計,包括了捕捉視訊畫面,存取AVI檔案,將視訊畫面存成AVI檔,這邊先從視訊存成AVI開始,將最初的Webcam播放程式在做調整,並詳細說明所有capture類的副程式內容.

webcam程式碼存成AVI檔
#include <cv.h>
#include <highgui.h>
#include <stdio.h>


int main()
{
    CvCapture *capture;
    IplImage *frame;

    capture=cvCreateCameraCapture(0);
    cvNamedWindow("Webcam",0);

    CvVideoWriter *writer;
    char AviFileName[]="Output.avi";
    int AviForamt = -1;
    int FPS = 25;
    CvSize AviSize = cvSize(640,480);
    int AviColor = 1;
    writer=cvCreateVideoWriter(AviFileName,AviForamt,FPS,AviSize,AviColor);

    int i=0;
    while(true)
    {
        frame = cvQueryFrame(capture);
        cvWriteFrame(writer,frame);

        cvShowImage("Webcam",frame);
        printf("%d\n",i);

        if(cvWaitKey(20)>0)     break;
        i++;
    }

    cvReleaseCapture(&capture);
    cvReleaseVideoWriter(&writer);
    cvDestroyWindow("Webcam");
}
執行結果:


先開一個CvCapture及IplImage,用cvCreateCameraCapture()選定視訊裝置編號,給視窗命名,接著,就是寫入AVI檔的重頭戲啦,用CvVideoWriter創立一個writer的資料結構,給它AVI檔名,AVI格式,FPS(Frame per second)每秒圖片播放頻率,CvSize資料結構及Avi檔的顏色種類,再用cvWriteFrame()寫入AVI檔,最後,記得用cvReleaseVideoWriter()把CvVideoWriter資料結構釋放,cvReleaseVideoWriter()非常的重要,因為AVI檔的檔案格式收尾就是要用到cvReleaseVideoWriter(),也就是說,如果不用到cvReleaseVideoWriter()AVI檔就無法開啟.這邊,先從cvCreateCameraCapture()詳細敘述.

多視訊介面的開啟,也是OpenCV不錯的應用,它的使用方法就是將cvCreateCameraCapture()的裝置代號重複使用,以下就是一個簡單的多視訊畫面開啟的實例.

多個Webcam的程式實作
#include <cv.h>
#include <highgui.h>
#include <stdio.h>
#include <windows.h>


int main()
{

    CvCapture *capture0;
    CvCapture *capture1;

    IplImage *frame0;
    IplImage *frame1;

    capture0 =cvCaptureFromCAM(0);
    capture1 =cvCaptureFromCAM(0);

    cvNamedWindow("Webcam0",1);
    cvNamedWindow("Webcam1",1);

    while(true)
    {
        frame0 = cvQueryFrame(capture0);
        frame1 = cvQueryFrame(capture1);

        cvShowImage("Webcam0",frame0);
        cvShowImage("Webcam1",frame1);


        if(cvWaitKey(10)>=0)
        {
            break;
        }

    }

    cvReleaseCapture(&capture0);
    cvDestroyWindow("Webcam0");

}

執行結果:
(1)選擇視訊裝置


(2)兩台Webcam同步播放


上面的程式,會跳出一個介面讓人選擇視訊裝置,這時選擇其中一個裝置就可以同步播放啦,但是,對於兩個視訊裝置二擇一的寫法,cvCreateCameraCapture()是不支援的,如果要將裝置做二擇一個設定,可以參考後面"cvcam.h"的相關設定.

cvCreateCameraCapture()
其實跟cvCaptureFromCAM()是一樣的,它被OpenCV定義成

#define cvCaptureFromCAM cvCreateCameraCapture

所以,當用cvCaptureFromCAM()會自動取代成cvCreateCameraCapture(),而在視訊裝置的使用上也大有學問,一般視訊裝置是0是自動偵測,有兩台以上就用函式及它的裝置代號重複呼叫,而它可以支援各種特殊裝置,如下:

#define CV_CAP_ANY 0 // autodetect

#define CV_CAP_MIL 100 // MIL proprietary drivers

#define CV_CAP_VFW 200 // platform native
#define CV_CAP_V4L 200
#define CV_CAP_V4L2 200

#define CV_CAP_FIREWARE 300 // IEEE 1394 drivers
#define CV_CAP_IEEE1394 300
#define CV_CAP_DC1394 300
#define CV_CAP_CMU1394 300

#define CV_CAP_STEREO 400 // TYZX proprietary drivers
#define CV_CAP_TYZX 400
#define CV_TYZX_LEFT 400
#define CV_TYZX_RIGHT 401
#define CV_TYZX_COLOR 402
#define CV_TYZX_Z 403

#define CV_CAP_QT 500 // QuickTime

對於多視訊裝置的實作,假如,有兩Window XP(VFW)的視訊裝置要控制,則用兩個相同的cvCreateCameraCapture()函式及兩個相同的CV_CAP_VFW代號,而OpenCV會有介面來選擇目標裝置.
cvCreateCameraCapture(裝置數字代號);

cvCreateVideoWriter()
它要放的引數分別為AVI檔名,AVI格式,FPS,CvSize資料結構及Avi檔的顏色種類,AVI的格式有很多種,由於影片有很多各個不同的壓縮格式,因此,被分為非常多類,許多的種類也只是在學術界採用,real player及media player很多都不適用,這邊壓縮格式的規格分為:

CV_FOURCC('P','I','M','1') MPEG-1 codec
CV_FOURCC('M','J','P','G') motion-jpeg codec (does not work well)
CV_FOURCC('M', 'P', '4', '2') MPEG-4.2 codec
CV_FOURCC('D', 'I', 'V', '3') MPEG-4.3 codec
CV_FOURCC('D', 'I', 'V', 'X') MPEG-4 codec
CV_FOURCC('U', '2', '6', '3') H263 codec
CV_FOURCC('I', '2', '6', '3') H263I codec
CV_FOURCC('F', 'L', 'V', '1') FLV1 codec

它的壓縮格是參數方法被定義在"highgui.h"裡的

#define CV_FOURCC(c1,c2,c3,c4)     \
            (((c1)&255) + (((c2)&255)<<8) + (((c3)&255)<<16) + (((c4)&255)<<24))


如果要使用mpge-1則直接使用int AviForamt=CV_FOURCC('P','I','M','1');就好啦,不過光是mpge-1壓縮格式real play跟media play就不支援播放,比較建議的是直接用-1,會有GUI介面幫你自己選擇檔案格式.雖然有些格是很多播放程式也是不支援,不過用起來方便許多.再來,FPS,每秒Frame的播放速度,frame有很多的翻譯,也可以叫它做框頁,用來做每秒畫面顯示的速度.AVI顏色種類,這個其實就很簡單啦,只有0跟1,0是黑白,1是彩色.
cvCreateVideoWriter("AVI檔名",AVI格式參數或代號,FPS,AVI大小CvSize資料結構,AVI顏色種類代號);

cvQueryFrame()
其實這是兩個副程式組合而成的,分別是cvGrabFrame()+cvRetrieveFrame(),這兩個副程式的實作會在下面的程式碼用出.
IplImage* cvQueryFrame(capture資料結構);

cvWriteFrame()
將frame寫入writer資料結構.
cvWriteFrame(writer資料結構,frame資料結構);

cvReleaseVideoWriter()
釋放writer資料結構,這邊cvReleaseVideoWriter()不只做了釋放資料結構的功能,還包括的AVI檔案格式的結尾製作,再做寫入AVI檔時一定要有cvReleaseVideoWriter()做結尾.
cvReleaseVideoWriter(writer資料結構)

--
附註:opencv1.1取消了AviForamt=-1的功能,並且要掛上ffopencv的函式庫才能使用,關於avi檔案的存取,必須要去Yahoo Group下載ffopencv110.dll覆蓋到C:\Program Files\OpenCV\bin的目錄底下





然後只能在Visual Studio的平台才能使用.

ffopencv使用的是ffmpeg library,ffmpeg只支援gcc 4.3版以上的編譯器,而Dev-C++使用的是gcc 3.4.2版的編譯器,因此在Dev-C++使用Opencv 1.1播放avi檔還是會有Error.




23 意見:

Steven 提到...

請問是if(cvWaitKey(20)>0) break;
來決定錄影時間嗎??

wa114040@gmail.com 提到...

是的.但是這是要用鍵盤點擊來決定錄製時間
如果另外要做時間設定的話(譬如兩分鐘)就要加入時間函式,時間到while迴圈就做break

匿名 提到...

正在学习相关内容,很感谢分享。

在看这一篇文档时,你的第一段代码,执行后提示错误,非法关闭,不知是因何而起?

匿名 提到...

接上,但将这一句改为:CvSize AviSize = cvSize(320,240),也就是将视频尺寸除以2后,发现无错,不知大家有没有遇到这种情况,可否检测视频图像尺寸?

wa114040@gmail.com 提到...

我也不行耶
我不太熟AVI檔播放格式
我在猜AVI檔是不是只支援640*480的大小
不過就第一段的程式碼來講 我還可以Run

汽水 提到...

您好
我有使用您第二段的開啟雙webcam功能程式碼

是我卻沒有辦法開啟兩個(兩支都是相同的webcam)

只能啟動一個而已

另一個卻都沒有畫面

不知道是哪裡有問題

http://www.wretch.cc/album/show.php?i=h2co333&b=11&f=1168521727&p=51
(結果畫面)

請問是哪裡有問題呢?

匿名 提到...

已經解決了@@~

原因是不能用同一組usb port...

匿名 提到...

感謝你那麼辛苦的做了這個教學網站
對我剛開始學習OPENCV很有幫助

謝囉~~~

Unknown 提到...

我在运行第一个程序的时候也发现这个问题,弹出错误,改为cvSize(320,240)后没问题了。我觉得应该和摄像头不同有关系。
可以采取以下代码,来提高程序的适应性:
cvQueryFrame(capture);//一定要有这句,否者下面的frameH,frameW取值为0,0
frameH=(int)cvGetCaptureProperty(capture,CV_CAP_PROP_FRAME_HEIGHT);
frameW=(int)cvGetCaptureProperty(capture,CV_CAP_PROP_FRAME_WIDTH);

wa114040@gmail.com 提到...

呵呵 了解
你說的意思是將Code改成
#include <cv.h>
#include <highgui.h>
#include <stdio.h>

int main()
{
CvCapture *capture;
IplImage *frame;

capture=cvCreateCameraCapture(0);

frame = cvQueryFrame(capture);
int frameH=(int)cvGetCaptureProperty(capture,CV_CAP_PROP_FRAME_HEIGHT);
int frameW=(int)cvGetCaptureProperty(capture,CV_CAP_PROP_FRAME_WIDTH);
CvVideoWriter *writer;
CvSize AviSize = cvSize(frameW,frameH);
writer=cvCreateVideoWriter("Output.avi",-1,25,AviSize,1);
cvNamedWindow("Webcam",0);
int i=0;
while(true)
{
frame = cvQueryFrame(capture);
cvWriteFrame(writer,frame);

cvShowImage("Webcam",frame);
printf("%d\n",i);

if(cvWaitKey(20)>0) break;
i++;
}

cvReleaseCapture(&capture);
cvReleaseVideoWriter(&writer);
cvDestroyWindow("Webcam");
}

這樣吧~

匿名 提到...

您好 不好意思 我也是最近才在研究OPENCV的 想請問一下 有沒有辦法做網路串流呢 因為我希望抓出一個一個FRAME 處理過後再傳輸到網路 可是這樣就不會RELEASE VIDEO WRITER了 因為串流一直跑不知道您有沒有什麼相關的資訊呢 謝謝

匿名 提到...

您好
我把上面的程式碼貼上去後
執行會出現於0x73b72853的8.exe(我的檔案名稱為8)中發生未處理的例外狀況OxC0000005:讀取位置0x01520888時發生存取違規 我是選擇執行後的第一個檔 想請問這個要怎麼解決

Unknown 提到...

cvReleaseVideoWriter()
釋放writer資料結構,這邊cvReleaseVideoWriter()不只做了釋放資料結構的功能,還包括的AVI檔案格式的結尾製作,再做寫入AVI檔時一定要有cvReleaseVideoWriter()做結尾.

请问:假如在程序执行过程中,突然断电而导致最后刚好没有执行cvReleaseVideoWriter()进行资源释放。当然这样的结果就是保存的视频文件是破损的。对于这样的情况?有什么办法应对?谢谢指导!

匿名 提到...

您好
我適用VISUAL STDIO 2008和OPENCV1.0的軟體 使用這篇程式碼後出現的Output.aviㄧ直都打不開 使用下一篇的程式碼也打不開(我有灌XviD codec)也是不行
請問是格式上的問題嗎?還是軟體的版本問題
?亦或是Header的問題

匿名 提到...

你好我在寫衣個程式
裡面有用到openCV去抓取羅技的webcam
用到的是 cvCaptureFromCAM( -1 ) 來抓取
在寫程式的時候都沒遇到太大的問題

但是我的程式最後要用windows media encoder去做串流到網路上
在連接網路串流的時候發現media encoder的軟體和我使用的 cvCaptureFromCAM( -1 ) function
他們會去搶webcam來使用
導致在開啟程式的時候就沒辦法做網路串流
在做網路串流的時候程式就沒辦法去抓取到webcam的畫面

請問大大有遇過類似的情形嗎?

wa114040@gmail.com 提到...

拿現成的軟體是不可能做好的網路串流的~因為程式功能都寫死了
最好是能找到能整合opencv的Source code或是MS有在.Net平台發佈的code

hn12303158 提到...

yesterday您好
我也遇到錄製後的AVI檔案無法用Media Player開啟的問題

我的OpenCV版本是1.1, 安裝了Xvid, 使用VS 2008開發, ffopencv110.dll也已附蓋過, 但還是無法解決問題

請問您可以給我一些建議嗎?

匿名 提到...

請問一下如何在MFC開AVI影像檔

匿名 提到...

我是opencv新手, 我想問是否要install左directx SDK才能用上面的codes capture webcam image? 因為我用vs2008 run上面的codes去capture USB webcam image, 但只出了一個grey background instead of the image.

匿名 提到...

請問我在run第一個程式,在結束錄製AVI時會一直跳出例外狀況,如果我AVI格式使用-1他就會跑出 [下面的框架可能錯誤及/或遺失,未載入 kernel32.dll 的符號]。
如果我AVI格式是CV_FOURCC('P','I','M','1')他就會跑出[下面的框架可能錯誤及/或遺失,未載入 opencv_ffmpeg210d.dll 的符號]請問我該怎麼解決呢?謝謝您。

匿名 提到...

你好,我想問一下 我有嘗試使用雙鏡頭,但是我的那個鏡頭插入電腦後 USB port都是預設成0,導致我目前程式都只會開啟一個鏡頭,有什麼方式可以解決嗎??

謝謝回答

zox657 提到...

請問如何截取視訊的畫面儲存成jpg檔

匿名 提到...

我是用
opencv 2.4.6
vc2010
我可以創建出avi檔~但是我無法開啟用media player開啟檔案~!!!

Copyright 2008-2009,yester