代码改变世界

利用Aforge做的摄像监控程序(带视频差异录像)

2010-06-26 11:44  穆容  阅读(6987)  评论(9编辑  收藏  举报

简介:本来想用红外线对射传感器做,苦于最近手头比较紧,就改用摄像头了。

Aforge是一套.NET开发的开源图像,视频处理库,涵盖面广的邪乎,我这里用到的部分只是冰山里的一滴水。

原理: 利用Aforge的图像差异算法,对比每帧图像和它上一帧图像的差异度,如果达到标准,计数器开始计数,当变化量达到一个值的时候,就开始录像,将接下来的每一帧写入一个AVI文件。同理,在开始录像的同时启动一个静止量的计数器。当静止指标达到限量后,停止录像。

 

主要代码:

public partial class Form1 : Form
    {
        FilterInfoCollection videoDevices;
        private string device;
        private float motionAlarmLevel = 0.015f;
        private List<float> motionHistory = new List<float>();
        MotionDetector detector = new MotionDetector(
            new TwoFramesDifferenceDetector(),
            new MotionAreaHighlighting());
        private int flash = 0;
        private bool beginREC = false;
        private bool StopREC = true;
        private int statCount = 0;
        private int MoveCount = 0;
        private const int MaxStat = 10;
        private AVIWriter writer;

        public Form1()
        {
            Control.CheckForIllegalCrossThreadCalls = false;
            InitializeComponent();
            #region 初始化设备列表
            try
            {
                // enumerate video devices
                videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);

                if (videoDevices.Count == 0)
                    throw new ApplicationException();

                // add all devices to combo
                foreach (FilterInfo device in videoDevices)
                {
                    devicesCombo.Items.Add(device.Name);
                }
                devicesCombo.Items.Insert(0, "");

            }
            catch (ApplicationException)
            {
                devicesCombo.Items.Add("No local capture devices");
                devicesCombo.Enabled = false;
            }

            devicesCombo.SelectedIndex = 0;
            #endregion
        }

        private void devicesCombo_SelectedIndexChanged(object sender, EventArgs e)
        {
            device = videoDevices[devicesCombo.SelectedIndex].MonikerString;
            // create video source
            VideoCaptureDevice videoSource = new VideoCaptureDevice(device);

            // open it
            OpenVideoSource(videoSource);
        }

        // Open video source
        private void OpenVideoSource(IVideoSource source)
        {
            // set busy cursor
            this.Cursor = Cursors.WaitCursor;

            // stop current video source
            videoSourcePlayer.SignalToStop();
            videoSourcePlayer.WaitForStop();

            // start new video source
            videoSourcePlayer.VideoSource = source;
            videoSourcePlayer.Start();

            //// reset statistics
            //statIndex = statReady = 0;

            //// start timer
            //timer.Start();

            this.Cursor = Cursors.Default;
        }

        private void videoSourcePlayer_NewFrame(object sender, ref Bitmap image)
        {
            if (detector != null)
            {
                float motionLevel = detector.ProcessFrame(image);

                //if (motionLevel > motionAlarmLevel)
                //{
                //    // flash for 2 seconds
                //    flash = (int)(2 * (1000 / alarmTimer.Interval));
                //}

                //// check objects' count
                //if (detector.MotionProcessingAlgorithm is BlobCountingObjectsProcessing)
                //{
                //    BlobCountingObjectsProcessing countingDetector = (BlobCountingObjectsProcessing)detector.MotionProcessingAlgorithm;
                //    objectsCountLabel.Text = "Objects: " + countingDetector.ObjectsCount.ToString();
                //}
                //else
                //{
                //    objectsCountLabel.Text = "";
                //}

                int t1 = (int)(motionAlarmLevel * 500);
                int t2 = (int)(0.075 * 500);
                if (motionLevel * 500 > t1)
                {
                    if (StopREC)
                    {
                        MoveCount++;
                    }
                }
                else
                {
                    if (beginREC)
                    {
                        statCount++;
                    }

                }
                try
                {
                    if (MoveCount == MaxStat)
                    {
                        if (StopREC)
                        {
                            StopREC = false;
                            beginREC = true;
                            writer = new AVIWriter("wmv3");
                            writer.Open(@"I:\log"+System.DateTime.Now.ToString("yyyyMMddhhmmss")+".avi", 640, 480);
                            this.listBox1.Items.Insert(0, "REC NOW!");
                            writer.AddFrame(image);
                        }
                        else
                        {
                            writer.AddFrame(image);
                            this.listBox1.Items.Insert(0, "RECING!");
                        }
                    }
                    if (statCount == MaxStat)
                    {
                        if (beginREC)
                        {
                            StopREC = true;
                            beginREC = false;
                            statCount = 0;
                            MoveCount = 0;
                            writer.Close();
                            this.listBox1.Items.Insert(0, "REC STOP!");
                        }

                    }
                }
                catch (Exception ex)
                {
                    this.listBox1.Items.Insert(0, ex.Message);
                }

                if (motionLevel * 500 > t1)
                {
                    this.listBox1.Items.Insert(0,"t1");
                }
                if (motionLevel * 500 > t2)
                {
                    this.listBox1.Items.Insert(0, "t2");
                }
                motionHistory.Add(motionLevel);
                //try
                //{
                //    this.listBox1.Items.Insert(0, motionLevel.ToString());
                //}
                //catch (Exception ex)
                //{

                //}
                if (motionHistory.Count > 300)
                {
                    motionHistory.RemoveAt(0);
                }

                //if (showMotionHistoryToolStripMenuItem.Checked)
                //    DrawMotionHistory(image);
            }
            DrawMotionHistory(image);
        }

        private void DrawMotionHistory(Bitmap image)
        {
            Color greenColor = Color.FromArgb(128, 0, 255, 0);
            Color yellowColor = Color.FromArgb(128, 255, 255, 0);
            Color redColor = Color.FromArgb(128, 255, 0, 0);

            BitmapData bitmapData = image.LockBits(new Rectangle(0, 0, image.Width, image.Height),
                ImageLockMode.ReadWrite, image.PixelFormat);

            int t1 = (int)(motionAlarmLevel * 500);
            int t2 = (int)(0.075 * 500);

            for (int i = 1, n = motionHistory.Count; i <= n; i++)
            {
                int motionBarLength = (int)(motionHistory[n - i] * 500);

                if (motionBarLength == 0)
                    continue;

                if (motionBarLength > 50)
                    motionBarLength = 50;

                Drawing.Line(bitmapData,
                    new IntPoint(image.Width - i, image.Height - 1),
                    new IntPoint(image.Width - i, image.Height - 1 - motionBarLength),
                    greenColor);

                if (motionBarLength > t1)
                {
                    Drawing.Line(bitmapData,
                        new IntPoint(image.Width - i, image.Height - 1 - t1),
                        new IntPoint(image.Width - i, image.Height - 1 - motionBarLength),
                        yellowColor);
                }

                if (motionBarLength > t2)
                {
                    Drawing.Line(bitmapData,
                        new IntPoint(image.Width - i, image.Height - 1 - t2),
                        new IntPoint(image.Width - i, image.Height - 1 - motionBarLength),
                        redColor);
                }
            }

            image.UnlockBits(bitmapData);
        }

        private void button2_Click(object sender, EventArgs e)
        {
            StopREC = true;
            beginREC = false;
            statCount = 0;
            MoveCount = 0;
            writer.Close();
            this.listBox1.Items.Insert(0, "REC STOP!");
            this.Close();
        }


    }

 

