【C#】运行mindvision工业相机

本文档详细介绍了如何使用迈德威视工业相机的SDK进行开发,从安装驱动开始,逐步指导如何搭建开发环境,创建项目并实现基本功能,如相机设置、启动和停止预览、抓图等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1 运行demo

假设我们手上有了一款相机,可以按照如下流程进行测试

1.1 安装相机驱动

登录
http://www.mindvision.com.cn/
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

正常安装即可,安装完了以后可以在目录中看到如下文件
在这里插入图片描述

1.2 使用VS2010打开demo

在这里插入图片描述

在这里插入图片描述
注意,如果这里报错,提示没有C#环境,建议你新建一个工程,到联网模板里去找,选择C#应用程序,VS2010会自动下载相关的模板
在这里插入图片描述
回到我们的工程,设置FirstStep为启动项目
在这里插入图片描述
运行即可

在这里插入图片描述
效果:
在这里插入图片描述

2 学习代码

然后我们可以新建一个工程,模仿这个demo去实现上面这个功能,实现对C#的学习

2.1 新建项目

在这里插入图片描述
选择C#窗体程序,如果你没有C#环境,可以选择左下角的联机模板,创建C#,会自动下载。
在这里插入图片描述
确定即可。

2.2 添加引用(相机SDK)

在项目“引用”上右键
在这里插入图片描述
找到迈德威视工业相机的驱动安装位置
在这里插入图片描述

进入相机驱动的安装目录

在这里插入图片描述
选择dll
在这里插入图片描述
确定即可。
在这里插入图片描述

(这里直接引用他们的demo里的dll,其实也可以自己写一个项目,模仿MDSDK项目,然后项目属性的输出类似改为类库,再引用即可。建议熟悉后再尝试,现在继续往下看)

2.3 添加四个按钮

右键cs文件
在这里插入图片描述
可以看到下面的InitializeComponent函数,这个函数里面设定了控件(如按钮,文字等)的属性,包括名称、位置、尺寸等等,还有相关的调用方案,一般是自动生成,不用我们修改。
在这里插入图片描述

先添加四个按钮,点击设计界面,如果你没有这个标签页,双击cs文件能打开这个标签。
在这里插入图片描述
我们打开工具箱,从中拖几个按钮过去
在这里插入图片描述
找到公共控件的Button
在这里插入图片描述
拖过去即可,然后再移动鼠标到右下角,把我们的窗口拖到合适大小
在这里插入图片描述
再添加4个按钮,如图:
在这里插入图片描述

2.4 按钮事件

双击某一个按钮,进入代码界面
在这里插入图片描述
可以看到自动生成的点击事件函数:
在这里插入图片描述
复制如下内容到这个函数里

if (m_Grabber != IntPtr.Zero)
    MvApi.CameraShowSettingPage(m_hCamera, 1);

CameraShowSettingPage是进入相机设置界面。这里表示当相机指针不为Zero,进入设置界面。m_Grabber 在相机初始化时会被赋值。

可以看到有标红,
在这里插入图片描述

有一些变量和类需要先初始化,在顶部添加如下代码:
在这里插入图片描述

using MVSDK;
using CameraHandle = System.Int32;
protected IntPtr m_Grabber = IntPtr.Zero;		
protected CameraHandle m_hCamera = 0;

IntPtr:表示指针或句柄的平台特定整数类型,这里你可以认为是定义了一个整数类型的相机句柄,后面会用这个m_Grabber 来操作相机,如打开关闭相机等。

按钮1的点击事件完成,为了更容易识别,我们把按钮1设置为中文名称,右键按钮
在这里插入图片描述
将名称“button1”
在这里插入图片描述
改为“设置”
在这里插入图片描述
效果如下:
在这里插入图片描述

再改第二个名称
在这里插入图片描述
四个都改完后的效果
在这里插入图片描述
然后我们分别给各个按钮添加点击事件
双击第二个“播放”按钮,添加代码:
在这里插入图片描述
添加一个方法即可。

if (m_Grabber != IntPtr.Zero)
	MvApi.CameraGrabber_StartLive(m_Grabber);

表示启动相机。

再双击停止按钮,添加代码
在这里插入图片描述

if (m_Grabber != IntPtr.Zero)
    MvApi.CameraGrabber_StopLive(m_Grabber);

可以看到,由于迈德威视的相机SDK封装的比较完善,我们只需要一个方法就可以实现很多调用了。

但是最后一个抓图(截图)方法会比较复杂一些,因为涉及到一些关于文件保存的问题。双击抓图按钮,添加代码:
在这里插入图片描述
其实主要还是SaveImage和SaveAsBmp方法,然后将文件保存到指定路径中

