【C#】运行mindvision工业相机

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缩放显示的问题
在这里插入图片描述
在这里插入图片描述

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

猜你喜欢

转载自blog.csdn.net/bfz_50/article/details/82757871