请注意:AForge.Video.VFW.AVIWriter的大部分功能需要使用:Win32.AVIMakeCompressedStream(out streamCompressed, stream, ref options, IntPtr.Zero);但是这个方法在某些电脑上会报错。究其原因,可能是由于缺少directshow,所以我重写了AVIWRITE的部分方法,去掉了视频压缩的部分。如下:

 public void Open( string fileName, int width, int height )
        {
            // close previous file
            Close( );

            lock ( this )
            {
                // calculate stride
                stride = width * 3;
                if ( ( stride % 4 ) != 0 )
                    stride += ( 4 - stride % 4 );

                // create new file
                if ( Win32.AVIFileOpen( out file, fileName, Win32.OpenFileMode.Create | Win32.OpenFileMode.Write, IntPtr.Zero ) != 0 )
                    throw new ApplicationException( "Failed opening file" );

                this.width = width;
                this.height = height;

                // describe new stream
                Win32.AVISTREAMINFO info = new Win32.AVISTREAMINFO( );

                info.type = Win32.mmioFOURCC( "vids" );
                info.handler = Win32.mmioFOURCC( codec );
                info.scale = 1;
                info.rate = rate;
                info.suggestedBufferSize = stride * height;

                // create stream
                if (Win32.AVIFileCreateStream(file, out stream, ref info) != 0)
                    throw new ApplicationException("Failed creating stream");

                // describe compression options
                Win32.AVICOMPRESSOPTIONS options = new Win32.AVICOMPRESSOPTIONS( );

                options.handler = Win32.mmioFOURCC( codec );
                options.quality = quality;

                // uncomment if video settings dialog is required to show
                // Win32.AVISaveOptions( stream, ref options );

                // create compressed stream
                //if (Win32.AVIMakeCompressedStream(out streamCompressed, stream, ref options, IntPtr.Zero) != 0)
                //    throw new ApplicationException("Failed creating compressed stream");
                //Win32.AVIMakeCompressedStream(out streamCompressed, stream, ref options, IntPtr.Zero);
                // describe frame format
                Win32.BITMAPINFOHEADER bitmapInfoHeader = new Win32.BITMAPINFOHEADER( );

                bitmapInfoHeader.size = Marshal.SizeOf( bitmapInfoHeader.GetType( ) );
                bitmapInfoHeader.width = width;
                bitmapInfoHeader.height = height;
                bitmapInfoHeader.planes = 1;
                bitmapInfoHeader.bitCount = 24;
                bitmapInfoHeader.sizeImage = 0;
                bitmapInfoHeader.compression = 0; // BI_RGB

                // set frame format
                if (Win32.AVIStreamSetFormat(stream, 0, ref bitmapInfoHeader, Marshal.SizeOf(bitmapInfoHeader.GetType())) != 0)
                    throw new ApplicationException("Failed creating compressed stream");

                // alloc unmanaged memory for frame
                buffer = Marshal.AllocHGlobal( stride * height );

                if ( buffer == IntPtr.Zero )
                    throw new ApplicationException( "Insufficient memory for internal buffer" );

                position = 0;
            }
        }

 

 public void AddFrame( Bitmap frameImage )
        {
            lock ( this )
            {
                // check if AVI file was properly opened
                if ( buffer == IntPtr.Zero )
                    throw new ApplicationException( "AVI file should be successfully opened before writing" );

                // check image dimension
                //if ((frameImage.Width != width) || (frameImage.Height != height))
                //    throw new ApplicationException("Invalid image dimension");

                // lock bitmap data
                BitmapData imageData = frameImage.LockBits(
                    new Rectangle( 0, 0, width, height ),
                    ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb );

                // copy image data
                int srcStride = imageData.Stride;
                int dstStride = stride;

                int src = imageData.Scan0.ToInt32( ) + srcStride * ( height - 1 );
                int dst = buffer.ToInt32( );

                for ( int y = 0; y < height; y++ )
                {
                    Win32.memcpy( dst, src, dstStride );
                    dst += dstStride;
                    src -= srcStride;
                }

                // unlock bitmap data
                frameImage.UnlockBits( imageData );

                // write to stream
                if (Win32.AVIStreamWrite(stream, position, 1, buffer,
                    stride * height, 0, IntPtr.Zero, IntPtr.Zero ) != 0 )
                    throw new ApplicationException( "Failed adding frame" );

                position++;
            }
        }