天天看點

(4opencv)如何基于GOCW,建立一個實時視訊程式

直接使用提供的代碼架構進行修改,是最快得到效果的方法;但是這樣的靈活性較差,而且真正的程式員從來都不會停滞在這一步:我們需要的是“将架構解析到最小化、理清楚每個建構之間的關系”,隻有這樣才能靈活運用。

一、準備工作

1、高拍儀已經接通,如果需要的話,還要安裝驅動;

2、vs2012程式設計環境,能夠編寫Csharp和OpenCV程式(具體不清楚可以回過頭來看配置);

3、

(4opencv)如何基于GOCW,建立一個實時視訊程式

是DirectShow.net(http://directshownet.sourceforge.net/docs.html)的可使用類

(4opencv)如何基于GOCW,建立一個實時視訊程式

它本身包含文檔,有時間可以看一下。最新更新時間2010年。

4、

(4opencv)如何基于GOCW,建立一個實時視訊程式

是由

(4opencv)如何基于GOCW,建立一個實時視訊程式

生成的。這裡可以先立足修改已經編輯成功的項目(具體原理将在下一課講解)

二、配置程式

1、添加引用

(4opencv)如何基于GOCW,建立一個實時視訊程式

directshow.net的話,直接引用dll就可以了

(4opencv)如何基于GOCW,建立一個實時視訊程式

2、拖動控件

使用Csharp編寫界面,可以重複使用

(4opencv)如何基于GOCW,建立一個實時視訊程式

的定位功能

(4opencv)如何基于GOCW,建立一個實時視訊程式

以及Dock的停靠功能

(4opencv)如何基于GOCW,建立一個實時視訊程式

圖像顯示的地方,肯定需要的是picturebox,不妨連同lena一起拷貝過來

(4opencv)如何基于GOCW,建立一個實時視訊程式

由于采集處理是一個實時過程,我們采用timer控件來控制(關于是使用timer還是開線程,那種比較好,我們在架構融合的時候專門比較,并選擇)

(4opencv)如何基于GOCW,建立一個實時視訊程式

性Interval采用50即可,以為50*24>1000,一般來說還是有認為24幀以上比較連貫。

三、編寫代碼

1、添加頭檔案和引用,并添加capture.cs

(4opencv)如何基于GOCW,建立一個實時視訊程式
(4opencv)如何基于GOCW,建立一個實時視訊程式

其中,Capture是一個專門對Directshow的采集裝置的封裝,裡面有豐富的功能;是官方提供的代碼,可以較為方向應用。

注意修改命名空間

(4opencv)如何基于GOCW,建立一個實時視訊程式

2、編寫選擇視訊準備函數(注意這裡預設裝置為640*480),并且我在選擇的時候預設選擇了第2個(序号為1)的裝置,因為我用的是筆記本,有内置攝像頭

相關函數的操作,注意參考相關注釋

  //選擇視訊裝置         

public

void

 InitVideoDevice()         {             

try

            {                 

if

 (cam != null)                     cam.Dispose();                 //讀取參數                 

int

 VIDEODEVICE = 1; // zero based index of video capture device to use                 

const

int

 VIDEOWIDTH = 640;// 是用預設(最大)分辨率                 

const

int

 VIDEOHEIGHT = 480; // Depends on video device caps                 

const

int

 VIDEOBITSPERPIXEL = 24; // BitsPerPixel values determined by device                 cam = 

new

 Capture(VIDEODEVICE, VIDEOWIDTH, VIDEOHEIGHT, VIDEOBITSPERPIXEL, picPreview  );             }             

catch

            {                 MessageBox.Show("攝像頭打開錯誤,請首先確定攝像頭連接配接并至少支援1024*768分辨率!");             }         }

并且在form的init中進行調用,確定不能夠出錯

public

 FormMain()         {             InitializeComponent();            

            //構造攝像頭資料

            foreach (DsDevice ds in DsDevice.GetDevicesOfCat(FilterCategory.VideoInputDevice))

            {

                cbCam.Items.Add(ds.Name);

            }

            //初始化攝像頭

            InitVideoDevice();           }

此時,已經可以預覽,并且獲得所有視訊裝置

(4opencv)如何基于GOCW,建立一個實時視訊程式

4、編寫timer事件

為了将OpenCV的函數融入進去,必須自己編寫timer事件。在這個timer事件中,最重要的操作就是

讀取directshow.net産生的結果

調用OpenCV的函數進行處理

将處理的結果回報到directshow.net中去顯示出來

private

void

 timer_Tick(object sender, EventArgs e)         {             // Release any previous buffer             

if

 (m_ip != IntPtr.Zero)             {                 Marshal.FreeCoTaskMem(m_ip);                 m_ip = IntPtr.Zero;             }             // capture image             

try

            {                 m_ip = cam.Click();             }             

catch

            {                 //do nothing,允許丢幀 TODO:是否改成繼承上一幀更好             }             Bitmap b = 

new

 Bitmap(cam.Width, cam.Height, cam.Stride, PixelFormat.Format24bppRgb, m_ip);             // If the image is upsidedown             b.RotateFlip(RotateFlipType.RotateNoneFlipY);             srcImage = b;             

if

 (picPreview.Image != null)                 picPreview.Image.Dispose();             //調用clr+opencv圖像處理子產品             MemoryStream ms = 

new

 MemoryStream();             b.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);             byte[] bytes = ms.GetBuffer();             Bitmap bitmap = client.testMethod(bytes);             //顯示結果             picPreview.Image = bitmap;         }

這段代碼比較關鍵

 // Release any previous buffer             

if

 (m_ip != IntPtr.Zero)             {                 Marshal.FreeCoTaskMem(m_ip);                 m_ip = IntPtr.Zero;             }

首先判斷指針是否為空

  // capture image             

try

            {                 m_ip = cam.Click();             }             

catch

            {                 //do nothing,允許丢幀 TODO:是否改成繼承上一幀更好             }    Bitmap b = 

new

 Bitmap(cam.Width, cam.Height, cam.Stride, PixelFormat.Format24bppRgb, m_ip);             // If the image is upsidedown             b.RotateFlip(RotateFlipType.RotateNoneFlipY);             srcImage = b;

而後通過調用Click()獲得目前視訊資料,并且将其轉換為BitMap格式

if

 (picPreview.Image != null)                 picPreview.Image.Dispose();             //調用clr+opencv圖像處理子產品             MemoryStream ms = 

new

 MemoryStream();             b.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);             byte[] bytes = ms.GetBuffer();             Bitmap bitmap = client.testMethod(bytes);

最為關鍵的調用client.testMethod方法來進行圖像處理,并将結果直接轉換為bitmap,最後這個結果顯示在另外一個picturebox上面。

如果你去看這個testMethod,是一個非常典型的“三明治”結構:包括将<byte>結構轉換為Mat,調用OpenCV函數對Mat進行處理,将Mat結果傳回出來。

Bitmap^  GOClrClass::testMethod(cli::array<

unsigned

char

>^ pCBuf1) {     ////////////////////////////////将輸入cli::array<unsigned char>轉換為cv::Mat/////////////////////////     pin_ptr<System::Byte> p1 = &pCBuf1[0];     

unsigned

char

* pby1 = p1;     cv::Mat img_data1(pCBuf1->Length,1,CV_8U,pby1);     cv::Mat img_object = cv::imdecode(img_data1,IMREAD_UNCHANGED);     

if

 (!img_object.data)         

return

 nullptr;     ////////////////////////////////////////////OpenCV的算法處理過程////////////////////////////////////     cvtColor(img_object,img_object,COLOR_BGR2GRAY);     cvtColor(img_object,img_object,COLOR_GRAY2BGR);     Mat drawing = img_object.clone();          /////////////////////////将cv::Mat轉換為Bitmap(隻能傳輸cv_8u3格式資料)///////////////////////////////     

if

 (!drawing.data)         

return

 nullptr;     Bitmap^ bitmap = MatToBitmap(drawing);     

return

 bitmap; }

而主要算法,隻是一個灰階處理。(我首先将彩色圖像轉換為灰階,然後再将灰階轉換為彩色,是為了保持3通道)

四、測試結果

為了顯示結果,我添加了一個picResult的picturebox,則調用OpenCV的處理結果顯示在右側。

(4opencv)如何基于GOCW,建立一個實時視訊程式

(4opencv)如何基于GOCW,建立一個實時視訊程式

到此為止,基于GOCW,建立一個實時視訊程式的基本流程已經明晰了,如果感興趣,相關的原理請關注後續部落格。

感謝閱讀至此,

希望有所幫助。

P.S小技巧:在tab選擇到預覽視窗的時候,才打開timer,這樣能夠保證最好效率。

private

void

 tabControl_SelectedIndexChanged(object sender, EventArgs e)         {             

if

 (tabControl.SelectedIndex == 1)//隻有在預覽的時候打開圖像處理                 timer.Enabled = 

true

;             

else

                timer.Enabled = 

false

;         }

來自為知筆記(Wiz)

目前方向:圖像拼接融合、圖像識别

聯系方式:[email protected]

繼續閱讀