private Line2 FitSimilarLine(List <Line2> lines, Line2 target, double angle = 20) { NumericalRecipes.RansacLine2d rcl = new NumericalRecipes.RansacLine2d(); List <Vector2> linepoints = new List <Vector2>(); linepoints.AddRange(target.SamplePoints()); //ransac for (int i = 0; i < lines.Count; i++) { if (Line2.IsParallel(lines[i], target, angle)) { if (target.DistanceToLine(lines[i].start) < 30 && target.DistanceToLine(lines[i].end) < 30) { linepoints.AddRange(lines[i].SamplePoints()); } } } Line2 bestline = rcl.Estimate(linepoints); if (bestline == null) { return(target); } if (Vector2.Dot(bestline.dir, target.dir) < 0) { bestline.Flip(); } return(bestline); }
private Line2 FitCloseLine(List <Line2> lines, Line2 target, double dis = 30) { List <Vector2> linepoints = new List <Vector2>(); linepoints.AddRange(target.SamplePoints()); //ransac for (int i = 0; i < lines.Count; i++) { if (Line2.IsParallel(lines[i], target, 45)) { double d = double.MaxValue; foreach (Vector2 v in linepoints) { d = Math.Min(Math.Min(Vector2.Distance(lines[i].start, v), Vector2.Distance(lines[i].end, v)), d); } if (d < dis) { linepoints.AddRange(lines[i].SamplePoints()); } } } // least square //Vector2 dir = Utility.GetDirection(linepoints); //Line2 bestline = new Line2(linepoints[0], dir, true); //foreach (Vector2 v in linepoints) // bestline.UpdateEnd(v); //ransac NumericalRecipes.RansacLine2d rcl = new NumericalRecipes.RansacLine2d(); Line2 bestline = rcl.Estimate(linepoints); if (bestline == null) { return(target); } if (Vector2.Dot(bestline.dir, target.dir) < 0) { bestline.Flip(); } return(bestline); }
private List <Vector2> ApproximateStraightAxis(List <Line2> skel_lines) { // from skeleton lines(aka. thining image lines) (find lines that have the same direction with guessed axis <- when top face is known) // ransac, fit one line as main axis // update end points // set top circle center as start point // extend end point Line2 new_main_axis = null; Image <Rgb, byte> mainaxis_img = body_img.Copy().Convert <Rgb, byte>(); Line2 main_axis = null; if (iscube) { main_axis = ApproximateFromCubeTop(); } else { main_axis = ApproximateFromTop(); } if (main_axis == null) { return(null); } if (noface) { NumericalRecipes.RansacLine2d rcl = new NumericalRecipes.RansacLine2d(); List <Vector2> thin_points = IExtension.GetMaskPoints(this.ori_thin_img); List <Vector2> linepoints = new List <Vector2>(); for (int i = 0; i < skel_lines.Count; i++) { linepoints.AddRange(skel_lines[i].SamplePoints()); } //Line2 bestline = rcl.Estimate(linepoints); Line2 bestline = rcl.Estimate(thin_points); double diss = Vector2.Distance(bestline.start, face_center[0]); double dise = Vector2.Distance(bestline.end, face_center[0]); if (dise < diss) { bestline.Flip(); } new_main_axis = bestline; } else { // use ori thinning image as guidance LineSegment2D[] lines = ori_thin_img.HoughLinesBinary( 1, //Distance resolution in pixel-related units Math.PI / 180.0, //Angle resolution measured in radians. 3, //threshold 4, //min Line width 1 //gap between lines )[0]; //Get the lines from the first channel skel_lines.Clear(); foreach (LineSegment2D line in lines) { skel_lines.Add(new Line2(new Vector2(line.P1.X, line.P1.Y), new Vector2(line.P2.X, line.P2.Y))); } Line2 bestline = FitSimilarLine(skel_lines, main_axis); if (Line2.IsParallel(bestline, main_axis, 5)) { new_main_axis = bestline; } else { new_main_axis = main_axis; } } // update end List <Vector2> ori_skel_points = IExtension.GetMaskPoints(ori_thin_img); for (int i = 0; i < ori_skel_points.Count; i++) { new_main_axis.UpdateEnd(ori_skel_points[i]); } new_main_axis.start = new_main_axis.ProjToLine(face_center.First()); new_main_axis.start = new_main_axis.GetPointwithT(4); List <Vector2> axis_points = new List <Vector2>(); // axis_points.Add(face_center.First()); axis_points.AddRange(new_main_axis.SamplePoints()); axis_points.Add(new_main_axis.GetPointwithT((float)new_main_axis.Length() * 1.2f)); axis_points = IExtension.ResetPath(axis_points, 3); #region visualize Image <Rgb, byte> mainaxis_point_img = body_img.Copy().Convert <Rgb, byte>(); foreach (Vector2 v in axis_points) { mainaxis_point_img.Draw(new CircleF(new PointF(v.x, v.y), 2.0f), new Rgb(255, 0, 0), 1); } mainaxis_point_img.Draw(new CircleF(new PointF(axis_points.First().x, axis_points.First().y), 3.0f), new Rgb(0, 255, 0), 1); mainaxis_point_img.Save(index_forname.ToString() + this.label_forname.ToString() + "_axis_straight.png"); #endregion return(axis_points); }
private List <Line2> Skeletonize(out bool iscurve) { Image <Gray, byte> img2 = body_img.Copy(); Image <Gray, byte> eroded = new Image <Gray, byte>(img2.Size); Image <Gray, byte> temp = new Image <Gray, byte>(img2.Size); Image <Gray, byte> skel = new Image <Gray, byte>(img2.Size); body_img.Save("test.png"); #region with matlab string argument1 = "\"" + "test.png" + "\""; System.Diagnostics.Process process = new System.Diagnostics.Process(); process.StartInfo.FileName = System.Environment.CurrentDirectory + "\\Assets\\frommatlab\\skeleton.exe"; process.StartInfo.Arguments = argument1; process.StartInfo.UseShellExecute = false; process.StartInfo.CreateNoWindow = true; process.StartInfo.RedirectStandardOutput = true; //启动 process.Start(); process.WaitForExit(); #endregion skel = new Image <Gray, byte>("prune.png"); ori_thin_img = new Image <Gray, byte>("thin.png"); ori_prune_img = skel; #region thining - comment //skel.SetValue(0); //CvInvoke.Threshold(img2, temp, 127, 256, 0); //var element = CvInvoke.GetStructuringElement(ElementShape.Cross, new Size(3, 3), new Point(-1, -1)); //bool done = false; ////skeleton //int itr = 0; //while (!done) //{ // CvInvoke.Erode(img2, eroded, element, new Point(-1, -1), 1, BorderType.Reflect, default(MCvScalar)); // CvInvoke.Dilate(eroded, temp, element, new Point(-1, -1), 1, BorderType.Reflect, default(MCvScalar)); // CvInvoke.Subtract(img2, temp, temp); // CvInvoke.BitwiseOr(skel, temp, skel); // eroded.CopyTo(img2); // itr++; // if (CvInvoke.CountNonZero(img2) == 0) done = true; //} //Image<Gray, Byte> cannyimg = body_img.Canny(60, 100); //CvInvoke.Dilate(cannyimg, cannyimg, element, new Point(-1, -1), 3, BorderType.Reflect, default(MCvScalar)); //CvInvoke.Subtract(skel, cannyimg, skel); //ori_skel_img = skel.Copy(); ////thinning //if (!noface) //{ // #region thinning // List<Mat> cs = new List<Mat>(); // List<Mat> ds = new List<Mat>(); // for (int i = 0; i < 8; i++) // { // cs.Add(CvInvoke.GetStructuringElement(ElementShape.Cross, new Size(3, 3), new Point(-1, -1))); // ds.Add(CvInvoke.GetStructuringElement(ElementShape.Cross, new Size(3, 3), new Point(-1, -1))); // } // cs[0].SetTo(new int[] { 0, 0, 0, 0, 1, 0, 1, 1, 1 }); // cs[1].SetTo(new int[] { 1, 0, 0, 1, 1, 0, 1, 0, 0 }); // cs[2].SetTo(new int[] { 1, 1, 1, 0, 1, 0, 0, 0, 0 }); // cs[3].SetTo(new int[] { 0, 0, 1, 0, 1, 1, 0, 0, 1 }); // ds[0].SetTo(new int[] { 1, 1, 1, 0, 0, 0, 0, 0, 0 }); // ds[1].SetTo(new int[] { 0, 0, 1, 0, 0, 1, 0, 0, 1 }); // ds[2].SetTo(new int[] { 0, 0, 0, 0, 0, 0, 1, 1, 1 }); // ds[3].SetTo(new int[] { 1, 0, 0, 1, 0, 0, 1, 0, 0 }); // cs[4].SetTo(new int[] { 0, 0, 0, 1, 1, 0, 1, 1, 0 }); // cs[5].SetTo(new int[] { 1, 1, 0, 1, 1, 0, 0, 0, 0 }); // cs[6].SetTo(new int[] { 0, 1, 1, 0, 1, 1, 0, 0, 0 }); // cs[7].SetTo(new int[] { 0, 0, 0, 0, 1, 1, 0, 1, 1 }); // ds[4].SetTo(new int[] { 0, 1, 1, 0, 0, 1, 0, 0, 0 }); // ds[5].SetTo(new int[] { 0, 0, 0, 0, 0, 1, 0, 1, 1 }); // ds[6].SetTo(new int[] { 0, 0, 0, 1, 0, 0, 1, 1, 0 }); // ds[7].SetTo(new int[] { 1, 1, 0, 1, 0, 0, 0, 0, 0 }); // Image<Gray, byte> img3 = skel.Copy(); // Image<Gray, byte> temp2 = skel.CopyBlank(); // Image<Gray, byte> lastimg3 = skel.Copy(); // done = false; // while (!done) // { // for (int i = 0; i < 8; i++) // { // temp = this.HitOrMiss(img3, cs[i], ds[i]); // CvInvoke.Subtract(img3, temp, img3); // } // CvInvoke.Subtract(lastimg3, img3, temp2); // lastimg3 = img3.Copy(); // if (CvInvoke.CountNonZero(temp2) == 0) done = true; // } // //img3.Save("thining.png"); // #endregion // skel = img3.Copy(); // ori_thinning_img = img3.Copy(); //} ////// remove noise ////for (int i = 0; i < img3.Height; i++) ////{ //// for (int j = 0; j < img3.Width; j++) //// { //// if (img3[i, j].Equals(new Gray(255))) //// { //// bool change = false; //// for (int pad = 1; pad < 3; pad++) //// { //// if (i >= pad && i < img3.Height - pad && j >= pad && j < img3.Width - pad) //// { //// if (img3[i - pad, j].Equals(new Gray(0)) && //// img3[i - pad, j - pad].Equals(new Gray(0)) && //// img3[i - pad, j + pad].Equals(new Gray(0)) && //// img3[i + pad, j].Equals(new Gray(0)) && //// img3[i + pad, j - pad].Equals(new Gray(0)) && //// img3[i + pad, j + pad].Equals(new Gray(0)) && //// img3[i, j - pad].Equals(new Gray(0)) && //// img3[i, j + pad].Equals(new Gray(0))) //// change = true; //// } //// } //// if (change) //// img3[i, j] = new Gray(0); //// } //// } ////} ////img3.Save("thiningdenoise.png"); #endregion // get line // consider both straight line and curve LineSegment2D[] lines = skel.HoughLinesBinary( 1, //Distance resolution in pixel-related units Math.PI / 180.0, //Angle resolution measured in radians. 3, //threshold 4, //min Line width 1 //gap between lines )[0]; //Get the lines from the first channel Image <Gray, byte> lineimg = skel.CopyBlank(); List <Line2> skel_lines = new List <Line2>(); foreach (LineSegment2D line in lines) { //remove image boundaries //if (line.P1.X > 10 && line.P1.Y > 10 && line.P1.X < body_img.Height - 10 && line.P1.Y < body_img.Width && // line.P2.X > 10 && line.P2.Y > 10 && line.P2.X < body_img.Height - 10 && line.P2.Y < body_img.Width - 10) //{ skel_lines.Add(new Line2(new Vector2(line.P1.X, line.P1.Y), new Vector2(line.P2.X, line.P2.Y))); lineimg.Draw(line, new Gray(255), 2); //} } if (debug) { lineimg.Save("skel-line.png"); } // cluster according to direction and relative distance // too many cluster means curve axis IMGSIZE = Math.Min(body_img.Width, body_img.Height); if (skel_lines.Count > 0) { double[][] xy = new double[skel_lines.Count][]; for (int i = 0; i < skel_lines.Count; i++) { xy[i] = new double[] { skel_lines[i].start.x, skel_lines[i].start.y, skel_lines[i].end.x, skel_lines[i].end.y }; } MeanShift clusterMS = new MeanShift(4, new UniformKernel(), 0.02); clusterMS.Distance = new myDistanceClass(); MeanShiftClusterCollection clustering = clusterMS.Learn(xy); var lineLabels = clustering.Decide(xy); int clustercount = lineLabels.DistinctCount(); //Debug.Log("cluster count: " + clustercount); if (debug) { Image <Rgb, byte> lineimg_rgb = lineimg.Convert <Rgb, byte>(); System.Random rnd = new System.Random(); Rgb[] colortable = new Rgb[clustering.Count]; for (int i = 0; i < clustering.Count; i++) { colortable[i] = new Rgb(rnd.Next(255), rnd.Next(255), rnd.Next(255)); } for (int i = 0; i < skel_lines.Count; i++) { int label = lineLabels[i]; lineimg_rgb.Draw(skel_lines[i].ToLineSegment2D(), colortable[label], 2); } lineimg_rgb.Save("skel-line-cluster.png"); } if (noface) { thred = 2; // 2 } if (clustercount > thred) { iscurve = true; } else { iscurve = false; } } else { iscurve = false; NumericalRecipes.RansacLine2d rcl = new NumericalRecipes.RansacLine2d(); List <Vector2> linepoints = new List <Vector2>(); linepoints = IExtension.GetMaskPoints(skel); Line2 bestline = rcl.Estimate(linepoints); skel_lines.Add(bestline); } return(skel_lines); }