海康相机丢包问题

前言

首先,如果是网口相机,发现丢包问题肯定要先看防火墙是不是关了,以及网络设置是否设置正确,这两个解决方法可以通过查看相机厂商提供的网络问题排查手册解决,这里就先不赘述了。

这里主要是解决海康相机在上面的排查手段都做了之后还存在丢包现象,提供一个我个人的解决方法,仅供参考。

然后这个解决方法是c#语言的,当然了,对于其他语言也是存在一定意义的

问题描述

首先,一定要明确下什么是丢包,相机采集的图像到PC软件端时,这张照片出现了少量或者大量的图像错误,甚至这一帧全没了。就是海康网口相机拍摄的照片其中出现了很多横条,这些横条所在位置的数据丢了,导致缓存中是上次的照片.

解决方法

我这个解决方法应该不能叫解决问题的本质,也就是丢包的照片依然在,只是在拍出了丢包的照片之后,进行重拍。也就是我们需要知道这次相机拍的是丢包的,海康相机SDK就提供了这么两个结构体

  • MV_MATCH_INFO_NET_DETECT 网络流量和丢包信息反馈结构体,对应类型为 MV_MATCH_TYPE_NET_DETECT(网口相机)
  • MV_MATCH_INFO_USB_DETECT Host收到从u3v设备端的总字节数,对应类型为 MV_MATCH_TYPE_USB_DETECT (USB相机)
        public struct MV_MATCH_INFO_USB_DETECT
        {
            public long nReviceDataSize;
            public uint nRevicedFrameCount;
            public uint nErrorFrameCount;
            public uint[] nReserved;
        }
        public struct MV_MATCH_INFO_NET_DETECT
        {
            public long nReviceDataSize;
            public long nLostPacketCount;
            public uint nLostFrameCount;
            public uint nNetRecvFrameCount;
            public long nRequestResendPacketCount;
            public long nResendPacketCount;
        }

观察发现他都有个反应丢包数量的参数。
于是定义一个能进行判断是否丢包的类

        class LostFrameInfo
        {
            public bool isGige = true;//默认是网口相机
            /// <summary>
            /// 已接收数据大小 [统计StartGrabbing和StopGrabbing之间的数据量] 
            /// </summary>
            public long nReviceDataSize;

            //Gige

            /// <summary>
            /// 丢失的包数量
            /// </summary>
            public long nLostPacketCount;
            /// <summary>
            /// 丢帧数量
            /// </summary>
            public uint nLostFrameCount;
            public uint nNetRecvFrameCount;
            /// <summary>
            /// 请求重发包数 
            /// </summary>
            public long nRequestResendPacketCount;
            /// <summary>
            /// 重发包数
            /// </summary>
            public long nResendPacketCount;

            //USB

            /// <summary>
            /// 已收到的帧数
            /// </summary>
            public uint nRevicedFrameCount;
            /// <summary>
            /// 错误帧数 
            /// </summary>
            public uint nErrorFrameCount;
            /// <summary>
            /// 保留字节
            /// </summary>
            public uint[] nReserved;

            public override string ToString()
            {
                if (isGige)
                    return $"nReviceDataSize:{nReviceDataSize};nLostPacketCount:{nLostPacketCount};nLostFrameCount:{nLostFrameCount};nNetRecvFrameCount:{nNetRecvFrameCount}" +
                        $"nRequestResendPacketCount:{nRequestResendPacketCount};nResendPacketCount:{nResendPacketCount}";
                else
                    return $"nReviceDataSize:{nReviceDataSize};nRevicedFrameCount:{nRevicedFrameCount};nErrorFrameCount:{nErrorFrameCount}";
            }
            /// <summary>
            /// 跟前一个LostFrameInfo做对比
            /// </summary>
            /// <param name="preLostFrameInfo"></param>
            /// <returns></returns>
            public bool IsLostFrame(LostFrameInfo preLostFrameInfo)
            {
                if (this.isGige)
                    return this.nLostFrameCount > preLostFrameInfo.nLostFrameCount;
                else
                    return this.nErrorFrameCount > preLostFrameInfo.nErrorFrameCount;
            }

            public bool IsLostFrame()
            {
                if (this.isGige)
                    return this.nLostFrameCount > 0 || nLostPacketCount > 0;
                else
                    return this.nErrorFrameCount > 0;
            }

            /// <summary>
            /// 跟前一个LostFrameInfo做对比,重影问题就是这个值突然变大
            /// </summary>
            /// <param name="preLostFrameInfo"></param>
            /// <returns></returns>
            public bool IsLostPacket(LostFrameInfo preLostFrameInfo)
            {
                if (this.isGige)
                    return this.nLostPacketCount > preLostFrameInfo.nLostPacketCount;
                else
                    return false;
            }

            public bool IsLostPacket()
            {
                if (this.isGige)
                    return this.nLostPacketCount > 0 || nLostPacketCount > 0;
                else
                    return false;
            }
            public void SetPara(MyCamera.MV_MATCH_INFO_NET_DETECT MV_NetInfo)
            {
                this.isGige = true;
                this.nReviceDataSize = MV_NetInfo.nReviceDataSize;
                this.nLostPacketCount = MV_NetInfo.nLostPacketCount;
                this.nLostFrameCount = MV_NetInfo.nLostFrameCount;
                this.nNetRecvFrameCount = MV_NetInfo.nNetRecvFrameCount;
                this.nRequestResendPacketCount = MV_NetInfo.nRequestResendPacketCount;
                this.nResendPacketCount = MV_NetInfo.nResendPacketCount;
            }

            public void SetPara(MyCamera.MV_MATCH_INFO_USB_DETECT MV_NetInfo)
            {
                this.isGige = false;
                this.nReviceDataSize = MV_NetInfo.nReviceDataSize;
                this.nRevicedFrameCount = MV_NetInfo.nRevicedFrameCount;
                this.nErrorFrameCount = MV_NetInfo.nErrorFrameCount;
                this.nReserved = MV_NetInfo.nReserved;
            }
        }

