Пример #1
0
        /// <summary>
        /// Highlights a motion detection cell, typically to indicate a threshold was tripped.
        /// </summary>
        /// <param name="r">Red channel of the highlight RGB color</param>
        /// <param name="g">Green channel of the highlight RGB color</param>
        /// <param name="b">Blue channel of the highlight RGB color</param>
        /// <param name="driver">The <see cref="FrameDiffDriver"/> containing the buffer</param>
        /// <param name="metadata">The <see cref="FrameAnalysisMetadata"/> structure with frame properties</param>
        /// <param name="index">The array index of the cell to highlight</param>
        /// <param name="buffer">The frame buffer to draw into</param>
        protected void HighlightCell(byte r, byte g, byte b, FrameDiffDriver driver, FrameAnalysisMetadata metadata, int index, byte[] buffer)
        {
            for (int x = driver.CellRect[index].X; x < driver.CellRect[index].X + driver.CellRect[index].Width; x++)
            {
                var y = driver.CellRect[index].Y;
                var i = (x * metadata.Bpp) + (y * metadata.Stride);
                buffer[i]     = r;
                buffer[i + 1] = g;
                buffer[i + 2] = b;
                y            += driver.CellRect[index].Height - 1;
                i             = (x * metadata.Bpp) + (y * metadata.Stride);
                buffer[i]     = r;
                buffer[i + 1] = g;
                buffer[i + 2] = b;
            }

            for (int y = driver.CellRect[index].Y; y < driver.CellRect[index].Y + driver.CellRect[index].Height; y++)
            {
                var x = driver.CellRect[index].X;
                var i = (x * metadata.Bpp) + (y * metadata.Stride);
                buffer[i]     = r;
                buffer[i + 1] = g;
                buffer[i + 2] = b;
                x            += driver.CellRect[index].Width - 1;
                i             = (x * metadata.Bpp) + (y * metadata.Stride);
                buffer[i]     = r;
                buffer[i + 1] = g;
                buffer[i + 2] = b;
            }
        }
Пример #2
0
        }   // not necessary for this algorithm

        /// <inheritdoc />
        public bool DetectMotion(FrameDiffDriver driver, FrameAnalysisMetadata metadata)
        {
            Parallel.ForEach(driver.CellDiff, (cell, loopState, loopIndex)
                             => CheckDiff(loopIndex, driver, metadata, _parameters));

            int diff = 0;

            for (int i = 0; i < driver.CellDiff.Length; i++)
            {
                diff += driver.CellDiff[i];

                if (_parameters.AnalysisMode && driver.CellDiff[i] == 1)
                {
                    HighlightCell(255, 0, 255, driver, metadata, i, _analysisBuffer);
                }
            }

            var detected = diff >= _cellCountThreshold;

            // Draw a bar across the frame; red indicates motion, green indicates no motion
            if (_parameters.AnalysisMode && diff > 0)
            {
                int x2 = (int)(((diff * 2f) / (driver.CellDiff.Length / 2f)) * (metadata.Width / 2f));
                (byte r, byte g) = detected ? ((byte)255, (byte)0) : ((byte)0, (byte)255);
                DrawIndicatorBlock(r, g, 0, 0, x2, 0, 10, _analysisBuffer, metadata);
            }

            if (_parameters.AnalysisMode)
            {
                _outputHandler?.Process(_fullRawFrameImageContext);
            }

            return(detected);
        }
Пример #3
0
        /// <inheritdoc />
        public void FirstFrameCompleted(FrameDiffDriver driver, FrameAnalysisMetadata metadata, ImageContext contextTemplate)
        {
            _fullRawFrameImageContext = contextTemplate;

            _parameters.CellPixelThreshold = (int)(metadata.CellWidth * metadata.CellHeight * (_cellPixelPercentage / 100f));

            _analysisBuffer = new byte[driver.TestFrame.Length];
            // Not necessary for this analysis, CheckDiff overwrites the buffer completely
            // Array.Copy(driver.TestFrame, _analysisBuffer, _analysisBuffer.Length);

            _fullRawFrameImageContext.Data = driver.TestFrame;
            _outputHandler?.Process(_fullRawFrameImageContext);

            _fullRawFrameImageContext.Data = _analysisBuffer;
        }
