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); // 傳遞設備信息}}
}