从视频C#中提取帧

时间:2016-02-13 14:04:15

标签: c# video image-processing win-universal-app

我试图制作一款使用相机录制视频并处理视频图像的应用。这就是我想要的。首先,我的应用程序使用Torch录制了10秒的视频。其次,我使用一种方法来播放视频以查看我录制的内容。

我坚持做三件事。

  1. 如何将视频转换为单独的帧(图像)?
  2. 是否可以在录制视频时异步转换视频?
  3. 当我将视频转换为单独的帧时,我该如何使用它们?它们是JPEG吗?我可以简单地将它们显示为图像吗?等
  4. 主要代码:

    using System;
    using Windows.UI.Xaml;
    using Windows.UI.Xaml.Controls;
    
    using Windows.UI.Xaml.Navigation;
    
    namespace App3
    {
    
    public sealed partial class MainPage : Page
    {          
        DispatcherTimer D;
        double basetimer = 0;
        public MainPage()
        {
            this.InitializeComponent();       
            this.NavigationCacheMode = NavigationCacheMode.Required;
            D = new DispatcherTimer();      
            D.Interval = new TimeSpan(0, 0, 1);
            D.Tick += timer_Tick;
            txt.Text = basetimer.ToString();
            Play.IsEnabled = false;            
        }  
        public Library Library = new Library();
        public object PreviewImage { get; private set; }
        void timer_Tick(object sender, object e)
        {
            basetimer = basetimer - 1;
            txt.Text = basetimer.ToString();
            if (basetimer == 0)
            {
                D.Stop();               
                Preview.Source = null;
                Library.Stop();
                Record.IsEnabled = false;
                Play.IsEnabled = true;
                Clear.IsEnabled = true;
                if (Library._tc.Enabled)
                {
                    Library._tc.Enabled = false;
                }                
            }
        }
        private void Record_Click(object sender, RoutedEventArgs e)
        {            
            if (Library.Recording)
            {
                Preview.Source = null;
                Library.Stop();
                Record.Icon = new SymbolIcon(Symbol.Video);                
            }
            else
            {
                basetimer = 11;
                D.Start();
                //D.Tick += timer_Tick;
                Display.Source = null;
                Library.Record(Preview);
                Record.Icon = new SymbolIcon(Symbol.VideoChat);
                Record.IsEnabled = false;
                Play.IsEnabled = false;
            }
        }
        private async void Play_Click(object sender, RoutedEventArgs e)
        {            
            await Library.Play(Dispatcher, Display);
            //Extract_Image_From_Video(Library.buffer);            
        }
        private  void Clear_Click(object sender, RoutedEventArgs e)
        {
            Display.Source = null;            
            Record.Icon = new SymbolIcon(Symbol.Video);
            txt.Text = "0";
            basetimer=  0;
            Play.IsEnabled = false;
            Record.IsEnabled =true;
            if (Library.capture != null)
            {
                D.Stop();
                Library.Recording = false;
                Preview.Source = null;               
                Library.capture.Dispose();
                Library.capture = null;
                basetimer = 11;
            }
            }
        }
    }
    

    图书馆班级:

    using System;
    using System.Diagnostics;
    using System.Linq;
    using System.Threading.Tasks;
    using Windows.Devices.Enumeration;
    using Windows.Media.Capture;
    using Windows.Media.Devices;
    using Windows.Media.MediaProperties;
    using Windows.Storage;
    using Windows.Storage.Streams;
    using Windows.UI.Core;
    using Windows.UI.Xaml.Controls;
    using Windows.UI.Xaml.Media.Imaging;
    using Windows.Graphics.Imaging;
    using Emgu.CV.Structure;
    using Emgu.CV;
    using System.Collections.Generic;
    
    public class Library
    {
    
    private const string videoFilename = "video.mp4";
    private string filename;
    public MediaCapture capture;
    public InMemoryRandomAccessStream buffer;
    public static bool Recording;
    public TorchControl _tc;
    public int basetimer  ;   
    public async Task<bool> init()
    {
        if (buffer != null)
        {
            buffer.Dispose();
        }
        buffer = new InMemoryRandomAccessStream();
        if (capture != null)
        {
            capture.Dispose();
        }
        try
        {
    
            if (capture == null)
            {
                var allVideoDevices = await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture);               
                DeviceInformation cameraDevice =
                allVideoDevices.FirstOrDefault(x => x.EnclosureLocation != null &&
                x.EnclosureLocation.Panel == Windows.Devices.Enumeration.Panel.Back);
                capture = new MediaCapture();
                var mediaInitSettings = new MediaCaptureInitializationSettings { VideoDeviceId = cameraDevice.Id };
                // Initialize 
                try
                {
                    await capture.InitializeAsync(mediaInitSettings);
                    var videoDev = capture.VideoDeviceController;
                    _tc = videoDev.TorchControl;
                    Recording = false;
                    _tc.Enabled = false;                                      
                }
                catch (UnauthorizedAccessException)
                {
                    Debug.WriteLine("UnauthorizedAccessExeption>>");
                }
                catch (Exception ex)
                {
                    Debug.WriteLine("Exception when initializing MediaCapture with {0}: {1}", cameraDevice.Id, ex.ToString());
                }
            }
                capture.Failed += (MediaCapture sender, MediaCaptureFailedEventArgs errorEventArgs) =>
            {
                Recording = false;
                _tc.Enabled = false;
                throw new Exception(string.Format("Code: {0}. {1}", errorEventArgs.Code, errorEventArgs.Message));
            };
        }
        catch (Exception ex)
        {
            if (ex.InnerException != null && ex.InnerException.GetType() == typeof(UnauthorizedAccessException))
            {
                throw ex.InnerException;
            }
            throw;
        }
        return true;
    }
    public async void Record(CaptureElement preview)
    {    
        await init();
        preview.Source = capture; 
        await capture.StartPreviewAsync();
        await capture.StartRecordToStreamAsync(MediaEncodingProfile.CreateMp4(VideoEncodingQuality.Auto), buffer);
        if (Recording) throw new InvalidOperationException("cannot excute two records at the same time");
        Recording = true;
        _tc.Enabled = true;
    
    }
    public async void Stop()
    {
        await capture.StopRecordAsync();
        Recording = false;
        _tc.Enabled = false;       
    }    
    
    public async Task Play(CoreDispatcher dispatcher, MediaElement playback)
    {
        IRandomAccessStream video = buffer.CloneStream();
    
        if (video == null) throw new ArgumentNullException("buffer");
        StorageFolder storageFolder = Windows.ApplicationModel.Package.Current.InstalledLocation;
        if (!string.IsNullOrEmpty(filename))
        {
            StorageFile original = await storageFolder.GetFileAsync(filename);
            await original.DeleteAsync();
        }
        await dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
        {
            StorageFile storageFile = await storageFolder.CreateFileAsync(videoFilename, CreationCollisionOption.GenerateUniqueName);
            filename = storageFile.Name;
            using (IRandomAccessStream fileStream = await storageFile.OpenAsync(FileAccessMode.ReadWrite))
            {
                await RandomAccessStream.CopyAndCloseAsync(video.GetInputStreamAt(0), fileStream.GetOutputStreamAt(0));
                await video.FlushAsync();
                video.Dispose();
            }
            IRandomAccessStream stream = await storageFile.OpenAsync(FileAccessMode.Read);
    
            playback.SetSource(stream, storageFile.FileType);
            playback.Play();
    
    
    
    
    
        });
    
    
    }   
    

