海康、度申、迈德多个相机的联合使用

项目要求:

项目环境:

项目实现:

窗口初始化

NuGet 包管理器 :安装包

添加多个窗口(deviceform、cameraform、displayform、toolform等)

DeviceForm设计

添加节点:

删除节点记录:

拖拽节点:鼠标点击事件

CameraForm设计

接收传入节点

选择数据节点

graphic

DisplayForm设计

ToolForm设计

主窗口设计

参数定义

 添加工作栏

查找相机

 打开指定相机

添加相机功能菜单

成果展示

项目要求:

打开的各个功能模块像工作栏移动;

选择打开指定相机,输出采集数据;

输出数据可以传给指定工具。

项目环境:

        C#、winform、DockPanelSuite

项目实现:

窗口初始化

NuGet 包管理器 :安装包

添加多个窗口(deviceform、cameraform、displayform、toolform等)

        使用DockPanelSuite,子窗口必须继承:WeifenLuo.WinFormsUI.Docking.DockContent

public partial class Tool : WeifenLuo.WinFormsUI.Docking.DockContent

        为主窗口选择theme

dockPanel1.Theme = vS2015LightTheme1;

        向主窗口添加子窗口,同时设置子窗口的停靠方式

DeviceList DeviceForm = new DeviceList();
CameraList CameraForm = new CameraList();
DispalyPicture DisplayForm = new DispalyPicture();

private void Form3_Load(object sender, EventArgs e)
{
    DeviceForm.Text = "cameratree";
    DeviceForm.Show(dockPanel1);
    DeviceForm.DockTo(dockPanel1, DockStyle.Left);

    CameraForm.Text = "opentree";
    CameraForm.Show(dockPanel1);
    CameraForm.DockTo(dockPanel1, DockStyle.Right);

    DisplayForm.Text = "display";
    DisplayForm.Show(dockPanel1);
    DisplayForm.DockTo(dockPanel1, DockStyle.Fill);
}

DeviceForm设计

        DeviceForm指实现枚举相机treeview窗口,其中treeview命名为cameratree,节点命名规则为根节点为相机类型,根节点下子节点为该相机类型枚举到的相机,编号为相机索引。

添加节点:

 注:枚举相机在主窗口实现

public void add_cameranode(string cameratype, uint count)
{
    TreeNode[] targetnode = cameratree.Nodes.Find(cameratype, false);
    if (targetnode.Length > 0)
    {
        for (int i = 0; i < count; i++)
        {
            TreeNode cameranode = new TreeNode((cameraname[cameratype] + " " + i.ToString()), i + 1, i + 1);
            cameranode.Name = i.ToString();
            cameranode.Tag = cameratype;
            targetnode[0].Nodes.Add(cameranode);
        }
    }
    else
    {
        MessageBox.Show("nofind cameratree");
    }
}

删除节点记录:

        将指定节点从已打开相机节点记录中删除

public void remove_opennode(TreeNode selectnode)
{
    opennodes.RemoveAll(node => node.Tag == selectnode.Tag && node.Name == selectnode.Name);
}

拖拽节点:鼠标点击事件

private void cameratree_MouseDown(object sender, MouseEventArgs e)
{
    if (e.Button == MouseButtons.Right)
    {
        TreeNode selectedNode = cameratree.GetNodeAt(e.X, e.Y);
        if (selectedNode != null && !cameraname.ContainsKey(selectedNode.Name) && !opennodes.Contains(selectedNode))
        {
            if (opennodes.Count == 4)
            {
                MessageBox.Show("out of camera_max");
                return;
            }
            cameratree.SelectedNode = selectedNode;
            DragDropEffects i = cameratree.DoDragDrop(selectedNode, DragDropEffects.Move);
            if (i == DragDropEffects.Move && selectedNode.Tag.ToString() != "tool")
            {
                opennodes.Add(selectedNode);
            }
        }
    }
}

CameraForm设计

        CameraForm指打开相机的treeview窗口,即接收拖拽节点的treeview,其中treeview命名为opentree,节点命名规则同cameratree,区别是opentree根节点下的子节点为打开的相机。

