影像處理演算_學弟提問_如何做相鄰影格的處理_使用在大學所學的資料結構(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
à支援aviwmvmpgmovmp4……




準備好多種檔案格式和不同解析度檔案供載入測試









這樣就確認確實有影格進入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;
        }
    }
}

















留言

這個網誌中的熱門文章

何謂淨重(Net Weight)、皮重(Tare Weight)與毛重(Gross Weight)

Architecture(架構) 和 Framework(框架) 有何不同?_軟體設計前的事前規劃的藍圖概念

經得起原始碼資安弱點掃描的程式設計習慣培養(五)_Missing HSTS Header