if (m_Grabber != IntPtr.Zero)
{
    IntPtr Image;
    if (MvApi.CameraGrabber_SaveImage(m_Grabber, out Image, 2000) ==
        CameraSdkStatus.CAMERA_STATUS_SUCCESS)
    {
        string filename = System.IO.Path.Combine(
        AppDomain.CurrentDomain.BaseDirectory.ToString(), 
        string.Format("{0}.bmp", System.Environment.TickCount));

        MvApi.CameraImage_SaveAsBmp(Image, filename);

        MvApi.CameraImage_Destroy(Image);

        MessageBox.Show(filename);
    }
    else
    {
        MessageBox.Show("Snap failed");
    }
}

System.IO.Path.Combine:将路径与文件名合并起来,如C:\ABC.BMP
{0}:占位符,代表后面的第一个变量,类似于打印时的%d

四个按钮的事件写完了。

2.5 定时器控件

定时器控件用于底部状态栏数据的更新,这一块不是很重要,了解一下即可。
在这里插入图片描述
拖过去
在这里插入图片描述

双击上面那个闹钟,进入代码界面,写定时器事件

if (m_Grabber != IntPtr.Zero)
{
    tSdkGrabberStat stat;
    MvApi.CameraGrabber_GetStat(m_Grabber, out stat);
    
    string info = String.Format(
        "| Resolution:{0}*{1} | DispFPS:{2} | CapFPS:{3} |", 
        stat.Width, stat.Height, stat.DispFps, stat.CapFps);
        
    StateLabel.Text = info;
}

状态栏的信息用于获取相机采集到的画面的宽高和帧率等信息。
可以发现有一个地方标红了,
在这里插入图片描述
是标签控件,相当于状态栏的地方,说明标签没有添加,这时候我们可以把标签添加过去。

在这里插入图片描述

在这里插入图片描述
右击属性
在这里插入图片描述

将(Name)的值改为StateLabel
在这里插入图片描述

回来即可发现不再标红
在这里插入图片描述

2.6 相机的回调事件

相机的回调用于不断的刷新图像,我们在窗口设定了一个Image,然后不断的更新这个Image。

我们先在这里调用这个方法
在这里插入图片描述

protected pfnCameraGrabberFrameCallback m_FrameCallback;
m_FrameCallback = new pfnCameraGrabberFrameCallback(CameraGrabberFrameCallback);

然后我们再定义CameraGrabberFrameCallback

在这里插入图片描述
注意这里的第二个和第三个参数,pFrameBuffer是得到的帧缓存,在获取image时需要传入该参数;pFrameHead是图像帧头信息,用于获取图像格式。

private void CameraGrabberFrameCallback(
    IntPtr Grabber,
    IntPtr pFrameBuffer,
    ref tSdkFrameHead pFrameHead,
    IntPtr Context)
{

}

我们在函数体中添加如下代码:

GC.Collect();//强制进行即时垃圾回收,防止内存溢出

int w = pFrameHead.iWidth;
int h = pFrameHead.iHeight;

Boolean gray = (pFrameHead.uiMediaType ==
    (uint)MVSDK.emImageFormat.CAMERA_MEDIA_TYPE_MONO8);
    
Bitmap Image = new Bitmap(w, h,
    gray ? w : w * 3,
    gray ? PixelFormat.Format8bppIndexed : PixelFormat.Format24bppRgb,
    pFrameBuffer);

if (gray)
{
    Image.Palette = m_GrayPal;
}

this.Invoke((EventHandler)delegate
{
    DispWnd.Image = Image;
    DispWnd.Refresh();
});

在这里对image进行绘制,首先要判断相机的类型(彩色or黑白),然后进行Bitmap绘制,最后输出到DispWnd中。
可以看到有一些标红的地方,
在这里插入图片描述
首先pixel format是像素格式,它需要System.Drawing.Imaging的引用。
然后是m_GrayPal,该参数类型是定义组成调色板的颜色的数组,在初始化相机时会被赋值,当确定相机是黑白相机(gray为真)时,对image的图像调色板palette属性进行赋值。
我们添加System.Drawing.Imaging引用和m_GrayPal初始化即可。
在这里插入图片描述

using System.Drawing.Imaging;
protected ColorPalette m_GrayPal;

回来即可发现前两个不再标红
在这里插入图片描述

然后DispWnd,这个是一个PictureBox,顾名思义——图片盒子,就是用来显示我们图像的控件名称,我们回到设计窗口,将PictureBox拖过去。
在这里插入图片描述

