WPF實(shí)現(xiàn)獲取攝像頭幀圖的代碼示例
一.前言
項(xiàng)目需求:支持uvc的攝像頭,取出其畫面幀圖,進(jìn)行相關(guān)疊加,并重新展示在image控件上
環(huán)境:用的是.net framework 4.8.1 。 當(dāng)然.net6 也支持
使用的第三方插件:AForge.Video.DirectShow
備注:winform和uwp都可以進(jìn)行參考
二.項(xiàng)目demo代碼
MainWindow.xaml部分
<Window x:Class="WpfApp2.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:WpfApp2" xmlns:vlc="clr-namespace:LibVLCSharp.WPF;assembly=LibVLCSharp.WPF" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <Grid> <Image x:Name="video" Margin="0,40,0,0"/> <Button x:Name="StartButton" Content="start" HorizontalAlignment="Left" Margin="39,11,0,0" VerticalAlignment="Top" Click="StartButton_event"/> <Button x:Name="StopButton" Content="stop" HorizontalAlignment="Left" Margin="88,10,0,0" VerticalAlignment="Top" Click="StopButton_event"/> </Grid> </Window>
MainWindow.cs部分
using AForge.Video;
using AForge.Video.DirectShow;
using LibVLCSharp.Shared;
using LoggerServiceFK;
using SkiaSharp;
using System;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Drawing;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Interop;
using System.Windows.Media.Imaging;
namespace WpfApp2 {
///
/// MainWindow.xaml 的交互邏輯
///
public partial class MainWindow : Window
{
private VideoCaptureDevice videoSource;
private bool isCapturing = false;
public MainWindow()
{
InitializeComponent();
}
private void VideoSource_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
if (isCapturing)
{
// Convert AForge.NET Framework's Bitmap to WPF's BitmapSource
Bitmap aforgeBitmap = (Bitmap)eventArgs.Frame.Clone();
// Display the video frame in an Image control
Dispatcher.Invoke(() =>
{
//這里就可以對(duì)圖片進(jìn)行相關(guān)疊加操作,再賦值給source
video.Source = Convert(aforgeBitmap);
});
}
}
public static BitmapSource Convert(Bitmap bitmap)
{
if (bitmap == null)
{
throw new ArgumentNullException(nameof(bitmap));
}
// 獲取 Bitmap 的 HBitmap 句柄
IntPtr hBitmap = bitmap.GetHbitmap();
// 使用 CreateBitmapSourceFromHBitmap 方法創(chuàng)建 BitmapSource
BitmapSource bitmapSource = Imaging.CreateBitmapSourceFromHBitmap(
hBitmap,
IntPtr.Zero,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());
// 釋放 Bitmap 的 HBitmap 句柄
NativeMethods.DeleteObject(hBitmap);
return bitmapSource;
}
private static class NativeMethods
{
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
[return: System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.Bool)]
public static extern bool DeleteObject(IntPtr hObject);
}
private void StartButton_event(object sender, RoutedEventArgs e)
{
//這里獲取usb攝像頭的地方
FilterInfoCollection videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
if (videoDevices.Count > 0)
{
//這里默認(rèn)選擇設(shè)備列表[0],如果是筆記本外接usb攝像頭要取數(shù)組[1]
videoSource = new VideoCaptureDevice(videoDevices[0].MonikerString);
videoSource.NewFrame += VideoSource_NewFrame;
videoSource.Start();
isCapturing = true;
}
}
private void StopButton_event(object sender, RoutedEventArgs e)
{
if (videoSource != null && videoSource.IsRunning)
{
//SignalToStop()停止信號(hào)就行,使用stop()方法會(huì)導(dǎo)致更新線程卡死
videoSource.SignalToStop();
isCapturing = false;
}
}
}
}
上面這部分代碼就是取圖片幀的方法,基本延遲在200ms左右,比vlc插件調(diào)取更快。
三.需要定制化下,如何優(yōu)化此代碼
demo所展示的只是基本取圖,如要在取圖的基礎(chǔ)上 疊加定制化內(nèi)容并不影響取圖效率,該如何考慮?
本人分享一個(gè)解決辦法:
首先不使用Bitmap 類型,改為SKBitmap類型———SKBitmap 使用的是 SkiaSharp的庫(kù)
把Bitmap轉(zhuǎn)成SKBitmap類型
var CurrentBitmap = new SKBitmap(640,480); CurrentBitmap=aforgeBitmap.ToSKBitmap();
需要定制化的內(nèi)容 使用SKBitmap類型的指針進(jìn)行處理,速度更快——此處根據(jù)項(xiàng)目本身進(jìn)行處理
定制后的SKBitmap類型內(nèi)容再轉(zhuǎn)換成WriteableBitmap類型,使用WritePixels方法進(jìn)行構(gòu)成,video.source可以進(jìn)行讀取
//參考例子 var writeableBitmap = new WriteableBitmap(640, 480, 96, 96, PixelFormats.Bgr32, null); writeableBitmap.WritePixels(new Int32Rect(0, 0, skbitmap.Width, skbitmap.Height), skbitmap.GetPixels(), skbitmap.RowBytes * skbitmap.Height, skbitmap.RowBytes);
這個(gè)定制轉(zhuǎn)換的效果與demo展示的效率相當(dāng)
四. demo展示

以上就是WPF實(shí)現(xiàn)獲取攝像頭幀圖的代碼示例的詳細(xì)內(nèi)容,更多關(guān)于WPF取攝像頭幀圖的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C# 類型轉(zhuǎn)換(隱式類型,顯式類型,自定義類型)
本文詳細(xì)介紹了C#中的類型轉(zhuǎn)換,包括隱式類型轉(zhuǎn)換和顯式類型轉(zhuǎn)換(強(qiáng)制類型轉(zhuǎn)換),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-11-11
c#實(shí)現(xiàn)萬(wàn)年歷示例分享 萬(wàn)年歷農(nóng)歷查詢
這篇文章主要介紹了c#實(shí)現(xiàn)萬(wàn)年歷的方法,可以顯示農(nóng)歷、節(jié)氣、節(jié)日、星座、星宿、屬相、生肖、閏年月、時(shí)辰,大家參考使用吧2014-01-01
WinForm實(shí)現(xiàn)程序一段時(shí)間不運(yùn)行自動(dòng)關(guān)閉的方法
這篇文章主要介紹了WinForm實(shí)現(xiàn)程序一段時(shí)間不運(yùn)行自動(dòng)關(guān)閉的方法,涉及WinForm計(jì)時(shí)器及進(jìn)程操作的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-09-09
解決WPF附加屬性的Set函數(shù)不調(diào)用的問(wèn)題
這篇文章介紹了解決WPF附加屬性的Set函數(shù)不調(diào)用的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-06-06

