影像處理演算_學弟提問_如何做相鄰影格的處理_使用在大學所學的資料結構(SolidFoundation)
主要問題:
一個問題
朝和老師希望我們
輸入影片然後取相鄰影格 再進行處理
我們這裡套用到了
DataStructure 的 SolidFoundation
DataStructure 的 SolidFoundation
所以使用 資料結構中的 Queue 來處理 影格讀取
那這裡影格就可搭配Queue來處理
你把影格想為客人
然後假設你是電員要發電影票、爆米花飲料給排隊的客人….
(這概念就是Queue了)
開發環境: visual studio 2015
Emgucv版本: 3.1
直接在 visual studio 2015 Tools ->
NugetPackage -> 找 emgucv
即可
(3.1版)
那我們思考完之後再來下去寫程式
我們要先知道在C#程式中
有哪些關於 Queue 的 實作
上 MSDN
看到 有一個
Queue 的 類
一些關於Queue的程式實作Blog教學學習分享文
影片教學(都兩分鐘左右)
緊接著準備好影片
Youtube 搜尋一個簡短影片檔範例
崩跑羚羊
https://www.youtube.com/watch?v=DJ7zATJhRm4
推薦的影片下載網站
(1)賣噹噹
à只會幫你轉
MP4 、 3GP 、WEBM格式
(2)OnlineVideoConverter
à支援avi、wmv、mpg、mov、mp4……
準備好多種檔案格式和不同解析度檔案供載入測試
這樣就確認確實有影格進入Queue中了
佇列(Queue)常用的方法如下
名稱 說明
Count 取得佇列中目前的項目數量
Dequeue 從佇列前端取出一個項目,同時將其移除
Enqueue 從佇列尾端加入一個項目
Peek 從佇列前端取出一個項目,但不移除
添加的影格Index更新功能程式
添加的存影格功能程式
int i = 0;
//存影格用的
可以存下檢查 Queue 中
是否有影格
foreach (Mat img in inQueue)
{
i++;
try
{
img.Save(@"C:\frame\img" + i.ToString() + ".jpg");
//為了避免出現 Additional information: 在 GDI+ 中發生泛型錯誤。 加上一組try... catch...
//錯誤說明link :
https://dotblogs.com.tw/atowngit/2010/01/13/13003
}
catch
{
}
}
第一階段 Code
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Emgu.CV;
using Emgu.CV.CvEnum;
using Emgu.CV.Structure;
namespace emgucv_video_controller
{
public partial class Form1 : Form
{
//Emgucv3.1 官方字典使用說明書Link:
// http://www.emgu.com/wiki/index.php/Version_History#Emgu.CV-3.1.0
// http://www.emgu.com/wiki/files/3.1.0/document/html/8dee1f02-8c8a-4e37-87f4-05e10c39f27d.htm
# region variable
Mat currentFrame;
Capture grabber;
int videoFps = 0;//frame rate
#endregion
//C# Queue 官方使用 link:
//https://msdn.microsoft.com/en-us/library/7977ey2c(v=vs.110).aspx
//
//Stackoverflow上有人曾經將Queue跟emgucv結合
//http://stackoverflow.com/questions/11612046/parallel-image-processing-artifacts
//
#region datastructure variable
Queue<Mat> inQueue = new Queue<Mat>(); //物件尚未實體化就呼叫它的屬性或方法 記得先實體化
//inQueue 是 global variable
#endregion
public Form1()
{
InitializeComponent();
}
private void updateFrame(object sender, EventArgs e)
{
//currentFrame = grabber.QueryFrame();
currentFrame = grabber.QueryFrame();
if (currentFrame != null)
{
inQueue.Enqueue(currentFrame);
label2.Text = inQueue.Count.ToString();
pictureBox1.Image = currentFrame.ToImage<Bgr,byte>().ToBitmap();
int i = 0;
//存影格用的 可以存下檢查 Queue 中 是否有影格
foreach (Mat img in inQueue)
{
i++;
try
{
img.Save(@"C:\frame\img" + i.ToString() + ".jpg");
//為了避免出現 Additional information: 在 GDI+ 中發生泛型錯誤。 加上一組try... catch...
//錯誤說明link : https://dotblogs.com.tw/atowngit/2010/01/13/13003
}
catch
{
}
}
}
}
private void btnOpenVideo_Click(object sender, EventArgs e)
{
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Filter = "3gpp文件|*.3gpp|MP4文件|*.mp4|AVI文件|*.avi|RMVB文件|*.rmvb|WMV文件|*.wmv|MKV文件|*.mkv|所有文件|*.*";
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
grabber = new Capture(openFileDialog.FileName);
Application.Idle += new EventHandler(updateFrame);
//新版的3.x 記得預設為double 必須 使用 cast運算
videoFps = (int)CvInvoke.cveVideoCaptureGet(grabber, CapProp.Fps);
//舊版的2.x以前 在 新版的已經不適用
//videoFps = (int)CvInvoke.cvGetCaptureProperty(grabber, Emgu.CV.CvEnum.CAP_PROP.CV_CAP_PROP_FPS);
}
}
private void btnGet2Frames_Click(object sender, EventArgs e)
{
}
private void btnPlay_Click(object sender, EventArgs e)
{
grabber.Start();
}
private void btnPause_Click(object sender, EventArgs e)
{
grabber.Pause();
}
}
}
之後我們再把界面和程式做更改
最後程式碼
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using Emgu.CV; using Emgu.CV.CvEnum; using Emgu.CV.Structure; namespace EmguReadVideo { public partial class Form1 : Form { //Emgucv3.1 官方字典使用說明書Link: // http://www.emgu.com/wiki/index.php/Version_History#Emgu.CV-3.1.0 // http://www.emgu.com/wiki/files/3.1.0/document/html/8dee1f02-8c8a-4e37-87f4-05e10c39f27d.htm # region variable Mat currentFrame; Capture grabber; int videoFps = 0;//frame rate int frameNumber=0; bool isJump = false; #endregion //C# Queue 官方使用 link: //https://msdn.microsoft.com/en-us/library/7977ey2c(v=vs.110).aspx // //Stackoverflow上有人曾經將Queue跟emgucv結合 //http://stackoverflow.com/questions/11612046/parallel-image-processing-artifacts // #region datastructure variable Queue<Mat> inQueue = new Queue<Mat>(); //物件尚未實體化就呼叫它的屬性或方法 記得先實體化 //inQueue 是 global variable #endregion public Form1() { InitializeComponent(); } private void btnRead_Click(object sender, EventArgs e) { OpenFileDialog openFileDialog = new OpenFileDialog(); openFileDialog.Filter = "3gpp文件|*.3gpp|MP4文件|*.mp4|AVI文件|*.avi|RMVB文件|*.rmvb|WMV文件|*.wmv|MKV文件|*.mkv|所有文件|*.*"; if (openFileDialog.ShowDialog() == DialogResult.OK) { grabber = new Capture(openFileDialog.FileName); Application.Idle += new EventHandler(updateFrame); //新版的3.x 記得預設為double 必須 使用 cast運算 //videoFps = (int)CvInvoke.cveVideoCaptureGet(grabber, CapProp.Fps); //舊版的2.x以前 在 新版的已經不適用 //videoFps = (int)CvInvoke.cvGetCaptureProperty(grabber, Emgu.CV.CvEnum.CAP_PROP.CV_CAP_PROP_FPS); } } private void updateFrame(object sender, EventArgs e) { currentFrame = grabber.QueryFrame(); grabber.Stop(); if (currentFrame != null) { grabber.Stop(); inQueue.Enqueue(currentFrame); label2.Text = inQueue.Count.ToString(); //label4.Text = videoFps.ToString(); label4.Text = CvInvoke.cveVideoCaptureGet(grabber, CapProp.Fps).ToString(); pictureBox1.Image = currentFrame.ToImage<Bgr, byte>().ToBitmap(); /* int i = 0; //存影格用的 可以存下檢查 Queue 中 是否有影格 foreach (Mat img in inQueue) { i++; try { img.Save(@"C:\frame\img" + i.ToString() + ".jpg"); //為了避免出現 Additional information: 在 GDI+ 中發生泛型錯誤。 加上一組try... catch... //錯誤說明link : https://dotblogs.com.tw/atowngit/2010/01/13/13003 } catch { } } */ } if (isJump) { currentFrame = inQueue.ElementAt(frameNumber); pictureBox1.Image = currentFrame.ToImage<Bgr, byte>().ToBitmap(); } } private void btnQueueClear_Click(object sender, EventArgs e) { inQueue.Clear(); label2.Text = inQueue.Count.ToString(); } private void btnPlay_Click(object sender, EventArgs e) { Application.Idle += new EventHandler(updateFrame); } private void btnPause_Click(object sender, EventArgs e) { Application.Idle -= new EventHandler(updateFrame); } private void btnJump_Click(object sender, EventArgs e) { frameNumber = int.Parse(textBox1.Text); //inQueue.ElementAt(frameNumber); isJump = true; } } }
留言
張貼留言