Esempio n. 1
0
        private void Find863(Image <Gray, byte> img, CircleImage info)
        {
            int centerX = (info.Rect[0].X + info.Rect[2].X) / 2;
            int centerY = (info.Rect[0].Y + info.Rect[2].Y) / 2;

            int leftX  = (info.Rect[2].X + info.Rect[3].X) / 2;
            int leftY  = (info.Rect[2].Y + info.Rect[3].Y) / 2;
            int rightX = (info.Rect[0].X + info.Rect[1].X) / 2;
            int rightY = (info.Rect[0].Y + info.Rect[1].Y) / 2;

            int minX     = leftX < centerX ? leftX : centerX;
            int maxX     = leftX > centerX ? leftX : centerX;
            int distance = System.Math.Abs(maxX - minX);

            if (distance > centerX)
            {
                _log.Warn("The picture locates too left");
            }

            int sum = 0;

            for (int x = 0; x <= distance; x++)
            {
                sum += img.Data[centerY, centerX - x, 0];
            }
            _log.Debug($"Total distance {distance:F3}");

            for (int i = distance / 2; i <= distance; i++)
            {
                int dsum = 0;
                for (int x = 0; x <= i; x++)
                {
                    dsum += img.Data[centerY, centerX - x, 0];
                }

                double ratio = (double)dsum / sum;
                _log.Debug($"radius({i}) dsum({dsum}) sum({sum}) ratio {ratio:F3}");
                if (ratio > 0.865)
                {
                    info.X863 = i;
                    break;
                }
            }
        }
Esempio n. 2
0
        private Dictionary <string, string> AnalyzeCalc(CircleImage img)
        {
            Dictionary <string, string> data = new Dictionary <string, string>();

            data["Emitter Count"] = img.Circles.Count.ToString();
            try
            {
                data["Emission Uniformity"] = CalcUniformity(img).ToString("F3");
            }
            catch (Exception ex)
            {
                data["Emission Uniformity"] = "N/A";
            }

            int   id  = 0;
            float max = img.Circles.Max(c => c.Radius);

            for (id = 0; id < img.Circles.Count; id++)
            {
                if (img.Circles[id].Radius == max)
                {
                    break;
                }
            }
            data["Max Radius"] = $"{max}({id})";

            float min = img.Circles.Min(c => c.Radius);

            for (id = 0; id < img.Circles.Count; id++)
            {
                if (img.Circles[id].Radius == min)
                {
                    break;
                }
            }
            data["Min Radius"] = $"{min}({id})";

            return(data);
        }