在这里插入图片描述
然后右键这个控件,设置它的名称。
在这里插入图片描述

在这里插入图片描述
回到代码,即可发现不再标红。
在这里插入图片描述

2.7 相机的初始化

我们在窗口构造函数处添加相机的初始化代码
在这里插入图片描述
代码很好理解,创建相机的状态参数status,设备列表数组DevList,并获取已连接相机的数量,如果数组不为空则返回数组的长度,否则返回0。

private void InitCamera()
{
    CameraSdkStatus status = 0;

    tSdkCameraDevInfo[] DevList;
    MvApi.CameraEnumerateDevice(out DevList);
    int NumDev = (DevList != null ? DevList.Length : 0);
}

然后添加,获取相机设备的数量
在这里插入图片描述

if (NumDev < 1)
{
    MessageBox.Show("未扫描到相机”);
    return;
}
else if (NumDev == 1)
{
    status = MvApi.CameraGrabber_Create(out m_Grabber, ref DevList[0]);
}
else
{
    status = MvApi.CameraGrabber_CreateFromDevicePage(out m_Grabber);
}

判断当前的相机数量
在这里插入图片描述

if (status == 0)
{
    MvApi.CameraGrabber_GetCameraDevInfo(m_Grabber, out m_DevInfo);
    MvApi.CameraGrabber_GetCameraHandle(m_Grabber, out m_hCamera);
    MvApi.CameraCreateSettingPage(m_hCamera, this.Handle, m_DevInfo.acFriendlyName, null, (IntPtr)0, 0);

    MvApi.CameraGrabber_SetRGBCallback(m_Grabber, m_FrameCallback, IntPtr.Zero);
    tSdkCameraCapbility cap;
    MvApi.CameraGetCapability(m_hCamera, out cap);
    if (cap.sIspCapacity.bMonoSensor != 0)
    {
        MvApi.CameraSetIspOutFormat(m_hCamera, (uint)MVSDK.emImageFormat.CAMERA_MEDIA_TYPE_MONO8);
                     
        Bitmap Image = new Bitmap(1, 1, PixelFormat.Format8bppIndexed);
        m_GrayPal = Image.Palette;
        for (int Y = 0; Y < m_GrayPal.Entries.Length; Y++)
            m_GrayPal.Entries[Y] = Color.FromArgb(255, Y, Y, Y);
    }               
}

上图是有一个相机的时候执行的操作,其中标红的地方是因为m_DevInfo
没有定义,添加后即可
在这里插入图片描述

protected tSdkCameraDevInfo m_DevInfo;

不标红了
在这里插入图片描述

设置完成后我们需要添加启动的操作
在这里插入图片描述

MvApi.CameraSetMirror(m_hCamera, 1, 1);
MvApi.CameraGrabber_StartLive(m_Grabber);

如果if (status == 0)不通过,说明相机打开失败,我们需要进行提醒
在这里插入图片描述

else
{
    MessageBox.Show(String.Format("打开相机失败,原因:{0}", status));
}

相机的初始化也已经完成,最后一步是设置窗口的关闭事件,需要将相机的活动销毁

右键窗口空白处
在这里插入图片描述
在这里插入图片描述
双击右侧空白处,即可自动添加代码,然后写销毁事件即可
在这里插入图片描述
点击运行
在这里插入图片描述

在这里插入图片描述

运行后可以发现,图像不清晰,询问技术得知,是PictureBox缩放显示的问题
在这里插入图片描述
在这里插入图片描述

再次运行即可显示
在这里插入图片描述

<think>嗯,用户问的是如何用C#代码将迈德威视的彩色图像转换为康耐视的彩色图像。首先,我需要了解这两个品牌的图像数据格式可能有什么不同。迈德威视和康耐视都是工业相机厂商,他们的SDK可能使用不同的图像数据结构或像素格式。 首先,我应该确认迈德威视相机输出的图像格式。假设常见的可能是RGB24或者BGR24排列,每个像素占3个字节。而康耐视的可能需要特定的格式,比如CogImage24Planar,这是康耐视图像处理库Cognex VisionPro中的一种格式,采用平面存储方式,即所有红色分量连续存储,接着是绿色,最后是蓝色。 接下来,转换的关键在于理解两种格式的存储方式。例如,如果迈德威视的图像是RGB24交错排列(即每个像素按R、G、B顺序排列),而康耐视需要的是三个独立的平面(RRR...GGG...BBB...),则需要将交错的像素拆分到三个平面中。 用户可能需要从迈德威视的SDK获取图像数据,比如通过byte数组,然后处理这个数组,分解成R、G、B三个平面,再创建CogImage24Planar对象。此外,还需要注意图像的宽度、高度和可能的步长(stride)对齐问题,确保内存布局正确。 可能的步骤包括: 1. 获取迈德威视相机的图像数据,得到一个字节数组。 2. 确定源图像的像素格式(如RGB24)和分辨率。 3. 将交错的字节数据分解为R、G、B三个独立的平面数组。 4. 创建CogImage24Planar实例,将三个平面数据复制进去。 5. 处理可能的对齐问题,比如步长是否为宽度乘以3,或者是否有填充字节。 需要注意的错误点包括:字节顺序是否正确(比如是否是BGR而不是RGB),是否处理了可能的图像步长差异,以及内存分配是否正确。此外,VisionPro的API可能有特定的要求,比如需要锁定位图数据,或者使用特定的构造函数。 如果用户没有提供具体的像素格式或代码示例,可能需要做一些假设,并建议用户参考两者的SDK文档,确认具体的图像格式细节。此外,性能方面,如果处理大图像,可能需要高效的算法或使用不安全代码和指针操作来提升速度。 最后,给出示例代码的大纲,展示如何分解字节数组到三个平面,并实例化CogImage24Planar。同时提醒用户检查像素格式、处理可能的异常和内存问题,以及建议查阅相关文档。</think>要将迈德威视(MindVision相机的彩色图像转换为康耐视(Cognex VisionPro)兼容的格式(如 `CogImage24Planar`),关键在于理解两者的像素存储方式并进行数据重组。以下是转换步骤和示例代码: --- ### **关键概念** 1. **迈德威视图像格式** 通常输出为交错的 `RGB24` 或 `BGR24` 格式(如 `PixelFormat.Format24bppRgb`),每个像素按 `R-G-B` 或 `B-G-R` 顺序排列。 2. **康耐视 `CogImage24Planar`** 采用平面存储(Planar),即所有红色分量连续存放,随后是绿色、蓝色分量。例如: `RRRR...GGGG...BBBB...` --- ### **转换步骤** 1. 从迈德威视SDK获取原始图像字节数组。 2. 将交错的像素数据拆分为独立的 R、G、B 平面。 3. 创建 `CogImage24Planar` 对象并填充平面数据。 --- ### **C# 示例代码** ```csharp using Cognex.VisionPro; using Cognex.VisionPro.ImageProcessing; using System.Drawing.Imaging; public CogImage24Planar ConvertMindVisionToCognex(byte[] mindVisionData, int width, int height) { // 假设迈德威视数据为RGB24交错格式(每个像素3字节:R-G-B) // 若实际为BGR,需调整R/B平面顺序 int pixelCount = width * height; // 创建三个平面数组 byte[] redPlane = new byte[pixelCount]; byte[] greenPlane = new byte[pixelCount]; byte[] bluePlane = new byte[pixelCount]; // 分解交错数据到平面 for (int i = 0; i < mindVisionData.Length; i += 3) { int pixelIndex = i / 3; redPlane[pixelIndex] = mindVisionData[i]; // R greenPlane[pixelIndex] = mindVisionData[i+1]; // G bluePlane[pixelIndex] = mindVisionData[i+2]; // B } // 创建Cognex图像(Planar格式) CogImage24Planar cogImage = new CogImage24Planar(); cogImage.Allocate(width, height); // 填充平面数据 cogImage.GetPlane(Cognex.VisionPro.ImagePlaneConstants.Red).SetImageData(redPlane); cogImage.GetPlane(Cognex.VisionPro.ImagePlaneConstants.Green).SetImageData(greenPlane); cogImage.GetPlane(Cognex.VisionPro.ImagePlaneConstants.Blue).SetImageData(bluePlane); return cogImage; } ``` --- ### **注意事项** 1. **像素顺序** 若迈德威视输出为 `BGR`,需交换 `redPlane` 和 `bluePlane` 的赋值。 2. **图像步长(Stride)** 若原始数据存在行填充(如步长不是 `width * 3`),需在循环中处理行边界。 3. **性能优化** 对于大图像,建议使用 `unsafe` 代码和指针操作提升效率。 4. **VisionPro API** 确保已正确引用 `Cognex.VisionPro.dll` 并在项目中安装VisionPro运行时。 --- ### **扩展参考** - 查阅 **迈德威视SDK文档** 确认实际的像素格式。 - 康耐视官方文档:`CogImage24Planar` 的内存布局要求。 - 处理异常:检查图像尺寸是否匹配、内存分配是否成功。 通过上述方法,即可实现从迈德威视到康耐视彩色图像格式的高效转换。
评论 21
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值