本帖內容摘要:將開源進行到底——如何在ZED內利用底層V4L2+OPENCV進行圖像處理以及移植策略。
百轉千回,終於到了最后的總結時間,每一個帖子都是幾天幾周反復探索的結果,將一些教訓和彎路都分享一下,能給利用zed開發攝像頭和視頻的同學一點指導。
1. ZED開發攝像頭的幾種思路以及選擇。。。
想在ZED上開發攝像頭,其實和其它ARM系列上開發攝像頭,是異曲同工的,都有兩種基本思路:
第一,利用OPENCV的CvCapture*cvCaptureFromCAM( int index )來實現,屏蔽掉V4L2底層的繁瑣操作。
第二,通過V4L2,從攝像頭的像素格式,視頻流格式,包括視頻的輸出格式等作設置和定制,包括視頻幀顯示的大小等都可以進行修改。
那么很顯然,包括我在內,大多數新手一開始肯定希望如何利用第一種方案,簡單嘛,首先在PC下的虛擬機UBuntu 12.04內實現攝像頭讀取,然后存儲為一幅照片,驗證上面的函數是否可行。一開始必然是不行的,那么通過下面的辦法,安裝一些第三方庫,便可以讓程序走通,但是。。。一會兒就知道,這條路是死路
apt-get install ffmpeg libavcodec-dev libavcodec52 libavformat52 libavformat-dev
apt-get install libgstreamer0.10-0-dbg libgstreamer0.10-0 libgstreamer0.10-dev
apt-get install libxine1-ffmpeg libxine-dev libxine1-bin
apt-get install libunicap2 libunicap2-dev
apt-get install libdc1394-22-dev libdc1394-22 libdc1394-utils
apt-get install swig
apt-get install libv4l-0 libv4l-dev
apt-get install python-numpy
apt-get install libpython2.6 python-dev python2.6-dev #You must install this for python support
裝好之后重新編譯攝像頭程序,還是不行。
需要重新編譯Opencv於是cmake,make ,sudo make install這樣以后,攝像頭就順利打開了。
然而,問題是,本機上可以了,那么這些庫里哪些是真正讓攝像頭打開的呢,經過對這些庫的了解,才發現,最為關鍵的幾個庫為ffmpeg以及libv4l,libavcodec。特別是libv4l是直接用來捕獲攝像頭的庫,只有有了這些,在opencv重新編譯后,才能夠將cvCaptureFromCAM於真正的設備連接,從而獲取視頻。
本機PC上確實可以,但是我們最終目的是在嵌入式ARM內實現,這又該怎么辦,雖然論壇里也有一些帖子中說到關於v4l2/v4l的配置問題,經過很多帖子的閱讀,而且經過很多實驗,發現很不容易,最大的問題就是libv4l.so,沒有ARM的版本,如果能夠在ARM平台下找到libv4l.so的庫文件,選上with v4l,在編譯OPENCV時就是走不通,因為首先在交叉編譯器的目錄下就得有這個ARM版本的libv4l.so的庫啊,但是實際是沒有,而且網上也沒有人提供這項資源。
所以,這種方案走不通,pass了。
那么,如何在ZED內打開攝像頭呢,OK,底層的V4L2真的那么恐怖嗎,其實非也,底層V4L2非常容易理解,而且也不難,看我細細道來。
V4L是Linux環境下開發視頻采集設備驅動程序的一套規范(API),它為驅動程序的編寫提供統一的接口,並將所有的視頻采集設備的驅動程序都納入其的管理之中。V4L不僅給驅動程序編寫者帶來極大的方便,同時也方便了應用程序的編寫和移植。V4L2是V4L的升級版,我們使用的OOB是3.3的內核,不再支持V4L,所以是以v4l2作為底層的攝像頭視頻開發。
video4linux2(V4L2)是Linux內核中關於視頻設備的內核驅動,它為Linux中視頻設備訪問提供了通用接口,在Linux系統中,V4L2驅動的Video設備節點路徑通常/dev/video/中的videoX。
V4L2的主要作用使程序有發現設備和操作設備的能力.它主要是用一系列的回調函數來實現這些功能,像設置攝像頭的頻率、幀頻、視頻壓縮格式和圖像參數等等。此框架只能運行在Linux操作系統中,而且是針對uvc的免驅usb設備的編程框架。
V4L2打開視頻的流程可以用以下的軟件框圖表示:
就分這么幾步,具體的操作,我也不敢妄自吹噓,確實也是學超群天晴的博客而來。 http://www.cnblogs.com/surpassal/archive/2012/12/22/zed_webcam_lab2.html
至少我覺得很好用,這種視頻開發思路,雖然有點費周折,但是不用移植任何第三方庫,就可以在ZED內打開攝像頭,而且最為關鍵的,CV下的cvCaptureFromCAM,在ZED內最大是640*480,但是V4L2的底層函數,則可以完全地按照攝像頭的像素來設置窗口大小,像我的Logitech C270,像素300萬,我甚至可以放大到1920*1080來觀察攝像頭視頻,這就是V4L2的強大之處。具體的開發過程大家可以參照上面的鏈接,還是大神寫的好啊,慚愧。
2. V4L2+OPENCV,如何在V4L2讀取攝像頭視頻的基礎上,利用OPENCV進行處理。。。
OpenCV的移植並不復雜,按照教材上一步步來,基本的函數都可以直接拿來使用,當然前提是指定Opencv庫文件的路徑,然而,Opencv進行處理,是基於IplImage數據類型的,IplImage是CV內的struct類型的圖像變量。
而V4L2是通過malloc申請動態內存,並將圖像連續存放在uchar *的指針所指向的內存內部的,如何轉換呢?
由於我這里很早就開始用QT進行程序開發,因此,我就毫不猶豫的,想到用QT來做中介,
沒錯,具體怎么實現呢,OK,uchar *的變量,可以通過下列函數,直接轉化為QImage,沒有任何問題
QImage frame;
frame->loadFromData((uchar *)pp,window_width * window_hight * 3 * sizeof(char));
這就將轉換為了QImage的圖像對象,可以任意在QT內貼圖啊,存儲啊等等。
那么然后,QImage如何和IplImage轉換呢,最基本的轉換函數為,當然這是網上大家通用的一個:
void labeltest::cvxCopyQImage(const QImage *qImage, IplImage *pIplImage) //QImage to Iplimage
{
int x, y;
for(x = 0; x < pIplImage->width; ++x)
{
for(y = 0; y < pIplImage->height; ++y)
{
QRgb rgb = qImage->pixel(x, y);
cvSet2D(pIplImage, y, x, CV_RGB(qRed(rgb), qGreen(rgb), qBlue(rgb)));
}
}
}
Ok,在經過OPENCV一陣處理后,特別是很多CV函數,都需要首先對圖像進行灰度化,即BGR2GRAY,之后圖像的通道數都變為1,圖像的數據量也發生變化,處理后的數據想要顯示在QT中,怎么辦呢,兩種思路:
1. 如果是彩色圖像,則很簡單一句話:
IplImage *img = cvLoadImage("lena.jpg", 1);
QImage qImage(img->imageData, img->width, img->height, img->widthStep, QImage::Format_RGB888);