接收传入节点

        传入节点有两种:第一种从cameratree拖拽的相机节点,拖拽成功实现打开对应相机,并在其节点下添加子节点,子节点对应该相机的数据。第二种为第一种生成的数据节点,将其拖拽到待使用的工具上,使相机的数据传递给对应工具,同时连接的两个节点之间用线条连接。

第二种效果如下:

判断传入节点的方式是:判断该节点位于所属二叉树的深度

部分代码如下:(注:部分代码在主窗口,这里不予显示)

private void opentree_DragEnter(object sender, DragEventArgs e)
{
    if (e.Data.GetDataPresent(typeof(TreeNode)))
    {
        e.Effect = DragDropEffects.Move;
    }
}

private void opentree_DragDrop(object sender, DragEventArgs e)
{
    if (e.Data.GetDataPresent(typeof(TreeNode)))
    {
        TreeNode draggedNode = (TreeNode)e.Data.GetData(typeof(TreeNode));
        if (draggedNode.Level == 2)
        {
            Point targetPoint = opentree.PointToClient(new Point(e.X, e.Y));
            TreeNode targetNode = opentree.GetNodeAt(targetPoint);
            TreeNode[] toolnode = opentree.Nodes.Find("tool", false);
            if (targetNode != null && toolnode.Length > 0 && toolnode[0].Nodes.Contains(targetNode))
            {
                starnodelist.Add(draggedNode);
                endnodelist.Add(targetNode);
                paint(draggedNode, targetNode);
            }
        }
        else
        {
            string cameratype = draggedNode.Tag.ToString(); //英文
            string cameratype2 = cameraname[cameratype];    //中文
            TreeNode[] targetNode = opentree.Nodes.Find(cameratype, false);
            if (targetNode.Length < 1)
            {
                TreeNode camera = new TreeNode(cameratype2, draggedNode.ImageIndex, draggedNode.SelectedImageIndex);
                camera.Name = cameratype;
                opentree.Nodes.Add(camera);
            }
            targetNode = opentree.Nodes.Find(cameratype, false);
            TreeNode cameranode = (TreeNode)draggedNode.Clone();
            targetNode[0].Nodes.Add(cameranode);

            opentree.SelectedNode = cameranode;
        }
    }
}

选择数据节点

private void opentree_ItemDrag(object sender, ItemDragEventArgs e)
{
    TreeNode selectnode = (TreeNode)e.Item;
    if (selectnode.Level == 2 && !starnodelist.Contains(selectnode))
        this.DoDragDrop(e.Item, DragDropEffects.Move);
}

graphic

        拖动相机节点传递数据给工具,相机与工具之间用线条显示连接;双击线段可以删除线段。

        1.根据给出的起始和结束节点绘制线条

private void paint(TreeNode starnode, TreeNode endnode)
{
    try
    {
        if (!starnode.IsVisible)
        {
            starnode = starnode.Parent;
            paint(starnode, endnode);
            return;
        }
        if (!endnode.IsVisible)
        {
            endnode = endnode.Parent;
        }

        Point pt1 = starnode.Bounds.Location;
        pt1.Offset(starnode.Bounds.Width, starnode.Bounds.Height / 2);
        Point pt2 = endnode.Bounds.Location;
        pt2.Offset(endnode.Bounds.Width, endnode.Bounds.Height / 2);
        Point pt12 = pt1;
        int width = graphicsPaths.Count * 10 + 20;
        pt12.Offset(width, 0);
        Point pt21 = pt12;
        pt21.Y = pt2.Y;
        Point[] pointlist = { pt1, pt12, pt21, pt2 };

        graphicsPaths.Add(new GraphicsPath());
        graphicsPaths[graphicsPaths.Count - 1].AddLines(pointlist);
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
        return;
    }
}

        2.删除线段

