AForge 라이브러리를 사용하여 메모리 버퍼의 웹캠에서 60 초 분량의 이미지를 실행중인 프로그램을 유지하는 프로그램이 있습니다. 움직임이 감지되면 다음 30 초를 동일한 버퍼에 기록하고 처음 30 초를 덮어 씁니다. 사실상, 이미 기록되지 않은 움직임의 양면에서 30 초 분량의 동영상을 롤업하여 총 60 초의 비디오를 제공합니다.AVI 비디오 60 초의 발자국 축소
AFURA COMPRESSED의 비트 맵 이미지는 RAM에 3GB 정도입니다. 그 위에, 결과 avi 파일은 약 3 메가 바이트입니다. 그것은 꽤 큰 차이입니다!
어디에서 잘못 될지 누가 알 수 있습니까? 이 속도로 매 시간마다 디스크에 직접 비디오를 녹화하고 모든 이벤트에 대해 수동으로 주기적으로 비디오를 재생하는 것이 더 유용 할 것입니다!
CameraController.cs - 각 연결된 웹캠에 대한 초기화를 정렬 :
시스템은 다음과 같은 세 가지 구성 요소로 구성되어 있습니다. 이전에 사용 된 설정에 대한 아이디어를 제공하기 위해 주석 처리 된 구성 요소에 남겨 두었습니다.
public class CameraController : ServiceBase
{
public virtual void OnStart()
{
Start(60, 0.4f);
}
private FilterInfoCollection _VideoCaptureDevices;
private MotionDetector _MotionDetector;
private Dictionary<string, Recording> _Streams = new Dictionary<string, Recording>();
private Dictionary<int, VideoCaptureDevice> _Devices = new Dictionary<int, VideoCaptureDevice>();
private int _Framerate;
private int _MaxVideoLength;
private float _MotionSensitivity;
public void Start(int maxVideoLength, float motionSensitivity){
_MaxVideoLength = maxVideoLength;
_MotionSensitivity = motionSensitivity;
Init();
}
public void Init()
{
try
{
_MotionDetector = GetDefaultMotionDetector();
_VideoCaptureDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
int counter = 0;
foreach (FilterInfo device in _VideoCaptureDevices)
{
var videoDevice = new VideoCaptureDevice(device.MonikerString);
//_Framerate = videoDevice.VideoCapabilities[0].AverageFrameRate == 0
// ? 25
// : videoDevice.VideoCapabilities[0].AverageFrameRate;
_Framerate = 15;
_Streams.Add([email protected], new Recording(counter, device.Name, [email protected], _MaxVideoLength, _Framerate));
videoDevice.NewFrame += new NewFrameEventHandler(NewFrame);
videoDevice.Start();
_Devices.Add(counter++, videoDevice);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
public void NewFrame(object sender, NewFrameEventArgs eventArgs)
{
try
{
var device = (VideoCaptureDevice) sender;
_Streams[@device.Source].AddBitmap((Bitmap) eventArgs.Frame.Clone());
if (_Streams[@device.Source].IsRecording)
{
_Streams[@device.Source].CheckRecording();
if (_Streams[@device.Source].SaveRequired)
_Streams[@device.Source].WriteToFile();
}
else
{
var motion = _MotionDetector.ProcessFrame(_Streams[@device.Source].Bitmap);
if (motion > _MotionSensitivity)
_Streams[@device.Source].StartRecording();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
public void StopVideo(bool stopWebcams = false)
{
foreach (var device in _Devices)
{
var stream = _Streams[device.Value.Source];
if(stream.IsRecording)
stream.FileWriter.Close();
if(device.Value.IsRunning && stopWebcams)
device.Value.SignalToStop();
}
}
public static AForge.Vision.Motion.MotionDetector GetDefaultMotionDetector()
{
AForge.Vision.Motion.IMotionDetector detector = null;
AForge.Vision.Motion.IMotionProcessing processor = null;
AForge.Vision.Motion.MotionDetector motionDetector = null;
//detector = new AForge.Vision.Motion.TwoFramesDifferenceDetector()
//{
// DifferenceThreshold = 15,
// SuppressNoise = true
//};
//detector = new AForge.Vision.Motion.CustomFrameDifferenceDetector()
//{
// DifferenceThreshold = 15,
// KeepObjectsEdges = true,
// SuppressNoise = true
//};
detector = new AForge.Vision.Motion.SimpleBackgroundModelingDetector()
{
DifferenceThreshold = 10,
FramesPerBackgroundUpdate = 10,
KeepObjectsEdges = true,
MillisecondsPerBackgroundUpdate = 10,
SuppressNoise = true
};
//processor = new AForge.Vision.Motion.GridMotionAreaProcessing()
//{
// HighlightColor = System.Drawing.Color.Red,
// HighlightMotionGrid = true,
// GridWidth = 100,
// GridHeight = 100,
// MotionAmountToHighlight = 100F
//};
processor = new AForge.Vision.Motion.BlobCountingObjectsProcessing()
{
//HighlightColor = System.Drawing.Color.Red,
//HighlightMotionRegions = true,
MinObjectsHeight = 10,
MinObjectsWidth = 10
};
motionDetector = new AForge.Vision.Motion.MotionDetector(detector, processor);
return motionDetector;
}
}
그런 다음 Recording.cs있다 - 컨트롤 할 때 녹음
public class Recording
{
public int Id { get; set; }
public string Name { get; set; }
public string Source { get; set; }
public Bitmap Bitmap { get; set; }
public bool IsRecording { get; set; }
public bool SaveRequired { get; set; }
public int TimeLimitSec { get; set; }
public int FrameRate { get; set; }
public string DirString = ConfigurationManager.AppSettings["DesinationFolder"].ToString();
public Stopwatch Timer = new Stopwatch();
public VideoFileWriter FileWriter = new VideoFileWriter();
public VideoBuffer VideoBuffer;
public int BufferPosition { get; set; }
public Recording(int id, string name, string source, int timeLimit, int framerate)
{
Id = id;
Name = name;
Source = @source;
IsRecording = false;
SaveRequired = false;
TimeLimitSec = timeLimit;
FrameRate = framerate;
VideoBuffer = new VideoBuffer(timeLimit, framerate);
}
public string FileName { get; set; }
public void StartRecording()
{
IsRecording = true;
Timer.Reset();
Timer.Start();
}
public void StopRecording()
{
IsRecording = false;
SaveRequired = true;
Timer.Reset();
Timer.Stop();
}
public void WriteToFile()
{
try
{
if (!Directory.Exists(@DirString))
Directory.CreateDirectory(@DirString);
FileName = @DirString + @"\Video_" + Id + "_" + Name + "_" + DateTime.Now.ToFileTime() + ".avi";
FileWriter.Open(FileName, Bitmap.Width, Bitmap.Height, FrameRate, VideoCodec.Default);
for (int frame = 0; frame < VideoBuffer.BufferPosition; frame++)
{
FileWriter.WriteVideoFrame(Compression.Decompress<Bitmap>(VideoBuffer.Buffer[frame]));
}
FileWriter.Close();
SaveRequired = false;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
public void AddBitmap(Bitmap bitmap)
{
try
{
this.Bitmap = bitmap;
this.VideoBuffer.AddBitmap(bitmap);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
public void CheckRecording()
{
try
{
if (IsRecording && Timer.Elapsed.TotalSeconds > TimeLimitSec)
StopRecording();
}
catch (Exception ex)
{
var msg = ex.Message;
Console.WriteLine(ex.Message);
}
}
private void SaveImage()
{
Bitmap.Save(@"D:\Storage\IMG_"+ Id + "_" + Name + "_" + DateTime.Now.ToFileTime() + ".jpg");
}
}
그리고 마지막으로 VideoBuffer.cs 쓰기/시작/중지 - 비트 맵의 실행 버퍼를 제어 할 수 있습니다. 비트 맵은 byte []로 압축되어 있습니다.
public class VideoBuffer
{
public int BufferLengthSeconds { get; set; }
public byte[][] Buffer { get; set; }
public int BufferPosition { get; set; }
public int MaxPosition { get; set; }
public bool Recorded { get; set; }
public VideoBuffer(int secondsToBuffer, int framerate)
{
MaxPosition = secondsToBuffer * framerate * 2; // Have our buffer before an event is started, as well as the length of time for the next
//Buffer = new Bitmap[MaxPosition + 1]; // Plus one allows us to add the latest bitmap and then clone everything but the first index
Buffer = new byte[MaxPosition + 1][];
BufferPosition = 0;
}
public void AddBitmap(Bitmap bitmap)
{
try
{
// If we haven't reached the maximum buffer size, keep adding it as normal
if (BufferPosition < MaxPosition)
{
Buffer[BufferPosition++] = Compression.Compress(bitmap);
}
else
{
// Otherwise, shuffle everything down one.
Buffer[MaxPosition] = Compression.Compress(bitmap);
var tempBuffer = new byte[MaxPosition + 1][];
Array.Copy(Buffer, 1, tempBuffer, 0, Buffer.Length - 1);
tempBuffer.CopyTo(Buffer, 0);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
그래서 정말 IS 질문은, 어떻게 더 버퍼의 메모리 풋 프린트를 줄이고,하지만 여전히 한 번에 메모리에 영상의 마지막 30 초 유지?
나는 이번 주에 불타 버려서 무엇이 빠졌는지를 볼 수 없다. 모든 제안을 환영합니다!
메모리 매핑 된 파일로 원하는 작업을 수행 할 수 있습니까? – mjwills
그런데 왜 다시 프레임 형태로 60 초를 저장합니까? – Evk
메모리 매핑 된 파일로 인해 디스크에 너무 많은 부하가 걸릴 수 있습니다. 하지만 요즘에는 6GB RAM이 많지 않습니다.이 작업을 수행하기 위해 몇 개의 RAM이 있습니까? 분명히 당신은 충분한 RAm을 가지고 있지 않으므로 저장을 위해 프레임을 압축해야하고 작업을 위해 다시 압축을 풀 필요가 있습니다. https://stackoverflow.com/questions/3517965/convert-bmp-to-png-in-memory-for-clipboard-pasting-in-net 또는 50 달러에 RAM을 더 구입하십시오. – Harry