Esempio n. 3
0
        private CircleImage FindRegularCircle(string path, Parameters param = null)
        {
            _log.Debug(param.ToString());

            bool saveFile = param.SaveFile;
            bool useCanny = param.UseCanny;

            Path   = path;
            RawImg = EmguIntfs.Load(path);

            Image <Gray, Byte> _grayedUmat = EmguIntfs.ToImage(EmguIntfs.Grayed(RawImg));

            Image <Gray, Byte> _bin = EmguIntfs.Binarize(param.BinThreshold, _grayedUmat);

            _bin.Save(Utils.String.FilePostfix(Path, "-0-bin"));

            Image <Gray, byte> _edged = EmguIntfs.Canny(_bin,
                                                        param.Canny1Threshold1,
                                                        param.Canny1Threshold2,
                                                        param.Canny1ApertureSize,
                                                        param.Canny1I2Gradient);

            _edged.Save(Utils.String.FilePostfix(Path, "-1-edge"));

            Image <Gray, byte>    tempc = new Image <Gray, byte>(_bin.Width, _bin.Height);
            Image <Gray, byte>    d     = new Image <Gray, byte>(_bin.Width, _bin.Height);
            VectorOfVectorOfPoint con   = new VectorOfVectorOfPoint();

            CvInvoke.FindContours(_edged, con, tempc, RetrType.Ccomp, ChainApproxMethod.ChainApproxSimple);
            for (int conId = 0; conId < con.Size; conId++)
            {
                CvInvoke.DrawContours(d, con, conId, new MCvScalar(255, 0, 255, 255), 2);
            }
            d.Save(Utils.String.FilePostfix(Path, "-1-contour"));

            List <RotatedRect> rects = new List <RotatedRect>();

            for (int conId = 0; conId < con.Size; conId++)
            {
                if (con[conId].Size > 5)
                {
                    rects.Add(CvInvoke.FitEllipse(con[conId]));
                }
            }

            foreach (var rect in rects)
            {
                CvInvoke.Ellipse(d, rect, new Bgr(Color.White).MCvScalar, 2);
            }
            d.Save(Utils.String.FilePostfix(Path, "-1-rects"));

            Circles = CvInvoke.HoughCircles(_edged, HoughType.Gradient,
                                            param.Hough1Dp,
                                            param.Hough1MinDist,
                                            param.Hough1Param1,
                                            param.Hough1Param2,
                                            param.Hough1MinRadius, param.Hough1MaxRadius);
            Circles = Calc.Sort(Circles);
            #region filter 86.3%
            FilteredCircles    = new List <CircleF>();
            FilteredLights     = new List <int>();
            FilteredCircles2nd = new List <CircleF>();
            var raw = _grayedUmat;
            foreach (var circle in Circles)
            {
                int extra = param.FilterSquareExtra;

                int startX = (int)System.Math.Floor(circle.Center.X - circle.Radius - extra);
                int startY = (int)System.Math.Floor(circle.Center.Y - circle.Radius - extra);
                int len    = (int)System.Math.Ceiling((double)circle.Radius * 2.0) + 2 * extra;
                if (startX < 0 || startY < 0)
                {
                    _log.Warn("FilterSizeExtra may be too big, filter abandoned");
                    continue;
                }

                int strength = raw.Data[(int)circle.Center.Y, (int)circle.Center.X, 0];
                if (strength >= 30)/* filter fake circles */
                {
                    FilteredCircles.Add(circle);
                    FilteredCircles2nd.Add(circle);

                    int threshold = (int)((double)strength * 0.863);

                    raw.ROI = new Rectangle(startX, startY, len, len);
                    Image <Gray, Byte> oneCircle = EmguIntfs.Binarize(threshold, raw);
                    raw.ROI = Rectangle.Empty;

                    for (int x = 0; x < len; x++)
                    {
                        for (int y = 0; y < len; y++)
                        {
                            raw.Data[startY + y, startX + x, 0] = oneCircle.Data[y, x, 0];
                        }
                    }
                }
            }
            if (saveFile)
            {
                raw.Save(Utils.String.FilePostfix(Path, "-2-filter"));
            }
            #endregion

            if (useCanny)
            {
                _edged = EmguIntfs.Canny(raw,
                                         param.Canny2Threshold1,
                                         param.Canny2Threshold2,
                                         param.Canny2ApertureSize,
                                         param.Canny2I2Gradient);
                if (saveFile)
                {
                    _edged.Save(Utils.String.FilePostfix(Path, "-3-edge"));
                }
            }
            else
            {
                _edged = raw;
            }

            Circles2nd = CvInvoke.HoughCircles(_edged, HoughType.Gradient,
                                               param.Hough2Dp,
                                               param.Hough2MinDist,
                                               param.Hough2Param1,
                                               param.Hough2Param2,
                                               param.Hough2MinRadius, param.Hough2MaxRadius);
            Circles2nd         = Calc.Sort(Circles2nd);
            FilteredCircles2nd = new List <CircleF>();
            List <int> brightness = new List <int>();

            _log.Info($"Circles Information");
            for (int i = 0; i < Circles2nd.Length; i++)
            {
                CircleF circle = Circles2nd[i];

                int strength = raw.Data[(int)circle.Center.Y, (int)circle.Center.X, 0];
                if (strength > 30)
                {
                    int b = CountPixels(_grayedUmat, ref circle, ValidRatio);
                    brightness.Add(b);
                    _log.Info($"Circle{i:D3}: ({circle.Center.X},{circle.Center.Y}) {circle.Radius} {b}");

                    FilteredCircles2nd.Add(circle);
                }
            }

            #region draw
            Mat _result = RawImg.Mat;

            for (int c = 0; c < FilteredCircles2nd.Count; c++)
            {
                Point center = Point.Round(FilteredCircles2nd[c].Center);
                center.X *= 1;
                center.Y *= 1;
                int radius = (int)FilteredCircles2nd[c].Radius * 1;

                //if (2 * radius < _result.Size.Height && 2 * radius < _result.Size.Width)
                {
                    CvInvoke.Circle(_result, center, radius, new Bgr(Color.Red).MCvScalar, 1);
                    CvInvoke.PutText(_result, c.ToString("D3"), new Point((int)FilteredCircles2nd[c].Center.X, (int)FilteredCircles2nd[c].Center.Y), Emgu.CV.CvEnum.FontFace.HersheyScriptComplex, 1, new MCvScalar(255, 255, 0), 1);
                }
            }
            _result.Save(Utils.String.FilePostfix(Path, "-result"));
            #endregion

            CircleImage ret = new CircleImage();
            ret.Circles    = FilteredCircles2nd;
            ret.Brightness = brightness;
            ret.RetImg     = _result.Bitmap;

            return(ret);
        }