#region 删除线条
//根据传入节点,删除起始节点是传入节点的线段
public void deleteline(TreeNode starnode)
{
    if (starnode == null)
        return;
    int index = starnodelist.IndexOf(starnode);
    if (index > -1)
    {
        graphicsPaths.RemoveAt(index);
        starnodelist.RemoveAt(index);
        endnodelist.RemoveAt(index);
    }
    else
    {
        MessageBox.Show("select line again!");
    }
}

//根据鼠标点击确定的线段索引,删除线段
public bool deleteline()
{
    if (selectindex != -1)
    {
        graphicsPaths[selectindex].Dispose();
        graphicsPaths.RemoveAt(selectindex);
        starnodelist.RemoveAt(selectindex);
        endnodelist.RemoveAt(selectindex);
        selectindex = -1;
        return true;
    }
    else
    {
        MessageBox.Show("select line again!");
        return false;
    }
}

//根据鼠标双击位置确认线段
private void opentree_MouseDoubleClick(object sender, MouseEventArgs e)
{
    if (e.Button == MouseButtons.Left)
    {
        Point point = new Point(e.X, e.Y);
        foreach (GraphicsPath pt in graphicsPaths)
        {
            bool isvisible = false;
            isvisible = pt.IsOutlineVisible(point, pen);
            if (isvisible)
            {
                Pen selectpen = new Pen(Color.Red, 2);
                AdjustableArrowCap aac = new AdjustableArrowCap(3, 4);
                selectpen.CustomEndCap = aac;
                graphics.DrawPath(selectpen, pt);
                selectindex = graphicsPaths.IndexOf(pt);
                return;
            }
        }
    }
}
#endregion

        3.opentree展开和关闭节点,更新graphic

#region 刷新treeview,重新绘图
//更新函数
public void reflash()
{
    opentree.Refresh();
    graphicsPaths = new List<GraphicsPath>();
    for (int i = 0; i < starnodelist.Count; i++)
    {
        paint(starnodelist[i], endnodelist[i]);
    }
    foreach (GraphicsPath path in graphicsPaths)
    {
        graphics.DrawPath(pen, path);
    }
}

//鼠标停留一段时间,自动更新
private void opentree_NodeMouseHover(object sender, TreeNodeMouseHoverEventArgs e)
{
    reflash();
}

//关闭节点更新
private void opentree_AfterCollapse(object sender, TreeViewEventArgs e)
{
    reflash();
}

//展开节点更新
private void opentree_AfterExpand(object sender, TreeViewEventArgs e)
{
    reflash();
}

//定时器更新
private void timer1_Tick(object sender, EventArgs e)
{
    reflash();
}
#endregion

DisplayForm设计

List<PictureBox> camerapicture = new List<PictureBox>();

#region 显示模块        
private void onecamera()
{
    //布局对象
    TableLayoutPanel tableLayoutPanel = new TableLayoutPanel();

    //设置布局的列数与行数(1列1行)
    tableLayoutPanel.ColumnCount = 1;
    tableLayoutPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));  //设置百分比

    tableLayoutPanel.RowCount = 1;
    tableLayoutPanel.RowStyles.Add(new ColumnStyle(SizeType.Percent, 100F));  //设置百分比

    //添加控件
    tableLayoutPanel.Controls.Add(camerapicture[0]);
    tableLayoutPanel.Dock = DockStyle.Fill;
    tableLayoutPanel.AutoSize = true;
    //this.Invoke(new AddControlDelegate(AddControl), new object[] { this.panel3, tableLayoutPanel });
    panel1.Controls.Add(tableLayoutPanel);
}

