【工业相机实战】基于 C# WinForms 的映美精(ic4)相机采集与显示全流程实现

目录

一、学习效果展示

二、实现步骤

[2.1. winform界面设计](#2.1. winform界面设计)

[2.2. 代码实现](#2.2. 代码实现)

[2.2.1 加载可用相机设备](#2.2.1 加载可用相机设备)

[2.2.2 打开/关闭相机](#2.2.2 打开/关闭相机)

2.2.3相机参数获取

2.2.4采集模式


一、学习效果展示

C#映美精相机前期开发学习

二、实现步骤

2.1. winform界面设计

左侧为图像实时显示区域,右侧为相机初始化、参数设置、采集控制和图像保存模块。

①图像显示 ,采用的是picturebox控件**,但并不能直接显示相机采集到的图像数据,需经转换显示**

这个是重要细节,自己踩坑很久

② 相机初始化,采用的是两个button按键,一个combox控件;

两个button按键分别控制相机打开和相机关闭,combox控件显示可用的相机设备

③参数获取与设置,使用了4个textbox控件,一个combox控件,两个button控件

4个textbox控件分别接受相机帧率、曝光时间、增益、对比度参数;

comboxk控件主要是显示相机分辨率,本来也是想进行分辨率设置,但是相机分辨率设置会影响到帧率参数,高的分辨率不能够支持高的帧率。参数设置还是建议使用官方sdk直接设置好。

两个button控件分别用于获取参数和设置参数,其中设置参数功能暂时没写。

**④采集模式,**使用了三个button控件,分别对应单帧采集、连续采集、停止采集三个功能。

**⑤文件保存,**使用了一个button控件,直接将采集到的图片进行保存到指定的文件夹中。

2.2. 代码实现

2.2.1 加载可用相机设备

结合映美精相机sdk库,枚举出目前可用的相机设备并将设备加载到combox列表中

cs 复制代码
        //将相机列表加入combox1中
        #region
        private List<DeviceInfo> adddevice()
        {
            var devicesname1 = ic4.DeviceEnum.Devices.ToList();
            return devicesname1;
        }
       private void additemtobox(List<DeviceInfo> camerax)
       {
            //首先对列表进行清理
            comboBox1.Items.Clear();
            //如果没有连接相机设备
            if (camerax.Count == 0)
            {
                MessageBox.Show("没有连接相机设备");
                return;
            }
            else
            {
                //加载当连接相机设备
                foreach (var i in camerax)
                {
                    comboBox1.Items.Add("model:"+i.ModelName + "serial:" + i.Serial);
                }
            }
       }    

2.2.2 打开/关闭相机

结合相机sdk库文件,撰写映美精相机打开和关闭程序

① 打开相机

cs 复制代码
        #endregion
        //打开相机
        #region
        /// <summary>
        /// 打开相机
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button2_Click(object sender, EventArgs e)
        {
            if (comboBox1.Items.Count == 0||comboBox1.SelectedIndex==-1)
            {
                MessageBox.Show("没有找到可用设备");
                return;
            }
            else
            {
                var firstDevInfox = ic4.DeviceEnum.Devices[comboBox1.SelectedIndex];
                grabbername.DeviceOpen(firstDevInfox);
                if (grabbername.IsDeviceOpen != true)
                {
                    MessageBox.Show("相机打开失败");
                    return;
                }
                //设置像素和像素模式
                grabbername.DevicePropertyMap.SetValue(ic4.PropId.PixelFormat, ic4.PixelFormat.Mono8);
                //设置roi区域
                setroiregion(grabbername);
                //防止多次被打开
                button2.Enabled = false; 
                关闭相机.Enabled = true;  
                //相机打开后可以获取相机参数
                button3.Enabled = true; 
            }
            
        }

② 关闭相机

cs 复制代码
        private void 关闭相机_Click_1(object sender, EventArgs e)
        {
            if (grabbername.IsDeviceOpen!=true)
            {
                MessageBox.Show("请先打开相机");
                return;
            }
            //关闭当前相机
            grabbername.DeviceClose();
            //允许重新打开相机
            button2.Enabled = true; 
            关闭相机.Enabled = false;
            //显示相机参数
            button3.Enabled = false;

        }

2.2.3相机参数获取

结合映美精sdk库,撰写获取相机分辨率、帧率、曝光时间、增益、对比度参数

cs 复制代码
private void combox2show()
{
    var shuxing = grabbername.DevicePropertyMap;
    //读取相机分辨率
    var xxvalue = shuxing.Find(ic4.PropId.Width);
    var yyvalue = shuxing.Find(ic4.PropId.Height);
    int xx = Convert.ToInt16(xxvalue.Value);
    int yy = Convert.ToInt16(yyvalue.Value);
    foreach (var item in comboBox2.Items)
    {
        if ((Convert.ToString(xx) + 'x' + Convert.ToString(yy)) == item.ToString())
        {
            comboBox2.SelectedItem = item;
            break;
        }
    }
    //读取相机帧率
    var FrameRate = shuxing.Find(ic4.PropId.AcquisitionFrameRate);
    textBox2.Text = FrameRate.Value.ToString(); 
    //读取相机曝光率
    var exposuretime = shuxing.Find(ic4.PropId.ExposureTime);
    textBox3.Text = exposuretime.Value.ToString();
    //读取相机增益
    var gain = shuxing.Find(ic4.PropId.Gain);
    textBox4.Text = gain.Value.ToString();
    //读取相机对比度
    var duibi = shuxing.Find(ic4.PropId.Contrast);
    textBox5.Text = duibi.Value.ToString();
}

2.2.4采集模式

①单帧采集开发

cs 复制代码
        //单帧采集图像并显示
        private void button5_Click(object sender, EventArgs e)
        {
            if (grabbername.IsDeviceOpen && (comboBox1.Items.Count != 0 || comboBox1.SelectedIndex != -1))
            {
                snapSink = new SnapSink();
                grabbername.StreamSetup(snapSink, StreamSetupOption.AcquisitionStart);

                using (ic4.ImageBuffer image = snapSink.SnapSingle(TimeSpan.FromSeconds(1)))
                {
                    // 获取图像宽高和像素格式
                    int width = Convert.ToInt32(grabbername.DevicePropertyMap.Find(ic4.PropId.Width).Value);
                    int height = Convert.ToInt32(grabbername.DevicePropertyMap.Find(ic4.PropId.Height).Value);

                    //设置调色板并转换图片
                     
                    // 显示
                    var old = pictureBox1.Image;
                    pictureBox1.Image = bmp;
                    old?.Dispose();
                }
                grabbername.StreamStop();
                snapSink = null;
            }
            else
                MessageBox.Show("请打开相机");
        }

②连续采集开发

cs 复制代码
        /// <summary>
        /// 连续采集图像
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button6_Click(object sender, EventArgs e)
        {
            //单帧采集拒绝
            button5.Enabled = false;
            //参数设置部分不可修改
            comboBox2.Enabled = false;
            textBox2.Enabled= false;
            textBox3.Enabled= false;    
            textBox4.Enabled= false;
            textBox5.Enabled= false;

            if (grabbername.IsDeviceOpen && (comboBox1.Items.Count != 0 || comboBox1.SelectedIndex != -1))
            {
                pictureBox1.SizeMode = PictureBoxSizeMode.Zoom;
                StartRealtime();
            }
            else
            { MessageBox.Show("请先打开相机"); }
        }

③关闭连续采集

cs 复制代码
        /// <summary>
        /// 停止连续采集
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button7_Click(object sender, EventArgs e)
        {
            StopRealtime();
            button5.Enabled = true;
            comboBox2.Enabled = true;
            textBox2.Enabled = true;
            textBox3.Enabled = true;
            textBox4.Enabled = true;
            textBox5.Enabled = true;
        }

2.2.5保存文件

cs 复制代码
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Windows.Forms;

private void btnSave_Click(object sender, EventArgs e)
{
    Bitmap snap = null;

    // 1) 取出当前最新帧(拷贝一份到本地变量)
    lock (_frameLock)
    {
        if (_latestFrame != null)
            snap =_latestFrame.Clone();
    }

    if (snap == null)
    {
        MessageBox.Show("当前没有可保存的图像,请先开始采集/显示。", "提示",
            MessageBoxButtons.OK, MessageBoxIcon.Information);
        return;
    }

    try
    {
        // 2) 选择保存路径与格式
        using (var sfd = new SaveFileDialog())
        {
            sfd.Title = "保存图片";
            sfd.Filter = "PNG (*.png)|*.png|BMP (*.bmp)|*.bmp|JPEG (*.jpg)|*.jpg";
            sfd.FileName = $"frame_{DateTime.Now:yyyyMMdd_HHmmss}.png";

            if (sfd.ShowDialog() != DialogResult.OK) return;

            // 3) 根据扩展名决定编码格式
            string ext = Path.GetExtension(sfd.FileName).ToLowerInvariant();
            ImageFormat fmt = ImageFormat.Png;
            if (ext == ".bmp") fmt = ImageFormat.Bmp;
            else if (ext == ".jpg" || ext == ".jpeg") fmt = ImageFormat.Jpeg;

            // 4) 保存
            snap.Save(sfd.FileName, fmt);
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show("保存失败:" + ex.Message, "错误",
            MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
    finally
    {
        snap.Dispose();
    }
}

需要完整代码联系博主哈,赚点买菜钱

相关推荐
HAPPY酷3 小时前
为啥双击 .sln 文件即可在 Visual Studio 中加载整个解决方案
ide·visual studio
千谦阙听4 小时前
数据结构入门:栈与队列
数据结构·学习·visual studio
你再说一遍?3644 小时前
计算机视觉实训作业记录:基于 YOLOv12 的水下目标检测模型优化与实现
yolo·目标检测·计算机视觉
m0_748233174 小时前
C语言vsC#:核心差异全解析
c语言·开发语言·c#
CSDN_RTKLIB4 小时前
MSVC单独配置源字符集、执行字符集
c++·visual studio
MyBFuture4 小时前
C# 关于联合编程基础
开发语言·c#·visual studio·vision pro
Sunsets_Red5 小时前
单调队列优化dp
c语言·c++·算法·c#·信息学竞赛
故事不长丨5 小时前
《C#委托与事件深度解析:区别、联系与实战应用》
开发语言·c#·委托·事件·event
星爷AG I5 小时前
9-19 视觉识别(AGI基础理论)
人工智能·计算机视觉·agi
程序猿小玉兒6 小时前
解决大文件上传失败问题
c#·.net