281 lines
9.3 KiB
C#
281 lines
9.3 KiB
C#
using Basler.Pylon;
|
|
using Microsoft.Win32;
|
|
using Microsoft.WindowsAPICodePack.Dialogs;
|
|
using System;
|
|
using System.IO;
|
|
using System.Threading.Tasks;
|
|
|
|
using System.Windows;
|
|
using System.Windows.Media.Imaging;
|
|
|
|
namespace WpfApp1
|
|
{
|
|
public partial class MainWindow : Window
|
|
{
|
|
private Camera _camera;
|
|
private string _saveFolder = @"C:\CapturedImages";
|
|
private ICameraInfo? _selectedCameraInfo;
|
|
private bool _isCameraStarted = false;
|
|
|
|
public MainWindow()
|
|
{
|
|
InitializeComponent();
|
|
WindowStyle = WindowStyle.None;
|
|
ResizeMode = ResizeMode.NoResize;
|
|
WindowState = WindowState.Maximized;
|
|
|
|
ButtonPanel1.IsEnabled = false;
|
|
StatusText.Text = "正在初始化相机...请稍后";
|
|
Task.Run(() => InitializeCameraAsync());
|
|
}
|
|
|
|
private async Task InitializeCameraAsync()
|
|
{
|
|
try
|
|
{
|
|
var cameras = CameraFinder.Enumerate();
|
|
if (cameras.Count == 0)
|
|
{
|
|
Dispatcher.Invoke(() =>
|
|
{
|
|
ButtonPanel1.IsEnabled = true;
|
|
StatusText.Text = "未检测到相机";
|
|
});
|
|
return;
|
|
}
|
|
|
|
_selectedCameraInfo = cameras[0];
|
|
|
|
await Task.CompletedTask;
|
|
|
|
Dispatcher.Invoke(() =>
|
|
{
|
|
ButtonPanel1.IsEnabled = true;
|
|
StatusText.Text = "相机初始化完成,请选择相机并随后‘开启推流’开始取流";
|
|
StartCameraButton.Content = "开启推流";
|
|
});
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Dispatcher.Invoke(() => MessageBox.Show("初始化失败: " + ex.Message));
|
|
}
|
|
}
|
|
|
|
private void StartCameraButton_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
try
|
|
{
|
|
// 确保相机已打开
|
|
if ((_camera == null || !_camera.IsOpen) && _selectedCameraInfo != null)
|
|
{
|
|
if (_camera != null)
|
|
{
|
|
try
|
|
{
|
|
_camera.StreamGrabber.Stop();
|
|
_camera.StreamGrabber.ImageGrabbed -= OnImageGrabbed;
|
|
_camera.Close();
|
|
}
|
|
catch { }
|
|
finally { _camera = null; }
|
|
}
|
|
|
|
_camera = new Camera(_selectedCameraInfo);
|
|
_camera.Open();
|
|
_camera.Parameters[PLCamera.AcquisitionMode].SetValue(PLCamera.AcquisitionMode.Continuous);
|
|
}
|
|
|
|
if (_camera == null || !_camera.IsOpen)
|
|
{
|
|
StatusText.Text = "请先选择一个相机";
|
|
return;
|
|
}
|
|
|
|
if (!_isCameraStarted)
|
|
{
|
|
_camera.StreamGrabber.ImageGrabbed += OnImageGrabbed;
|
|
_camera.StreamGrabber.Start(GrabStrategy.LatestImages, GrabLoop.ProvidedByStreamGrabber);
|
|
_isCameraStarted = true;
|
|
StatusText.Text = "推流已开启";
|
|
StartCameraButton.Content = "关闭推流";
|
|
}
|
|
else
|
|
{
|
|
try
|
|
{
|
|
_camera.StreamGrabber.Stop();
|
|
_camera.StreamGrabber.ImageGrabbed -= OnImageGrabbed;
|
|
_isCameraStarted = false;
|
|
StatusText.Text = "推流已关闭";
|
|
StartCameraButton.Content = "开启推流";
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
StatusText.Text = "关闭推流失败:" + ex.Message;
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
StatusText.Text = "推流切换失败:" + ex.Message;
|
|
}
|
|
}
|
|
|
|
private void OnImageGrabbed(object sender, ImageGrabbedEventArgs e)
|
|
{
|
|
try
|
|
{
|
|
using (IGrabResult result = e.GrabResult)
|
|
{
|
|
if (!result.GrabSucceeded) return;
|
|
|
|
var converter = new PixelDataConverter();
|
|
converter.OutputPixelFormat = PixelType.BGRA8packed;
|
|
|
|
byte[] buffer = new byte[result.Width * result.Height * 4];
|
|
converter.Convert(buffer, result);
|
|
|
|
Dispatcher.Invoke(() =>
|
|
{
|
|
CameraImage.Source = BitmapSource.Create(
|
|
result.Width, result.Height, 96, 96,
|
|
System.Windows.Media.PixelFormats.Bgra32,
|
|
null, buffer, result.Width * 4);
|
|
});
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
// 忽略异常
|
|
}
|
|
}
|
|
|
|
private void CaptureButton_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
if (CameraImage.Source == null)
|
|
{
|
|
StatusText.Text = "没有图像可保存";
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
string filePath = Path.Combine(_saveFolder,
|
|
$"Capture_{DateTime.Now:yyyyMMdd_HHmmss}.png");
|
|
|
|
SaveImage(CameraImage.Source as BitmapSource, filePath);
|
|
|
|
StatusText.Text = $"图像已保存到:{filePath}";
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
StatusText.Text = "保存失败:" + ex.Message;
|
|
}
|
|
}
|
|
|
|
private void SaveImage(BitmapSource bitmap, string filePath)
|
|
{
|
|
var encoder = new PngBitmapEncoder();
|
|
encoder.Frames.Add(BitmapFrame.Create(bitmap));
|
|
|
|
using (FileStream stream = new FileStream(filePath, FileMode.Create))
|
|
{
|
|
encoder.Save(stream);
|
|
}
|
|
}
|
|
|
|
private void ChangeFolderButton_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
var selected = FolderHelper.SelectFolder();
|
|
|
|
if (selected != null)
|
|
{
|
|
_saveFolder = selected;
|
|
StatusText.Text = $"保存目录已切换为:{_saveFolder}";
|
|
}
|
|
}
|
|
|
|
protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
|
|
{
|
|
base.OnClosing(e);
|
|
|
|
if (_camera != null)
|
|
{
|
|
try
|
|
{
|
|
_camera.StreamGrabber.Stop();
|
|
_camera.StreamGrabber.ImageGrabbed -= OnImageGrabbed;
|
|
_camera.Close();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
StatusText.Text = "关闭相机时出错:" + ex.Message;
|
|
}
|
|
finally
|
|
{
|
|
_camera = null;
|
|
_isCameraStarted = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void SelectCameraButton_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
var dlg = new SelectCamera();
|
|
dlg.Owner = this;
|
|
|
|
if (dlg.ShowDialog() == true)
|
|
{
|
|
var selectedInfo = dlg.SelectedCameraInfo;
|
|
_selectedCameraInfo = selectedInfo;
|
|
|
|
// 关闭旧相机,打开新相机,但不取流
|
|
try
|
|
{
|
|
if (_camera != null)
|
|
{
|
|
try
|
|
{
|
|
_camera.StreamGrabber.Stop();
|
|
_camera.StreamGrabber.ImageGrabbed -= OnImageGrabbed;
|
|
_camera.Close();
|
|
}
|
|
catch { }
|
|
finally { _camera = null; _isCameraStarted = false; }
|
|
}
|
|
|
|
_camera = new Camera(_selectedCameraInfo);
|
|
_camera.Open();
|
|
_camera.Parameters[PLCamera.AcquisitionMode].SetValue(PLCamera.AcquisitionMode.Continuous);
|
|
|
|
_isCameraStarted = false;
|
|
StatusText.Text = $"已选择并打开相机:{selectedInfo[CameraInfoKey.SerialNumber]}(未取流)。点击‘开启推流’开始/停止推流";
|
|
StartCameraButton.Content = "开启推流";
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
StatusText.Text = "打开相机失败:" + ex.Message;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void ExitButton_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
Close();
|
|
}
|
|
|
|
private void TimedCaptureButton_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
// 定时拍摄只要求相机已打开,无需取流
|
|
if (_camera == null || !_camera.IsOpen)
|
|
{
|
|
MessageBox.Show("请先选择相机(会自动打开但不取流)");
|
|
return;
|
|
}
|
|
var dlg = new TimedCapture(_camera);
|
|
dlg.Owner = this;
|
|
dlg.ShowDialog();
|
|
}
|
|
}
|
|
}
|