Esempio n. 4
0
        public override CircleImage FindCircle(string path, Parameters param = null)
        {
            _log.Debug(param.ToString());

            bool saveFile = param.SaveFile;
            bool useCanny = param.UseCanny;

            Path   = path;
            RawImg = EmguIntfs.Load(path);

            Image <Gray, Byte> _grayedUmat = EmguIntfs.ToImage(EmguIntfs.Grayed(RawImg));
            Image <Gray, Byte> _bin        = EmguIntfs.Binarize(param.BinThreshold, _grayedUmat);

            if (saveFile)
            {
                _bin.Save(Utils.String.FilePostfix(Path, "-0-bin"));
            }

            Image <Gray, byte> tempc = new Image <Gray, byte>(_bin.Width, _bin.Height);
            Image <Gray, byte> d     = new Image <Gray, byte>(_bin.Width, _bin.Height);

            VectorOfVectorOfPoint con = new VectorOfVectorOfPoint();

            CvInvoke.FindContours(_bin, con, tempc, RetrType.Ccomp, ChainApproxMethod.ChainApproxSimple);
            for (int conId = 0; conId < con.Size; conId++)
            {
                CvInvoke.DrawContours(d, con, conId, new MCvScalar(255, 0, 255, 255), 2);
            }
            if (saveFile)
            {
                d.Save(Utils.String.FilePostfix(Path, "-1-contour"));
            }

            List <RotatedRect>   ellipses = new List <RotatedRect>();
            List <List <Point> > rects    = new List <List <Point> >();

            for (int conId = 0; conId < con.Size; conId++)
            {
                if (con[conId].Size > 100)
                {
                    var ellipse = CvInvoke.FitEllipse(con[conId]);

                    PointF[] points = new PointF[4];
                    points = ellipse.GetVertices();
                    rects.Add(points.Select(x => Point.Truncate(x)).ToList());

                    ellipse.Angle = ellipse.Angle - 90;
                    ellipses.Add(ellipse);
                }
            }
            if (ellipses.Count > 1)
            {
                _log.Warn("More than 1 ellipse found, please check the image");
            }

            CircleImage ret = new CircleImage();

            ret.Ellipse = ellipses[0];
            ret.Rect    = rects[0];
            ret.RetImg  = Draw(RawImg, ellipses, rects);
            if (saveFile)
            {
                ret.RetImg.Save(Utils.String.FilePostfix(Path, "-2-ellipse"));
            }

            _log.Debug($"Ellipse X: {ret.Ellipse.Size.Height}, Y: {ret.Ellipse.Size.Width}");

            Find863(_grayedUmat, ret);

            return(ret);
        }
