一、通过VisionPro工具进行连续运行,不断的获取最终的结果实现实时画面;
1.1 VisionPro的自带工具
使用VisionPro工具获取实时画面是比较取巧的一种方式,不需要很复杂的代码即可实现,主要是通过运行VisionPro程序来或得结果,从而达到我们需要的画面,VisionPro里面自己携带了一个工具,名称:CogAcqFifoTool,这个工具是可以直接连接相机并可进行各种属性的保存,比如相机的曝光,增益等;
1.2 代码实现
如果只是获取实时画面在Toolblock里面添加这一个工具即可,然后在二次开发时,加载这个Toolblock的程序,再获取到CogAcqFifoTool工具的输出画面即可;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Cognex.VisionPro;
using Cognex.VisionPro.ToolBlock;
namespace Camera_Live
{
public partial class Form1 : Form
{
CogToolBlock toolBlock;//定义一个Toolblock变量
public Form1()
{
InitializeComponent();
}
/// <summary>
/// 实时画面的显示,打开相机
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OpenCamera_CheckedChanged(object sender, EventArgs e)
{
//1.加载Toolblock工具,需要包含有CogAcqFifoTool工具的程序
toolBlock = (CogToolBlock)CogSerializer.LoadObjectFromFile(vppPath.Text);
//2.获取到Vpp程序内的CogAcqFifoTool工具
CogAcqFifoTool fifoTool = toolBlock.Tools["CogAcqFifoTool1"] as CogAcqFifoTool;
//使用线程循环运行取得实时图像
Task.Run(() =>
{
do
{
//3.运行工具
fifoTool.Run();
//4.将工具的输出图片给显示的控件上
cogRecordDisplay1.Image = fifoTool.OutputImage;
//5.图像适应控件在中央
cogRecordDisplay1.AutoFit = true;
} while (OpenCamera.Checked);
});
}
/// <summary>
/// 关闭相机
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void CloseCamera_CheckedChanged(object sender, EventArgs e)
{
toolBlock.Dispose();
}
}
}
这里面我使用了两个radiobutton来实现了重复的运行CogAcqFifoTool,从而得到自己的实时画面;
1.3 USB3.0相机的实现方法
当然这是VisionPro自带的工具,这个工具主要还是针对的是网口的相机,像海康,大华,Balser等大牌都可以使用,但此工具不支持USB3.0的相机,而现在USB接口相机也比较的常用,那该怎么办呢?海康这边非常的照顾客户给我们提供了相应的工具,
按照文档提供的方法即可将工具添加进去了,使用方法和上面一样;在程序中使用这个工具是这样子的:
MvCameraAcqTool.MvCameraAcqTool mvCameraAcq;//相机变量
是不是很简单,哈哈!!!
二、通过相机的SDK开发从而实现实时画面;
2.1 SDK开发流程
这里就主要以海康相机SDK开发做介绍了,其他相机的大家根据各自的SDK说明开发就可以了。我们先来看下海康SDK开发文档的编程引导:
先要通过枚举的方式找到对应设备,在创建设备,打开设备,开始取流,后面可以传递给VisionPro控件;
2.2 代码实现
首先是枚举设备
/// <summary>
/// 枚举相机
/// </summary>
private void DeviceListAcq()
{
int nRet;
// ch:创建设备列表 || en: Create device list
System.GC.Collect();
//获取相机的列表,包含网口和U口相机
nRet = MyCamera.MV_CC_EnumDevices_NET(MyCamera.MV_GIGE_DEVICE | MyCamera.MV_USB_DEVICE, ref m_pDeviceList);
if (MyCamera.MV_OK != nRet)
{
MessageBox.Show("Enum Devices Fail");
return;
}
}
其次是打开设备
/// <summary>
/// 打开设备
/// </summary>
private void OpenCamera()
{
//判断是否有相机
if (m_pDeviceList.nDeviceNum == 0)
{
MessageBox.Show("No device,please select");
return;
}
//这里选择了第一个相机
MyCamera.MV_CC_DEVICE_INFO device =
(MyCamera.MV_CC_DEVICE_INFO)Marshal.PtrToStructure(m_pDeviceList.pDeviceInfo[0],
typeof(MyCamera.MV_CC_DEVICE_INFO));
int nRet = -1;
m_pMyCamera = new MyCamera();
//获取设备信息
nRet = m_pMyCamera.MV_CC_CreateDevice_NET(ref device);
if (MyCamera.MV_OK != nRet)
{
return;
}
// ch:打开设备 | en:Open device
nRet = m_pMyCamera.MV_CC_OpenDevice_NET();
if (MyCamera.MV_OK != nRet)
{
MessageBox.Show("Open Device Fail");
return;
}
// ch:获取包大小 || en: Get Payload Size
MyCamera.MVCC_INTVALUE_EX stParam = new MyCamera.MVCC_INTVALUE_EX();
nRet = m_pMyCamera.MV_CC_GetIntValueEx_NET("PayloadSize", ref stParam);
if (MyCamera.MV_OK != nRet)
{
MessageBox.Show("Get PayloadSize Fail");
return;
}
g_nPayloadSize = (uint)stParam.nCurValue;
// ch:获取高 || en: Get Height
nRet = m_pMyCamera.MV_CC_GetIntValueEx_NET("Height", ref stParam);
if (MyCamera.MV_OK != nRet)
{
MessageBox.Show("Get Height Fail");
return;
}
uint nHeight = (uint)stParam.nCurValue;
// ch:获取宽 || en: Get Width
nRet = m_pMyCamera.MV_CC_GetIntValueEx_NET("Width", ref stParam);
if (MyCamera.MV_OK != nRet)
{
MessageBox.Show("Get Width Fail");
return;
}
uint nWidth = (uint)stParam.nCurValue;
// ch:获取步长 || en: Get nRowStep
m_nRowStep = nWidth * nHeight;
}
然后就是取流了
/// <summary>
/// 开始采图
/// </summary>
private void StartGrab()
{
int nRet;
// ch:开启抓图 | en:start grab
nRet = m_pMyCamera.MV_CC_StartGrabbing_NET();
if (MyCamera.MV_OK != nRet)
{
MessageBox.Show("Start Grabbing Fail");
return;
}
m_bGrabbing = true;
Thread hReceiveImageThreadHandle = new Thread(ReceiveImageWorkThread);
hReceiveImageThreadHandle.Start(m_pMyCamera);
//软触发
m_pMyCamera.MV_CC_SetEnumValue_NET("TriggerSource", 7);
}
相机的图片的黑白和彩色的判断
#region 判断图片是黑白还是彩色
/// <summary>
/// 图像是否为Mono格式
/// </summary>
/// <param name="enType"></param>
/// <returns></returns>
private bool IsMonoPixelFormat(MyCamera.MvGvspPixelType enType)
{
switch (enType)
{
case MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono8:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono10:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono10_Packed:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono12:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono12_Packed:
return true;
default:
return false;
}
}
/// <summary>
/// 图像是否为彩色
/// </summary>
/// <param name="enType"></param>
/// <returns></returns>
private bool IsColorPixelFormat(MyCamera.MvGvspPixelType enType)
{
switch (enType)
{
case MyCamera.MvGvspPixelType.PixelType_Gvsp_RGB8_Packed:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BGR8_Packed:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_RGBA8_Packed:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BGRA8_Packed:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_YUV422_Packed:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_YUV422_YUYV_Packed:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerGR8:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerRG8:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerGB8:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerBG8:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerGB10:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerGB10_Packed:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerBG10:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerBG10_Packed:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerRG10:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerRG10_Packed:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerGR10:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerGR10_Packed:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerGB12:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerGB12_Packed:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerBG12:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerBG12_Packed:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerRG12:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerRG12_Packed:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerGR12:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerGR12_Packed:
return true;
default:
return false;
}
}
/// <summary>
/// 其他黑白格式转为Mono8
/// </summary>
/// <param name="obj"></param>
/// <param name="pInData">输出图片数据</param>
/// <param name="pOutData">输出图片数据</param>
/// <param name="nHeight">高</param>
/// <param name="nWidth">宽</param>
/// <param name="nPixelType">像素格式</param>
/// <returns></returns>
public Int32 ConvertToMono8(object obj, IntPtr pInData, IntPtr pOutData, ushort nHeight, ushort nWidth, MyCamera.MvGvspPixelType nPixelType)
{
if (IntPtr.Zero == pInData || IntPtr.Zero == pOutData)
{
return MyCamera.MV_E_PARAMETER;
}
int nRet = MyCamera.MV_OK;
MyCamera device = obj as MyCamera;
MyCamera.MV_PIXEL_CONVERT_PARAM stPixelConvertParam = new MyCamera.MV_PIXEL_CONVERT_PARAM();
stPixelConvertParam.pSrcData = pInData;//源数据
if (IntPtr.Zero == stPixelConvertParam.pSrcData)
{
return -1;
}
stPixelConvertParam.nWidth = nWidth;//图像宽度
stPixelConvertParam.nHeight = nHeight;//图像高度
stPixelConvertParam.enSrcPixelType = nPixelType;//源数据的格式
stPixelConvertParam.nSrcDataLen = (uint)(nWidth * nHeight * ((((uint)nPixelType) >> 16) & 0x00ff) >> 3);
stPixelConvertParam.nDstBufferSize = (uint)(nWidth * nHeight * ((((uint)MyCamera.MvGvspPixelType.PixelType_Gvsp_RGB8_Packed) >> 16) & 0x00ff) >> 3);
stPixelConvertParam.pDstBuffer = pOutData;//转换后的数据
stPixelConvertParam.enDstPixelType = MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono8;
stPixelConvertParam.nDstBufferSize = (uint)(nWidth * nHeight * 3);
nRet = device.MV_CC_ConvertPixelType_NET(ref stPixelConvertParam);//格式转换
if (MyCamera.MV_OK != nRet)
{
return -1;
}
return nRet;
}
/// <summary>
/// 其他彩色格式转为RGB8
/// </summary>
/// <param name="obj"></param>
/// <param name="pSrc"></param>
/// <param name="nHeight"></param>
/// <param name="nWidth"></param>
/// <param name="nPixelType"></param>
/// <param name="pDst"></param>
/// <returns></returns>
public Int32 ConvertToRGB(object obj, IntPtr pSrc, ushort nHeight, ushort nWidth, MyCamera.MvGvspPixelType nPixelType, IntPtr pDst)
{
if (IntPtr.Zero == pSrc || IntPtr.Zero == pDst)
{
return MyCamera.MV_E_PARAMETER;
}
int nRet = MyCamera.MV_OK;
MyCamera device = obj as MyCamera;
MyCamera.MV_PIXEL_CONVERT_PARAM stPixelConvertParam = new MyCamera.MV_PIXEL_CONVERT_PARAM();
stPixelConvertParam.pSrcData = pSrc;//源数据
if (IntPtr.Zero == stPixelConvertParam.pSrcData)
{
return -1;
}
stPixelConvertParam.nWidth = nWidth;//图像宽度
stPixelConvertParam.nHeight = nHeight;//图像高度
stPixelConvertParam.enSrcPixelType = nPixelType;//源数据的格式
stPixelConvertParam.nSrcDataLen = (uint)(nWidth * nHeight * ((((uint)nPixelType) >> 16) & 0x00ff) >> 3);
stPixelConvertParam.nDstBufferSize = (uint)(nWidth * nHeight * ((((uint)MyCamera.MvGvspPixelType.PixelType_Gvsp_RGB8_Packed) >> 16) & 0x00ff) >> 3);
stPixelConvertParam.pDstBuffer = pDst;//转换后的数据
stPixelConvertParam.enDstPixelType = MyCamera.MvGvspPixelType.PixelType_Gvsp_RGB8_Packed;
stPixelConvertParam.nDstBufferSize = (uint)nWidth * nHeight * 3;
nRet = device.MV_CC_ConvertPixelType_NET(ref stPixelConvertParam);//格式转换
if (MyCamera.MV_OK != nRet)
{
return -1;
}
return MyCamera.MV_OK;
}
#endregion
接收图片数据的函数,显示图片
/// <summary>
/// 显示图片
/// </summary>
/// <param name="nHeight">高</param>
/// <param name="nWidth">宽</param>
/// <param name="pImageBuf">图片数据</param>
/// <param name="enPixelType">像素格式</param>
public void VisionProDisplay(UInt32 nHeight, UInt32 nWidth, IntPtr pImageBuf, MyCamera.MvGvspPixelType enPixelType)
{
// ch: 显示 || display
try
{
//黑白图片
if (enPixelType == MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono8)
{
CogImage8Root cogImage8Root = new CogImage8Root();
cogImage8Root.Initialize((Int32)nWidth, (Int32)nHeight, pImageBuf, (Int32)nWidth, null);
//图像的转换
CogImage8Grey cogImage8Grey = new CogImage8Grey();
cogImage8Grey.SetRoot(cogImage8Root);
//显示图片
this.cogRecordDisplay1.Image = cogImage8Grey.ScaleImage((int)nWidth, (int)nHeight);
this.cogRecordDisplay1.AutoFit = true;
System.GC.Collect();
}
else //彩色图片
{
CogImage8Root image0 = new CogImage8Root();
IntPtr ptr0 = new IntPtr(pImageBuf.ToInt64());
image0.Initialize((int)nWidth, (int)nHeight, ptr0, (int)nWidth, null);
CogImage8Root image1 = new CogImage8Root();
IntPtr ptr1 = new IntPtr(pImageBuf.ToInt64() + m_nRowStep);
image1.Initialize((int)nWidth, (int)nHeight, ptr1, (int)nWidth, null);
CogImage8Root image2 = new CogImage8Root();
IntPtr ptr2 = new IntPtr(pImageBuf.ToInt64() + m_nRowStep * 2);
image2.Initialize((int)nWidth, (int)nHeight, ptr2, (int)nWidth, null);
CogImage24PlanarColor colorImage = new CogImage24PlanarColor();
colorImage.SetRoots(image0, image1, image2);
this.cogRecordDisplay1.Image = colorImage.ScaleImage((int)nWidth, (int)nHeight);
this.cogRecordDisplay1.AutoFit = true;
System.GC.Collect();
}
}
catch (System.Exception ex)
{
MessageBox.Show(ex.ToString());
return;
}
return;
}
/// <summary>
/// 接收图片线程函数
/// </summary>
/// <param name="obj"></param>
public void ReceiveImageWorkThread(object obj)
{
int nRet = MyCamera.MV_OK;
MyCamera device = obj as MyCamera;
MyCamera.MV_FRAME_OUT_INFO_EX pFrameInfo = new MyCamera.MV_FRAME_OUT_INFO_EX();
IntPtr pData = Marshal.AllocHGlobal((int)g_nPayloadSize);
if (pData == IntPtr.Zero)
{
return;
}
IntPtr pImageBuffer = Marshal.AllocHGlobal((int)m_nRowStep * 3);
if (pImageBuffer == IntPtr.Zero)
{
return;
}
IntPtr pTemp = IntPtr.Zero;
Byte[] byteArrImageData = new Byte[m_nRowStep * 3];
while (m_bGrabbing)
{
nRet = device.MV_CC_GetOneFrameTimeout_NET(pData, g_nPayloadSize, ref pFrameInfo, 1000);
if (MyCamera.MV_OK == nRet)
{
MyCamera.MvGvspPixelType pixelType = MyCamera.MvGvspPixelType.PixelType_Gvsp_RGB8_Packed;
if (IsColorPixelFormat(pFrameInfo.enPixelType)) // 彩色图像处理
{
if (pFrameInfo.enPixelType == MyCamera.MvGvspPixelType.PixelType_Gvsp_RGB8_Packed)
{
pTemp = pData;
}
else
{
// 其他格式彩色图像转为RGB
nRet = ConvertToRGB(obj, pData, pFrameInfo.nHeight, pFrameInfo.nWidth, pFrameInfo.enPixelType, pImageBuffer);
if (MyCamera.MV_OK != nRet)
{
return;
}
pTemp = pImageBuffer;
}
// Packed转Plane
unsafe
{
byte* pBufForSaveImage = (byte*)pTemp;
UInt32 nSupWidth = (pFrameInfo.nWidth + (UInt32)3) & 0xfffffffc;
for (int nRow = 0; nRow < pFrameInfo.nHeight; nRow++)
{
for (int col = 0; col < pFrameInfo.nWidth; col++)
{
byteArrImageData[nRow * nSupWidth + col] = pBufForSaveImage[nRow * pFrameInfo.nWidth * 3 + (3 * col)];
byteArrImageData[pFrameInfo.nWidth * pFrameInfo.nHeight + nRow * nSupWidth + col] = pBufForSaveImage[nRow * pFrameInfo.nWidth * 3 + (3 * col + 1)];
byteArrImageData[pFrameInfo.nWidth * pFrameInfo.nHeight * 2 + nRow * nSupWidth + col] = pBufForSaveImage[nRow * pFrameInfo.nWidth * 3 + (3 * col + 2)];
}
}
pTemp = Marshal.UnsafeAddrOfPinnedArrayElement(byteArrImageData, 0);
}
}
else if (IsMonoPixelFormat(pFrameInfo.enPixelType)) // Mono图像处理
{
if (pFrameInfo.enPixelType == MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono8)
{
pTemp = pData;
}
else
{
// 其他格式Mono转为Mono8
nRet = ConvertToMono8(device, pData, pImageBuffer, pFrameInfo.nHeight, pFrameInfo.nWidth, pFrameInfo.enPixelType);
if (MyCamera.MV_OK != nRet)
{
return;
}
pTemp = pImageBuffer;
}
pixelType = MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono8;
}
else
{
continue;
}
VisionProDisplay(pFrameInfo.nHeight, pFrameInfo.nWidth, pTemp, pixelType);
}
else
{
continue;
}
}
if (pData != IntPtr.Zero)
{
Marshal.FreeHGlobal(pData);
}
if (pImageBuffer != IntPtr.Zero)
{
Marshal.FreeHGlobal(pImageBuffer);
}
return;
}
最后是关闭相机
/// <summary>
/// 关闭设备
/// </summary>
private void CloseCamera()
{
if (m_bGrabbing)
{
m_bGrabbing = false;
// ch:停止抓图 || en:Stop grab image
m_pMyCamera.MV_CC_StopGrabbing_NET();
}
// ch:关闭设备 || en: Close device
m_pMyCamera.MV_CC_CloseDevice_NET();
m_pMyCamera.MV_CC_DestroyDevice_NET();
m_bGrabbing = false;
}
2.3 代码源码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Media.Media3D;
using Cognex.VisionPro;
using MvCamCtrl.NET;
namespace CamerHiK
{
public partial class Camera : Form
{
#region 参数
MyCamera.MV_CC_DEVICE_INFO_LIST m_pDeviceList; //相机列表
private MyCamera m_pMyCamera;
bool m_bGrabbing;
UInt32 g_nPayloadSize = 0;
UInt32 m_nRowStep = 0;
#endregion
public Camera()
{
InitializeComponent();
}
#region 获取相机列表,打开相机,画面显示
/// <summary>
/// 打开程序事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Form1_Load(object sender, EventArgs e)
{
Task task1 = new Task(() =>
{
DeviceListAcq();//枚举设备
});
task1.Start();
task1.Wait();
OpenCamera();//打开设备
StartGrab();//连续采图
}
/// <summary>
/// 关闭程序事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
Task.Run(() =>
{
CloseCamera();//关闭设备
});
Task.WaitAll();
Process.GetCurrentProcess().Kill();
}
/// <summary>
/// 枚举相机
/// </summary>
private void DeviceListAcq()
{
int nRet;
// ch:创建设备列表 || en: Create device list
System.GC.Collect();
//获取相机的列表,包含网口和U口相机
nRet = MyCamera.MV_CC_EnumDevices_NET(MyCamera.MV_GIGE_DEVICE | MyCamera.MV_USB_DEVICE, ref m_pDeviceList);
if (MyCamera.MV_OK != nRet)
{
MessageBox.Show("Enum Devices Fail");
return;
}
}
/// <summary>
/// 打开设备
/// </summary>
private void OpenCamera()
{
//判断是否有相机
if (m_pDeviceList.nDeviceNum == 0)
{
MessageBox.Show("No device,please select");
return;
}
//这里选择了第一个相机
MyCamera.MV_CC_DEVICE_INFO device =
(MyCamera.MV_CC_DEVICE_INFO)Marshal.PtrToStructure(m_pDeviceList.pDeviceInfo[0],
typeof(MyCamera.MV_CC_DEVICE_INFO));
int nRet = -1;
m_pMyCamera = new MyCamera();
//获取设备信息
nRet = m_pMyCamera.MV_CC_CreateDevice_NET(ref device);
if (MyCamera.MV_OK != nRet)
{
return;
}
// ch:打开设备 | en:Open device
nRet = m_pMyCamera.MV_CC_OpenDevice_NET();
if (MyCamera.MV_OK != nRet)
{
MessageBox.Show("Open Device Fail");
return;
}
// ch:获取包大小 || en: Get Payload Size
MyCamera.MVCC_INTVALUE_EX stParam = new MyCamera.MVCC_INTVALUE_EX();
nRet = m_pMyCamera.MV_CC_GetIntValueEx_NET("PayloadSize", ref stParam);
if (MyCamera.MV_OK != nRet)
{
MessageBox.Show("Get PayloadSize Fail");
return;
}
g_nPayloadSize = (uint)stParam.nCurValue;
// ch:获取高 || en: Get Height
nRet = m_pMyCamera.MV_CC_GetIntValueEx_NET("Height", ref stParam);
if (MyCamera.MV_OK != nRet)
{
MessageBox.Show("Get Height Fail");
return;
}
uint nHeight = (uint)stParam.nCurValue;
// ch:获取宽 || en: Get Width
nRet = m_pMyCamera.MV_CC_GetIntValueEx_NET("Width", ref stParam);
if (MyCamera.MV_OK != nRet)
{
MessageBox.Show("Get Width Fail");
return;
}
uint nWidth = (uint)stParam.nCurValue;
// ch:获取步长 || en: Get nRowStep
m_nRowStep = nWidth * nHeight;
}
/// <summary>
/// 开始采图
/// </summary>
private void StartGrab()
{
int nRet;
// ch:开启抓图 | en:start grab
nRet = m_pMyCamera.MV_CC_StartGrabbing_NET();
if (MyCamera.MV_OK != nRet)
{
MessageBox.Show("Start Grabbing Fail");
return;
}
m_bGrabbing = true;
Thread hReceiveImageThreadHandle = new Thread(ReceiveImageWorkThread);
hReceiveImageThreadHandle.Start(m_pMyCamera);
//软触发
m_pMyCamera.MV_CC_SetEnumValue_NET("TriggerSource", 7);
}
/// <summary>
/// 关闭设备
/// </summary>
private void CloseCamera()
{
if (m_bGrabbing)
{
m_bGrabbing = false;
// ch:停止抓图 || en:Stop grab image
m_pMyCamera.MV_CC_StopGrabbing_NET();
}
// ch:关闭设备 || en: Close device
m_pMyCamera.MV_CC_CloseDevice_NET();
m_pMyCamera.MV_CC_DestroyDevice_NET();
m_bGrabbing = false;
}
/// <summary>
/// 显示图片
/// </summary>
/// <param name="nHeight">高</param>
/// <param name="nWidth">宽</param>
/// <param name="pImageBuf">图片数据</param>
/// <param name="enPixelType">像素格式</param>
public void VisionProDisplay(UInt32 nHeight, UInt32 nWidth, IntPtr pImageBuf, MyCamera.MvGvspPixelType enPixelType)
{
// ch: 显示 || display
try
{
//黑白图片
if (enPixelType == MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono8)
{
CogImage8Root cogImage8Root = new CogImage8Root();
cogImage8Root.Initialize((Int32)nWidth, (Int32)nHeight, pImageBuf, (Int32)nWidth, null);
//图像的转换
CogImage8Grey cogImage8Grey = new CogImage8Grey();
cogImage8Grey.SetRoot(cogImage8Root);
//显示图片
this.cogRecordDisplay1.Image = cogImage8Grey.ScaleImage((int)nWidth, (int)nHeight);
this.cogRecordDisplay1.AutoFit = true;
System.GC.Collect();
}
else //彩色图片
{
CogImage8Root image0 = new CogImage8Root();
IntPtr ptr0 = new IntPtr(pImageBuf.ToInt64());
image0.Initialize((int)nWidth, (int)nHeight, ptr0, (int)nWidth, null);
CogImage8Root image1 = new CogImage8Root();
IntPtr ptr1 = new IntPtr(pImageBuf.ToInt64() + m_nRowStep);
image1.Initialize((int)nWidth, (int)nHeight, ptr1, (int)nWidth, null);
CogImage8Root image2 = new CogImage8Root();
IntPtr ptr2 = new IntPtr(pImageBuf.ToInt64() + m_nRowStep * 2);
image2.Initialize((int)nWidth, (int)nHeight, ptr2, (int)nWidth, null);
CogImage24PlanarColor colorImage = new CogImage24PlanarColor();
colorImage.SetRoots(image0, image1, image2);
this.cogRecordDisplay1.Image = colorImage.ScaleImage((int)nWidth, (int)nHeight);
this.cogRecordDisplay1.AutoFit = true;
System.GC.Collect();
}
}
catch (System.Exception ex)
{
MessageBox.Show(ex.ToString());
return;
}
return;
}
/// <summary>
/// 接收图片线程函数
/// </summary>
/// <param name="obj"></param>
public void ReceiveImageWorkThread(object obj)
{
int nRet = MyCamera.MV_OK;
MyCamera device = obj as MyCamera;
MyCamera.MV_FRAME_OUT_INFO_EX pFrameInfo = new MyCamera.MV_FRAME_OUT_INFO_EX();
IntPtr pData = Marshal.AllocHGlobal((int)g_nPayloadSize);
if (pData == IntPtr.Zero)
{
return;
}
IntPtr pImageBuffer = Marshal.AllocHGlobal((int)m_nRowStep * 3);
if (pImageBuffer == IntPtr.Zero)
{
return;
}
IntPtr pTemp = IntPtr.Zero;
Byte[] byteArrImageData = new Byte[m_nRowStep * 3];
while (m_bGrabbing)
{
nRet = device.MV_CC_GetOneFrameTimeout_NET(pData, g_nPayloadSize, ref pFrameInfo, 1000);
if (MyCamera.MV_OK == nRet)
{
MyCamera.MvGvspPixelType pixelType = MyCamera.MvGvspPixelType.PixelType_Gvsp_RGB8_Packed;
if (IsColorPixelFormat(pFrameInfo.enPixelType)) // 彩色图像处理
{
if (pFrameInfo.enPixelType == MyCamera.MvGvspPixelType.PixelType_Gvsp_RGB8_Packed)
{
pTemp = pData;
}
else
{
// 其他格式彩色图像转为RGB
nRet = ConvertToRGB(obj, pData, pFrameInfo.nHeight, pFrameInfo.nWidth, pFrameInfo.enPixelType, pImageBuffer);
if (MyCamera.MV_OK != nRet)
{
return;
}
pTemp = pImageBuffer;
}
// Packed转Plane
unsafe
{
byte* pBufForSaveImage = (byte*)pTemp;
UInt32 nSupWidth = (pFrameInfo.nWidth + (UInt32)3) & 0xfffffffc;
for (int nRow = 0; nRow < pFrameInfo.nHeight; nRow++)
{
for (int col = 0; col < pFrameInfo.nWidth; col++)
{
byteArrImageData[nRow * nSupWidth + col] = pBufForSaveImage[nRow * pFrameInfo.nWidth * 3 + (3 * col)];
byteArrImageData[pFrameInfo.nWidth * pFrameInfo.nHeight + nRow * nSupWidth + col] = pBufForSaveImage[nRow * pFrameInfo.nWidth * 3 + (3 * col + 1)];
byteArrImageData[pFrameInfo.nWidth * pFrameInfo.nHeight * 2 + nRow * nSupWidth + col] = pBufForSaveImage[nRow * pFrameInfo.nWidth * 3 + (3 * col + 2)];
}
}
pTemp = Marshal.UnsafeAddrOfPinnedArrayElement(byteArrImageData, 0);
}
}
else if (IsMonoPixelFormat(pFrameInfo.enPixelType)) // Mono图像处理
{
if (pFrameInfo.enPixelType == MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono8)
{
pTemp = pData;
}
else
{
// 其他格式Mono转为Mono8
nRet = ConvertToMono8(device, pData, pImageBuffer, pFrameInfo.nHeight, pFrameInfo.nWidth, pFrameInfo.enPixelType);
if (MyCamera.MV_OK != nRet)
{
return;
}
pTemp = pImageBuffer;
}
pixelType = MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono8;
}
else
{
continue;
}
VisionProDisplay(pFrameInfo.nHeight, pFrameInfo.nWidth, pTemp, pixelType);
}
else
{
continue;
}
}
if (pData != IntPtr.Zero)
{
Marshal.FreeHGlobal(pData);
}
if (pImageBuffer != IntPtr.Zero)
{
Marshal.FreeHGlobal(pImageBuffer);
}
return;
}
#region 判断图片是黑白还是彩色
/// <summary>
/// 图像是否为Mono格式
/// </summary>
/// <param name="enType"></param>
/// <returns></returns>
private bool IsMonoPixelFormat(MyCamera.MvGvspPixelType enType)
{
switch (enType)
{
case MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono8:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono10:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono10_Packed:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono12:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono12_Packed:
return true;
default:
return false;
}
}
/// <summary>
/// 图像是否为彩色
/// </summary>
/// <param name="enType"></param>
/// <returns></returns>
private bool IsColorPixelFormat(MyCamera.MvGvspPixelType enType)
{
switch (enType)
{
case MyCamera.MvGvspPixelType.PixelType_Gvsp_RGB8_Packed:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BGR8_Packed:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_RGBA8_Packed:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BGRA8_Packed:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_YUV422_Packed:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_YUV422_YUYV_Packed:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerGR8:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerRG8:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerGB8:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerBG8:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerGB10:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerGB10_Packed:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerBG10:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerBG10_Packed:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerRG10:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerRG10_Packed:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerGR10:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerGR10_Packed:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerGB12:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerGB12_Packed:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerBG12:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerBG12_Packed:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerRG12:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerRG12_Packed:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerGR12:
case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerGR12_Packed:
return true;
default:
return false;
}
}
/// <summary>
/// 其他黑白格式转为Mono8
/// </summary>
/// <param name="obj"></param>
/// <param name="pInData">输出图片数据</param>
/// <param name="pOutData">输出图片数据</param>
/// <param name="nHeight">高</param>
/// <param name="nWidth">宽</param>
/// <param name="nPixelType">像素格式</param>
/// <returns></returns>
public Int32 ConvertToMono8(object obj, IntPtr pInData, IntPtr pOutData, ushort nHeight, ushort nWidth, MyCamera.MvGvspPixelType nPixelType)
{
if (IntPtr.Zero == pInData || IntPtr.Zero == pOutData)
{
return MyCamera.MV_E_PARAMETER;
}
int nRet = MyCamera.MV_OK;
MyCamera device = obj as MyCamera;
MyCamera.MV_PIXEL_CONVERT_PARAM stPixelConvertParam = new MyCamera.MV_PIXEL_CONVERT_PARAM();
stPixelConvertParam.pSrcData = pInData;//源数据
if (IntPtr.Zero == stPixelConvertParam.pSrcData)
{
return -1;
}
stPixelConvertParam.nWidth = nWidth;//图像宽度
stPixelConvertParam.nHeight = nHeight;//图像高度
stPixelConvertParam.enSrcPixelType = nPixelType;//源数据的格式
stPixelConvertParam.nSrcDataLen = (uint)(nWidth * nHeight * ((((uint)nPixelType) >> 16) & 0x00ff) >> 3);
stPixelConvertParam.nDstBufferSize = (uint)(nWidth * nHeight * ((((uint)MyCamera.MvGvspPixelType.PixelType_Gvsp_RGB8_Packed) >> 16) & 0x00ff) >> 3);
stPixelConvertParam.pDstBuffer = pOutData;//转换后的数据
stPixelConvertParam.enDstPixelType = MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono8;
stPixelConvertParam.nDstBufferSize = (uint)(nWidth * nHeight * 3);
nRet = device.MV_CC_ConvertPixelType_NET(ref stPixelConvertParam);//格式转换
if (MyCamera.MV_OK != nRet)
{
return -1;
}
return nRet;
}
/// <summary>
/// 其他彩色格式转为RGB8
/// </summary>
/// <param name="obj"></param>
/// <param name="pSrc"></param>
/// <param name="nHeight"></param>
/// <param name="nWidth"></param>
/// <param name="nPixelType"></param>
/// <param name="pDst"></param>
/// <returns></returns>
public Int32 ConvertToRGB(object obj, IntPtr pSrc, ushort nHeight, ushort nWidth, MyCamera.MvGvspPixelType nPixelType, IntPtr pDst)
{
if (IntPtr.Zero == pSrc || IntPtr.Zero == pDst)
{
return MyCamera.MV_E_PARAMETER;
}
int nRet = MyCamera.MV_OK;
MyCamera device = obj as MyCamera;
MyCamera.MV_PIXEL_CONVERT_PARAM stPixelConvertParam = new MyCamera.MV_PIXEL_CONVERT_PARAM();
stPixelConvertParam.pSrcData = pSrc;//源数据
if (IntPtr.Zero == stPixelConvertParam.pSrcData)
{
return -1;
}
stPixelConvertParam.nWidth = nWidth;//图像宽度
stPixelConvertParam.nHeight = nHeight;//图像高度
stPixelConvertParam.enSrcPixelType = nPixelType;//源数据的格式
stPixelConvertParam.nSrcDataLen = (uint)(nWidth * nHeight * ((((uint)nPixelType) >> 16) & 0x00ff) >> 3);
stPixelConvertParam.nDstBufferSize = (uint)(nWidth * nHeight * ((((uint)MyCamera.MvGvspPixelType.PixelType_Gvsp_RGB8_Packed) >> 16) & 0x00ff) >> 3);
stPixelConvertParam.pDstBuffer = pDst;//转换后的数据
stPixelConvertParam.enDstPixelType = MyCamera.MvGvspPixelType.PixelType_Gvsp_RGB8_Packed;
stPixelConvertParam.nDstBufferSize = (uint)nWidth * nHeight * 3;
nRet = device.MV_CC_ConvertPixelType_NET(ref stPixelConvertParam);//格式转换
if (MyCamera.MV_OK != nRet)
{
return -1;
}
return MyCamera.MV_OK;
}
#endregion
#endregion
代码整体有点长,主要是解决取流,数据的采集问题,当然大部分的代码都是我按照海康的示例来进行修改的,但也实现了我们需要的功能。
三、网口相机的最好解决方法;
前面讲到,网口相机在VisionPro里面是有现成的工具的,那我们就可以直接引用对应的dll文件使用代码的形式来实现实时画面,而不是必须使用vpp程序的功能来实现画面:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Cognex.VisionPro;
using Cognex.VisionPro.FGGigE;
using Cognex.VisionPro.ToolBlock;
namespace Camera_Live
{
public partial class Form1 : Form
{
ICogAcqFifo mycogCamra;//定义一个相机对象
private ICogFrameGrabber mFrameGrabber = null;
List<String> CameraVideo = new List<String>();//相机信息列表
public Form1()
{
InitializeComponent();
}
/// <summary>
/// 获得相机列表,并提示相机数量
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Form1_Load(object sender, EventArgs e)
{
CogFrameGrabberGigEs GigeCamera = new CogFrameGrabberGigEs();
if (GigeCamera.Count < 1)
{
MessageBox.Show("没有找到相机!");
}
for (int i = 0; i < GigeCamera.Count; i++)
{
mFrameGrabber = GigeCamera[i];
//遍历已连接相机信息,相机名称,序列号,模式
CameraVideo.Add(mFrameGrabber.Name + mFrameGrabber.SerialNumber + mFrameGrabber.AvailableVideoFormats[0]);
}
//提示已连接的相机数量
MessageBox.Show(CameraVideo.Count.ToString());
}
/// <summary>
/// 获取到第一个相机,并显示在控件上
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button1_Click(object sender, EventArgs e)
{
//1.获取得相机列表
CogFrameGrabberGigEs CogCamera = new CogFrameGrabberGigEs();
//2.取第一个相机,从0开始排序
ICogFrameGrabber CameraGra = CogCamera[0];
//3.初始化相机
mycogCamra = CameraGra.CreateAcqFifo(CameraGra.AvailableVideoFormats[0], CogAcqFifoPixelFormatConstants.Format8Grey, 0, true);
//4.控件绑定相机并显示画面
cogRecordDisplay1.StartLiveDisplay(mycogCamra, false);
//5.相机的几个重要参数显示
MessageBox.Show("相机曝光:" + mycogCamra.OwnedExposureParams.Exposure.ToString() + "增益:" +
mycogCamra.OwnedBrightnessParams.Brightness.ToString() + "伽马" + mycogCamra.OwnedContrastParams.Contrast.ToString());
}
}
}
这种方法只适合与网口相机,还是比较实用的;