c# winform 调用 海康威视工业相机(又全又细又简洁)
1.准备一个海康相机
从垃圾桶里翻出来一个USB口相机。
2.下载MVS 和SDK
海康机器人-机器视觉-下载中心
mvs:
sdk:
用MVS 调试一下,能连接就行。
海康威视相机,MVS连接成功,但无图像怎么办?-CSDN博客
3.打开VS,创建一个新项目
添加引用,点击浏览,找到 MvCameraControl.Net.dll。
MvCameraControl.Net.dll文件,在MVS的安装目录,路径:MVS\MVS\Development\DotNet
注意根据c#
选择win32 win64 还是anycpu。
在form1.cs中using MvCamCtrl.NET;
然后添加一些控件
定义枚举相机函数,把他放到 “寻找相机”事件中
然后,把枚举的相机 都写入 下拉框。
此阶段代码如下:
form1.cs
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using MvCamCtrl.NET;namespace test_HKCamera
{public partial class Form1 : Form{MyCamera device = new MyCamera();public static MyCamera.MV_CC_DEVICE_INFO_LIST stDevList = new MyCamera.MV_CC_DEVICE_INFO_LIST();public Form1(){InitializeComponent();}public List<string> ListDevices()//枚举相机{List<string> result = new List<string>();/**/if (MyCamera.MV_OK != MyCamera.MV_CC_EnumDevices_NET(MyCamera.MV_GIGE_DEVICE | MyCamera.MV_USB_DEVICE, ref stDevList)){MessageBox.Show("枚举设备失败");return null;}if (0 == stDevList.nDeviceNum){// MessageBox.Show("未找到设备");return null;}MyCamera.MV_CC_DEVICE_INFO stDevInfo;for (int i = 0; i < stDevList.nDeviceNum; i++){stDevInfo = (MyCamera.MV_CC_DEVICE_INFO)Marshal.PtrToStructure(stDevList.pDeviceInfo[i], typeof(MyCamera.MV_CC_DEVICE_INFO));if (stDevInfo.nTLayerType == MyCamera.MV_GIGE_DEVICE){// 网口USB设备处理IntPtr buffer = Marshal.UnsafeAddrOfPinnedArrayElement(stDevInfo.SpecialInfo.stGigEInfo, 0);MyCamera.MV_GIGE_DEVICE_INFO gigeInfo = (MyCamera.MV_GIGE_DEVICE_INFO)Marshal.PtrToStructure(buffer, typeof(MyCamera.MV_GIGE_DEVICE_INFO));result.Add(gigeInfo.chSerialNumber);}else if (stDevInfo.nTLayerType == MyCamera.MV_USB_DEVICE){// USB设备处理IntPtr buffer = Marshal.UnsafeAddrOfPinnedArrayElement(stDevInfo.SpecialInfo.stUsb3VInfo, 0);MyCamera.MV_USB3_DEVICE_INFO usbInfo = (MyCamera.MV_USB3_DEVICE_INFO)Marshal.PtrToStructure(buffer,typeof(MyCamera.MV_USB3_DEVICE_INFO));result.Add(usbInfo.chSerialNumber);}}return result;}private void button_find_Click(object sender, EventArgs e)//寻找相机按钮{List<string> lstdevices = ListDevices();if (lstdevices == null){MessageBox.Show("无相机");}else{MessageBox.Show("已找到设备");foreach (string device in lstdevices){comboBox1.Items.Add(device);//找到的设备写入下拉框}}comboBox1.Enabled = true;}private void button_takephoto_Click(object sender, EventArgs e)//拍照按钮{}}
}
form1.designer.cs
namespace test_HKCamera
{partial class Form1{/// <summary>/// Required designer variable./// </summary>private System.ComponentModel.IContainer components = null;/// <summary>/// Clean up any resources being used./// </summary>/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>protected override void Dispose(bool disposing){if (disposing && (components != null)){components.Dispose();}base.Dispose(disposing);}#region Windows Form Designer generated code/// <summary>/// Required method for Designer support - do not modify/// the contents of this method with the code editor./// </summary>private void InitializeComponent(){button_find = new Button();comboBox1 = new ComboBox();button_takephoto = new Button();pictureBox1 = new PictureBox();((System.ComponentModel.ISupportInitialize)pictureBox1).BeginInit();SuspendLayout();// // button_find// button_find.Location = new Point(248, 178);button_find.Name = "button_find";button_find.Size = new Size(227, 98);button_find.TabIndex = 0;button_find.Text = "寻找相机";button_find.UseVisualStyleBackColor = true;button_find.Click += button_find_Click;// // comboBox1// comboBox1.FormattingEnabled = true;comboBox1.Location = new Point(169, 437);comboBox1.Name = "comboBox1";comboBox1.Size = new Size(400, 32);comboBox1.TabIndex = 1;// // button_takephoto// button_takephoto.Location = new Point(235, 668);button_takephoto.Name = "button_takephoto";button_takephoto.Size = new Size(240, 92);button_takephoto.TabIndex = 2;button_takephoto.Text = "拍照";button_takephoto.UseVisualStyleBackColor = true;button_takephoto.Click += button_takephoto_Click;// // pictureBox1// pictureBox1.Location = new Point(698, 141);pictureBox1.Name = "pictureBox1";pictureBox1.Size = new Size(800, 600);pictureBox1.TabIndex = 3;pictureBox1.TabStop = false;// // Form1// AutoScaleDimensions = new SizeF(11F, 24F);AutoScaleMode = AutoScaleMode.Font;ClientSize = new Size(1597, 918);Controls.Add(pictureBox1);Controls.Add(button_takephoto);Controls.Add(comboBox1);Controls.Add(button_find);Name = "Form1";Text = "Form1";((System.ComponentModel.ISupportInitialize)pictureBox1).EndInit();ResumeLayout(false);}#endregionprivate Button button_find;private ComboBox comboBox1;private Button button_takephoto;private PictureBox pictureBox1;}
}
运行
接下来完善拍照功能。
修改button_find_Click
遍历SDK返回的原始设备列表,保存设备信息到 _deviceList
for (int i = 0; i < stDevList.nDeviceNum; i++)
{
var devInfo = (MyCamera.MV_CC_DEVICE_INFO)Marshal.PtrToStructure(
stDevList.pDeviceInfo[i],
typeof(MyCamera.MV_CC_DEVICE_INFO)
);
_deviceList.Add(devInfo);
增加 oneshot功能:
创建设备对象:实例化MyCamera对象,用于后续操作。
创建设备句柄:调用MV_CC_CreateDevice_NET,传入选中的设备信息,创建设备句柄。
打开设备:使用MV_CC_OpenDevice_NET以独占模式打开设备。
开始采集图像:调用MV_CC_StartGrabbing_NET启动图像采集。
获取图像参数:通过MV_CC_GetIntValue_NET获取PayloadSize,即图像数据的大小。
分配缓冲区:使用Marshal.AllocHGlobal分配非托管内存,用于存储图像数据。
获取单帧图像:调用MV_CC_GetOneFrameTimeout_NET,设置超时时间为1000毫秒,尝试获取一帧图像。
显示图像:如果成功获取图像数据,填充MV_DISPLAY_FRAME_INFO结构体,并调用MV_CC_DisplayOneFrame_NET显示图像。
释放资源:释放之前分配的非托管内存缓冲区。
finally块:确保在方法执行完毕后,无论是否发生异常,都会停止采集、关闭设备并销毁设备句柄
public void OneShot(PictureBox pictureBox, MyCamera.MV_CC_DEVICE_INFO selectedDevice){MyCamera device = new MyCamera();int nRet = MyCamera.MV_OK;try{// 直接使用传入的设备信息nRet = device.MV_CC_CreateDevice_NET(ref selectedDevice);if (nRet != MyCamera.MV_OK){MessageBox.Show($"创建设备失败: 0x{nRet:X8}");return;}nRet = device.MV_CC_OpenDevice_NET(MyCamera.MV_ACCESS_Exclusive, 0);if (nRet != MyCamera.MV_OK){MessageBox.Show($"打开设备失败: 0x{nRet:X8}");return;}nRet = device.MV_CC_StartGrabbing_NET();if (nRet != MyCamera.MV_OK){MessageBox.Show($"开始采集失败: 0x{nRet:X8}");return;}// 获取图像参数MyCamera.MVCC_INTVALUE stParam = new MyCamera.MVCC_INTVALUE();nRet = device.MV_CC_GetIntValue_NET("PayloadSize", ref stParam);if (nRet != MyCamera.MV_OK){MessageBox.Show($"获取图像大小失败: 0x{nRet:X8}");return;}// 分配缓冲区IntPtr pBuf = Marshal.AllocHGlobal((int)stParam.nCurValue);MyCamera.MV_FRAME_OUT_INFO_EX frameInfo = new MyCamera.MV_FRAME_OUT_INFO_EX();// 获取单帧图像nRet = device.MV_CC_GetOneFrameTimeout_NET(pBuf, stParam.nCurValue, ref frameInfo, 1000);if (nRet == MyCamera.MV_OK){// 显示图像MyCamera.MV_DISPLAY_FRAME_INFO displayInfo = new MyCamera.MV_DISPLAY_FRAME_INFO{hWnd = pictureBox.Handle,pData = pBuf,nDataLen = frameInfo.nFrameLen,nWidth = frameInfo.nWidth,nHeight = frameInfo.nHeight,enPixelType = frameInfo.enPixelType};device.MV_CC_DisplayOneFrame_NET(ref displayInfo);}else{MessageBox.Show($"获取图像超时: 0x{nRet:X8}");}// 释放资源Marshal.FreeHGlobal(pBuf);}finally{// 确保资源释放if (device != null){device.MV_CC_StopGrabbing_NET();device.MV_CC_CloseDevice_NET();device.MV_CC_DestroyDevice_NET();}}}
在“拍照事件”中,传入
private void button_takephoto_Click(object sender, EventArgs e)//拍照按钮
{
try {
_selectedDeviceInfo = _deviceList[comboBox1.SelectedIndex];
} catch {
MessageBox.Show("请选择相机");
}
OneShot(pictureBox1, _selectedDeviceInfo); // 传递设备信息
}
运行后:
图像很黑,设置一下曝光
nRet = device.MV_CC_SetFloatValue_NET("ExposureTime", 15000);//设置曝光时间
运行后:
完整代码
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using MvCamCtrl.NET;namespace test_HKCamera
{public partial class Form1 : Form{//用于临时存储通过海康SDK枚举到的原始设备列表public static MyCamera.MV_CC_DEVICE_INFO_LIST stDevList = new MyCamera.MV_CC_DEVICE_INFO_LIST();//从下拉框 comboBox1 中选择的设备信息private MyCamera.MV_CC_DEVICE_INFO _selectedDeviceInfo;//保存当前枚举到的所有设备信息||下拉框 comboBox1 的选项List<MyCamera.MV_CC_DEVICE_INFO> _deviceList = new List<MyCamera.MV_CC_DEVICE_INFO>();public Form1(){InitializeComponent();}public List<string> ListDevices()//枚举相机{List<string> result = new List<string>();/**/if (MyCamera.MV_OK != MyCamera.MV_CC_EnumDevices_NET(MyCamera.MV_GIGE_DEVICE | MyCamera.MV_USB_DEVICE, ref stDevList)){MessageBox.Show("枚举设备失败");return null;}if (0 == stDevList.nDeviceNum){// MessageBox.Show("未找到设备");return null;}MyCamera.MV_CC_DEVICE_INFO stDevInfo;for (int i = 0; i < stDevList.nDeviceNum; i++){stDevInfo = (MyCamera.MV_CC_DEVICE_INFO)Marshal.PtrToStructure(stDevList.pDeviceInfo[i], typeof(MyCamera.MV_CC_DEVICE_INFO));if (stDevInfo.nTLayerType == MyCamera.MV_GIGE_DEVICE){// 网口USB设备处理IntPtr buffer = Marshal.UnsafeAddrOfPinnedArrayElement(stDevInfo.SpecialInfo.stGigEInfo, 0);MyCamera.MV_GIGE_DEVICE_INFO gigeInfo = (MyCamera.MV_GIGE_DEVICE_INFO)Marshal.PtrToStructure(buffer, typeof(MyCamera.MV_GIGE_DEVICE_INFO));result.Add(gigeInfo.chSerialNumber);}else if (stDevInfo.nTLayerType == MyCamera.MV_USB_DEVICE){// USB设备处理IntPtr buffer = Marshal.UnsafeAddrOfPinnedArrayElement(stDevInfo.SpecialInfo.stUsb3VInfo, 0);MyCamera.MV_USB3_DEVICE_INFO usbInfo = (MyCamera.MV_USB3_DEVICE_INFO)Marshal.PtrToStructure(buffer,typeof(MyCamera.MV_USB3_DEVICE_INFO));result.Add(usbInfo.chSerialNumber);}}return result;}public void OneShot(PictureBox pictureBox, MyCamera.MV_CC_DEVICE_INFO selectedDevice){MyCamera device = new MyCamera();int nRet = MyCamera.MV_OK;try{// 直接使用传入的设备信息nRet = device.MV_CC_CreateDevice_NET(ref selectedDevice);if (nRet != MyCamera.MV_OK){MessageBox.Show($"创建设备失败: 0x{nRet:X8}");return;}nRet = device.MV_CC_OpenDevice_NET(MyCamera.MV_ACCESS_Exclusive, 0);if (nRet != MyCamera.MV_OK){MessageBox.Show($"打开设备失败: 0x{nRet:X8}");return;}nRet = device.MV_CC_StartGrabbing_NET();if (nRet != MyCamera.MV_OK){MessageBox.Show($"开始采集失败: 0x{nRet:X8}");return;}//nRet = device.MV_CC_SetFloatValue_NET("ExposureTime", 15000);//设置曝光时间// 获取图像参数MyCamera.MVCC_INTVALUE stParam = new MyCamera.MVCC_INTVALUE();nRet = device.MV_CC_GetIntValue_NET("PayloadSize", ref stParam);if (nRet != MyCamera.MV_OK){MessageBox.Show($"获取图像大小失败: 0x{nRet:X8}");return;}// 分配缓冲区IntPtr pBuf = Marshal.AllocHGlobal((int)stParam.nCurValue);MyCamera.MV_FRAME_OUT_INFO_EX frameInfo = new MyCamera.MV_FRAME_OUT_INFO_EX();// 获取单帧图像nRet = device.MV_CC_GetOneFrameTimeout_NET(pBuf, stParam.nCurValue, ref frameInfo, 1000);if (nRet == MyCamera.MV_OK){// 显示图像MyCamera.MV_DISPLAY_FRAME_INFO displayInfo = new MyCamera.MV_DISPLAY_FRAME_INFO{hWnd = pictureBox.Handle,pData = pBuf,nDataLen = frameInfo.nFrameLen,nWidth = frameInfo.nWidth,nHeight = frameInfo.nHeight,enPixelType = frameInfo.enPixelType};device.MV_CC_DisplayOneFrame_NET(ref displayInfo);}else{MessageBox.Show($"获取图像超时: 0x{nRet:X8}");}// 释放资源Marshal.FreeHGlobal(pBuf);}finally{// 确保资源释放if (device != null){device.MV_CC_StopGrabbing_NET();device.MV_CC_CloseDevice_NET();device.MV_CC_DestroyDevice_NET();}}}private void button_find_Click(object sender, EventArgs e)//寻找相机按钮{List<string> lstdevices = ListDevices();if (lstdevices == null){MessageBox.Show("无相机");}else{MessageBox.Show("已找到设备");foreach (string device in lstdevices){comboBox1.Items.Add(device);//找到的设备写入下拉框}for (int i = 0; i < stDevList.nDeviceNum; i++){var devInfo = (MyCamera.MV_CC_DEVICE_INFO)Marshal.PtrToStructure(stDevList.pDeviceInfo[i],typeof(MyCamera.MV_CC_DEVICE_INFO));_deviceList.Add(devInfo); }}comboBox1.Enabled = true;}private void button_takephoto_Click(object sender, EventArgs e)//拍照按钮{try {_selectedDeviceInfo = _deviceList[comboBox1.SelectedIndex];} catch {MessageBox.Show("请选择相机");}OneShot(pictureBox1, _selectedDeviceInfo); // 传递设备信息}}
}