Esempio n. 5
0
 private double CalcUniformity(CircleImage img)
 {
     return(Utils.Math.StdEv(img.Brightness.Select(x => (double)x).ToList()));
 }
Esempio n. 6
0
        public override CircleImage FindCircle(string path, Parameters param = null)
        {
            _log.Debug(param.ToString());

            int picId = 0;

            Path   = path;
            RawImg = EmguIntfs.Load(path);

            bool strengthen = param.ExtraStrengthen;
            bool saveFile   = param.SaveFile;
            bool useCanny   = param.UseCanny;

            #region 1st with constant filter and find circles
            Image <Gray, Byte> _grayedUmat = EmguIntfs.ToImage(EmguIntfs.Grayed(RawImg));

            if (strengthen)
            {
                for (int x = 0; x < _grayedUmat.Width; x++)
                {
                    for (int y = 0; y < _grayedUmat.Height; y++)
                    {
                        int value = _grayedUmat.Data[y, x, 0] * 2;
                        _grayedUmat.Data[y, x, 0] = (byte)(value > 255 ? 255 : value);
                    }
                }
                if (saveFile)
                {
                    _grayedUmat.Save(Utils.String.FilePostfix(Path, "-0-strength"));
                }
            }

            Image <Gray, Byte> image = EmguIntfs.Binarize(param.BinThreshold, _grayedUmat);
            image = EmguIntfs.PyrRemoveNoise(image);
            if (saveFile)
            {
                image.Save(Utils.String.FilePostfix(Path, $"-{picId++}-filter"));
            }

            Image <Gray, Byte> _edged;
            if (useCanny)
            {
                _edged = EmguIntfs.Canny(image,
                                         param.Canny1Threshold1,
                                         param.Canny1Threshold2,
                                         param.Canny1ApertureSize,
                                         param.Canny1I2Gradient);
                if (saveFile)
                {
                    _edged.Save(Utils.String.FilePostfix(Path, $"-{picId++}-edge"));
                }
            }
            else
            {
                _edged = _grayedUmat;
            }


            Circles = CvInvoke.HoughCircles(image, HoughType.Gradient,
                                            param.Hough1Dp,
                                            param.Hough1MinDist,
                                            param.Hough1Param1,
                                            param.Hough1Param2,
                                            param.Hough1MinRadius, param.Hough1MaxRadius);
            Circles = Calc.Sort(Circles);

            List <CircleF> FilteredCircles = new List <CircleF>();
            List <int>     brightness      = new List <int>();

            for (int i = 0; i < Circles.Length; i++)
            {
                CircleF circle = Circles[i];

                int strength = image.Data[(int)circle.Center.Y, (int)circle.Center.X, 0];
                if (strength >= 30)/* filter fake circles */
                {
                    int b = CountPixels(_grayedUmat, ref circle, ValidRatio);
                    brightness.Add(b);
#if false
                    /*this value is used to compare with CountPixels*/
                    int s = CountPixelsSquare(_grayedUmat, circle);
                    if (System.Math.Abs((double)(b - s) / b) > 0.001)
                    {
                        _log.Warn($"CountPixels({b}) CountPixelsSquare({s}) diff too much");
                    }
#endif
                    //_log.Info($"Circle{i:D3}: ({circle.Center.X},{circle.Center.Y}) {circle.Radius} {b}");
                    FilteredCircles.Add(circle);
                }
            }
            #endregion

            if (saveFile)
            {
                Bitmap circleOnFilter = DrawCircle(new Image <Bgr, byte>(image.Bitmap), Circles.ToList());
                circleOnFilter.Save(Utils.String.FilePostfix(Path, $"-{picId++}-circleOnFilter"));

                Bitmap circleOnEdge = DrawCircle(new Image <Bgr, byte>(_edged.Bitmap), Circles.ToList());
                circleOnEdge.Save(Utils.String.FilePostfix(Path, $"-{picId++}-circleOnEdge"));
            }

            #region 2nd find circle
            //#region filter 86.3%
            //FilteredCircles = new List<CircleF>();
            //FilteredLights = new List<int>();
            //var raw = _grayedUmat;
            //foreach (var circle in Circles)
            //{
            //    int extra = param.FilterSquareExtra;

            //    int startX = (int)System.Math.Floor(circle.Center.X - circle.Radius - extra);
            //    int startY = (int)System.Math.Floor(circle.Center.Y - circle.Radius - extra);
            //    int len = (int)System.Math.Ceiling((double)circle.Radius * 2.0) + 2 * extra;
            //    if (startX < 0 || startY < 0)
            //    {
            //        _log.Warn("FilterSizeExtra may be too big, filter abandoned");
            //        continue;
            //    }

            //    int strength = raw.Data[(int)circle.Center.Y, (int)circle.Center.X, 0];
            //    if (strength >= 30)/* filter fake circles */
            //    {
            //        FilteredCircles.Add(circle);

            //        int threshold = (int)((double)strength * 0.863);

            //        raw.ROI = new Rectangle(startX, startY, len, len);
            //        Image<Gray, Byte> oneCircle = EmguIntfs.Binarize(threshold, raw);
            //        raw.ROI = Rectangle.Empty;

            //        for (int x = 0; x < len; x++)
            //        {
            //            for (int y = 0; y < len; y++)
            //            {
            //                raw.Data[startY + y, startX + x, 0] = oneCircle.Data[y, x, 0];
            //            }
            //        }
            //    }
            //}
            //if (saveFile)
            //{
            //    raw.Save(Utils.String.FilePostfix(Path, "-2-filter"));
            //}
            //#endregion

            //if (useCanny)
            //{
            //    _edged = EmguIntfs.Canny(raw,
            //        param.Canny2Threshold1,
            //        param.Canny2Threshold2,
            //        param.Canny2ApertureSize,
            //        param.Canny2I2Gradient);
            //    if (saveFile)
            //    {
            //        _edged.Save(Utils.String.FilePostfix(Path, "-3-edge"));
            //    }
            //}
            //else
            //{
            //    _edged = raw;
            //}

            //Circles2nd = CvInvoke.HoughCircles(_edged, HoughType.Gradient,
            //    param.Hough2Dp,
            //    param.Hough2MinDist,
            //    param.Hough2Param1,
            //    param.Hough2Param2,
            //    param.Hough2MinRadius, param.Hough2MaxRadius);
            //Circles2nd = Sort(Circles2nd);
            //FilteredCircles2nd = new List<CircleF>();
            //List<int> brightness = new List<int>();

            //_log.Info($"Circles Information");
            //int i = 0;
            //foreach (var circle in Circles2nd)
            //{
            //    int strength = raw.Data[(int)circle.Center.Y, (int)circle.Center.X, 0];
            //    if (strength > 30)
            //    {
            //        FilteredCircles2nd.Add(circle);
            //        int b = CountPixels(_grayedUmat, circle);
            //        brightness.Add(b);
            //        _log.Info($"Circle{i:D3}: ({circle.Center.X},{circle.Center.Y}) {circle.Radius} {b}");

            //        i++;
            //    }
            //}

            //if (saveFile)
            //{
            //    Bitmap circleOnFilter = DrawCircle(new Image<Bgr, byte>(raw.Bitmap), FilteredCircles2nd,  param.ShowFirstResult ? FilteredCircles : null);
            //    circleOnFilter.Save(Utils.String.FilePostfix(Path, $"-{picId++}-circleOnFilter"));

            //    Bitmap circleOnEdge = DrawCircle(new Image<Bgr, byte>(_edged.Bitmap), FilteredCircles2nd, param.ShowFirstResult ? FilteredCircles : null);
            //    circleOnEdge.Save(Utils.String.FilePostfix(Path, $"-{picId++}-circleOnEdge"));
            //}
            #endregion

            CircleImage ret = new CircleImage();
            ret.Circles    = FilteredCircles;
            ret.Brightness = brightness;
            ret.RetImg     = DrawCircle(RawImg, FilteredCircles, Circles.ToList());
            ret.RetImg.Save(Utils.String.FilePostfix(Path, $"-{picId++}-result"));

            if (saveFile)
            {
                ret.Data = AnalyzeCalc(ret);
            }

            return(ret);
        }