获取是否丢帧信息

// ch:获取丢帧数 | en:Get Throw Frame Number
        private LostFrameInfo GetLostFrame()
        {
            MyCamera.MV_ALL_MATCH_INFO pstInfo = new MyCamera.MV_ALL_MATCH_INFO();
            LostFrameInfo lostFrameInfo = new LostFrameInfo();
            if (_pDeviceInfo.nTLayerType == MyCamera.MV_GIGE_DEVICE)
            {
                MyCamera.MV_MATCH_INFO_NET_DETECT MV_NetInfo = new MyCamera.MV_MATCH_INFO_NET_DETECT();
                pstInfo.nInfoSize = (uint)System.Runtime.InteropServices.Marshal.SizeOf(typeof(MyCamera.MV_MATCH_INFO_NET_DETECT));
                pstInfo.nType = MyCamera.MV_MATCH_TYPE_NET_DETECT;
                int size = Marshal.SizeOf(MV_NetInfo);
                try
                {
                    pstInfo.pInfo = Marshal.AllocHGlobal(size);
                    Marshal.StructureToPtr(MV_NetInfo, pstInfo.pInfo, false);

                    _myCamera.MV_CC_GetAllMatchInfo_NET(ref pstInfo);
                    MV_NetInfo = (MyCamera.MV_MATCH_INFO_NET_DETECT)Marshal.PtrToStructure(pstInfo.pInfo, typeof(MyCamera.MV_MATCH_INFO_NET_DETECT));
                    lostFrameInfo.SetPara(MV_NetInfo);
                }
                catch (Exception ex)
                {
                    NlogHelper.Error(ex);
                }
                finally
                {
                    Marshal.FreeHGlobal(pstInfo.pInfo);
                }
                return lostFrameInfo;
            }
            else if (_pDeviceInfo.nTLayerType == MyCamera.MV_USB_DEVICE)
            {
                MyCamera.MV_MATCH_INFO_USB_DETECT MV_NetInfo = new MyCamera.MV_MATCH_INFO_USB_DETECT();
                pstInfo.nInfoSize = (uint)System.Runtime.InteropServices.Marshal.SizeOf(typeof(MyCamera.MV_MATCH_INFO_USB_DETECT));
                pstInfo.nType = MyCamera.MV_MATCH_TYPE_USB_DETECT;
                int size = Marshal.SizeOf(MV_NetInfo);
                try
                {
                    pstInfo.pInfo = Marshal.AllocHGlobal(size);
                    Marshal.StructureToPtr(MV_NetInfo, pstInfo.pInfo, false);

                    _myCamera.MV_CC_GetAllMatchInfo_NET(ref pstInfo);
                    MV_NetInfo = (MyCamera.MV_MATCH_INFO_USB_DETECT)Marshal.PtrToStructure(pstInfo.pInfo, typeof(MyCamera.MV_MATCH_INFO_USB_DETECT));
                    lostFrameInfo.SetPara(MV_NetInfo);
                }
                catch (Exception ex)
                {
                    NlogHelper.Error(ex);
                }
                finally
                {
                    Marshal.FreeHGlobal(pstInfo.pInfo);
                }
                return lostFrameInfo;
            }
            else
            {
                return null;
            }
        }

