1. 程式人生 > >(4opencv)如何基於GOCW,創建一個實時視頻程序

(4opencv)如何基於GOCW,創建一個實時視頻程序

高拍儀 turn draw bsp 文件 創建 bitmap 一課 當前

直接使用提供的代碼框架進行修改,是最快得到效果的方法;但是這樣的靈活性較差,而且真正的程序員從來都不會停滯在這一步:我們需要的是“將框架解析到最小化、理清楚每個構建之間的關系”,只有這樣才能靈活運用。一、準備工作1、高拍儀已經接通,如果需要的話,還要安裝驅動;2、vs2012編程環境,能夠編寫Csharp和OpenCV程序(具體不清楚可以回過頭來看配置);3、技術分享圖片是DirectShow.net(http://directshownet.sourceforge.net/docs.html)的可使用類技術分享圖片它本身包含文檔,有時間可以看一下。最新更新時間2010年。4、技術分享圖片是由技術分享圖片生成的。這裏可以先立足修改已經編輯成功的項目(具體原理將在下一課講解)

二、配置程序1、添加引用技術分享圖片directshow.net的話,直接引用dll就可以了技術分享圖片2、拖動控件使用Csharp編寫界面,可以重復使用技術分享圖片的定位功能技術分享圖片以及Dock的停靠功能技術分享圖片
圖像顯示的地方,肯定需要的是picturebox,不妨連同lena一起拷貝過來技術分享圖片
由於采集處理是一個實時過程,我們采用timer控件來控制(關於是使用timer還是開線程,那種比較好,我們在框架融合的時候專門比較,並選擇)技術分享圖片性Interval采用50即可,以為50*24>1000,一般來說還是有認為24幀以上比較連貫。

三、編寫代碼1、添加頭文件和引用,並添加capture.cs技術分享圖片技術分享圖片
其中,Capture是一個專門對Directshow的采集設備的封裝,裏面有豐富的功能;是官方提供的代碼,可以較為方向應用。
註意修改命名空間技術分享圖片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();
}

此時,已經可以預覽,並且獲得所有視頻設備技術分享圖片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的處理結果顯示在右側。技術分享圖片

技術分享圖片
到此為止,基於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)

(4opencv)如何基於GOCW,創建一個實時視頻程序