成人午夜视频全免费观看高清-秋霞福利视频一区二区三区-国产精品久久久久电影小说-亚洲不卡区三一区三区一区

一個基于Emgu的運動檢測實例

最近在做一個威視IPC的視覺跟蹤項目,因為實際操作跟本人無關,只是因為興趣做點小研究而已,因為平臺主要是用C#的,那視覺處理庫無疑選擇Emgu會比較理想一點,Emgu是OpenCV的一個C#封裝,網(wǎng)上放出來的資料并不多見,搜索耗費不少的時間,Emgu的入門好像網(wǎng)上有些挺好的文章,在此不贅述。

站在用戶的角度思考問題,與客戶深入溝通,找到撫寧網(wǎng)站設計與撫寧網(wǎng)站推廣的解決方案,憑借多年的經(jīng)驗,讓設計與互聯(lián)網(wǎng)技術結合,創(chuàng)造個性化、用戶體驗好的作品,建站類型包括:網(wǎng)站設計、網(wǎng)站制作、企業(yè)官網(wǎng)、英文網(wǎng)站、手機端網(wǎng)站、網(wǎng)站推廣、域名注冊、網(wǎng)頁空間、企業(yè)郵箱。業(yè)務覆蓋撫寧地區(qū)。

本來項目的要求應該是要實時的,但使用Emgu好像挺難實時的,且不說實時視頻幀很難保證,就Emgu的一句圖像比較函數(shù)在我i5的機器下就花掉了100多ms,然而接近實時也并非不可能的,例如使用更好的CPU或使用顯卡運算,也許存在更好的視覺處理庫,方法應該不少的。我的項目實際要求是統(tǒng)計物體運動軌跡再作一些簡單的判斷而已,所以我采取一種惡心的方式,將視頻數(shù)據(jù)流存放到一個Queue中,再開一條線程慢慢處理這此數(shù)據(jù),反正我只需要事后得知結果而已,保證原始數(shù)據(jù)的實時顯得更重要一點。

事先聲明一點,因為開發(fā)的原因,沒法在辦公室里調試攝像頭,我建了一個ImageStream的類,用于封裝采集到的視頻數(shù)據(jù),因為Emgu中使用的是Image<TColor>的類型,這里邊會有一些圖像格式轉換的工作需要注意。將視頻數(shù)據(jù)Byte[]轉成為Image<TColor>不算太難吧,也就是一句話的事而已,可能需要注意JPEG跟BMP格式的。因為是模擬,我將電腦上JPG圖片轉成為Byte[]數(shù)據(jù)流,放到ImageStream里,開一個線程塞圖像數(shù)據(jù),一個線程處理圖像,大概流程就是這樣。

先上ImageStream類的代碼,如下:

using Emgu.CV;
using Emgu.CV.Structure;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace QImageClass
{
    /// <summary>
    /// 用于保存Image數(shù)據(jù)流的類
    /// </summary>
    public class ImageStream
    {
        /// <summary>
        /// 時間值
        /// </summary>
        public DateTime m_DateTime;
        /// <summary>
        /// 源文件名
        /// </summary>
        public string m_SrcFileName;
        /// <summary>
        /// 圖像流
        /// </summary>
        public MemoryStream m_ImageStream = null;
        /// <summary>
        /// 構造函數(shù)
        /// </summary>
        /// <param name="dt"></param>
        /// <param name="pBuf"></param>
        public ImageStream(DateTime dt, byte[] pBuf, string srcFileName = null)
        {
            this.m_DateTime = dt;
            this.m_ImageStream = new MemoryStream(pBuf);
            this.m_SrcFileName = srcFileName;
        }
        /// <summary>
        /// 轉換成為Emgu的圖像
        /// </summary>
        /// <returns></returns>
        public Image<Bgr, Byte> ToEmguImage()
        {
            Image img = Image.FromStream(this.m_ImageStream);
            return new Image<Bgr, Byte>((Bitmap)(img));
        }
        /// <summary>
        /// 根據(jù)時間作為文件名
        /// </summary>
        /// <returns></returns>
        public string ToFileName()
        {
            string file = this.m_DateTime.Year.ToString("D4") + "-" +
                this.m_DateTime.Month.ToString("D2") + "-" +
                this.m_DateTime.Day.ToString("D2") + "-" +
                this.m_DateTime.Hour.ToString("D2") + "-" +
                this.m_DateTime.Minute.ToString("D2") + "-" +
                this.m_DateTime.Second.ToString("D2") + "-" +
                this.m_DateTime.Millisecond.ToString("D3");
            return file;
        }
    }
}