调用

        private bool GetOneFrame(ImageType type,ref MyCamera.MV_FRAME_OUT frameOutInfo, string fileName = "")
        {
            frameOutInfo = new MyCamera.MV_FRAME_OUT();
            int nRet = MyCamera.MV_OK;
            int tryTimes = 0;
            const int RETRY_TIMES = 2;

            lock (_getOneFrameObj)
            {
                bool result = false;
                do
                {
                    try
                    {
                        preLostFrameInfo = GetLostFrame();
                        NlogHelper.Trace("Before 获取图像帧:" + preLostFrameInfo.ToString());

                        _myCamera.MV_CC_ClearImageBuffer_NET();
                        nRet = _myCamera.MV_CC_GetImageBuffer_NET(ref frameOutInfo, 10000);
                        if (nRet == MyCamera.MV_OK)
                        {
                            bool isLostFrame = false;
                            bool isLostPacket = false;

                            LostFrameInfo lostFrameInfo = GetLostFrame();
                            NlogHelper.Trace("After 获取图像帧:" + lostFrameInfo.ToString());
                            //if(tryTimes == 0)
                            //{
                            //    lostFrameInfo.nLostPacketCount += 200;
                            //    NlogHelper.Trace("更改nLostPacketCount:" + lostFrameInfo.ToString());
                            //}

                            if (lostFrameInfo.IsLostFrame(preLostFrameInfo))
                            {
                                isLostFrame = true;
                                NlogHelper.Error($"疑似丢帧");
                                NlogHelper.Trace($"发生丢帧,相机重拍");
                            }

                            if (lostFrameInfo.IsLostPacket(preLostFrameInfo))
                            {
                                isLostPacket = true;
                                NlogHelper.Error($"疑似丢包");
                                NlogHelper.Trace($"发生丢包,相机重拍");
                            }

                            if (RemoveCustomPixelFormats(frameOutInfo.stFrameInfo.enPixelType))
                            {
                                _myCamera.MV_CC_FreeImageBuffer_NET(ref frameOutInfo);
                                NlogHelper.Trace($"获取图像帧:RemoveCustomPixelFormats");
                                continue;
                            }

                            if (!isLostFrame && !isLostPacket) //如果没丢帧或者没丢包就结束循环
                            {
                                if (type == ImageType.NotSave)
                                {
                                    //注意这里没有调用,需要调用者使用完后调用 MV_CC_FreeImageBuffer_NET
                                    _myCamera.MV_CC_FreeImageBuffer_NET(ref frameOutInfo);
                                }
                                else
                                {
                                    if (!string.IsNullOrEmpty(fileName))
                                    {
                                        SaveImage(frameOutInfo, type, fileName);
                                    }
                                    _myCamera.MV_CC_FreeImageBuffer_NET(ref frameOutInfo);
                                }
                                
                                result = true;
                                break;
                            }
                            else
                            {
                                _myCamera.MV_CC_FreeImageBuffer_NET(ref frameOutInfo);
                            }
                        }
                        else
                        {
                            NlogHelper.Trace($"GetOneFrame : MV_CC_GetImageBuffer_NET is not ok {nRet}");
                        }
                    }
                    catch (Exception ex)
                    {
                        NlogHelper.Error(ex);
                    }
                    finally
                    {
                        tryTimes++;
                    }
                } while (tryTimes <= RETRY_TIMES);

                return result;
            }
        }

相机调用获取一帧MV_CC_GetImageBuffer_NET之前,先获取一下帧信息,然后调用获取一帧MV_CC_GetImageBuffer_NET之后,再获取一下帧信息,前后两个对象对比,如果有丢帧或者丢包就重拍

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值