Dla projektu, musiałem to zrobić. To, co zrobiłem, może nie spełnić wszystkich twoich wymagań, ale może dać ci pomysł. Najpierw zapisałem każdy obraz klatki koloru na dysku lokalnym z sekwencyjnym nazwaniem. Następnie za pomocą ffmpeg przekonwertowałem sekwencyjny obraz na plik wideo, w moim przypadku było to wideo MP4, a nie AVI.
Aby zapisać kolor ramki obrazu sekwencyjnie, można kodować jak poniżej,
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.Kinect;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;
namespace Kinect_Video_Recorder
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
KinectSensor ks;
ColorFrameReader cfr;
byte[] colorData;
ColorImageFormat format;
WriteableBitmap wbmp;
BitmapSource bmpSource;
int imageSerial;
public MainWindow()
{
InitializeComponent();
ks = KinectSensor.GetDefault();
ks.Open();
var fd = ks.ColorFrameSource.CreateFrameDescription(ColorImageFormat.Bgra);
uint frameSize = fd.BytesPerPixel * fd.LengthInPixels;
colorData = new byte[frameSize];
format = ColorImageFormat.Bgra;
imageSerial = 0;
cfr = ks.ColorFrameSource.OpenReader();
cfr.FrameArrived += cfr_FrameArrived;
}
void cfr_FrameArrived(object sender, ColorFrameArrivedEventArgs e)
{
if (e.FrameReference == null) return;
using (ColorFrame cf = e.FrameReference.AcquireFrame())
{
if(cf == null) return;
cf.CopyConvertedFrameDataToArray(colorData, format);
var fd = cf.FrameDescription;
// Creating BitmapSource
var bytesPerPixel = (PixelFormats.Bgr32.BitsPerPixel)/8;
var stride = bytesPerPixel * cf.FrameDescription.Width;
bmpSource = BitmapSource.Create(fd.Width, fd.Height, 96.0, 96.0, PixelFormats.Bgr32, null, colorData, stride);
// WritableBitmap to show on UI
wbmp = new WriteableBitmap(bmpSource);
kinectImage.Source = wbmp;
// JpegBitmapEncoder to save BitmapSource to file
// imageSerial is the serial of the sequential image
JpegBitmapEncoder encoder = new JpegBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bmpSource));
using (var fs = new FileStream("./img/" + (imageSerial++) + ".jpeg", FileMode.Create, FileAccess.Write))
{
encoder.Save(fs);
}
}
}
}
}
powyższym przykładzie zapisuje obrazy w formacie JPEG. jeśli chcesz zapisać go jako format png, użyj PngBitmapEncoder
.
Teraz zapisaliśmy kolejne obrazy na dysku twardym. Aby przekonwertować te sekwencyjne obrazy do pliku wideo, możesz użyć ffmpeg. Możesz także użyć Aforge.net. Ale nigdy tego nie używałem. W moim przypadku wywołałem proces ffmpeg.exe
z mojego programu C#, jak poniżej.
Process.Start("ffmpeg.exe", "-framerate 10 -i ./img/%d.jpeg -c:v libx264 -r 30 -pix_fmt yuv420p kinect_video.mp4");
Uwaga:
- Dokonaj docelową Budowa x64. Spowoduje to zwiększenie limitu pamięci programu.
- Mam kodowany podstawowy implementation w tej sprawie. Możesz sprawdzić, czy chcesz.
Nadzieja to pomaga :)
możemy użyć VideoWriter classs i funkcji WriteFrame w emgucv zapisać jako plik wideo AVI, ale ta funkcja nie strumieniowe, –
chcę rozwijać program, który może uratować ciągle Kinect danych kolorów źródło do pliku na twardym RAM-ie, bo pamięć za mało –