Пример #1
0
 /// <summary>
 /// 根据图片判断是否需要保存
 /// </summary>
 /// <param name="fileName"></param>
 /// <returns></returns>
 public static bool IsNeedToSave(String fileName)
 {
     try
     {
         using (Mat img = Cv2.ImRead(fileName, ImreadModes.GrayScale))
         {
             return(IsNeedToSave(img));
         }
     }
     catch (Exception ex)
     {
         NLogHelper.Trace("判断图片是否需要保存错误:" + ex.ToString());
         return(false);
     }
 }
Пример #2
0
        /// <summary>
        /// 是否需要保存图片
        /// </summary>
        /// <param name="mat">指的是刚刚读进来的灰度图片</param>
        /// <returns></returns>
        public static bool IsNeedToSave(Mat mat)
        {
            if (mat == null || mat.IsDisposed)
            {
                return(false);
            }

            #region 预判断

            if ((DateTime.Now - lastCallTime).TotalMilliseconds < 600)
            {
                //调用间隔至少为600ms
                NLogHelper.Trace("调用频繁,不需要截图");
                return(false);
            }

            lastCallTime = DateTime.Now;

            #endregion

            #region 加载背景图片
            if (backgroundMat == null || backgroundMat.IsDisposed)
            {
                if (!File.Exists(backgroundFile))
                {
                    NLogHelper.Trace("未找到背景图片:" + backgroundFile);
                    backgroundMat = null;
                }
                else
                {
                    try
                    {
                        backgroundMat = Cv2.ImRead(backgroundFile, ImreadModes.GrayScale);
                        //去噪
                        backgroundMat = backgroundMat.MedianBlur(3);
                    }
                    catch (Exception ex)
                    {
                        NLogHelper.Trace("加载背景图片失败:" + ex);
                        if (backgroundMat != null && backgroundMat.IsEnabledDispose)
                        {
                            backgroundMat.Dispose();
                        }
                        backgroundMat = null;
                    }
                }
            }
            #endregion

            #region 图片处理

            ////进行图像灰度化
            if (mat.Channels() > 1)
            {
                Mat outMat = new Mat();
                Cv2.CvtColor(mat, outMat, ColorConversionCodes.BGRA2GRAY);
                mat = outMat;
            }
            //图片去噪
            mat = mat.MedianBlur(3);
            int width  = mat.Width;
            int height = mat.Height;
            //当前使用的背景图片
            Mat usedBackgroundMat = null;
            if (backgroundMat != null)
            {
                if (backgroundMat.Width != width || backgroundMat.Height != height)
                {
                    NLogHelper.Trace("背景图片与原图大小不一样,进行缩放");
                    usedBackgroundMat = backgroundMat.Resize(new Size(width, height));
                }
                else
                {
                    usedBackgroundMat = backgroundMat;
                }
            }

            //是否使用了lightMethod 光照模型去除背景, 拍摄同样一张图片但是不带物体
            bool usedLightMethod = false;
            if (usedBackgroundMat != null && usedBackgroundMat.Width == width && usedBackgroundMat.Height == height)
            {
                if (lightMethod == 0)
                {
                    mat             = usedBackgroundMat - mat;
                    usedLightMethod = true;
                }
                else if (lightMethod == 1)
                {
                    mat.ConvertTo(mat, MatType.CV_32F);
                    usedBackgroundMat.ConvertTo(usedBackgroundMat, MatType.CV_32F);
                    mat = (1 - (usedBackgroundMat / mat)) * 255;
                    mat.ConvertTo(mat, MatType.CV_8U);
                    usedLightMethod = true;
                }
            }

            //二值化图像
            if (usedLightMethod)
            {
                mat = mat.Threshold(30, 255, ThresholdTypes.Binary);
            }
            else
            {
                mat = mat.Threshold(140, 255, ThresholdTypes.Binary);
            }

            #endregion

            #region 联通组件

            ConnectedComponents components = mat.ConnectedComponentsEx();

            List <ConnectedComponents.Blob> blobList = new List <ConnectedComponents.Blob>();

            for (int i = 0; i < components.Blobs.Count; i++)
            {
                if (i == 0)
                {
                    //背景,
                    continue;
                }

                ConnectedComponents.Blob blob = components.Blobs[i];
                //实际区域大小
                if (blob.Area > MinArea && blob.Width > MinWidth && blob.Height > MinHeight)
                {
                    if (blob.Width > width * 0.9 && blob.Height > 0.9)
                    {
                        //发现超大物体,此物体有可能是背景或者其它干扰
                        NLogHelper.Trace("超大物体忽略");
                    }
                    else
                    {
                        //一瓶矿泉水  width = 227 height=171 area=15907
                        blobList.Add(blob);
                    }
                }
            }

            NLogHelper.Trace(string.Format("原图共有{0}个物体", blobList.Count));
            #endregion

            #region 判断是否需要截图

            //获取上一次的blobs
            List <ConnectedComponents.Blob> oldLastBlobs = lastBlobList;
            lastBlobList = blobList;

            if (blobList.Count == 0)
            {
                //没有图片,不需要保存
                NLogHelper.Trace("没有图片,不需要保存");
                return(false);
            }

            //获取最大的宽度的项
            ConnectedComponents.Blob maxItem = blobList.OrderByDescending(r => r.Width).First();

            if (oldLastBlobs == null || oldLastBlobs.Count == 0)
            {
                //之前没有图片 或者 中间范围内没有图片
                if (maxItem.Width > width * 0.7 && maxItem.Height > height * 0.4)
                {
                    //最大的物体很大
                    NLogHelper.Trace("之前没有图像,最大的物体很大,进行保存");
                    return(true);
                }
                else
                {
                    //查找位于中间的个体数量
                    List <ConnectedComponents.Blob> middleBlobs = FindMiddleObjects(width, blobList, 0.81);
                    if (middleBlobs.Count > 0)
                    {
                        //中间有物体
                        NLogHelper.Trace("之前没有图像,中间有物体,进行保存");
                        return(true);
                    }
                    else
                    {
                        //中间没有物体或者物体没有完全到中间
                        NLogHelper.Trace("之前没有图像,中间没有物体或者物体没有完全到中间,进行保存");
                        return(false);
                    }
                }
            }
            else
            {
                //if (maxItem.Width > width*0.7 && maxItem.Height> height*0.4)
                //{
                //    //最大的物体很大
                //    return true;
                //}

                //之前图片有物体
                List <ConnectedComponents.Blob> newMiddleBlobs = FindMiddleObjects(width, blobList, 0.81);
                //获取中间旧的
                List <ConnectedComponents.Blob> oldMiddleBlobs = FindMiddleObjects(width, oldLastBlobs, 0.81);

                if (newMiddleBlobs.Count == 0)
                {
                    //中间没有,认为不需要截图
                    NLogHelper.Trace("之前有图像,新图中间没有,认为不需要截图");
                    return(false);
                }

                //新的中间有图
                if (oldMiddleBlobs.Count == 0)
                {
                    //之前有图片,但图片不在中间,新的又有了
                    NLogHelper.Trace("之前有图片,但图片不在中间,新的又有了,需要截图");
                    return(true);
                }
                else
                {
                    int minDiff = 1;//任务现在和之前相差超过minDiff个物体需要截图
                    //现在和以前均有图片
                    if ((newMiddleBlobs.Count - oldMiddleBlobs.Count) > minDiff)
                    {
                        //现在跟置前有两个以上的不同图片
                        NLogHelper.Trace("现在跟之前有两个以上的不同图片,需要截图");
                        return(true);
                    }
                    else
                    {
                        ////先按最左点排序,再按中心点排序,再按照面积排序  升序
                        newMiddleBlobs = newMiddleBlobs.OrderBy(r => r.Left).ThenBy(r => r.Width).ThenBy(r => r.Centroid.Y).ThenBy(r => r.Area).ToList();
                        oldMiddleBlobs = oldMiddleBlobs.OrderBy(r => r.Left).ThenBy(r => r.Width).ThenBy(r => r.Centroid.Y).ThenBy(r => r.Area).ToList();

                        var lcsTuple = LCS(newMiddleBlobs, oldMiddleBlobs);
                        List <ConnectedComponents.Blob> commonBlobs  = lcsTuple.Item1;
                        List <ConnectedComponents.Blob> onlyNewBlobs = lcsTuple.Item2;
                        List <ConnectedComponents.Blob> onlyOldBlobs = lcsTuple.Item3;

                        if (commonBlobs.Count == 0)
                        {
                            //现在和以前没有公共部分,截图
                            NLogHelper.Trace("现在和以前没有公共部分,需要截图");
                            return(true);
                        }
                        else if (onlyNewBlobs.Count == 0 && onlyOldBlobs.Count == 0)
                        {
                            //全部是公共部分
                            NLogHelper.Trace("现在和以前全部是公共部分,不需要截图");
                            return(false);
                        }
                        else if (onlyOldBlobs.Count == 0)
                        {
                            //新的部分多了,除此之外都是公共的
                            NLogHelper.Trace("新的部分多了,除此之外都是公共的,需要截图");
                            return(true);
                        }
                        else if (onlyNewBlobs.Count == 0)
                        {
                            //旧的部分多了,除此之外全是公共的
                            NLogHelper.Trace("旧的部分多了,除此之外全是公共的,不需要截图");
                            return(false);
                        }
                        else
                        {
                            //旧的部分,新的部分,公共的部分都有
                            NLogHelper.Trace("旧的部分,新的部分,公共的部分都有,需要截图");
                            return(true);
                        }
                    }
                }
            }

            #endregion
        }