private void twocamera()
{
    //布局对象
    TableLayoutPanel tableLayoutPanel = new TableLayoutPanel();

    //设置布局的行数
    tableLayoutPanel.RowCount = 3;  //分成上下两部分
    tableLayoutPanel.RowStyles.Add(new ColumnStyle(SizeType.Percent, 20F));  //设置百分比
    tableLayoutPanel.RowStyles.Add(new ColumnStyle(SizeType.Percent, 60F));
    tableLayoutPanel.RowStyles.Add(new ColumnStyle(SizeType.Percent, 20F));

    //创建布局器对象
    TableLayoutPanel tableLayUP = new TableLayoutPanel() { Dock = DockStyle.Fill };
    //左右等分(1行2列)
    tableLayUP.ColumnCount = 2;
    tableLayUP.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F));  //设置百分比
    tableLayUP.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F));

    //添加相机
    tableLayUP.Controls.Add(camerapicture[0], 0, 0);  //行列坐标
    tableLayUP.Controls.Add(camerapicture[1], 1, 0);

    //将上半部分添加到布局器中
    tableLayUP.AutoSize = true;
    tableLayoutPanel.Controls.Add(tableLayUP, 0, 1);

    //添加控件
    tableLayoutPanel.AutoSize = true;
    tableLayoutPanel.Dock = DockStyle.Fill;
    panel1.Controls.Add(tableLayoutPanel);
}

private void threecamera()
{
    //布局对象
    TableLayoutPanel tableLayoutPanel = new TableLayoutPanel();

    //设置布局的行数
    tableLayoutPanel.RowCount = 2;  //分成上下两部分
    tableLayoutPanel.RowStyles.Add(new ColumnStyle(SizeType.Percent, 50F));  //设置百分比
    tableLayoutPanel.RowStyles.Add(new ColumnStyle(SizeType.Percent, 50F));

    //创建布局器对象
    TableLayoutPanel tableLayUP = new TableLayoutPanel() { Dock = DockStyle.Fill };
    //左右等分(1行2列)
    tableLayUP.ColumnCount = 2;
    tableLayUP.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F));  //设置百分比
    tableLayUP.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F));
    //添加相机
    tableLayUP.Controls.Add(camerapicture[0], 0, 0);  //行列坐标
    tableLayUP.Controls.Add(camerapicture[1], 1, 0);

    //将上半部分添加到布局器中
    tableLayoutPanel.Controls.Add(tableLayUP, 0, 0);

    //创建布局器对象
    TableLayoutPanel tableLayDown = new TableLayoutPanel() { Dock = DockStyle.Fill };
    //左中右等分(1行3列)只用中间一列
    tableLayDown.ColumnCount = 3;
    tableLayDown.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 20F));  //设置百分比
    tableLayDown.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 60F));
    tableLayDown.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 20F));
    //添加相机
    tableLayDown.Controls.Add(camerapicture[2], 1, 0);  //行列坐标

    //将下半部分添加到布局器中
    tableLayoutPanel.Controls.Add(tableLayDown, 0, 1);

    //添加控件
    tableLayoutPanel.Dock = DockStyle.Fill;
    panel1.Controls.Add(tableLayoutPanel);
}

private void fourcamera()
{
    //布局对象
    TableLayoutPanel tableLayoutPanel = new TableLayoutPanel();

    //设置布局的行数与列数
    tableLayoutPanel.ColumnCount = 2;
    tableLayoutPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F));  //设置百分比
    tableLayoutPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F));

    tableLayoutPanel.RowCount = 2;
    tableLayoutPanel.RowStyles.Add(new ColumnStyle(SizeType.Percent, 50F));  //设置百分比
    tableLayoutPanel.RowStyles.Add(new ColumnStyle(SizeType.Percent, 50F));

    //添加lab标签
    tableLayoutPanel.Controls.Add(camerapicture[0], 0, 0);  //行列坐标
    tableLayoutPanel.Controls.Add(camerapicture[1], 1, 0);
    tableLayoutPanel.Controls.Add(camerapicture[2], 0, 1);
    tableLayoutPanel.Controls.Add(camerapicture[3], 1, 1);

    //添加控件
    tableLayoutPanel.Dock = DockStyle.Fill;
    panel1.Controls.Add(tableLayoutPanel);
}

