从视频C#中提取帧
c#
image-processing
7
0

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

我被困在三件事上。

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

主要代码:

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();





    });


}   
参考资料:
Stack Overflow
收藏
评论
共 3 个回答
高赞 时间 活跃

在与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++;
    }
}

希望有一天能对某人有所帮助。

收藏
评论

使用ffmpeg并安装Accord.Video.FFMPEG

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

我是昨天才发现的。

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

您可以选择适合您项目的部件并进行更改(例如,从摄像机获取视频分辨率)

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

收藏
评论
新手导航
  • 社区规范
  • 提出问题
  • 进行投票
  • 个人资料
  • 优化问题
  • 回答问题

关于我们

常见问题

内容许可

联系我们

@2020 AskGo
京ICP备20001863号