コード例 #1
0
        public void wykrywanie_konturow(int t1, int t2)
        {
            Thread.Sleep(50);
            try
            {
                Image <Gray, byte> img  = imgInPuzzle.Convert <Gray, byte>();
                Image <Gray, byte> img1 = img;

                Mat graymat = new Mat();
                Mat mask    = new Mat();

                graymat = img1.Mat;

                CvInvoke.AdaptiveThreshold(graymat, mask, 255, AdaptiveThresholdType.MeanC, ThresholdType.BinaryInv, t1 * 10 - 1, t2);

                contours = new Emgu.CV.Util.VectorOfVectorOfPoint();
                con      = new Emgu.CV.Util.VectorOfVectorOfPoint();

                Mat hier = new Mat(mask.Rows, mask.Cols, DepthType.Cv8U, 0);

                CvInvoke.FindContours(mask, contours, hier, Emgu.CV.CvEnum.RetrType.External, Emgu.CV.CvEnum.ChainApproxMethod.ChainApproxSimple);

                for (int i = 0; i < contours.Size; i++)
                {
                    double a = CvInvoke.ContourArea(contours[i], false);
                    if (a > 600 && a < ((mask.Cols * mask.Rows) / 2))
                    {
                        con.Push(contours[i]);
                    }
                }

                CvInvoke.DrawContours(mask, con, -1, new MCvScalar(255, 255, 255), 1);

                ilosc_konturow.Text = "Liczba konturów: " + con.Size.ToString();

                zdj.Source = ToBitmapSource(mask);
            }
            catch (System.NullReferenceException)
            {
                System.Windows.MessageBox.Show("Wczytaj zdjęcia", "Podpowiadarka do puzzli - Błąd", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }
コード例 #2
0
ファイル: MainForm.cs プロジェクト: Lerbytech/ShapeDetection
        public void PerformShapeDetection()
        {
            if (fileNameTextBox.Text != String.Empty)
            {
                Stopwatch watch = Stopwatch.StartNew();
                watch.Start();
                StringBuilder msgBuilder = new StringBuilder("Performance: ");

                #region get image

                img = new Image<Bgr, byte>(fileNameTextBox.Text);
                img = img.Resize(0.5, Inter.Linear).SmoothMedian(5);
                #endregion

                #region HSV magic
                //min.Hue = MinHueTB.Value; min.Satuation = MinSatTB.Value; min.Value = MinValTB.Value;
                //max.Hue = MaxHueTB.Value; max.Satuation = MaxSatTB.Value; max.Value = MaxValTB.Value;

                HsvMagic(img, maskHsvBlack, maskHsvBlue);

                circleImageBox.Image = maskHsvBlack;
                originalImageBox.Image = img;

                img.ToBitmap().Save("C:\\Emgu\\Dump\\Img.png",System.Drawing.Imaging.ImageFormat.Png);
                maskHsvBlack.ToBitmap().Save("C:\\Emgu\\Dump\\maskHsvBlack.png",  System.Drawing.Imaging.ImageFormat.Png);
                maskHsvBlue.ToBitmap().Save("C:\\Emgu\\Dump\\maskHsvBlue.png",  System.Drawing.Imaging.ImageFormat.Png);
                #endregion

                #region Canny and edge detection

                double cannyThreshold = 1.0;
                double cannyThresholdLinking = 500.0;

                Image<Gray, Byte> cannyBlue = maskHsvBlue.Canny(cannyThreshold, cannyThresholdLinking);
                Image<Gray, Byte> cannyBlack = maskHsvBlack.Canny(cannyThreshold, cannyThresholdLinking);

                watch.Stop();
                msgBuilder.Append(String.Format("Hsv and Canny - {0} ms; ", watch.ElapsedMilliseconds));
                #endregion
                cannyBlue.ToBitmap().Save("C:\\Emgu\\Dump\\cannyBlue.png", System.Drawing.Imaging.ImageFormat.Png);
                cannyBlack.ToBitmap().Save("C:\\Emgu\\Dump\\cannyBlack.png", System.Drawing.Imaging.ImageFormat.Png);

                #region Find  rectangles

                #region detect black borders
                VectorOfVectorOfPoint blackborders = new VectorOfVectorOfPoint();//list of black borders
                List<RotatedRect> Black_boxList = new List<RotatedRect>(); //a box is a rotated rectangle
                VectorOfVectorOfPoint othercontours_black = new VectorOfVectorOfPoint();
                getBlackContours(cannyBlack, blackborders, Black_boxList, othercontours_black);
                resultImg = cannyBlack.Convert<Bgr, Byte>();
                #endregion

                #region blue borders

                VectorOfVectorOfPoint blueborders = new VectorOfVectorOfPoint();//list of blue borders
                List<RotatedRect> Blue_boxList = new List<RotatedRect>(); //a box is a rotated rectangle
                VectorOfVectorOfPoint othercontours_blue = new VectorOfVectorOfPoint();
                getBlueContours(cannyBlue, blueborders, Blue_boxList, othercontours_blue);

                #endregion

              #region clear duplicate boxes

                List<RotatedRect> fltrBlue_boxList = new List<RotatedRect>();
                SizeF TMP_SizeF = new SizeF(0,0);
                PointF TMP_PointF = new PointF(0, 0);
                float TMP_Angle = 0;

                if (Blue_boxList.Count >= 2)
                {
                  for (int i = 1; i < Blue_boxList.Count; i++)
                  {
                    if (Blue_boxList[i - 1].Size.Width * Blue_boxList[i - 1].Size.Height > 750)
                    {
                      if (Math.Abs(Blue_boxList[i - 1].Angle - Blue_boxList[i].Angle) < 1)
                      {
                        if (Math.Abs(Blue_boxList[i - 1].Center.X - Blue_boxList[i].Center.X) < 1 && Math.Abs(Blue_boxList[i - 1].Center.Y - Blue_boxList[i].Center.Y) < 1)
                          if (Math.Abs(Blue_boxList[i - 1].Size.Width - Blue_boxList[i].Size.Width) < 1 && Math.Abs(Blue_boxList[i - 1].Size.Height - Blue_boxList[i].Size.Height) < 1)
                          {
                            TMP_PointF.X = (float)(0.5 * (Blue_boxList[i - 1].Center.X + Blue_boxList[i].Center.X));
                            TMP_PointF.Y = (float)(0.5 * (Blue_boxList[i - 1].Center.Y + Blue_boxList[i].Center.Y));
                            TMP_SizeF.Width = (float)(0.5 * (Blue_boxList[i - 1].Size.Width + Blue_boxList[i].Size.Width));
                            TMP_SizeF.Height = (float)(0.5 * (Blue_boxList[i - 1].Size.Height + Blue_boxList[i].Size.Height));
                            TMP_Angle = (float)(0.5 * (Blue_boxList[i - 1].Angle + Blue_boxList[i].Angle));
                            fltrBlue_boxList.Add(new RotatedRect(TMP_PointF, TMP_SizeF, TMP_Angle));

                          }
                      }
                      else fltrBlue_boxList.Add(Blue_boxList[i]);
                    }
                  }
                }
                else { fltrBlue_boxList = Blue_boxList; } //Blue_boxList.Clear(); }

                List<RotatedRect> fltrBlack_boxList = new List<RotatedRect>();
              VectorOfVectorOfPoint fltr_blackborders = new VectorOfVectorOfPoint();
                TMP_SizeF.Width = 0;
                TMP_SizeF.Height = 0;
                TMP_PointF.X = 0;
                TMP_PointF.Y = 0;
                TMP_Angle = 0;

                if (Black_boxList.Count >= 2)
                {
                  for (int i = 1; i < Black_boxList.Count; i++)
                  {
                    if (Black_boxList[i - 1].Size.Width * Black_boxList[i - 1].Size.Height > 10)
                    {
                      if (Math.Abs(Black_boxList[i - 1].Angle - Black_boxList[i].Angle) < 1)
                      {
                        if (Math.Abs(Black_boxList[i - 1].Center.X - Black_boxList[i].Center.X) < 1 && Math.Abs(Black_boxList[i - 1].Center.Y - Black_boxList[i].Center.Y) < 1)
                          if (Math.Abs(Black_boxList[i - 1].Size.Width - Black_boxList[i].Size.Width) < 1 && Math.Abs(Black_boxList[i - 1].Size.Height - Black_boxList[i].Size.Height) < 1)
                          {
                            TMP_PointF.X = (float)(0.5 * (Black_boxList[i - 1].Center.X + Black_boxList[i].Center.X));
                            TMP_PointF.Y = (float)(0.5 * (Black_boxList[i - 1].Center.Y + Black_boxList[i].Center.Y));
                            TMP_SizeF.Width = (float)(0.5 * (Black_boxList[i - 1].Size.Width + Black_boxList[i].Size.Width));
                            TMP_SizeF.Height = (float)(0.5 * (Black_boxList[i - 1].Size.Height + Black_boxList[i].Size.Height));
                            TMP_Angle = (float)(0.5 * (Black_boxList[i - 1].Angle + Black_boxList[i].Angle));
                            fltrBlack_boxList.Add(new RotatedRect(TMP_PointF, TMP_SizeF, TMP_Angle));
                            //fltr_blackborders.Push();
                          }
                      }
                      else fltrBlack_boxList.Add(Black_boxList[i]);
                    }
                  }
                }
                else { fltrBlack_boxList = Black_boxList; }//Black_boxList.Clear(); }
                #endregion

              //////////
                circleImageBox.Image = maskHsvBlack;
              ////////////

                CvInvoke.DrawContours(resultImg, blackborders, -1, new Bgr(Color.Green).MCvScalar);
                CvInvoke.DrawContours(resultImg, othercontours_black, -1, new Bgr(Color.Red).MCvScalar);
                CvInvoke.DrawContours(resultImg, blueborders, -1, new Bgr(Color.Blue).MCvScalar);

                foreach (RotatedRect box in fltrBlack_boxList)
                {
                    CvInvoke.Polylines(resultImg, Array.ConvertAll(box.GetVertices(), Point.Round), true, new Bgr(Color.Aqua).MCvScalar, 1);
                }
                foreach (RotatedRect box in Black_boxList)
                {
                  CvInvoke.Polylines(img, Array.ConvertAll(box.GetVertices(), Point.Round), true, new Bgr(Color.Pink).MCvScalar, 1);
                }
                foreach (RotatedRect box in Blue_boxList)
                {
                  CvInvoke.Polylines(img, Array.ConvertAll(box.GetVertices(), Point.Round), true, new Bgr(Color.DarkViolet).MCvScalar, 1);
                }
                foreach (RotatedRect box in fltrBlue_boxList)
                {
                  CvInvoke.Polylines(resultImg, Array.ConvertAll(box.GetVertices(), Point.Round), true, new Bgr(Color.Yellow).MCvScalar, 1);
                }
                triangleRectangleImageBox.Image = resultImg;
                originalImageBox.Image = img;

                #region save to files
                Image<Bgr, Byte> TMPImageforSaving = new Image<Bgr, byte>(maskHsvBlack.Width, maskHsvBlack.Height, new Bgr(Color.Black));
                CvInvoke.DrawContours(TMPImageforSaving, blackborders, -1, new Bgr(Color.Green).MCvScalar);
                CvInvoke.DrawContours(TMPImageforSaving, othercontours_black, -1, new Bgr(Color.Red).MCvScalar);

                foreach (RotatedRect box in Black_boxList)
                {
                  CvInvoke.Polylines(TMPImageforSaving, Array.ConvertAll(box.GetVertices(), Point.Round), true, new Bgr(Color.Pink).MCvScalar, 1);
                }
                TMPImageforSaving.ToBitmap().Save("C:\\Emgu\\Dump\\NonFltrBlack.png", System.Drawing.Imaging.ImageFormat.Png);

                TMPImageforSaving = new Image<Bgr, byte>(TMPImageforSaving.Width, TMPImageforSaving.Height, new Bgr(Color.Black));
                CvInvoke.DrawContours(TMPImageforSaving, blackborders, -1, new Bgr(Color.Green).MCvScalar);
                CvInvoke.DrawContours(TMPImageforSaving, othercontours_black, -1, new Bgr(Color.Red).MCvScalar);
                foreach (RotatedRect box in Blue_boxList)
                {
                  CvInvoke.Polylines(TMPImageforSaving, Array.ConvertAll(box.GetVertices(), Point.Round), true, new Bgr(Color.DarkViolet).MCvScalar, 1);
                }
                TMPImageforSaving.ToBitmap().Save("C:\\Emgu\\Dump\\NonFltrBlue.png", System.Drawing.Imaging.ImageFormat.Png);
                TMPImageforSaving = new Image<Bgr, byte>(maskHsvBlack.Width, maskHsvBlack.Height, new Bgr(Color.Black));
                CvInvoke.DrawContours(TMPImageforSaving, blackborders, -1, new Bgr(Color.Green).MCvScalar);
                CvInvoke.DrawContours(TMPImageforSaving, othercontours_black, -1, new Bgr(Color.Red).MCvScalar);

                foreach (RotatedRect box in fltrBlack_boxList)
                {
                  CvInvoke.Polylines(TMPImageforSaving, Array.ConvertAll(box.GetVertices(), Point.Round), true, new Bgr(Color.Aqua).MCvScalar, 1);
                }
                TMPImageforSaving.ToBitmap().Save("C:\\Emgu\\Dump\\FltrBlack.png", System.Drawing.Imaging.ImageFormat.Png);

                TMPImageforSaving = new Image<Bgr, byte>(TMPImageforSaving.Width, TMPImageforSaving.Height, new Bgr(Color.Black));
                CvInvoke.DrawContours(TMPImageforSaving, blackborders, -1, new Bgr(Color.Green).MCvScalar);
                CvInvoke.DrawContours(TMPImageforSaving, othercontours_black, -1, new Bgr(Color.Red).MCvScalar);
                foreach (RotatedRect box in fltrBlue_boxList)
                {
                  CvInvoke.Polylines(TMPImageforSaving, Array.ConvertAll(box.GetVertices(), Point.Round), true, new Bgr(Color.Yellow).MCvScalar, 1);
                }
                TMPImageforSaving.ToBitmap().Save("C:\\Emgu\\Dump\\FltrBlue.png", System.Drawing.Imaging.ImageFormat.Png);
                #endregion

              /*
                List<VectorOfPoint> contours_for_work = new List<VectorOfPoint>();
                using (VectorOfVectorOfPoint contours = blackborders)
                {
                  for (int i = 0; i < contours.Size; i++)
                  {
                    contours_for_work.Add(contours[i]);
                  }
                }
                contours_for_work.Sort((VectorOfPoint cont1, VectorOfPoint cont2) =>
                 (bool) (CvInvoke.ContourArea(cont1) > CvInvoke.ContourArea(cont1)) );
              */

                VectorOfVectorOfPoint Big = new VectorOfVectorOfPoint();
                bool ready = false;
                using (VectorOfVectorOfPoint contours = blackborders)
                {
                    for (int i = 0; i < contours.Size && !ready; i++)
                    {

                        VectorOfPoint contourI = contours[i];
                        for (int j = i + 1; j < contours.Size && !ready; j++)
                        {
                            if (0.38 * CvInvoke.ContourArea(contours[j]) > CvInvoke.ContourArea(contourI) && 0.26 * CvInvoke.ContourArea(contours[j]) < CvInvoke.ContourArea(contourI))
                            {
                                Big.Push(contours[j]);
                                Big.Push(contours[i]);
                                ready = !ready;
                            }
                        }
                    }
                }

                TMPImageforSaving = new Image<Bgr, Byte>(resultImg.Width, resultImg.Height, new Bgr(Color.Black));
                CvInvoke.DrawContours(TMPImageforSaving, Big, -1, new Bgr(Color.White).MCvScalar);
                TMPImageforSaving.ToBitmap().Save("C:\\Emgu\\Dump\\DetectedContours.png", System.Drawing.Imaging.ImageFormat.Png);
              imgHsv[0].ToBitmap().Save("C:\\Emgu\\Dump\\ImgHsv - Hue.png", System.Drawing.Imaging.ImageFormat.Png);
              imgHsv[1].ToBitmap().Save("C:\\Emgu\\Dump\\ImgHsv - Sat.png", System.Drawing.Imaging.ImageFormat.Png);
              imgHsv[2].ToBitmap().Save("C:\\Emgu\\Dump\\ImgHsv - Val.png", System.Drawing.Imaging.ImageFormat.Png);
              Image<Hls, byte> HlsImg = img.Convert<Hls, Byte>();

              HlsImg[0].ToBitmap().Save("C:\\Emgu\\Dump\\Img HLS - Hue.png", System.Drawing.Imaging.ImageFormat.Png);
              HlsImg[1].ToBitmap().Save("C:\\Emgu\\Dump\\Img HLS - Light.png", System.Drawing.Imaging.ImageFormat.Png);
              HlsImg[2].ToBitmap().Save("C:\\Emgu\\Dump\\Img HLS - Sat.png", System.Drawing.Imaging.ImageFormat.Png);

                lineImageBox.Image = TMPImageforSaving;

                watch.Stop();
                msgBuilder.Append(String.Format("Triangles & Rectangles - {0} ms; ", watch.ElapsedMilliseconds));
                #endregion
                /*

                  lineImageBox.Image = resultImg;
                  originalImageBox.Image = img;
                  this.Text = msgBuilder.ToString();

                  #region draw and rectangles
                  Mat triangleRectangleImage = new Mat(img.Size, DepthType.Cv8U, 3);
                  triangleRectangleImage.SetTo(new MCvScalar(0));

                  foreach (RotatedRect box in boxList)
                  {
                      CvInvoke.Polylines(triangleRectangleImage, Array.ConvertAll(box.GetVertices(), Point.Round), true, new Bgr(Color.DarkOrange).MCvScalar, 2);
                  }

                  triangleRectangleImageBox.Image = triangleRectangleImage;
                  #endregion

                  #region draw lines
                  /*Mat lineImage = new Mat(img.Size, DepthType.Cv8U, 3);
                  lineImage.SetTo(new MCvScalar(0));
                 foreach (LineSegment2D line in lines)
                   CvInvoke.Line(lineImage, line.P1, line.P2, new Bgr(Color.Green).MCvScalar, 2);

                  lineImageBox.Image = lineImage;
                  #endregion
              }
              }

              #region draw
              //foreach (LineSegment2D line in lines)
              //CvInvoke.Line(lineImage, line.P1, line.P2, new Bgr(Color.Green).MCvScalar, 2);

              #endregion
               * */
            }
        }
コード例 #3
0
ファイル: MainForm.cs プロジェクト: Lerbytech/ShapeDetection
        public void getBlueContours(Image<Gray, Byte> src, VectorOfVectorOfPoint blueborders, List<RotatedRect> Blue_boxList, VectorOfVectorOfPoint othercontours_blue)
        {
            //blueborders = new VectorOfVectorOfPoint();//list of blue borders
              //Blue_boxList = new List<RotatedRect>(); //a box is a rotated rectangle
              //othercontours_blue = new VectorOfVectorOfPoint();

              using (VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint())
              {
            CvInvoke.FindContours(src, contours, null, RetrType.List, ChainApproxMethod.ChainApproxSimple);

            for (int i = 0; i < contours.Size; i++)
            {
              using (VectorOfPoint contour = contours[i])
              using (VectorOfPoint approxContour = new VectorOfPoint())
              {
                CvInvoke.ApproxPolyDP(contour, approxContour, CvInvoke.ArcLength(contour, true) * 0.05, true);
                if (CvInvoke.ContourArea(approxContour, false) > 250 && CvInvoke.BoundingRectangle(approxContour).Width * CvInvoke.BoundingRectangle(approxContour).Height > 1000) //only consider contours with area greater than 250
                {
                  if (approxContour.Size == 4)
                  {
                    Blue_boxList.Add(CvInvoke.MinAreaRect(approxContour));
                    blueborders.Push(contour);
                  }
                  else
                  {
                    othercontours_blue.Push(contour);
                    //Point[] pts = approxContour.ToArray();
                    //other.Add(PointCollection.PolyLine(pts, true));
                  }
                }
              }
            }
              }
        }
コード例 #4
0
ファイル: MainForm.cs プロジェクト: Lerbytech/ShapeDetection
        public void getBlackContours(Image<Gray, Byte> src, VectorOfVectorOfPoint blackborders, List<RotatedRect> Black_boxList, VectorOfVectorOfPoint othercontours_black)
        {
            //blackborders = new VectorOfVectorOfPoint();//list of black borders
             //Black_boxList = new List<RotatedRect>(); //a box is a rotated rectangle
             //othercontours_black = new VectorOfVectorOfPoint();

            Bitmap TMPGood = new Bitmap(src.ToBitmap() , src.Width, src.Height);
            Bitmap TMPBad = new Bitmap(src.ToBitmap(), src.Width, src.Height);
            Graphics gGood = Graphics.FromImage(TMPGood);
            Graphics gBad = Graphics.FromImage(TMPBad);
            //Pen RedPen = new Pen(Color.Red);
            //Pen GreenPen = new Pen(Color.Green);
            Brush RedBrush = new SolidBrush(Color.Red);
            Brush GreenBrush = new SolidBrush(Color.Green);

                using (VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint())
                {
                  CvInvoke.FindContours(src, contours, null, RetrType.List, ChainApproxMethod.ChainApproxSimple);
                    for (int i = 0; i < contours.Size; i++)
                    {
                        using (VectorOfPoint contour = contours[i])
                        using (VectorOfPoint approxContour = new VectorOfPoint())
                        {
                          Point[] ptsContour = contour.ToArray();
                          for (int k = 0; k < ptsContour.Length; k++)
                          {
                            gBad.FillEllipse(RedBrush, ptsContour[k].X, ptsContour[k].Y, 6, 6);
                          }

                            CvInvoke.ApproxPolyDP(contour, approxContour, CvInvoke.ArcLength(contour, true) * 0.05, true);
                            if (CvInvoke.ContourArea(approxContour, false) > 250) //only consider contours with area greater than 250
                            {
                              Point[] ptsApprox = approxContour.ToArray();

                              //TMP.Draw(pts, new Bgr(Color.DarkOrange), 5); //!!!!!!!!!!!!!!!
                              for (int k = 0; k < ptsApprox.Length; k++)
                              {
                                gGood.FillEllipse(GreenBrush, ptsApprox[k].X, ptsApprox[k].Y, 6, 6);
                              }

                                if (CvInvoke.ContourArea(approxContour, false) > 250 && approxContour.Size == 4)
                                {
                                    Black_boxList.Add(CvInvoke.MinAreaRect(approxContour));
                                    blackborders.Push(contour);
                                }
                                else
                                {
                                    othercontours_black.Push(contour);
                                    //Point[] pts = approxContour.ToArray();
                                    //other.Add(PointCollection.PolyLine(pts, true));
                                }
                            }
                        }
                    }
                }
                TMPGood.Save("C:\\Emgu\\Dump\\Black contour corners GOOD.png", System.Drawing.Imaging.ImageFormat.Png);
                TMPBad.Save("C:\\Emgu\\Dump\\Black contour corners BAD.png", System.Drawing.Imaging.ImageFormat.Png);
        }
コード例 #5
0
        VectorOfVectorOfPoint FindBlobs(Mat binary, int index)
        {
            VectorOfVectorOfPoint blobs = new VectorOfVectorOfPoint();

            // Fill the label_image with the blobs
            // 0  - background
            // 1  - unlabelled foreground
            // 2+ - labelled foreground

            Mat label_image = new Mat();
            binary.ConvertTo(label_image, DepthType.Cv8U);

            int label_count = 2; // starts at 2 because 0,1 are used already

            for (int y = 0; y < label_image.Rows; y++)
            {

                for (int x = 0; x < label_image.Cols; x++)
                {
                    var val = label_image.GetData(y, x)[0];

                    if (val != 255)
                    {
                        continue;
                    }
 
                    System.Drawing.Rectangle rect;
                    CvInvoke.FloodFill(label_image, new Mat(), new System.Drawing.Point(x, y), new MCvScalar(label_count), out rect, new MCvScalar(0), new MCvScalar(0), Connectivity.FourConnected, FloodFillType.Default);
                    //cv::floodFill(label_image, cv::Point(x,y), label_count, &rect, 0, 0, 4);

                    VectorOfPoint blob = new VectorOfPoint();

                    for (int i = rect.Y; i < (rect.Y + rect.Height); i++)
                    {

                        for (int j = rect.X; j < (rect.X + rect.Width); j++)
                        {
                            var val2 = label_image.GetData(y, x)[0];
                            if (val2 != label_count)
                            {
                                continue;
                            }

                            blob.Push(new System.Drawing.Point[] { new System.Drawing.Point(j, i) });
                        }
                    }

                    blobs.Push(blob);

                    label_count++;
                }
            }

            label_image.Save("labeled" + index + ".bmp");

            return blobs;
        }