Files
Z714System/外科辅料和患者防护罩激光抗性测试仪/BasicDemo/AutoCameraForm.cs
2026-01-06 13:34:31 +08:00

942 lines
35 KiB
C#
Raw 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 MvCamCtrl.NET;
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using Accord.Video;
using Accord.Video.FFMPEG;
namespace BasicDemo
{
public partial class AutoCameraForm : Form
{
[DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory", SetLastError = false)]
private static extern void CopyMemory(IntPtr dest, IntPtr src, uint count);
// 支持最多3个相机
private const int MAX_CAMERAS = 3;
// 相机相关对象数组
private MyCamera[] cameras = new MyCamera[MAX_CAMERAS];
private bool[] grabbingFlags = new bool[MAX_CAMERAS];
private Thread[] grabThreads = new Thread[MAX_CAMERAS];
private MyCamera.MV_FRAME_OUT_INFO_EX[] frameInfos = new MyCamera.MV_FRAME_OUT_INFO_EX[MAX_CAMERAS];
// 图像显示相关
private Bitmap[] displayBitmaps = new Bitmap[MAX_CAMERAS];
private IntPtr[] displayBufs = new IntPtr[MAX_CAMERAS];
private UInt32[] displayBufSizes = new UInt32[MAX_CAMERAS];
// 设备列表
private MyCamera.MV_CC_DEVICE_INFO_LIST deviceList = new MyCamera.MV_CC_DEVICE_INFO_LIST();
// UI控件
private PictureBox[] pictureBoxes = new PictureBox[MAX_CAMERAS];
private Label[] statusLabels = new Label[MAX_CAMERAS];
// 锁对象,用于线程同步
private static readonly object[] locks = new object[MAX_CAMERAS] { new object(), new object(), new object() };
// 状态回调
public delegate bool GetRunStatusDelegate();
private GetRunStatusDelegate _getRunStatusCallback;
private Thread _statusCheckThread;
// 添加:定义返回事件委托
public delegate void ReturnToPreviousFormDelegate();
public event ReturnToPreviousFormDelegate OnReturnRequested;
// 控制变量
private bool _shouldCapture = false;
private bool _camerasInitialized = false;
// 视频保存配置(新增)
private string _videoSavePath = @"D:\CameraRecordings\"; // 修改为你的保存路径
private double _frameRate = 30.0; // 默认帧率
// 构造函数
public AutoCameraForm(GetRunStatusDelegate getRunStatusCallback, ReturnToPreviousFormDelegate returnCallback = null, string videoSavePath = null)
{
_getRunStatusCallback = getRunStatusCallback;
// 如果提供了返回回调,就订阅
if (returnCallback != null)
{
OnReturnRequested += returnCallback;
}
//// 设置视频保存路径
//if (!string.IsNullOrEmpty(videoSavePath))
//{
// _videoSavePath = videoSavePath;
//}
//// 确保保存目录存在
//Directory.CreateDirectory(_videoSavePath);
InitializeComponent();
Control.CheckForIllegalCrossThreadCalls = false;
// 设置窗体大小
this.Size = new Size(1900, 1000);
this.Text = "三相机自动监控系统";
this.StartPosition = FormStartPosition.CenterScreen;
this.FormClosing += AutoCameraForm_FormClosing;
// 初始化UI
InitializeUI();
// 窗体加载时初始化相机
this.Load += (s, e) => InitializeCameras();
}
/// <summary>
/// 初始化UI界面
/// </summary>
private void InitializeUI()
{
this.BackColor = Color.FromArgb(240, 240, 240);
//Button btnDiagnose = new Button
//{
// Text = "诊断",
// Size = new Size(80, 30),
// Location = new Point(1800, 30),
// BackColor = Color.Yellow,
// ForeColor = Color.Black
//};
//btnDiagnose.Click += (s, e) => DiagnoseCameras();
//this.Controls.Add(btnDiagnose);
// 创建标题
Label titleLabel = new Label
{
Text = "三相机自动监控系统",
Font = new Font("Microsoft YaHei", 20, FontStyle.Bold),
ForeColor = Color.FromArgb(0, 112, 192),
Size = new Size(500, 40),
Location = new Point(700, 20),
TextAlign = ContentAlignment.MiddleCenter
};
this.Controls.Add(titleLabel);
// 创建状态栏
Panel statusBar = new Panel
{
BackColor = Color.FromArgb(0, 112, 192),
Size = new Size(1900, 30),
Location = new Point(0, 970)
};
this.Controls.Add(statusBar);
Label statusText = new Label
{
Text = "系统状态:正在初始化...",
Font = new Font("Microsoft YaHei", 10),
ForeColor = Color.White,
Size = new Size(300, 25),
Location = new Point(10, 2),
TextAlign = ContentAlignment.MiddleLeft
};
statusBar.Controls.Add(statusText);
// 创建三个相机显示区域
int pictureWidth = 620;
int pictureHeight = 850;
int margin = 20;
for (int i = 0; i < MAX_CAMERAS; i++)
{
// 创建容器面板
Panel cameraPanel = new Panel
{
BackColor = Color.White,
BorderStyle = BorderStyle.FixedSingle,
Size = new Size(pictureWidth, 900),
Location = new Point(margin + i * (pictureWidth + margin), 80)
};
this.Controls.Add(cameraPanel);
// 相机标题
Label cameraTitle = new Label
{
Text = $"相机 {i + 1}",
Font = new Font("Microsoft YaHei", 14, FontStyle.Bold),
ForeColor = Color.FromArgb(0, 112, 192),
Size = new Size(200, 30),
Location = new Point(10, 10),
TextAlign = ContentAlignment.MiddleLeft
};
cameraPanel.Controls.Add(cameraTitle);
// 状态标签
statusLabels[i] = new Label
{
Text = "状态:未连接",
Font = new Font("Microsoft YaHei", 10),
ForeColor = Color.Red,
Size = new Size(200, 25),
Location = new Point(10, 45),
TextAlign = ContentAlignment.MiddleLeft
};
cameraPanel.Controls.Add(statusLabels[i]);
// 图像显示区域
pictureBoxes[i] = new PictureBox
{
Size = new Size(pictureWidth - 40, pictureHeight),
Location = new Point(20, 80),
BackColor = Color.Black,
SizeMode = PictureBoxSizeMode.StretchImage,
BorderStyle = BorderStyle.FixedSingle
};
cameraPanel.Controls.Add(pictureBoxes[i]);
}
AddBackButton();
}
private void AddBackButton()
{
Button btnBack = new Button
{
Text = "返回",
Size = new Size(100, 40),
Location = new Point(1750, 30),
Font = new Font("Microsoft YaHei", 12),
BackColor = Color.FromArgb(0, 112, 192),
ForeColor = Color.White,
FlatStyle = FlatStyle.Flat
};
btnBack.Click += (s, e) =>
{
// 触发返回事件
OnReturnRequested?.Invoke();
// 关闭当前窗体
this.Close();
};
this.Controls.Add(btnBack);
}
/// <summary>
/// 初始化相机系统
/// </summary>
private void InitializeCameras()
{
try
{
UpdateSystemStatus("正在初始化SDK...");
// 等待窗体完全加载
Application.DoEvents();
Thread.Sleep(500);
// 1. 初始化SDK
int ret = MyCamera.MV_CC_Initialize_NET();
if (ret != MyCamera.MV_OK)
{
MessageBox.Show($"SDK初始化失败错误代码: {ret}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
UpdateSystemStatus("正在枚举设备...");
// 2. 枚举设备
ret = MyCamera.MV_CC_EnumDevices_NET(
MyCamera.MV_GIGE_DEVICE | MyCamera.MV_USB_DEVICE,
ref deviceList);
if (ret != MyCamera.MV_OK)
{
MessageBox.Show($"设备枚举失败,错误代码: {ret}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
// 3. 检查设备数量
if (deviceList.nDeviceNum < MAX_CAMERAS)
{
MessageBox.Show($"检测到 {deviceList.nDeviceNum} 个设备,需要至少 {MAX_CAMERAS} 个相机",
"错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
UpdateSystemStatus($"检测到 {deviceList.nDeviceNum} 个设备,准备初始化前 {MAX_CAMERAS} 个相机...");
// 4. 逐个初始化相机 - 增加间隔时间
for (int i = 0; i < MAX_CAMERAS; i++)
{
if (InitializeSingleCamera(i))
{
UpdateCameraStatus(i, "设备已就绪", Color.Blue);
}
Thread.Sleep(1000); // 增加间隔,避免同时打开冲突
}
_camerasInitialized = true;
UpdateSystemStatus("所有相机已初始化就绪,等待测试开始...");
// 5. 启动状态检查线程 - 延迟启动
Thread.Sleep(1000);
StartStatusCheckThread();
}
catch (Exception ex)
{
MessageBox.Show($"初始化系统时发生异常: {ex.Message}", "异常", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
/// <summary>
/// 启动状态检查线程
/// </summary>
private void StartStatusCheckThread()
{
_statusCheckThread = new Thread(CheckRunStatusLoop)
{
IsBackground = true
};
_statusCheckThread.Start();
}
/// <summary>
/// 状态检查循环 - 添加异常处理
/// </summary>
private void CheckRunStatusLoop()
{
bool lastStatus = false;
while (!this.IsDisposed && _camerasInitialized)
{
try
{
bool currentStatus = _getRunStatusCallback?.Invoke() ?? false;
if (currentStatus != lastStatus)
{
lastStatus = currentStatus;
// 使用TryInvoke避免窗体已关闭时的异常
if (!this.IsDisposed && this.IsHandleCreated)
{
this.BeginInvoke(new Action(() =>
{
try
{
if (currentStatus)
{
StartAllCamerasCapture();
}
else
{
StopAllCamerasCapture();
}
}
catch (Exception ex)
{
Console.WriteLine($"状态切换异常: {ex.Message}");
}
}));
}
}
Thread.Sleep(1000); // 延长检查间隔减少CPU使用
}
catch
{
// 忽略异常
}
}
}
/// <summary>
/// 开始所有相机采集
/// </summary>
private void StartAllCamerasCapture()
{
if (!_camerasInitialized) return;
UpdateSystemStatus("测试开始,正在启动相机采集...");
for (int i = 0; i < MAX_CAMERAS; i++)
{
if (cameras[i] != null && !grabbingFlags[i])
{
StartSingleCameraCapture(i);
}
}
UpdateSystemStatus("所有相机已开始采集");
}
/// <summary>
/// 停止所有相机采集
/// </summary>
private void StopAllCamerasCapture()
{
if (!_camerasInitialized) return;
UpdateSystemStatus("测试结束,正在停止相机采集...");
for (int i = 0; i < MAX_CAMERAS; i++)
{
if (cameras[i] != null && grabbingFlags[i])
{
StopSingleCameraCapture(i);
}
}
UpdateSystemStatus("所有相机已停止采集");
}
/// <summary>
/// 初始化单个相机
/// </summary>
private bool InitializeSingleCamera(int cameraIndex)
{
try
{
UpdateCameraStatus(cameraIndex, "正在打开...", Color.Orange);
// 1. 创建设备信息
MyCamera.MV_CC_DEVICE_INFO device =
(MyCamera.MV_CC_DEVICE_INFO)Marshal.PtrToStructure(
deviceList.pDeviceInfo[cameraIndex], typeof(MyCamera.MV_CC_DEVICE_INFO));
// 2. 创建相机对象
cameras[cameraIndex] = new MyCamera();
// 3. 创建设备
int ret = cameras[cameraIndex].MV_CC_CreateDevice_NET(ref device);
if (ret != MyCamera.MV_OK)
{
UpdateCameraStatus(cameraIndex, $"创建设备失败: {ret}", Color.Red);
return false;
}
// 4. 打开设备
ret = cameras[cameraIndex].MV_CC_OpenDevice_NET();
if (ret != MyCamera.MV_OK)
{
cameras[cameraIndex].MV_CC_DestroyDevice_NET();
UpdateCameraStatus(cameraIndex, $"打开设备失败: {ret}", Color.Red);
return false;
}
// 5. 如果是千兆网相机,设置最优包大小
if (device.nTLayerType == MyCamera.MV_GIGE_DEVICE)
{
int packetSize = cameras[cameraIndex].MV_CC_GetOptimalPacketSize_NET();
if (packetSize > 0)
{
cameras[cameraIndex].MV_CC_SetIntValueEx_NET("GevSCPSPacketSize", packetSize);
}
}
// 6. 设置采集模式
cameras[cameraIndex].MV_CC_SetEnumValue_NET("AcquisitionMode",
(uint)MyCamera.MV_CAM_ACQUISITION_MODE.MV_ACQ_MODE_CONTINUOUS);
cameras[cameraIndex].MV_CC_SetEnumValue_NET("TriggerMode",
(uint)MyCamera.MV_CAM_TRIGGER_MODE.MV_TRIGGER_MODE_OFF);
return true;
}
catch (Exception ex)
{
UpdateCameraStatus(cameraIndex, $"异常: {ex.Message}", Color.Red);
return false;
}
}
private void StartSingleCameraCapture(int cameraIndex)
{
try
{
if (cameras[cameraIndex] == null || grabbingFlags[cameraIndex])
return;
// 检查相机是否已正确打开
if (!IsCameraValid(cameraIndex))
{
UpdateCameraStatus(cameraIndex, "相机未正确初始化", Color.Red);
return;
}
// 1. 准备采集资源
if (!PrepareForGrabbing(cameraIndex))
{
UpdateCameraStatus(cameraIndex, "采集准备失败", Color.Red);
return;
}
// 2. 设置采集标志
grabbingFlags[cameraIndex] = true;
// 3. 创建采集线程
int index = cameraIndex;
grabThreads[cameraIndex] = new Thread(() => GrabThreadProc(index));
grabThreads[cameraIndex].Name = $"CameraGrabThread_{cameraIndex}";
grabThreads[cameraIndex].IsBackground = true;
// 启动线程
grabThreads[cameraIndex].Start();
// 等待线程启动
Thread.Sleep(100);
// 4. 开始采集
int ret = cameras[cameraIndex].MV_CC_StartGrabbing_NET();
if (ret != MyCamera.MV_OK)
{
UpdateCameraStatus(cameraIndex, $"开始采集失败: {ret}", Color.Red);
grabbingFlags[cameraIndex] = false;
return;
}
UpdateCameraStatus(cameraIndex, "正在采集...", Color.Green);
}
catch (Exception ex)
{
UpdateCameraStatus(cameraIndex, $"开始采集异常: {ex.Message}", Color.Red);
Console.WriteLine($"启动相机{cameraIndex + 1}异常: {ex.ToString()}");
}
}
/// <summary>
/// 检查相机是否有效
/// </summary>
private bool IsCameraValid(int cameraIndex)
{
try
{
return cameras[cameraIndex] != null;
}
catch
{
return false;
}
}
/// <summary>
/// 停止单个相机采集
/// </summary>
private void StopSingleCameraCapture(int cameraIndex)
{
try
{
if (cameras[cameraIndex] == null || !grabbingFlags[cameraIndex])
return;
// 1. 停止采集标志
grabbingFlags[cameraIndex] = false;
// 2. 等待采集线程结束
if (grabThreads[cameraIndex] != null && grabThreads[cameraIndex].IsAlive)
{
grabThreads[cameraIndex].Join(1000);
}
// 3. 停止相机采集
cameras[cameraIndex].MV_CC_StopGrabbing_NET();
// 4. 清理资源
CleanupCameraResources(cameraIndex);
UpdateCameraStatus(cameraIndex, "已停止采集", Color.Blue);
}
catch (Exception ex)
{
UpdateCameraStatus(cameraIndex, $"停止采集异常: {ex.Message}", Color.Red);
}
}
private bool PrepareForGrabbing(int cameraIndex)
{
try
{
// 获取图像参数
MyCamera.MVCC_INTVALUE_EX width = new MyCamera.MVCC_INTVALUE_EX();
int ret = cameras[cameraIndex].MV_CC_GetIntValueEx_NET("Width", ref width);
if (ret != MyCamera.MV_OK) return false;
MyCamera.MVCC_INTVALUE_EX height = new MyCamera.MVCC_INTVALUE_EX();
ret = cameras[cameraIndex].MV_CC_GetIntValueEx_NET("Height", ref height);
if (ret != MyCamera.MV_OK) return false;
MyCamera.MVCC_ENUMVALUE pixelFormat = new MyCamera.MVCC_ENUMVALUE();
ret = cameras[cameraIndex].MV_CC_GetEnumValue_NET("PixelFormat", ref pixelFormat);
if (ret != MyCamera.MV_OK) return false;
// 创建Bitmap
PixelFormat bitmapFormat = IsMonoPixelFormat(pixelFormat.nCurValue) ?
PixelFormat.Format8bppIndexed : PixelFormat.Format24bppRgb;
// 确保清理旧的Bitmap
if (displayBitmaps[cameraIndex] != null)
{
displayBitmaps[cameraIndex].Dispose();
displayBitmaps[cameraIndex] = null;
}
// 创建新的Bitmap
displayBitmaps[cameraIndex] = new Bitmap((int)width.nCurValue, (int)height.nCurValue, bitmapFormat);
// 如果是8位灰度图设置调色板
if (bitmapFormat == PixelFormat.Format8bppIndexed)
{
ColorPalette palette = displayBitmaps[cameraIndex].Palette;
for (int i = 0; i < palette.Entries.Length; i++)
{
palette.Entries[i] = Color.FromArgb(i, i, i);
}
displayBitmaps[cameraIndex].Palette = palette;
}
// 分配显示缓冲区
uint bufferSize = bitmapFormat == PixelFormat.Format8bppIndexed ?
(uint)(width.nCurValue * height.nCurValue) :
(uint)(width.nCurValue * height.nCurValue * 3);
// 确保清理旧的缓冲区
if (displayBufs[cameraIndex] != IntPtr.Zero)
{
Marshal.FreeHGlobal(displayBufs[cameraIndex]);
displayBufs[cameraIndex] = IntPtr.Zero;
}
displayBufs[cameraIndex] = Marshal.AllocHGlobal((int)bufferSize);
displayBufSizes[cameraIndex] = bufferSize;
frameInfos[cameraIndex] = new MyCamera.MV_FRAME_OUT_INFO_EX();
return true;
}
catch (Exception ex)
{
Console.WriteLine($"准备相机{cameraIndex + 1}失败: {ex.Message}");
return false;
}
}
/// <summary>
/// 判断是否为单色像素格式
/// </summary>
private bool IsMonoPixelFormat(uint pixelFormat)
{
switch (pixelFormat)
{
case (uint)MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono8:
case (uint)MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono10:
case (uint)MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono12:
case (uint)MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono10_Packed:
case (uint)MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono12_Packed:
return true;
default:
return false;
}
}
///// <summary>
///// 采集线程处理函数 - 简化版本
///// </summary>
//private void GrabThreadProc(int cameraIndex)
//{
// MyCamera camera = cameras[cameraIndex];
// MyCamera.MV_FRAME_OUT frameOut = new MyCamera.MV_FRAME_OUT();
// MyCamera.MV_PIXEL_CONVERT_PARAM convertParam = new MyCamera.MV_PIXEL_CONVERT_PARAM();
// MyCamera.MV_DISPLAY_FRAME_INFO displayInfo = new MyCamera.MV_DISPLAY_FRAME_INFO();
// // 帧率控制变量(新增)
// int framesWritten = 0;
// DateTime lastWriteTime = DateTime.Now;
// while (grabbingFlags[cameraIndex])
// {
// try
// {
// // 获取图像缓冲区
// int ret = camera.MV_CC_GetImageBuffer_NET(ref frameOut, 1000);
// if (ret == MyCamera.MV_OK)
// {
// lock (locks[cameraIndex])
// {
// // 更新帧信息
// frameInfos[cameraIndex] = frameOut.stFrameInfo;
// // 像素格式转换
// convertParam.nWidth = frameOut.stFrameInfo.nWidth;
// convertParam.nHeight = frameOut.stFrameInfo.nHeight;
// convertParam.enSrcPixelType = frameOut.stFrameInfo.enPixelType;
// convertParam.pSrcData = frameOut.pBufAddr;
// convertParam.nSrcDataLen = frameOut.stFrameInfo.nFrameLen;
// convertParam.pDstBuffer = displayBufs[cameraIndex];
// convertParam.nDstBufferSize = displayBufSizes[cameraIndex];
// if (displayBitmaps[cameraIndex].PixelFormat == PixelFormat.Format8bppIndexed)
// {
// convertParam.enDstPixelType = MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono8;
// }
// else
// {
// convertParam.enDstPixelType = MyCamera.MvGvspPixelType.PixelType_Gvsp_BGR8_Packed;
// }
// camera.MV_CC_ConvertPixelType_NET(ref convertParam);
// // 简单方案直接更新现有的Bitmap不创建新实例
// BitmapData bitmapData = displayBitmaps[cameraIndex].LockBits(
// new Rectangle(0, 0, (int)frameOut.stFrameInfo.nWidth, (int)frameOut.stFrameInfo.nHeight),
// ImageLockMode.ReadWrite, displayBitmaps[cameraIndex].PixelFormat);
// CopyMemory(bitmapData.Scan0, convertParam.pDstBuffer,
// (uint)(bitmapData.Stride * displayBitmaps[cameraIndex].Height));
// displayBitmaps[cameraIndex].UnlockBits(bitmapData);
// }
// // 使用SDK显示 - 这是最稳定的方式
// displayInfo.hWnd = pictureBoxes[cameraIndex].Handle;
// displayInfo.pData = frameOut.pBufAddr;
// displayInfo.nDataLen = frameOut.stFrameInfo.nFrameLen;
// displayInfo.nWidth = frameOut.stFrameInfo.nWidth;
// displayInfo.nHeight = frameOut.stFrameInfo.nHeight;
// displayInfo.enPixelType = frameOut.stFrameInfo.enPixelType;
// // 在UI线程中调用显示
// if (this.InvokeRequired)
// {
// this.Invoke(new Action(() =>
// {
// camera.MV_CC_DisplayOneFrame_NET(ref displayInfo);
// }));
// }
// else
// {
// camera.MV_CC_DisplayOneFrame_NET(ref displayInfo);
// }
// // 释放图像缓冲区
// camera.MV_CC_FreeImageBuffer_NET(ref frameOut);
// }
// }
// catch (Exception ex)
// {
// Console.WriteLine($"相机{cameraIndex + 1}采集异常: {ex.Message}");
// // 继续循环,不退出
// }
// }
//}
/// <summary>
/// 采集线程处理函数 - 添加视频录制(修改)
/// </summary>
private void GrabThreadProc(int cameraIndex)
{
MyCamera camera = cameras[cameraIndex];
MyCamera.MV_FRAME_OUT frameOut = new MyCamera.MV_FRAME_OUT();
MyCamera.MV_PIXEL_CONVERT_PARAM convertParam = new MyCamera.MV_PIXEL_CONVERT_PARAM();
MyCamera.MV_DISPLAY_FRAME_INFO displayInfo = new MyCamera.MV_DISPLAY_FRAME_INFO();
// 帧率控制变量(新增)
int framesWritten = 0;
DateTime lastWriteTime = DateTime.Now;
while (grabbingFlags[cameraIndex])
{
try
{
// 获取图像缓冲区
int ret = camera.MV_CC_GetImageBuffer_NET(ref frameOut, 1000);
if (ret == MyCamera.MV_OK)
{
lock (locks[cameraIndex])
{
// 更新帧信息
frameInfos[cameraIndex] = frameOut.stFrameInfo;
// 像素格式转换
convertParam.nWidth = frameOut.stFrameInfo.nWidth;
convertParam.nHeight = frameOut.stFrameInfo.nHeight;
convertParam.enSrcPixelType = frameOut.stFrameInfo.enPixelType;
convertParam.pSrcData = frameOut.pBufAddr;
convertParam.nSrcDataLen = frameOut.stFrameInfo.nFrameLen;
convertParam.pDstBuffer = displayBufs[cameraIndex];
convertParam.nDstBufferSize = displayBufSizes[cameraIndex];
if (displayBitmaps[cameraIndex].PixelFormat == PixelFormat.Format8bppIndexed)
{
convertParam.enDstPixelType = MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono8;
}
else
{
convertParam.enDstPixelType = MyCamera.MvGvspPixelType.PixelType_Gvsp_BGR8_Packed;
}
camera.MV_CC_ConvertPixelType_NET(ref convertParam);
// 更新Bitmap
BitmapData bitmapData = displayBitmaps[cameraIndex].LockBits(
new Rectangle(0, 0, (int)frameOut.stFrameInfo.nWidth, (int)frameOut.stFrameInfo.nHeight),
ImageLockMode.ReadWrite, displayBitmaps[cameraIndex].PixelFormat);
CopyMemory(bitmapData.Scan0, convertParam.pDstBuffer,
(uint)(bitmapData.Stride * displayBitmaps[cameraIndex].Height));
displayBitmaps[cameraIndex].UnlockBits(bitmapData);
}
// 使用SDK显示
displayInfo.hWnd = pictureBoxes[cameraIndex].Handle;
displayInfo.pData = frameOut.pBufAddr;
displayInfo.nDataLen = frameOut.stFrameInfo.nFrameLen;
displayInfo.nWidth = frameOut.stFrameInfo.nWidth;
displayInfo.nHeight = frameOut.stFrameInfo.nHeight;
displayInfo.enPixelType = frameOut.stFrameInfo.enPixelType;
// 在UI线程中调用显示
if (this.InvokeRequired)
{
this.Invoke(new Action(() =>
{
camera.MV_CC_DisplayOneFrame_NET(ref displayInfo);
}));
}
else
{
camera.MV_CC_DisplayOneFrame_NET(ref displayInfo);
}
// 释放图像缓冲区
camera.MV_CC_FreeImageBuffer_NET(ref frameOut);
}
}
catch (Exception ex)
{
Console.WriteLine($"相机{cameraIndex + 1}采集异常: {ex.Message}");
// 继续循环,不退出
}
}
}
/// <summary>
/// 清理相机资源(修改)
/// </summary>
private void CleanupCameraResources(int cameraIndex)
{
// 清理显示缓冲区
if (displayBufs[cameraIndex] != IntPtr.Zero)
{
Marshal.FreeHGlobal(displayBufs[cameraIndex]);
displayBufs[cameraIndex] = IntPtr.Zero;
}
// 清理Bitmap
if (displayBitmaps[cameraIndex] != null)
{
displayBitmaps[cameraIndex].Dispose();
displayBitmaps[cameraIndex] = null;
}
displayBufSizes[cameraIndex] = 0;
}
/// <summary>
/// 更新相机状态显示
/// </summary>
private void UpdateCameraStatus(int cameraIndex, string message, Color color)
{
if (statusLabels[cameraIndex].InvokeRequired)
{
statusLabels[cameraIndex].Invoke(new Action(() =>
{
statusLabels[cameraIndex].Text = $"状态:{message}";
statusLabels[cameraIndex].ForeColor = color;
}));
}
else
{
statusLabels[cameraIndex].Text = $"状态:{message}";
statusLabels[cameraIndex].ForeColor = color;
}
}
/// <summary>
/// 更新系统状态
/// </summary>
private void UpdateSystemStatus(string message)
{
// 这里可以添加系统状态栏更新逻辑
Console.WriteLine($"系统状态: {message}");
}
/// <summary>
/// 窗体关闭时的清理工作
/// </summary>
private void AutoCameraForm_FormClosing(object sender, FormClosingEventArgs e)
{
try
{
// 停止状态检查线程
if (_statusCheckThread != null && _statusCheckThread.IsAlive)
{
_statusCheckThread.Join(1000);
}
// 停止所有采集线程
for (int i = 0; i < MAX_CAMERAS; i++)
{
grabbingFlags[i] = false;
if (grabThreads[i] != null && grabThreads[i].IsAlive)
{
grabThreads[i].Join(1000);
}
if (cameras[i] != null)
{
cameras[i].MV_CC_StopGrabbing_NET();
cameras[i].MV_CC_CloseDevice_NET();
cameras[i].MV_CC_DestroyDevice_NET();
}
CleanupCameraResources(i);
}
// 反初始化SDK
MyCamera.MV_CC_Finalize_NET();
}
catch (Exception ex)
{
MessageBox.Show($"清理资源时发生异常: {ex.Message}", "警告",
MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
}
}