# C# WPF 多摄像头条码触发拍照系统 下面是一个完整的WPF应用程序实现,可以在输入条码后按回车键触发多个摄像头同时拍照并保存照片。 ## 1. 创建WPF项目 首先创建一个新的WPF应用程序项目。 ## 2. 安装必要的NuGet包 在NuGet包管理器中安装以下包: - AForge.Video.DirectShow (用于摄像头控制) - System.Drawing.Common (用于图像处理) ## 3. 完整代码实现 MainWindow.xaml ```xml <Window x:Class="MultiCameraBarcodeTrigger.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:MultiCameraBarcodeTrigger" mc:Ignorable="d" Title="多摄像头条码触发拍照" Height="600" Width="800"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="*"/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <!-- 条码输入区域 --> <StackPanel Grid.Row="0" Orientation="Horizontal" Margin="10"> <Label Content="输入条码:" VerticalAlignment="Center"/> <TextBox x:Name="txtBarcode" Width="200" Margin="5" KeyDown="TxtBarcode_KeyDown"/> <Button Content="选择保存路径" Margin="5" Click="BtnSelectFolder_Click"/> <TextBlock x:Name="txtSavePath" Margin="5" VerticalAlignment="Center"/> </StackPanel> <!-- 摄像头显示区域 --> <UniformGrid Grid.Row="1" Columns="2" Rows="2" Margin="10"> <Image x:Name="imgCamera1" Stretch="Uniform"/> <Image x:Name="imgCamera2" Stretch="Uniform"/> <Image x:Name="imgCamera3" Stretch="Uniform"/> <Image x:Name="imgCamera4" Stretch="Uniform"/> </UniformGrid> <!-- 状态信息 --> <StatusBar Grid.Row="2"> <StatusBarItem> <TextBlock x:Name="txtStatus" Text="准备就绪"/> </StatusBarItem> </StatusBar> </Grid> </Window> ``` MainWindow.xaml.cs ```csharp using System; using System.Collections.Generic; using System.Drawing; using System.IO; using System.Windows; using System.Windows.Controls; using System.Windows.Forms; using System.Windows.Media.Imaging; using AForge.Video; using AForge.Video.DirectShow; namespace MultiCameraBarcodeTrigger { public partial class MainWindow : Window { private List<VideoCaptureDevice> videoDevices = new List<VideoCaptureDevice>(); private List<System.Windows.Controls.Image> cameraImages = new List<System.Windows.Controls.Image>(); private string saveFolderPath = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures); private FilterInfoCollection videoDevicesCollection; public MainWindow() { InitializeComponent(); // 初始化摄像头显示控件列表 cameraImages.Add(imgCamera1); cameraImages.Add(imgCamera2); cameraImages.Add(imgCamera3); cameraImages.Add(imgCamera4); InitializeCameras(); } private void InitializeCameras() { try { // 获取所有可用的视频设备 videoDevicesCollection = new FilterInfoCollection(FilterCategory.VideoInputDevice); if (videoDevicesCollection.Count == 0) { txtStatus.Text = "没有检测到摄像头设备"; return; } // 初始化摄像头设备 for (int i = 0; i < Math.Min(videoDevicesCollection.Count, 4); i++) { var device = new VideoCaptureDevice(videoDevicesCollection[i].MonikerString); device.NewFrame += (sender, e) => Device_NewFrame(sender, e, i); device.Start(); videoDevices.Add(device); } txtStatus.Text = $"已初始化 {videoDevices.Count} 个摄像头"; } catch (Exception ex) { txtStatus.Text = $"初始化摄像头时出错: {ex.Message}"; } } private void Device_NewFrame(object sender, NewFrameEventArgs eventArgs, int cameraIndex) { try { if (cameraIndex >= cameraImages.Count) return; // 将帧转换为BitmapImage var bitmap = (Bitmap)eventArgs.Frame.Clone(); var bitmapImage = BitmapToBitmapImage(bitmap); // 在UI线程上更新图像 Dispatcher.Invoke(() => { cameraImages[cameraIndex].Source = bitmapImage; }); } catch (Exception ex) { Dispatcher.Invoke(() => txtStatus.Text = $"摄像头 {cameraIndex + 1} 帧处理错误: {ex.Message}"); } } private BitmapImage BitmapToBitmapImage(Bitmap bitmap) { using (var memory = new MemoryStream()) { bitmap.Save(memory, System.Drawing.Imaging.ImageFormat.Bmp); memory.Position = 0; var bitmapImage = new BitmapImage(); bitmapImage.BeginInit(); bitmapImage.StreamSource = memory; bitmapImage.CacheOption = BitmapCacheOption.OnLoad; bitmapImage.EndInit(); bitmapImage.Freeze(); return bitmapImage; } } private void TxtBarcode_KeyDown(object sender, System.Windows.Input.KeyEventArgs e) { if (e.Key == System.Windows.Input.Key.Enter && !string.IsNullOrWhiteSpace(txtBarcode.Text)) { CaptureImagesFromAllCameras(txtBarcode.Text); } } private void CaptureImagesFromAllCameras(string barcode) { try { if (videoDevices.Count == 0) { txtStatus.Text = "没有可用的摄像头"; return; } // 创建以条码命名的子文件夹 string barcodeFolder = Path.Combine(saveFolderPath, barcode); Directory.CreateDirectory(barcodeFolder); // 为每个摄像头拍照 for (int i = 0; i < videoDevices.Count; i++) { if (cameraImages[i].Source is BitmapSource bitmapSource) { string fileName = Path.Combine(barcodeFolder, $"Camera_{i + 1}_{DateTime.Now:yyyyMMddHHmmssfff}.jpg"); SaveBitmapSourceToFile(bitmapSource, fileName); } } txtStatus.Text = $"已为条码 {barcode} 保存 {videoDevices.Count} 张照片"; } catch (Exception ex) { txtStatus.Text = $"拍照保存时出错: {ex.Message}"; } } private void SaveBitmapSourceToFile(BitmapSource bitmapSource, string filePath) { var encoder = new JpegBitmapEncoder(); encoder.Frames.Add(BitmapFrame.Create(bitmapSource)); using (var stream = new FileStream(filePath, FileMode.Create)) { encoder.Save(stream); } } private void BtnSelectFolder_Click(object sender, RoutedEventArgs e) { var folderDialog = new FolderBrowserDialog(); folderDialog.Description = "选择照片保存目录"; folderDialog.SelectedPath = saveFolderPath; if (folderDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK) { saveFolderPath = folderDialog.SelectedPath; txtSavePath.Text = saveFolderPath; } } protected override void OnClosing(System.ComponentModel.CancelEventArgs e) { // 停止所有摄像头 foreach (var device in videoDevices) { if (device.IsRunning) { device.SignalToStop(); device.WaitForStop(); } } base.OnClosing(e); } } } ``` ## 4. 功能说明 1. 多摄像头支持: - 自动检测并初始化最多4个摄像头 - 每个摄像头画面显示在独立的Image控件中 2. 条码触发拍照: - 在文本框中输入条码后按回车键触发拍照 - 所有摄像头会同时拍照 3. 照片保存: - 照片按条码存储在单独的文件夹中 - 每个摄像头拍摄的照片以时间戳命名 - 可以自定义保存路径 4. 错误处理: - 处理摄像头初始化错误 - 处理拍照和保存过程中的异常 ## 5. 使用注意事项 1. 确保计算机已连接摄像头设备 2. 可能需要根据实际摄像头数量调整界面布局 3. 保存路径需要有写入权限 4. 对于高性能需求,可能需要优化图像处理部分 ## 6. 扩展建议 1. 添加条码扫描器支持,直接通过扫描枪输入条码 2. 增加照片预览和删除功能 3. 添加拍照倒计时或声音提示 4. 支持更多摄像头(需要调整界面布局) 5. 添加照片质量设置选项 这个实现使用了AForge.Video库来处理摄像头,它是一个成熟的计算机视觉库,适合此类应用场景。 [2025-04-10 16:21:42 | AI问答 | 2098点数解答]