public void imageshow(List<PictureBox> camera)
{
    camerapicture = camera;

    panel1.Controls.Clear();

    foreach (PictureBox i in camerapicture)
    {
        i.Dock = DockStyle.Fill;
        i.SizeMode = PictureBoxSizeMode.StretchImage;
    }

    switch (camerapicture.Count)
    {
        case 1: onecamera(); break;
        case 2: twocamera(); break;
        case 3: threecamera(); break;
        case 4: fourcamera(); break;
        default: break;
    }
}
#endregion

ToolForm设计

        略

主窗口设计

参数定义

hikvision my_hik = new hikvision();
do3think my_do3 = new do3think();
mindvision my_mind = new mindvision();

ImageList ImageList = new ImageList();
List<PictureBox> camerapicture = new List<PictureBox>();
List<TreeNode> opennodelist = new List<TreeNode>();

DeviceList DeviceForm = new DeviceList();
CameraList CameraForm = new CameraList();
DispalyPicture DisplayForm = new DispalyPicture();
System.Windows.Forms.TreeView T_cameratree;
System.Windows.Forms.TreeView T_opentree;

Dictionary<string, string> cameraname = new Dictionary<string, string>()
{{"do3think","度申"},
 {"hikvision","海康威视"},
 {"mindvision","迈德威视"},
 {"tool","工具" }
};

 添加工作栏

工作栏部分代码

#region 工具栏
private void deviceFormToolStripMenuItem_Click(object sender, EventArgs e)
{
    DeviceForm.Show(dockPanel1, DockState.DockLeftAutoHide);
}

private void cameraFormToolStripMenuItem_Click(object sender, EventArgs e)
{
    CameraForm.Show(dockPanel1, DockState.Float);
}

private void displayFormToolStripMenuItem_Click(object sender, EventArgs e)
{
    DisplayForm.Show(dockPanel1, DockState.Float);
}

#endregion

查找相机

/// <summary>
/// 查找可连接设备
/// </summary>
public void camerascan()
{
    uint h_count, d_count;
    int m_count;

    my_hik.CameraScan(out h_count);
    my_do3.CameraScan(out d_count);
    my_mind.CameraScan(out m_count);

    if (h_count > 0)
    {
        DeviceForm.add_cameranode("hikvision", h_count);
    }
    else
    {
        MessageBox.Show("nofind hikvision camera");
    }
    if (d_count > 0)
    {
        DeviceForm.add_cameranode("do3think", d_count);
    }
    else
    {
        MessageBox.Show("nofind do3think camera");
    }
    if (m_count > 0)
    {
        DeviceForm.add_cameranode("mindvision", (uint)m_count);
    }
    else
    {
        MessageBox.Show("nofind mindvision camera");
    }
}

 打开指定相机

/// <summary>
/// 打开指定相机
/// </summary>
public void cameraopen()
{
    TreeNode opennode = T_opentree.SelectedNode;
    bool openflag = false;
    string cameratype = opennode.Tag.ToString();
    int selectdevice = int.Parse(T_cameratree.SelectedNode.Name);
    camerapicture.Add(new PictureBox());
    camerapicture[camerapicture.Count - 1].Name = opennode.Tag.ToString() + " " + opennode.Name;
    switch (cameratype)
    {
        case "do3think":
            {
                openflag = my_do3.CameraOpen((uint)selectdevice, camerapicture[camerapicture.Count - 1].Handle);
            }
            break;
        case "hikvision":
            {
                openflag = my_hik.CameraOpen(selectdevice, camerapicture[camerapicture.Count - 1].Handle);
            }
            break;
        case "mindvision":
            {
                openflag = my_mind.CameraOpen(selectdevice, camerapicture[camerapicture.Count - 1].Handle);
            }
            break;
        default: break;
    }
    if (openflag == false)
    {
        DeviceForm.remove_opennode(opennode);
        T_cameratree.SelectedNode.Text += " (disconnect)";
        T_opentree.SelectedNode.Remove();
        camerapicture.RemoveAt(camerapicture.Count - 1);
        MessageBox.Show("fail open!");
    }
    else
    {
        opennodelist.Add(opennode);
        add_datanode();
    }
    DisplayForm.imageshow(camerapicture);
}

添加相机功能菜单

