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; } } }
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); }
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); }
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); }
private double CalcUniformity(CircleImage img) { return(Utils.Math.StdEv(img.Brightness.Select(x => (double)x).ToList())); }
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); }
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); }