Exemple #1
0
        /// <summary>
        /// 対象物の位置をロボット座標系で取得します。
        /// </summary>
        /// <param name="blob"></param>
        /// <returns></returns>
        public static (double x, double y) GetTargetRobotCoordinate(SettingsObj obj, ConnectedComponents.Blob blob)
        {
            var srcList = new List <DenseVector>(4);
            var dstList = new List <DenseVector>(4);

            // 各座標系の4点をリストに詰める
            srcList.Add(DenseVector.OfArray(new double[] { obj.TopLeftArPoseX, obj.TopLeftArPoseY }));
            srcList.Add(DenseVector.OfArray(new double[] { obj.TopRightArPoseX, obj.TopRightArPoseY }));
            srcList.Add(DenseVector.OfArray(new double[] { obj.BottomRightArPoseX, obj.BottomRightArPoseY }));
            srcList.Add(DenseVector.OfArray(new double[] { obj.BottomLeftArPoseX, obj.BottomLeftArPoseY }));
            dstList.Add((HomographyHelper.CreateVector2(obj.TopLeftDobotPoseX, obj.TopLeftDobotPoseY)));
            dstList.Add(HomographyHelper.CreateVector2(obj.TopRightDobotPoseX, obj.TopRightDobotPoseY));
            dstList.Add(HomographyHelper.CreateVector2(obj.BottomRightDobotPoseX, obj.BottomRightDobotPoseY));
            dstList.Add(HomographyHelper.CreateVector2(obj.BottomLeftDobotPoseX, obj.BottomLeftDobotPoseY));

            // 画像座標系での値
            Console.WriteLine($"homography_IMAGE:imgX:{blob.Left + blob.Width / 2}, imgY:{blob.Top + blob.Height / 2}");
            // 射影変換行列を求めて
            var h**o = HomographyHelper.FindHomography(srcList, dstList);

            // 入力平面から出力平面上の座標に変換
            var ret = h**o.Translate(blob.Left + blob.Width / 2, blob.Top + blob.Height / 2);

            // ロボット座標系での値
            Console.WriteLine($"homography_ROBOT:boxX:{ret.dstX}, boxY:{ret.dstY}");

            return(ret);
        }
Exemple #2
0
        /// <summary>
        /// 判断两个blob是否相同
        /// </summary>
        /// <param name="blob1"></param>
        /// <param name="blob2"></param>
        /// <returns></returns>
        private static bool IsSame(ConnectedComponents.Blob blob1, ConnectedComponents.Blob blob2)
        {
            //如果两个物体 ,宽度 高度,中心点 area 接近则认为它们是相同的
            if (Math.Abs(blob1.Width - blob2.Width) >= 40)
            {
                return(false);
            }

            if (Math.Abs(blob1.Height - blob2.Height) >= 35)
            {
                return(false);
            }

            if (Math.Abs(blob1.Centroid.Y - blob2.Centroid.Y) >= 30)
            {
                return(false);
            }

            if (Math.Abs(blob1.Area - blob2.Area) >= 7000)
            {
                return(false);
            }

            return(true);
        }
Exemple #3
0
        private static void Blob()
        {
            Mat src       = new Mat("data/shapes.png", ImreadModes.Color);
            Mat gray      = src.CvtColor(ColorConversionCodes.BGR2GRAY);
            Mat binary    = gray.Threshold(0, 255, ThresholdTypes.Otsu | ThresholdTypes.Binary);
            Mat labelView = new Mat();
            Mat rectView  = binary.CvtColor(ColorConversionCodes.GRAY2BGR);

            ConnectedComponents cc = Cv2.ConnectedComponentsEx(binary);

            if (cc.LabelCount <= 1)
            {
                return;
            }

            // draw labels

            /*
             * Scalar[] colors = cc.Blobs.Select(_ => Scalar.RandomColor()).ToArray();
             * int height = cc.Labels.GetLength(0);
             * int width = cc.Labels.GetLength(1);
             * var labelViewIndexer = labelView.GetGenericIndexer<Vec3b>();
             * for (int y = 0; y < height; y++)
             * {
             *  for (int x = 0; x < width; x++)
             *  {
             *      int labelValue = cc.Labels[y, x];
             *      labelViewIndexer[y, x] = colors[labelValue].ToVec3b();
             *  }
             * }
             */
            cc.RenderBlobs(labelView);

            // draw bonding boxes except background
            foreach (var blob in cc.Blobs.Skip(1))
            {
                rectView.Rectangle(blob.Rect, Scalar.Red);
            }

            // filter maximum blob
            ConnectedComponents.Blob maxBlob = cc.GetLargestBlob();
            //cc.Blobs.Skip(1).OrderByDescending(b => b.Area).First();
            Mat filtered = new Mat();

            cc.FilterByBlob(src, filtered, maxBlob);

            using (new Window("src", src))
                using (new Window("binary", binary))
                    using (new Window("labels", labelView))
                        using (new Window("bonding boxes", rectView))
                            using (new Window("maximum blob", filtered))
                            {
                                Cv2.WaitKey();
                            }
        }
