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);
}
#endregion
private 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); // 传递设备信息
}
}
}