#region 相机功能菜单
private void opentree_MouseClick(object sender, MouseEventArgs e)
{
    if (e.Button == MouseButtons.Right)
    {
        TreeNode selectedNode = T_opentree.GetNodeAt(e.X, e.Y);
        if (selectedNode != null && selectedNode.Level == 1 && selectedNode.Tag.ToString() != "tool")
        {
            T_opentree.SelectedNode = selectedNode;
            contextMenuStrip1.Show(T_opentree, e.Location);
        }
    }
}

private void SaveImageToolStripMenuItem_Click(object sender, EventArgs e)
{
    SaveFileDialog sfd = new SaveFileDialog();
    sfd.Filter = "bmp file(*.bmp)|*.bmp|jpeg file(*.jpeg)|*.jpeg|png file(*.png)|*.png|tif file(*.tif)|*.tif|gif file(*.gif)|*.gif|raw Files(*.dat)|*.dat";

    if (sfd.ShowDialog() == DialogResult.OK)
    {
        TreeNode selectnode = T_opentree.SelectedNode;
        TreeNodeCollection childNodes = selectnode.Parent.Nodes;
        int nodeindex = childNodes.IndexOf(selectnode);

        string filepath = sfd.FileName;

        switch (selectnode.Parent.Name)
        {
            case "do3think": my_do3.savefunc(filepath, nodeindex); break;
            case "hikvision": my_hik.savefunc(filepath, nodeindex); break;
            case "mindvision": my_mind.savefunc(filepath, nodeindex); break;
            default: break;
        }
    }
}

private void CloseCameraToolStripMenuItem_Click(object sender, EventArgs e)
{
    TreeNode selectnode = T_opentree.SelectedNode;
    TreeNodeCollection childNodes = selectnode.Parent.Nodes;
    int nodeindex = childNodes.IndexOf(selectnode);

    switch (selectnode.Tag.ToString())
    {
        case "do3think": my_do3.CameraClose(nodeindex); break;
        case "hikvision": my_hik.CameraClose(nodeindex); break;
        case "mindvision": my_mind.CameraClose(nodeindex); break;
        default: break;
    }

    int index = opennodelist.IndexOf(selectnode);
    camerapicture[index].Dispose();
    camerapicture.RemoveAt(index);
    opennodelist.Remove(selectnode);
    DeviceForm.remove_opennode(selectnode);
    List<TreeNode> starnodes = CameraForm.get_starnodelist();
    if (selectnode.FirstNode != null)
    {
        if (starnodes.Contains(selectnode.FirstNode))
        {
            CameraForm.deleteline(selectnode.FirstNode);
        }
    }
    selectnode.Remove();

    DisplayForm.imageshow(camerapicture);
    CameraForm.reflash();
    updata_tool();
}

private void 关闭工具ToolStripMenuItem_Click(object sender, EventArgs e)
{
    List<TreeNode> endnodes = CameraForm.get_endnodelist();
    TreeNode toolnode = T_opentree.SelectedNode;
    if (toolnode.Parent.Text == "工具" || toolnode.Parent.Text == "tool")
    {
        if (endnodes.Count > 0 && endnodes.Contains(toolnode))
        {
            return;
        }
        Tool toolform = (Tool)toolnode.Tag;
        toolform.Close();
        toolform.Dispose();
        toolnode.Remove();
    }
}
#endregion

成果展示

        以海康虚拟相机为例。开始运行程序,在初始化过程中查找相机。

拖动节点到opentree,即打开相机。

关闭displayform

点击工作栏“displayform”,重新打开displayform。在关闭期间,窗口没有真正关闭,而是将窗口隐藏。

同样,重新打开的窗口也可以随意拖动位置。

打开多个相机

功能栏切换语言

向工具传递图像数据,其中可以多个相机数据传递给一个工具。

删除线段,即断开数据传输。

相机功能菜单:保存图像、关闭相机、关闭工具。关闭相机后,连接自动断开,但没有断开连接,工具不能关闭。

关闭全部相机和工具。

  • 27
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值