Skip to content
This repository has been archived by the owner on Feb 22, 2024. It is now read-only.

Motion detection plug-in model and analysis #175

Merged
merged 15 commits into from
Oct 12, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 15 additions & 13 deletions src/MMALSharp.Common/ImageContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,54 +13,56 @@ namespace MMALSharp.Common
/// </summary>
public class ImageContext
{
// Fields are used rather than properties for hot-path performance reasons.

/// <summary>
/// The working data.
/// </summary>
public byte[] Data { get; set; }
public byte[] Data;

/// <summary>
/// Flag to indicate whether image frame is raw.
/// </summary>
public bool Raw { get; set; }
public bool Raw;

/// <summary>
/// The resolution of the frame we're processing.
/// </summary>
public Resolution Resolution { get; set; }
public Resolution Resolution;

/// <summary>
/// The encoding format of the frame we're processing.
/// </summary>
public MMALEncoding Encoding { get; set; }
public MMALEncoding Encoding;

/// <summary>
/// The pixel format of the frame we're processing.
/// </summary>
public MMALEncoding PixelFormat { get; set; }
public MMALEncoding PixelFormat;

/// <summary>
/// The image format to store the processed data in.
/// </summary>
public ImageFormat StoreFormat { get; set; }
public ImageFormat StoreFormat;

/// <summary>
/// Indicates if this frame represents the end of the stream.
/// </summary>
public bool Eos { get; set; }
public bool Eos;

/// <summary>
/// Indicates if this frame contains IFrame data.
/// </summary>
public bool IFrame { get; set; }
public bool IFrame;

/// <summary>
/// The timestamp value.
/// </summary>
public long? Pts { get; set; }
public long? Pts;

/// <summary>
/// The pixel format stride.
/// </summary>
public int Stride { get; set; }
public int Stride;
}
}
84 changes: 84 additions & 0 deletions src/MMALSharp.Common/Utility/FormatRawImageExtension.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// <copyright file="FormatRawImageExtension.cs" company="Techyian">
// Copyright (c) Ian Auty and contributors. All rights reserved.
// Licensed under the MIT License. Please see LICENSE.txt for License info.
// </copyright>

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Runtime.InteropServices;