3 个答案:

答案 0 :(得分:7)

在使用Accord遇到大量麻烦后,我最终使用MediaToolkit来解决类似的问题。

我需要为视频的每一秒保存一张图片:

using (var engine = new Engine())
{
    var mp4 = new MediaFile { Filename = mp4FilePath };

    engine.GetMetadata(mp4);

    var i = 0;
    while (i < mp4.Metadata.Duration.Seconds)
    {
        var options = new ConversionOptions { Seek = TimeSpan.FromSeconds(i) };
        var outputFile = new MediaFile { Filename = string.Format("{0}\\image-{1}.jpeg", outputPath, i) };
        engine.GetThumbnail(mp4, outputFile, options);
        i++;
    }
}

希望有一天能帮到某人。

答案 1 :(得分:6)

我昨天才知道这件事。

这是一个完整且易于理解的示例,它选择视频文件并在第一秒视频中保存快照。

您可以拍摄适合您项目的部分并更改部分内容(即从相机获取视频分辨率)

1)和3)

TimeSpan timeOfFrame = new TimeSpan(0, 0, 1);

        //pick mp4 file
        var picker = new Windows.Storage.Pickers.FileOpenPicker();
        picker.SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.VideosLibrary;
        picker.FileTypeFilter.Add(".mp4");
        StorageFile pickedFile = await picker.PickSingleFileAsync();
        if (pickedFile == null)
        {
            return;
        }
        ///


        //Get video resolution
        List<string> encodingPropertiesToRetrieve = new List<string>();
        encodingPropertiesToRetrieve.Add("System.Video.FrameHeight");
        encodingPropertiesToRetrieve.Add("System.Video.FrameWidth");
        IDictionary<string, object> encodingProperties = await pickedFile.Properties.RetrievePropertiesAsync(encodingPropertiesToRetrieve);
        uint frameHeight = (uint)encodingProperties["System.Video.FrameHeight"];
        uint frameWidth = (uint)encodingProperties["System.Video.FrameWidth"];
        ///


        //Use Windows.Media.Editing to get ImageStream
        var clip = await MediaClip.CreateFromFileAsync(pickedFile);
        var composition = new MediaComposition();
        composition.Clips.Add(clip);

        var imageStream = await composition.GetThumbnailAsync(timeOfFrame, (int)frameWidth, (int)frameHeight, VideoFramePrecision.NearestFrame);
        ///


        //generate bitmap 
        var writableBitmap = new WriteableBitmap((int)frameWidth, (int)frameHeight);
        writableBitmap.SetSource(imageStream);


        //generate some random name for file in PicturesLibrary
        var saveAsTarget = await KnownFolders.PicturesLibrary.CreateFileAsync("IMG" + Guid.NewGuid().ToString().Substring(0, 4) + ".jpg");


        //get stream from bitmap
        Stream stream = writableBitmap.PixelBuffer.AsStream();
        byte[] pixels = new byte[(uint)stream.Length];
        await stream.ReadAsync(pixels, 0, pixels.Length);

        using (var writeStream = await saveAsTarget.OpenAsync(FileAccessMode.ReadWrite))
        {
            var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, writeStream);
            encoder.SetPixelData(
                BitmapPixelFormat.Bgra8,
                BitmapAlphaMode.Premultiplied,
                (uint)writableBitmap.PixelWidth,
                (uint)writableBitmap.PixelHeight,
                96,
                96,
                pixels);
            await encoder.FlushAsync();

            using (var outputStream = writeStream.GetOutputStreamAt(0))
            {
                await outputStream.FlushAsync();
            }
        }

如果要在xaml Image中显示帧,则应使用imageStream

BitmapImage bitmapImage = new BitmapImage();
bitmapImage.SetSource(imageStream);

XAMLImage.Source = bitmapImage;

如果您想提取更多帧,还有composition.GetThumbnailsAsync

2)当您的计时器正在滴答时,请使用您的mediaCapture

答案 2 :(得分:2)

使用ffmpeg http://ffmpeg.org/

using (var vFReader = new VideoFileReader())
{
    vFReader.Open("video.mp4");
    for (int i = 0; i < vFReader.FrameCount; i++)
    {
        Bitmap bmpBaseOriginal = vFReader.ReadVideoFrame();
    }
    vFReader.Close();
}