Exemple #4
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
        }
        public static void TestMain()
        {
            while (true)
            {
                string fileName = @"./Images/";
                Console.WriteLine("输入图片名称");
                fileName += Console.ReadLine();
                Console.WriteLine(DateTime.Now.ToString("HH:mm:ss fff"));
                bool isNeedToSave = BlobUtils.IsNeedToSave(fileName);
                Console.WriteLine("IsNeedToSave = " + isNeedToSave);
                Console.WriteLine(DateTime.Now.ToString("HH:mm:ss fff"));
            }


            //图片名称
            string imgFile = @"./Images/check1.jpg";
            //光线模式文件
            string lightPatternFile = @"./Images/blank.jpg";
            //移除背景光线的方法  0 different差  1 div 除 (根据测试除的效果略好于差,均大幅好于不用)
            int lightMethod = 0;

            Console.WriteLine("lightmethod = " + lightMethod);
            // 分割的方法  1 connected component    2 connected components with statistic(统计)  3 find contour(轮廓线)
            int segmentMethod = 1;

            //转换为单通道灰度图
            Mat img      = Cv2.ImRead(imgFile, ImreadModes.GrayScale);
            Mat cloneImg = img.Clone();

            //noise removal 噪音去除
            img = img.MedianBlur(3);

            //使用光照模型去除背景, 拍摄同样一张图片但是不带物体
            Mat light = Cv2.ImRead(lightPatternFile, ImreadModes.GrayScale);

            light = light.MedianBlur(3);
            if (lightMethod == 0)
            {
                img = light - img;
            }
            else if (lightMethod == 1)
            {
                img.ConvertTo(img, MatType.CV_32F);
                light.ConvertTo(light, MatType.CV_32F);
                img = (1 - (light / img)) * 255;
                img.ConvertTo(img, MatType.CV_8U);
            }

            //二值化图像
            if (lightMethod == 0 || lightMethod == 1)
            {
                img = img.Threshold(30, 255, ThresholdTypes.Binary);
            }
            else
            {
                img = img.Threshold(140, 255, ThresholdTypes.BinaryInv);
            }


            if (segmentMethod == 1)
            {
                // 1 connected component    2 connected components with statistic(统计)  3 find contour(轮廓线)
                //int nLabels = Cv2.ConnectedComponents(img, label, PixelConnectivity.Connectivity8, MatType.CV_32S);

                ConnectedComponents components = img.ConnectedComponentsEx();
                int       nLabels   = components.LabelCount;
                Point[][] points    = img.FindContoursAsArray(RetrievalModes.External, ContourApproximationModes.ApproxSimple);
                int       findCount = 0;
                for (int i = 0; i < points.Length; i++)
                {
                    if (points[i].Length > 100)
                    {
                        findCount++;
                    }
                }
                findCount--;
                Console.WriteLine(points.Length + "=find" + findCount);
                Console.WriteLine("number of objects = " + components.LabelCount);
                int count = 0;
                List <ConnectedComponents.Blob> list = 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 > 2200 && blob.Width > 50 && blob.Height > 50)
                    {
                        //一瓶矿泉水  width = 227 height=171 area=15907
                        count++;
                        list.Add(blob);
                    }
                }


                list = list.OrderBy(r => r.Centroid.X).ToList();
                Console.WriteLine("实际个数是:" + count);
                Console.WriteLine("width=" + img.Width + ",height=" + img.Height);
                foreach (var blob in list)
                {
                    Console.WriteLine("area=" + blob.Area + ", (" + blob.Centroid.X + "," + blob.Centroid.Y + ")  width=" + blob.Width + ",height=" + blob.Height + "left=" + blob.Left);
                }

                Mat output = Mat.Zeros(img.Rows, img.Cols, MatType.CV_8UC3);

                for (int m = 1; m < nLabels; m++)
                {
                    //Mat mask = label.Equals(m);
                    //output.SetTo(Scalar.RandomColor(),mask);

                    Scalar scalar = Scalar.RandomColor();
                    Vec3b  vec3B  = scalar.ToVec3b();
                    for (int i = 0; i < img.Rows; i++)
                    {
                        for (int j = 0; j < img.Cols; j++)
                        {
                            int num = components.Labels[i, j];

                            if (num == m)
                            {
                                output.Set <Vec3b>(i, j, vec3B);
                            }
                        }
                    }
                }

                using (Window window = new Window("check"))
                {
                    window.ShowImage(output);
                    Cv2.WaitKey(0);
                }
            }


            using (Window window = new Window("check"))
            {
                window.ShowImage(cloneImg);
                Cv2.WaitKey(0);
            }

            //Mat src = Cv2.ImRead("./Images/check1.jpg", ImreadModes.GrayScale);

            //// Histogram view
            //const int Width = 260, Height = 200;
            //Mat render = new Mat(new Size(Width, Height), MatType.CV_8UC3, Scalar.All(255));

            //// Calculate histogram
            //Mat hist = new Mat();
            //int[] hdims = { 256 }; // Histogram size for each dimension
            //Rangef[] ranges = { new Rangef(0, 256), }; // min/max
            //Cv2.CalcHist(
            //    new Mat[] { src },
            //    new int[] { 0 },
            //    null,
            //    hist,
            //    1,
            //    hdims,
            //    ranges);

            //// Get the max value of histogram
            //double minVal, maxVal;
            //Cv2.MinMaxLoc(hist, out minVal, out maxVal);

            //Scalar color = Scalar.All(100);
            //// Scales and draws histogram
            //hist = hist * (maxVal != 0 ? Height / maxVal : 0.0);
            //for (int j = 0; j < hdims[0]; ++j)
            //{
            //    int binW = (int)((double)Width / hdims[0]);

            //    render.Rectangle(
            //        new Point(j * binW, render.Rows - (int)(hist.Get<float>(j))),
            //        new Point((j + 1) * binW, render.Rows),
            //        color);
            //}

            //using (new Window("Image", WindowMode.AutoSize | WindowMode.FreeRatio, src))
            //using (new Window("Histogram", WindowMode.AutoSize | WindowMode.FreeRatio, render))
            //{
            //    Cv2.WaitKey();
            //}

            //Mat mat = new Mat("./Images/check1.jpg",ImreadModes.GrayScale);

            //StringBuilder sb = new StringBuilder();
            //for (int i = 0; i < mat.Rows; i++)
            //{
            //    for (int j = 0; j < mat.Cols; j++)
            //    {
            //        double[] arr = mat.GetArray(i, j);
            //        sb.Append("(");
            //        for (int k = 0; k < arr.Length; k++)
            //        {
            //            sb.Append(arr[k] + ",");
            //        }
            //        sb.Append(")");

            //    }
            //    sb.AppendLine();
            //}

            //File.WriteAllText("1.txt",sb.ToString(),Encoding.UTF8);

            //using (Window window = new Window("Lena", WindowMode.Normal, mat))
            //{


            //    window.ShowImage(mat);

            //    Cv2.WaitKey(100000);
            //}


            //VideoCapture videoCapture = new VideoCapture(@"D:\BaiduYunDownload\希赛系统架构师视频\3 JG:第03章 系统开发基础.wmv");
            //Console.WriteLine(videoCapture.Fps+""+videoCapture.IsOpened());
            //int sleepTime = (int)Math.Round(1000/25.0);

            //using (Window window = new Window("capture"))
            //{
            //    using (Mat image = new Mat())
            //    {
            //        while (true)
            //        {
            //            videoCapture.Read(image);
            //            if (image.Empty())
            //            {
            //                break;
            //            }
            //            window.ShowImage(image);
            //            Cv2.WaitKey(sleepTime);
            //        }
            //    }
            //}
        }