namespace MMALSharp.Common.Utility
{
/// <summary>
/// An extension to convert raw <see cref="ImageContext"/> data to a bitmap <see cref="ImageFormat"/>.
/// </summary>
public static class FormatRawImageExtension
{
/// <summary>
/// Converts the raw image data in an <see cref="ImageContext"/> object to a specified bitmap
/// <see cref="ImageFormat"/> (such as <see cref="ImageFormat.Jpeg"/> or <see cref="ImageFormat.Png"/>).
/// </summary>
/// <param name="context">The image to convert. Must be raw data.</param>
public static void FormatRawImage(this ImageContext context)
{
if (!context.Raw)
{
throw new Exception("ImageContext does not contain raw data");
}

if (context.StoreFormat == null)
{
throw new Exception("ImageContext.StoreFormat does not define a target ImageFormat");
}

var pixfmt = MMALEncodingToPixelFormat(context.PixelFormat);

using (var bitmap = new Bitmap(context.Resolution.Width, context.Resolution.Height, pixfmt))
{
BitmapData bmpData = null;
try
{
bmpData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.WriteOnly, bitmap.PixelFormat);
var ptr = bmpData.Scan0;
int size = bmpData.Stride * bitmap.Height;
var data = context.Data;
Marshal.Copy(data, 0, ptr, size);
}
finally
{
bitmap.UnlockBits(bmpData);
}

using(var ms = new MemoryStream())
{
bitmap.Save(ms, context.StoreFormat);
context.Data = new byte[ms.Length];
Array.Copy(ms.ToArray(), 0, context.Data, 0, ms.Length);
}
}
}

private static PixelFormat MMALEncodingToPixelFormat(MMALEncoding encoding)
{
if(encoding == MMALEncoding.RGB24)
{
return PixelFormat.Format24bppRgb;
}

if (encoding == MMALEncoding.RGB32)
{
return PixelFormat.Format32bppRgb;
}

if (encoding == MMALEncoding.RGBA)
{
return PixelFormat.Format32bppArgb;
}

throw new Exception("Unsupported encoding / pixel format");
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,9 @@ public FrameBufferCaptureHandler()
{ }

/// <summary>
/// Creates a new <see cref="FrameBufferCaptureHandler"/> configured for motion detection using a raw video stream
/// where MMALStandalone.Instance is used (such as processing a pre-recorded file) rather than camera-based processing.
/// Creates a new <see cref="FrameBufferCaptureHandler"/> configured for motion detection analysis (either using a recorded
/// raw video stream where MMALStandalone.Instance is used, or when the camera is used but triggering motion detection events
/// is unnecessary). If motion detection events are desired, use the camera's WithMotionDetection method.
/// </summary>
/// <param name="motionConfig">The motion configuration.</param>
/// <param name="onDetect">A callback for when motion is detected.</param>
Expand Down
3 changes: 2 additions & 1 deletion src/MMALSharp.Processing/Handlers/IMotionCaptureHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ public interface IMotionCaptureHandler
/// <summary>
/// Disables motion detection. When configured, this will instruct the capture handler not to detect motion.
/// </summary>
/// <param name="disableCallbackOnly">When true, motion detection will continue but the OnDetect callback will not be invoked.</param>
/// <param name="disableCallbackOnly">When true, motion detection will continue but the OnDetect callback
/// will not be invoked. Call <see cref="EnableMotionDetection"/> to re-enable the callback.</param>
void DisableMotionDetection(bool disableCallbackOnly = false);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If a user calls this method and wants to re-enable the callback, how do they do this? Am I right in thinking they just modify OnDetectEnabled against a FrameDiffDriver instance?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Calling EnableMotionDetection will re-enable the callback. I will add that to the parameter docs.

}
}
4 changes: 2 additions & 2 deletions src/MMALSharp.Processing/Handlers/OutputCaptureHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,10 @@ public virtual void PostProcess()
}

/// <summary>
/// Allows manipulating of the image frame.
/// Allows manipulation of the image frame.
/// </summary>
/// <param name="context">A delegate to the manipulation you wish to carry out.</param>
/// <param name="storeFormat">The image format to save manipulated files in..</param>
/// <param name="storeFormat">The image format to save manipulated files in, or null to return raw data.</param>
public void Manipulate(Action<IFrameProcessingContext> context, ImageFormat storeFormat)
{
this.OnManipulate = context;
Expand Down
42 changes: 42 additions & 0 deletions src/MMALSharp.Processing/Processors/Effects/BoxBlur.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// <copyright file="BoxBlur.cs" company="Techyian">
// Copyright (c) Ian Auty and contributors. All rights reserved.
// Licensed under the MIT License. Please see LICENSE.txt for License info.
// </copyright>

using MMALSharp.Common;
using System;
using System.Diagnostics;

namespace MMALSharp.Processors.Effects
{
/// <summary>
/// An image processor used to apply a box-blur effect.
/// </summary>
public class BoxBlur : ConvolutionBase, IFrameProcessor
{
private const int _kernelWidth = 3;
private const int _kernelHeight = 3;
private double[,] _kernel = new double[3, 3]
{
{0.11111111, 0.11111111, 0.11111111 },
{0.11111111, 0.11111111, 0.11111111 },
{0.11111111, 0.11111111, 0.11111111 },
};

/// <inheritdoc />
public BoxBlur()
: base()
{ }

/// <inheritdoc />
public BoxBlur(int horizontalCellCount, int verticalCellCount)
: base(horizontalCellCount, verticalCellCount)
{ }

/// <inheritdoc />
public void Apply(ImageContext context)
{
this.ApplyConvolution(_kernel, _kernelWidth, _kernelHeight, context);
}
}
}
Loading