Пример #4
0
        private void ProcessCell(Rectangle rect, byte[] image, double[,] kernel, int kernelWidth, int kernelHeight, FrameAnalysisMetadata metadata, bool storeFromRaw)
        {
            // Rectangle and FrameAnalysisMetadata are structures; they are by-value copies and all fields are value-types which makes them thread safe

            int x2 = rect.X + rect.Width;
            int y2 = rect.Y + rect.Height;

            int index;

            // Indicates RGB needs to be swapped to BGR so that Bitmap.Save works correctly.
            if (storeFromRaw)
            {
                for (var x = rect.X; x < x2; x++)
                {
                    for (var y = rect.Y; y < y2; y++)
                    {
                        index = (x * metadata.Bpp) + (y * metadata.Stride);
                        byte swap = image[index];
                        image[index]     = image[index + 2];
                        image[index + 2] = swap;
                    }
                }
            }

            for (var x = rect.X; x < x2; x++)
            {
                for (var y = rect.Y; y < y2; y++)
                {
                    double r = 0;
                    double g = 0;
                    double b = 0;

                    if (x > kernelWidth && y > kernelHeight)
                    {
                        for (var t = 0; t < kernelWidth; t++)
                        {
                            for (var u = 0; u < kernelHeight; u++)
                            {
                                double k = kernel[t, u];

                                index = (Clamp(y + u, y2) * metadata.Stride) + (Clamp(x + t, x2) * metadata.Bpp);

                                r += image[index] * k;
                                g += image[index + 1] * k;
                                b += image[index + 2] * k;
                            }
                        }

                        r = (r < 0) ? 0 : r;
                        g = (g < 0) ? 0 : g;
                        b = (b < 0) ? 0 : b;
                    }

                    index = (x * metadata.Bpp) + (y * metadata.Stride);

                    image[index]     = (byte)r;
                    image[index + 1] = (byte)g;
                    image[index + 2] = (byte)b;
                }
            }
        }
Пример #5
0
 /// <summary>
 /// Draws a filled block into the frame buffer. Can be used as a visual indicator of internal app state.
 /// </summary>
 /// <param name="r">Red channel of the highlight RGB color</param>
 /// <param name="g">Green channel of the highlight RGB color</param>
 /// <param name="b">Blue channel of the highlight RGB color</param>
 /// <param name="x1">Left column of the block</param>
 /// <param name="x2">Right column of the block</param>
 /// <param name="y1">Top row of the block</param>
 /// <param name="y2">Bottom row of the block</param>
 /// <param name="buffer">The frame buffer to draw into</param>
 /// <param name="metrics">The <see cref="FrameAnalysisMetadata"/> structure with frame properties</param>
 protected void DrawIndicatorBlock(byte r, byte g, byte b, int x1, int x2, int y1, int y2, byte[] buffer, FrameAnalysisMetadata metrics)
 {
     for (int x = x1; x <= x2; x++)
     {
         for (int y = y1; y <= y2; y++)
         {
             var i = (x * metrics.Bpp) + (y * metrics.Stride);
             buffer[i]     = r;
             buffer[i + 1] = g;
             buffer[i + 2] = b;
         }
     }
 }
Пример #6
0
 /// <inheritdoc />
 public void ResetAnalyser(FrameDiffDriver driver, FrameAnalysisMetadata metadata)
 {
 }   // not necessary for this algorithm
Пример #7
0
        private void CheckDiff(long cellIndex, FrameDiffDriver driver, FrameAnalysisMetadata metadata, ThreadSafeParameters parameters)
        {
            // FrameAnalysisMetadata and ThreadSafeParameters are structures; they are by-value copies and all fields are value-types which makes them thread safe

            int diff = 0;
            var rect = driver.CellRect[cellIndex];

            int x2 = rect.X + rect.Width;
            int y2 = rect.Y + rect.Height;

            for (var col = rect.X; col < x2; col++)
            {
                for (var row = rect.Y; row < y2; row++)
                {
                    var index = (col * metadata.Bpp) + (row * metadata.Stride);

                    // Disregard full-black cells in the mask bitmap
                    if (driver.FrameMask != null)
                    {
                        var rgbMask = driver.FrameMask[index] + driver.FrameMask[index + 1] + driver.FrameMask[index + 2];

                        if (rgbMask == 0)
                        {
                            continue;
                        }
                    }

                    byte r    = driver.TestFrame[index];
                    byte g    = driver.TestFrame[index + 1];
                    byte b    = driver.TestFrame[index + 2];
                    int  rgb1 = r + g + b;

                    r = driver.CurrentFrame[index];
                    g = driver.CurrentFrame[index + 1];
                    b = driver.CurrentFrame[index + 2];
                    int rgb2 = r + g + b;

                    int rgbDiff = Math.Abs(rgb2 - rgb1);
                    if (rgbDiff > parameters.RGBThreshold)
                    {
                        diff++;
                    }

                    if (!parameters.AnalysisMode)
                    {
                        // Check for early exit opportunity
                        if (diff >= parameters.CellPixelThreshold)
                        {
                            continue;
                        }
                    }
                    else
                    {
                        // No early exit for analysis purposes

                        // Output in grayscale based on strength of the diff (765 = 255 x 3)
                        r = Math.Min((byte)255, (byte)((rgbDiff / 765f) * 255.999f));
                        g = r;
                        b = r;

                        // Highlight cell corners
                        if ((col == rect.X || col == x2 - 1) && (row == rect.Y || row == y2 - 1))
                        {
                            r = 128;
                            g = 0;
                            b = 128;
                        }

                        _analysisBuffer[index]     = r;
                        _analysisBuffer[index + 1] = g;
                        _analysisBuffer[index + 2] = b;
                    }
                }
            }

            driver.CellDiff[cellIndex] = (diff >= parameters.CellPixelThreshold) ? 1 : 0;
        }