Esempio n. 7
0
        public override CircleImage FindCircle(Image <Gray, ushort> bigImage, Parameters param = null)
        {
            _log.Debug(param.ToString());

            int picId = 0;

            Path = @"D:\CurImage.bmp";

            bool strengthen = param.ExtraStrengthen;
            bool saveFile   = param.SaveFile;
            bool useCanny   = param.UseCanny;

            #region 1st with constant filter and find circles
            if (strengthen)
            {
                for (int x = 0; x < bigImage.Width; x++)
                {
                    for (int y = 0; y < bigImage.Height; y++)
                    {
                        int value = bigImage.Data[y, x, 0] * 2;
                        bigImage.Data[y, x, 0] = (ushort)(value > 0x3fff ? 0x3fff : value);
                    }
                }
                if (saveFile)
                {
                    bigImage.Save(Utils.String.FilePostfix(Path, "-0-strength"));
                }
            }

            Image <Gray, ushort> image = EmguIntfs.Binarize(param.BinThreshold, bigImage);
            image = EmguIntfs.PyrRemoveNoise(image);
            if (saveFile)
            {
                image.Save(Utils.String.FilePostfix(Path, $"-{picId++}-filter"));
            }

            Image <Gray, Byte> _edged;
            if (useCanny)
            {
                _edged = EmguIntfs.Canny(image.Mat.ToImage <Gray, byte>(),
                                         param.Canny1Threshold1,
                                         param.Canny1Threshold2,
                                         param.Canny1ApertureSize,
                                         param.Canny1I2Gradient);
                if (saveFile)
                {
                    _edged.Save(Utils.String.FilePostfix(Path, $"-{picId++}-edge"));
                }
            }
            else
            {
                _edged = image.Mat.ToImage <Gray, byte>();
            }


            Circles = CvInvoke.HoughCircles(image.Mat.ToImage <Gray, byte>(), HoughType.Gradient,
                                            param.Hough1Dp,
                                            param.Hough1MinDist,
                                            param.Hough1Param1,
                                            param.Hough1Param2,
                                            param.Hough1MinRadius, param.Hough1MaxRadius);
            Circles = Calc.Sort(Circles);
            #endregion

            if (saveFile)
            {
                Bitmap circleOnFilter = DrawCircle(new Image <Bgr, byte>(image.Bitmap), Circles.ToList());
                circleOnFilter.Save(Utils.String.FilePostfix(Path, $"-{picId++}-circleOnFilter"));

                Bitmap circleOnEdge = DrawCircle(new Image <Bgr, byte>(_edged.Bitmap), Circles.ToList());
                circleOnEdge.Save(Utils.String.FilePostfix(Path, $"-{picId++}-circleOnEdge"));
            }


            #region filter 86.3%
            FilteredCircles = new List <CircleF>();
            FilteredLights  = new List <int>();

            var raw = bigImage.Copy();
            foreach (var circle in Circles)
            {
                int extra = param.FilterSquareExtra;

                int startX = (int)System.Math.Floor(circle.Center.X - circle.Radius - extra);
                int startY = (int)System.Math.Floor(circle.Center.Y - circle.Radius - extra);
                int len    = (int)System.Math.Ceiling((double)circle.Radius * 2.0) + 2 * extra;
                if (startX < 0 || startY < 0)
                {
                    _log.Warn("FilterSizeExtra may be too big, filter abandoned");
                    continue;
                }

                int strength = raw.Data[(int)circle.Center.Y, (int)circle.Center.X, 0];
                if (strength >= 1600)/* filter fake circles */
                {
                    FilteredCircles.Add(circle);

                    int threshold = (int)((double)strength * 0.863);

                    raw.ROI = new Rectangle(startX, startY, len, len);
                    Image <Gray, ushort> oneCircle = EmguIntfs.Binarize(threshold, raw);
                    raw.ROI = Rectangle.Empty;

                    for (int x = 0; x < len; x++)
                    {
                        for (int y = 0; y < len; y++)
                        {
                            raw.Data[startY + y, startX + x, 0] = oneCircle.Data[y, x, 0];
                        }
                    }
                }
            }
            if (saveFile)
            {
                raw.Save(Utils.String.FilePostfix(Path, "-2-filter"));
            }
            #endregion

            if (useCanny)
            {
                _edged = EmguIntfs.Canny(raw.Mat.ToImage <Gray, byte>(),
                                         param.Canny2Threshold1,
                                         param.Canny2Threshold2,
                                         param.Canny2ApertureSize,
                                         param.Canny2I2Gradient);
                if (saveFile)
                {
                    _edged.Save(Utils.String.FilePostfix(Path, "-3-edge"));
                }
            }
            else
            {
                _edged = raw.Mat.ToImage <Gray, byte>();
            }

            Circles2nd = CvInvoke.HoughCircles(_edged, HoughType.Gradient,
                                               param.Hough2Dp,
                                               param.Hough2MinDist,
                                               param.Hough2Param1,
                                               param.Hough2Param2,
                                               param.Hough2MinRadius, param.Hough2MaxRadius);
            Circles2nd         = Calc.Sort(Circles2nd);
            FilteredCircles2nd = new List <CircleF>();
            List <int> brightness = new List <int>();

            _log.Info($"Circles Information");
            int i = 0;
            foreach (var circle in Circles2nd)
            {
                int strength = raw.Data[(int)circle.Center.Y, (int)circle.Center.X, 0];
                if (strength > 30)
                {
                    FilteredCircles2nd.Add(circle);
                    int b = CountPixels(bigImage, circle);
                    brightness.Add(b);
                    _log.Info($"Circle{i:D3}: ({circle.Center.X},{circle.Center.Y}) {circle.Radius} {b}");

                    i++;
                }
            }

            if (saveFile)
            {
                Bitmap circleOnFilter = DrawCircle(new Image <Bgr, byte>(raw.Bitmap), FilteredCircles2nd, param.ShowFirstResult ? FilteredCircles : null);
                circleOnFilter.Save(Utils.String.FilePostfix(Path, $"-{picId++}-circleOnFilter"));

                Bitmap circleOnEdge = DrawCircle(new Image <Bgr, byte>(_edged.Bitmap), FilteredCircles2nd, param.ShowFirstResult ? FilteredCircles : null);
                circleOnEdge.Save(Utils.String.FilePostfix(Path, $"-{picId++}-circleOnEdge"));
            }

            CircleImage ret = new CircleImage();
            ret.Circles    = FilteredCircles2nd;
            ret.Brightness = brightness;
            ret.RetImg     = DrawCircle(bigImage.Mat.ToImage <Bgr, byte>(), FilteredCircles2nd, param.ShowFirstResult ? FilteredCircles : null);
            ret.RetImg.Save(Utils.String.FilePostfix(Path, $"-{picId++}-result"));

            return(ret);
        }