類中的m_DateTime跟m_SrcFileName只是作一個數(shù)據(jù)源的識別參數(shù)而已,為的是調試上的方便。

圖像運動檢測我封裝成為了一個Poser類,使用Add(ImageStream im)將圖像數(shù)據(jù)加入到處理隊列里,然后自行在ProcessThread的線程中處理,Poser的代碼如下:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Collections;
using System.Threading;
using Emgu.CV;
using Emgu.CV.Structure;
using System.Diagnostics;
using Emgu.CV.VideoSurveillance;
using Emgu.CV.CvEnum;
using System.Drawing;
namespace QImageClass
{
    /// <summary>
    /// Image序列處理類
    /// </summary>
    public class ImagePoser
    {
        /// <summary>
        /// 圖像流數(shù)據(jù)鏈表
        /// </summary>
        private Queue<ImageStream> _ImageStreamList = new Queue<ImageStream>();
        /// <summary>
        /// 退出線程的標志
        /// </summary>
        private bool _QuitThreadFlag = true;
        /// <summary>
        /// 加入序列的總數(shù)量
        /// </summary>
        private int _TotalImageCount = 0;
        /// <summary>
        /// 已經(jīng)處理完畢的數(shù)量
        /// </summary>
        private int _FinishedCount = 0;
        /// <summary>
        /// 互斥鎖
        /// </summary>
        private Mutex _WaitMutex = new Mutex();
        /// <summary>
        /// 前景與背景檢測器
        /// </summary>
        private FGDetector<Bgr> _ForeGroundDetector = null;
        /// <summary>
        /// 默認構造函數(shù)
        /// </summary>
        public ImagePoser()
        {
        }
        /// <summary>
        /// 開始進行圖像處理
        /// </summary>
        public void Start()
        {
            this._QuitThreadFlag = false;
            Thread thread = new Thread(new ThreadStart(this.ProcessThread));
            thread.Name = "ImagePoserThread";
            thread.Is true;
             thread.Start();
        }
        /// <summary>
        /// 停止圖像處理線程
        /// </summary>
        public void Stop()
        {
            this._QuitThreadFlag = true;
        }
        /// <summary>
        /// 退出條件
        /// </summary>
        /// <returns></returns>
        protected virtual bool StopCondition()
        {
            Queue<int> fifo = new Queue<int>();
            return false;
        }
        /// <summary>
        /// 添加圖像數(shù)據(jù)
        /// </summary>
        /// <param name="p_w_picpathStream"></param>
        public void Add(ImageStream p_w_picpathStream)
        {
            this._WaitMutex.WaitOne();
            this._ImageStreamList.Enqueue(p_w_picpathStream);
            this._TotalImageCount++;
            Debug.WriteLine("Poser Add : " + this._TotalImageCount.ToString());
            this._WaitMutex.ReleaseMutex();
        }
        /// <summary>
        /// 總共需要處理的數(shù)量
        /// </summary>
        /// <returns></returns>
        public int GetTotalCount()
        {
            return this._TotalImageCount;
        }
        /// <summary>
        /// 已經(jīng)處理完畢的數(shù)量
        /// </summary>
        /// <returns></returns>
        public int GetBeFinishedCount()
        {
            return this._FinishedCount;
        }
        /// <summary>
        /// 獲取當前未處理的數(shù)量
        /// </summary>
        /// <returns></returns>
        public int GetUnFinishedCount()
        {
            this._WaitMutex.WaitOne();
            int nListCount = this._ImageStreamList.Count;
            this._WaitMutex.ReleaseMutex();
            return nListCount;
        }
        /// <summary>
        /// 圖像處理線程
        /// </summary>
        private void ProcessThread()
        {
            //前景檢測器
            if (this._ForeGroundDetector == null)
            {
                this._ForeGroundDetector = new FGDetector<Bgr>(FORGROUND_DETECTOR_TYPE.FGD);
            }
            while (!this._QuitThreadFlag)
            {
                ImageStream im = null;
                this._WaitMutex.WaitOne();
                if (this._ImageStreamList.Count == 0)
                {
                    this._WaitMutex.ReleaseMutex();
                    Thread.Sleep(1);
                    continue;
                }
                Stopwatch st = new Stopwatch();
                st.Start();
                //抽取出一組ImageStream
                im = this._ImageStreamList.Dequeue();
                this._FinishedCount++;
                this._WaitMutex.ReleaseMutex();
                //轉換成為OpenCV所使用的圖片格式
                Image<Bgr, Byte> tagImage = (im.ToEmguImage()).Resize(0.5, INTER.CV_INTER_LINEAR);
                //tagImage.Save("E:\\" + im.ToFileName() + ".bmp");//保存Bmp格式文件
                //運動檢測
                //////////////////////////////////////////////////////////////////////////
                //高斯處理
                tagImage.SmoothGaussian(3);
                //獲取前景,將其轉成為灰度圖
                _ForeGroundDetector.Update(tagImage);
                Image<Gray, Byte> foreGroundMark = _ForeGroundDetector.ForegroundMask;
                //foreGroundMark.Save("E:\\" + im.ToFileName() + ".bmp");//保存Bmp格式文件
                //連續(xù)區(qū)域的邊緣點集
                Contour<Point> contour = foreGroundMark.FindContours();
                if (contour != null)
                {
                    //Rectangle rect = contour.BoundingRectangle;
                    //Image<Bgr, Byte> resImg = new Image<Bgr, Byte>(foreGroundMark.Size);
                                                                                                      
                    //繪畫邊緣點集
                    foreach (Point p in contour)
                    {
                        tagImage.Draw(new CircleF(p, 2.0f), new Bgr(Color.Red), 1);
                    }
                    //繪畫綁定矩形
                    tagImage.Draw(contour.BoundingRectangle, new Bgr(Color.Green), 1);
                }
                //保存處理后的圖片
                tagImage.Save("E:\\" + im.ToFileName() + ".bmp");//保存Bmp格式文件
                //計算圖像處理時間
                st.Stop();
                Debug.WriteLine("Poser處理耗時 : " + st.ElapsedMilliseconds.ToString() + "ms\r\n");
                Thread.Sleep(1);
            }
        }
    }
}

