Files
BaslerCapture/TimedCapture.xaml.cs
wangjialiang 14756339ee Testnew
2025-11-28 15:20:45 +08:00

243 lines
7.4 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using Basler.Pylon;
using System;
using System.IO;
using System.Windows;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
namespace WpfApp1
{
/// <summary>
/// TimedCapture.xaml 的交互逻辑
/// </summary>
public partial class TimedCapture : Window
{
private readonly Camera _camera;
private readonly DispatcherTimer _timer = new DispatcherTimer();
private string _saveFolder =
Environment.GetFolderPath(Environment.SpecialFolder.MyPictures);
private int _intervalMs = 1000;
private bool _isCapturing = false;
// 复用一个转换器,避免每次 new
private readonly PixelDataConverter _converter = new PixelDataConverter
{
OutputPixelFormat = PixelType.BGRA8packed
};
public TimedCapture(Camera camera)
{
InitializeComponent();
_camera = camera ?? throw new ArgumentNullException(nameof(camera));
var name = _camera.CameraInfo?[CameraInfoKey.FriendlyName];
CameraInfoTextBlock.Text = string.IsNullOrWhiteSpace(name)
? "未知相机"
: name;
FolderTextBox.Text = _saveFolder;
IntervalTextBox.Text = _intervalMs.ToString();
_timer.Tick += OnTimerTick;
_timer.IsEnabled = false;
UpdateUiState();
}
/// <summary>
/// 根据 _isCapturing 更新按钮文本和状态栏
/// </summary>
private void UpdateUiState(string? extraStatus = null)
{
if (_isCapturing)
{
ToggleCaptureButton.Content = "停止定时拍照";
if (extraStatus == null)
{
StatusTextBlock.Text = "状态:拍摄中";
}
else
{
StatusTextBlock.Text = extraStatus;
}
}
else
{
ToggleCaptureButton.Content = "开始定时拍照";
if (extraStatus == null)
{
StatusTextBlock.Text = "状态:已停止";
}
else
{
StatusTextBlock.Text = extraStatus;
}
}
}
/// <summary>
/// 选择保存路径
/// </summary>
private void BrowseButton_Click(object sender, RoutedEventArgs e)
{
var selected = FolderHelper.SelectFolder("请选择保存目录");
if (!string.IsNullOrWhiteSpace(selected))
{
_saveFolder = selected;
FolderTextBox.Text = _saveFolder;
}
}
/// <summary>
/// 单按钮:开始 / 停止 定时拍照
/// </summary>
private void ToggleCaptureButton_Click(object sender, RoutedEventArgs e)
{
if (!_isCapturing)
{
// 当前是“未拍照”状态,点击后尝试开始
if (!StartCapture())
{
// 开始失败,不改变 _isCapturing
return;
}
_isCapturing = true;
UpdateUiState();
}
else
{
// 当前在拍照,点击后停止
StopCapture();
_isCapturing = false;
UpdateUiState();
}
}
/// <summary>
/// 尝试开始定时拍照(参数校验、目录检查等)
/// 返回 true 表示成功启动
/// </summary>
private bool StartCapture()
{
if (_camera == null || !_camera.IsOpen)
{
MessageBox.Show("相机未打开");
return false;
}
// 读取间隔
if (!int.TryParse(IntervalTextBox.Text, out var ms) || ms <= 0)
{
MessageBox.Show("请输入有效的拍摄间隔(毫秒,>0");
return false;
}
_intervalMs = ms;
_timer.Interval = TimeSpan.FromMilliseconds(_intervalMs);
// 读取保存路径
if (string.IsNullOrWhiteSpace(FolderTextBox.Text))
{
MessageBox.Show("请选择保存文件夹");
return false;
}
_saveFolder = FolderTextBox.Text.Trim();
if (!Directory.Exists(_saveFolder))
{
try
{
Directory.CreateDirectory(_saveFolder);
}
catch (Exception ex)
{
MessageBox.Show("创建文件夹失败:" + ex.Message);
return false;
}
}
_timer.Start();
UpdateUiState("状态:拍摄中");
return true;
}
/// <summary>
/// 停止定时拍照
/// </summary>
private void StopCapture()
{
_timer.Stop();
UpdateUiState("状态:已停止");
}
/// <summary>
/// 定时抓拍:每次 Tick 抓一帧并保存
/// (现在 Tick 在 UI 线程执行,如果将来发现卡顿,可以再改成后台线程抓拍)
/// </summary>
private void OnTimerTick(object? sender, EventArgs e)
{
try
{
using (IGrabResult grabResult = _camera.StreamGrabber.GrabOne(_intervalMs))
{
if (grabResult == null || !grabResult.GrabSucceeded)
{
UpdateUiState("状态:抓拍失败(无效图像)");
return;
}
int width = grabResult.Width;
int height = grabResult.Height;
int stride = width * 4;
int bufferSize = stride * height;
// 每次使用局部 buffer避免多线程和尺寸问题
byte[] buffer = new byte[bufferSize];
_converter.Convert(buffer, grabResult);
var bitmap = BitmapSource.Create(
width,
height,
96,
96,
System.Windows.Media.PixelFormats.Bgra32,
null,
buffer,
stride);
string filePath = Path.Combine(
_saveFolder,
$"Timed_{DateTime.Now:yyyyMMdd_HHmmss_fff}.png");
SaveImage(bitmap, filePath);
UpdateUiState("状态:已保存 " + System.IO.Path.GetFileName(filePath));
}
}
catch (Exception ex)
{
UpdateUiState("状态:抓拍失败 - " + ex.Message);
}
}
private static void SaveImage(BitmapSource bitmap, string filePath)
{
var encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bitmap));
using var stream = new FileStream(filePath, FileMode.Create, FileAccess.Write);
encoder.Save(stream);
}
protected override void OnClosed(EventArgs e)
{
_timer.Stop();
base.OnClosed(e);
}
}
}