C# USB 摄像头 OpenCV 视频picBox呈现,抓拍图像保存呈现。没有注释版本。

1、winform 应用程序,两个picturebox空间,一个用于视频呈现,一个用于抓拍呈现。

2、引用包OpenCvSharp4、OpenCvSharp4.Extensions、OpenCvSharp4.runtime.win等。

复制代码
    public partial class Form2 : Form
    {
        // 修改成员变量
        private volatile Bitmap _latestFrameBitmap;
        private readonly object _bitmapLock = new object();
        private VideoCapture _capture;
        private CancellationTokenSource _cts;

        public Form2()
        {
            InitializeComponent();
        }

        private async void Form2_Load(object sender, EventArgs e)
        {
            _capture = new VideoCapture(0);
            if (!_capture.IsOpened())
            {
                MessageBox.Show("无法打开摄像头!");
                return;
            }

            _cts = new CancellationTokenSource();
            try
            {
                await StartCapturingAsync(_cts.Token);
            }
            catch (OperationCanceledException)
            {
                // 正常取消
            }
            catch (Exception ex)
            {
                MessageBox.Show($"捕获出错: {ex.Message}");
            }
        }

        private async Task StartCapturingAsync(CancellationToken token)
        {
            using (var frame = new Mat())
            {
                while (!token.IsCancellationRequested)
                {
                    _capture.Read(frame);
                    if (frame.Empty()) continue;

                    var newBitmap = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(frame);

                    // 更新最新帧
                    lock (_bitmapLock)
                    {
                        var old = _latestFrameBitmap;
                        _latestFrameBitmap = newBitmap;
                        old?.Dispose();
                    }

                    await UpdateCameraPreviewAsync(newBitmap);
                    await Task.Delay(30, token);
                }
            }
        }

        private async Task UpdateCameraPreviewAsync(Bitmap bitmap)
        {
            if (picCamera.IsDisposed)
            {
                bitmap.Dispose();
                return;
            }

            try
            {
                if (picCamera.InvokeRequired)
                {
                    picCamera.BeginInvoke(new Action(() => UpdateCamera(bitmap)));
                }
                else
                {
                    UpdateCamera(bitmap);
                }
            }
            catch (ObjectDisposedException)
            {
                bitmap.Dispose();
            }
        }

        private void UpdateCamera(Bitmap newBitmap)
        {
            if (picCamera.IsDisposed)
            {
                newBitmap.Dispose();
                return;
            }

            var old = picCamera.Image;
            picCamera.Image = newBitmap;
            old?.Dispose();
        }

        // 优化后的抓拍方法
        private async void catchBtn_Click(object sender, EventArgs e)
        {
            try
            {
                Bitmap snapshot = null;

                // 安全获取当前帧
                lock (_bitmapLock)
                {
                    if (_latestFrameBitmap != null)
                    {
                        snapshot = (Bitmap)_latestFrameBitmap.Clone();
                    }
                }

                if (snapshot == null)
                {
                    MessageBox.Show("当前没有可用的视频帧");
                    return;
                }

                // 异步保存防止界面卡顿
                await Task.Run(() => SaveSnapshot(snapshot));
            }
            catch (Exception ex)
            {
                MessageBox.Show($"抓拍失败: {ex.Message}");
            }
        }

        private void SaveSnapshot(Bitmap bitmap)
        {
            try
            {
                var fileName = GenerateUniqueFileName();
                using (bitmap) // 确保释放资源
                {
                    bitmap.Save(fileName, ImageFormat.Jpeg);

                    // 显示预览(需要克隆新实例)
                    var previewBitmap = (Bitmap)bitmap.Clone();

                    BeginInvoke(new Action(() =>
                    {
                        UpdateSnapshotPreview(previewBitmap);
                        MessageBox.Show($"图片已保存到:\n{fileName}");
                    }));
                }
            }
            catch (Exception ex)
            {
                BeginInvoke(new Action(() =>
                {
                    MessageBox.Show($"保存失败: {ex.Message}");
                }));
            }
        }

        // 新增预览更新方法
        private void UpdateSnapshotPreview(Bitmap newBitmap)
        {
            if (pictureBoxSnapshot.IsDisposed)
            {
                newBitmap.Dispose();
                return;
            }

            // 处理跨线程访问
            if (pictureBoxSnapshot.InvokeRequired)
            {
                pictureBoxSnapshot.BeginInvoke(new Action(() => UpdateSnapshotPreview(newBitmap)));
                return;
            }

            // 更新控件并释放旧资源
            var old = pictureBoxSnapshot.Image;
            pictureBoxSnapshot.Image = newBitmap;
            old?.Dispose();
        }

        private string GenerateUniqueFileName()
        {
            var docs = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures);
            var timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmssfff");
            return Path.Combine(docs, $"Snapshot_{timestamp}.jpg");
        }

        private void Form2_FormClosing(object sender, FormClosingEventArgs e)
        {
            _cts?.Cancel();
            _cts?.Dispose();

            // 释放所有资源
            _capture?.Dispose();
            lock (_bitmapLock)
            {
                _latestFrameBitmap?.Dispose();
            }

            // 清理预览图
            if (picCamera.Image != null)
            {
                var img = picCamera.Image;
                picCamera.Image = null;
                img.Dispose();
            }

            // 新增快照预览清理
            if (pictureBoxSnapshot.Image != null)
            {
                var img = pictureBoxSnapshot.Image;
                pictureBoxSnapshot.Image = null;
                img.Dispose();
            }
        }
    }