使用時,開啟一個線程(應該沒難度吧?),使用類似如下的代碼

/// <summary>
/// 填充數(shù)據(jù)流
/// </summary>
private void Thread1()
{
    //讀取資源文件
    EmunFileReader reader = new EmunFileReader("D:\\TEST_JPG - 副本", ".jpg");
    string[] fileList = reader.GetFileList();
    int nCount = reader.GetFileCount();
    //圖像處理器
    ImagePoser poser = new ImagePoser();
    poser.Start();
    foreach (string s in fileList)
    { 
        //將圖片轉成為ImageStream
        Debug.WriteLine(s);
        Image img = Image.FromFile(s);
        ImageStream ism = new ImageStream(DateTime.Now, ImageConvert.ImageToBytes(img, ImageFormat.Jpeg), s);
        poser.Add(ism);
        Thread.Sleep(1);
    }
    while (true)
    {
        if (poser.GetTotalCount() == nCount && poser.GetBeFinishedCount() == nCount)
        {
            poser.Stop();
            break;
        }
        else
        {
            Thread.Sleep(1);
        }
    }
}

至于原始圖片,大家可以自行尋找,我是用PS來P出一個會動的物體,原圖跟結果圖像都放在附件里,大家可以自己下載下來玩一下。

名稱欄目:一個基于Emgu的運動檢測實例
網(wǎng)站地址:http://jinyejixie.com/article14/ppesde.html

成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供用戶體驗、定制開發(fā)、網(wǎng)站制作、小程序開發(fā)、動態(tài)網(wǎng)站、移動網(wǎng)站建設

廣告

聲明:本網(wǎng)站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經(jīng)允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯(lián)

h5響應式網(wǎng)站建設
沙湾县| 自治县| 图木舒克市| 漳平市| 泾阳县| 娱乐| 沙坪坝区| 米泉市| 克东县| 阳新县| 赤水市| 米易县| 榕江县| 久治县| 来凤县| 沈丘县| 绍兴县| 西乌珠穆沁旗| 久治县| 陆川县| 南城县| 土默特右旗| 邵阳县| 繁昌县| 定州市| 磐安县| 临洮县| 彩票| 都匀市| 新民市| 漳平市| 临沂市| 祁东县| 南部县| 惠水县| 华蓥市| 三亚市| 麻江县| 清涧县| 井研县| 石城县|