public Tuple<string, int> Recognize(Image<Gray, byte> src) { var list = src.getEdge().Sample(100); #region 计算形状上下文 int r = 15; var scall = Jim.OCR.ShapeContext2D.ShapeContext.ComputeSC(list); var scq = new double[r, 60]; for (int i = 0; i < r; ++i) { int pos = rand.Next(list.Count); for (int k = 0; k < 60; ++k) { scq[i, k] = scall[pos, k]; } } #endregion #region 计算距离 var dists = new ValueIndexPair<double>[SC.template_sc.Length]; for (int i = 0; i < SC.template_sc.Length; ++i) { double[,] sci = SC.template_sc[i]; double[,] costmat = Jim.OCR.ShapeContext2D.ShapeContext.HistCost(scq, sci); double cost = 0; for (int j = 0; j < r; ++j) { double min = double.MaxValue; for (int u = 0; u < 100; ++u) { double val = costmat[j, u]; if (val < min) min = val; } cost += min; } dists[i] = new ValueIndexPair<double> { Value = cost, Index = i }; } #endregion #region 对结果排序 var arr = dists .OrderBy(p => p.Value) .Select(p => new { Distance = p.Value, Char = SC.template_chars[p.Index] }) //.Where(p => "ABCDEFGHIJKLMNPQRSTUVWXYZ123456789".IndexOf(p.Char) != -1) .Where(p => Filter.IndexOf(p.Char) != -1) .ToArray(); Dictionary<string, int> matchcount = new Dictionary<string, int>(); foreach (var pair in arr.Take(Knn)) { string ch = pair.Char; matchcount[ch] = matchcount.ContainsKey(ch) ? matchcount[ch] + 1 : 1; } var match = matchcount.Select(pair => new { Count = pair.Value, Ch = pair.Key }) .Where(v => v.Count > 0) .OrderByDescending(v => v.Count).ToArray(); //string result = ""; //foreach (var m in match.Take(3)) { // result += String.Format("Char:'{0}',Accuracy:{1}/{2}\t", m.Ch, m.Count, knn); //} #endregion return new Tuple<string, int> { First = match[0].Ch, Second = match[0].Count }; }
private void PrepareCalculate() { check = false; int[] arrayInt; int count = Convert.ToInt32(CountFindNumberTextBox.Text); UseArray.Clear(); CalculateArray.Text = ""; if (EnterArrayTextBox.Text.Length != 0) { arrayInt = EnterArrayTextBox.Text.Split(' ').Take(Convert.ToInt32(SizeArrayTextBox.Text)).Select(x => int.Parse(x)).ToArray(); try { SortedSet <ValueIndexPair> sorted = new SortedSet <ValueIndexPair>(new ValueIndexCompare()); for (int i = 0; i < arrayInt.Length; i++) { var pair = new ValueIndexPair(arrayInt[i], i); if (sorted.Count < count) { sorted.Add(pair); } else { if (sorted.Max.Value < arrayInt[i]) { sorted.Remove(sorted.Max); sorted.Add(pair); } } } foreach (var item in sorted) { CalculateArray.Text = CalculateArray.Text + " " + item.Value; } ; } catch (Exception eEnterArrayTextBox) { MessageBoxResult message = MessageBox.Show(eEnterArrayTextBox.Message, "Error", MessageBoxButton.OK); if (message == MessageBoxResult.OK) { check = true; } } } }
private static void fastPruningWithRSC() { int s = 100, r = 5; MyTimer timer = new MyTimer(); string[] templatefiles = Directory.GetFiles(@"D:\Play Data\train_data\sc\", "*.sc") .Take(1000).ToArray(); #region 打开模板 string templatepath = @"D:\Play Data\template\"; int templatecount = templatefiles.Length; Debug("打开{0}个模板--------------------------------------------", templatecount); double[][,] templates = new double[templatecount][,]; int[] templatenums = new int[templatecount]; timer.Restart(); for (int i = 0; i < templatefiles.Length; ++i) { string file = templatefiles[i]; string filename = Path.GetFileNameWithoutExtension(file); templatenums[i] = int.Parse(filename.Split('-')[1]); templates[i] = new double[s, 60]; unsafe { #region 指针也快不了多少 //byte[] data = File.ReadAllBytes(file); //fixed (byte* ptr = data) { // //using (var fs = new FileStream(file, FileMode.Open)) { // // using (var br = new BinaryReader(fs)) { // int offset = 0; // for (int j = 0; j < s; ++j) { // for (int k = 0; k < 60; ++k) { // //templates[i][j, k] = br.ReadDouble(); // fixed (double* t = &templates[i][j, k]) { // for (int p = 0; p < sizeof(double); ++p) // *((byte*)t + p) = *(ptr + offset++); // } // } // } //} #endregion using (var fs = new FileStream(file, FileMode.Open)) { using (var br = new BinaryReader(fs)) { for (int j = 0; j < s; ++j) { for (int k = 0; k < 60; ++k) { templates[i][j, k] = br.ReadDouble(); } } } } } if (i % 100 == 0) Debug("已完成{0}个", i); } Debug("模板读取完成,用时{0}ms.", timer.Stop()); #endregion string[] testfiles = Directory.GetFiles(@"D:\Play Data\test\", "*.bmp") .Take(100).ToArray(); #region 测试 int testcase = testfiles.Length, acc = 0; Debug("为{0}个对象寻找候选模板------------------------------------------", testcase); foreach (var file in testfiles) { timer.Restart(); string filenameext = Path.GetFileName(file); string filename = Path.GetFileNameWithoutExtension(file); int thisnum = int.Parse(filename.Split('-')[1]); Image<Gray, Byte> img = new Image<Gray, byte>(file); var list = getEdge(img.Resize(2.5, Emgu.CV.CvEnum.INTER.CV_INTER_LINEAR)).Sample(s); var sc100 = Jim.OCR.ShapeContext2D.ShapeContext.ComputeSC(list); double[,] scq = new double[r, 60]; for (int i = 0; i < 5; ++i) { int pos = rand.Next(s); for (int k = 0; k < 60; ++k) { scq[i, k] = sc100[pos, k]; } } var arr = new ValueIndexPair<double>[templatecount]; for (int i = 0; i < templatecount; ++i) { double[,] sci = templates[i]; double[,] costmat = Jim.OCR.ShapeContext2D.ShapeContext.HistCost(scq, sci); double cost = 0; for (int j = 0; j < 5; ++j) { double min = double.MaxValue; for (int u = 0; u < s; ++u) { double val = costmat[j, u]; if (val < min) min = val; } cost += min; } arr[i] = new ValueIndexPair<double> { Value = cost, Index = i }; } Array.Sort(arr, (a, b) => a.Value.CompareTo(b.Value)); int[] matchcount = new int[10]; double[] matchcost = new double[10]; int knn = 10; foreach (var pair in arr.Take(knn)) { int num = templatenums[pair.Index]; matchcount[num]++; matchcost[num] += pair.Value; } var match = matchcount.Select((val, i) => new { Count = val, Num = i }) .Where(v => v.Count > 0) .OrderByDescending(v => v.Count).ToArray(); //var match = matchcost.Select((val, i) => new { Cost = val / matchcount[i], Num = i }) // .Where(v => !double.IsNaN(v.Cost)) // .OrderBy(v => v.Cost).ToArray(); #region 进行精细匹配,效果一般 //double[] matchrate = new double[10]; //foreach (var m in match) { // if (m.Count == 0) break; // string template = Path.Combine(templatepath, m.Num + ".bmp"); // Jim.OCR.ShapeContext2D.ShapeContext sc = new Jim.OCR.ShapeContext2D.ShapeContext(file, template); // sc.debug_flag = false; // sc.timer_flag = false; // sc.display_flag = false; // sc.n_iter = 3; // sc.matchScale = 2.5; // sc.maxsamplecount = 100; // matchrate[m.Num] = sc.MatchFile(); //} //var bestmatches = matchrate.Select((val, i) => new { Cost = val, Num = i }) // .Where(m => m.Cost > 0) // .OrderBy(m => m.Cost).ToArray(); //int firstmatch = bestmatches[0].Num; #endregion int firstmatch = match[0].Num; var fc = Console.ForegroundColor; Console.ForegroundColor = firstmatch == thisnum ? ConsoleColor.Green : ConsoleColor.Red; string info = String.Format("{0} {1}ms - {2}\t", filename, timer.Stop(), (firstmatch == thisnum ? "Right" : "Wrong")); //foreach (var m in bestmatches.Take(4)) { foreach (var m in match) { info += String.Format("{0}/{1}\t", m.Num, m.Count); //info += String.Format("{0}/{1:F3}\t", m.Num, m.Cost); //info += String.Format("{0}/{1:F3}\t", m.Num, m.Cost); } Debug(info); Console.ForegroundColor = fc; if (firstmatch == thisnum) { ++acc; } } Debug("测试用例:{0}。正确率{1}。", testcase, acc); #endregion }
private static void testCluter() { int ss = 100, sq = 100, k = 10, m = 10; // 采样数,G取前k,S取前m int randcount = 5, randtake = 10, randselect = 3; var timer = new MyTimer(); var templatefiles = Directory.GetFiles(@"D:\Play Data\字符模板"); int templatecount = templatefiles.Length; var templateChars = new string[templatecount]; var templatePoints = new Vector2[templatecount][]; //var templatesc = new double[templatecount][,]; var templatesc = new double[templatecount][][]; #region 计算模板的SC for (int f = 0; f < templatecount; ++f) { string file = templatefiles[f], filename = Path.GetFileNameWithoutExtension(file); using (Image<Gray, Byte> img = new Image<Gray, byte>(file)) { var samples = getEdge(img).Sample(ss); templatesc[f] = Jim.OCR.ShapeContext2D.ShapeContext.ComputeSC2(samples); templatePoints[f] = samples.Select(p => new Vector2(p.X, p.Y)).ToArray(); } templateChars[f] = filename; Console.Write(filename); } Console.WriteLine(); Debug("模板读取完成"); #endregion #region 处理字符 foreach (string file in Directory.GetFiles(@"D:\Play Data\字符")) { string filename = Path.GetFileNameWithoutExtension(file); if (filename != "AB") continue; timer.Restart(); Image<Bgr, Byte> img = new Image<Bgr, Byte>(file); var samples = getEdge(img.Convert<Gray, Byte>()).Sample(sq); //double[,] SCQ = Jim.OCR.ShapeContext2D.ShapeContext.ComputeSC(samples); double[][] SCQ = Jim.OCR.ShapeContext2D.ShapeContext.ComputeSC2(samples); var Q_Points = samples.Select(p => new Vector2(p.X, p.Y)).ToArray(); var mmg = img.Convert<Bgr, Byte>(); Graphics g = Graphics.FromImage(mmg.Bitmap); Q_Points.ToList().ForEach(v => { mmg[(int)v.Y, (int)v.X] = new Bgr(0, 0, 255); }); var point_distance = new ValueIndexPair<double>[sq][]; #region 计算采样点之间的距离 for (int i = 0; i < sq; ++i) { double xi = Q_Points[i].X, yi = Q_Points[i].Y; point_distance[i] = new ValueIndexPair<double>[sq]; for (int j = 0; j < sq; ++j) { double xj = Q_Points[j].X, yj = Q_Points[j].Y; point_distance[i][j] = new ValueIndexPair<double> { Value = Math.Sqrt((xi - xj) * (xi - xj) + (yi - yj) * (yi - yj)), Index = j }; } Array.Sort(point_distance[i], (a, b) => a.Value.CompareTo(b.Value)); } #endregion var randpoints = new int[randcount][]; #region 随机取randcount个点,并在其周围randtake个点中取randselect个 for (int i = 0; i < randcount; ++i) { int pi = rand.Next(Q_Points.Length); var p = Q_Points[pi]; mmg.Draw(new CircleF(new PointF((float)p.X, (float)p.Y), 2), new Bgr(255, 0, 0), 1); randpoints[i] = new int[randselect]; bool[] vi = Utils.InitArray<bool>(randtake, false); for (int cnt = 0; cnt < randselect; ) { int rnd = rand.Next(randtake); if (!vi[rnd]) { vi[rnd] = true; randpoints[i][cnt++] = rnd; } } for (int ppp = 0; ppp < randselect; ++ppp) { var pt = Q_Points[point_distance[pi][randpoints[i][ppp]].Index]; //g.DrawString(i.ToString(), new Font("Arial", 7), new SolidBrush(Color.FromArgb(0, 128, 0)), new PointF((float)pt.X, (float)pt.Y)); } } #endregion #region 为这randcount组RSC分别选最好的模板 var rscmatch = new Tuple<int, double, Vector2>[randcount]; // <Si, d, L> for (int rc = 0; rc < randcount; ++rc) { var rsc_matches = new Tuple<double, Vector2>[templatecount]; // <d, L> for (int i = 0; i < templatecount; ++i) { #region 拷贝出一个rsc来 var rsc = new double[randselect][]; for (int j = 0; j < randselect; ++j) { rsc[j] = new double[60]; Array.Copy(SCQ[randpoints[rc][j]], rsc[j], 60); } #endregion var costmat = Jim.OCR.ShapeContext2D.ShapeContext.HistCost2(rsc, templatesc[i]); var matches = costmat.Select( row => row.Select((d, c) => new ValueIndexPair<double> { Value = d, Index = c }) .OrderBy(d => d.Value).First()).ToArray(); Vector2 L = Vector2.Zero; double M = 0; for (int j = 0; j < randselect; ++j) { int u = randpoints[rc][j], mu = matches[j].Index; double d = matches[j].Value; Vector2 pu = Q_Points[u], pmu = templatePoints[i][mu]; M += (1 - d); L += (1 - d) * (pu - pmu); } L /= M; rsc_matches[i] = new Tuple<double, Vector2> { First = matches.Sum(r => r.Value), Second = L }; } var best_template = rsc_matches.Select((mt, i) => new { Match = mt, i }) .OrderBy(t => t.Match.First) .First(); rscmatch[rc] = new Tuple<int, double, Vector2> { First = best_template.i, Second = best_template.Match.First, Third = best_template.Match.Second }; string label = templateChars[best_template.i]; g.DrawString(label, new Font("Arial", 48), Brushes.Green, new PointF((float)best_template.Match.Second.X, (float)best_template.Match.Second.Y)); } #endregion //Font f = new Font("Arial", 12); //var G = new Tuple<int, int, double>[templatecount][]; // <u, m(u), d> //#region 为每个Si挑选合适的Gi //{ // var costmats = new double[templatecount][,]; // for (int i = 0; i < templatecount; ++i) { // double[,] SCi = templatesc[i]; // costmats[i] = Jim.OCR.ShapeContext2D.ShapeContext.HistCost(SCQ, SCi); // G[i] = new Tuple<int, int, double>[sq * ss]; // for (int u = 0; u < sq; ++u) { // for (int j = 0; j < ss; ++j) { // G[i][u * ss + j] = new Tuple<int, int, double> { // First = u, // Second = j, // Third = costmats[i][u, j] // }; // } // } // Array.Sort(G[i], (da, db) => da.Third.CompareTo(db.Third)); // } //} //#endregion //var d_Q_S = new double[templatecount]; //#region 求出每个Si和Q的d(Q, Si) //{ // for (int i = 0; i < templatecount; ++i) { // var Gi = G[i].Take(k); // foreach (var g in Gi) { // int u = g.First, mu = g.Second; // double d = g.Third; // double Nu = G.Average(gi => gi.First(t => t.First == u).Third); // d_Q_S[i] += d / Nu; // } // d_Q_S[i] /= k; // } //} //#endregion //var firstmG = new Tuple<Tuple<int, int, double>[], double, int>[m]; // <G, d, i> <=> <<u, m(u), d>[], d, i> //#region 根据d(Q, Si)截取前20个最好的Gi //{ // var firstmdQS = d_Q_S.Select((d, i) => new ValueIndexPair<double> { Value = d, Index = i }) // .OrderBy(p => p.Value) // .Take(firstmG.Length).ToArray(); // for (int p = 0; p < firstmG.Length; ++p) { // double d = firstmdQS[p].Value; // int i = firstmdQS[p].Index; // firstmG[p] = new Tuple<Tuple<int, int, double>[], double, int> { // First = G[i].Take(k).ToArray(), // Second = d, // Third = i // }; // } //} //#endregion //#region 计算每个G的位置 //var L = new Vector2[m]; //{ // for (int i = 0; i < m; ++i) { // L[i] = Vector2.Zero; // double Mi = 0; // var Gi = firstmG[i]; // foreach (var u_mu_d in Gi.First) { // int u = u_mu_d.First, mu = u_mu_d.Second; // double d = u_mu_d.Third; // Vector2 pu = Q_Points[u], pmu = templatePoints[Gi.Third][mu]; // L[i] += (1 - d) * (pu - pmu); // Mi += (1 - d); // } // L[i] /= Mi; // g.DrawString(templateChars[Gi.Third], new Font("Arial", 12), Brushes.Green, // new PointF((float)L[i].X, (float)L[i].Y)); // } //} //#endregion mmg.Save(Path.Combine(@"D:\Play Data\测试玩意", filename + ".bmp")); Debug("{0}\t用时{1}ms.", filename, timer.Stop()); } #endregion }
private static void testCAPTCHA() { var timer = new MyTimer(); int s = 100, K = 100, m = 180; string[] templatefiles = Directory.GetFiles(@"D:\Play Data\my_template_data\scq-" + K + "-" + m, "*.scq") .Take(10000).ToArray(); #region 打开量化的模板 int templatecount = templatefiles.Length; Debug("打开{0}个量化模板----------------------------------------", templatecount); timer.Restart(); int[][] templatehistograms = new int[templatecount][]; string[] templatechars = new string[templatecount]; for (int f = 0; f < templatecount; ++f) { string file = templatefiles[f]; string filename = Path.GetFileNameWithoutExtension(file); templatechars[f] = filename.Split('-')[1]; templatehistograms[f] = new int[K]; using (var fs = new FileStream(file, FileMode.Open)) { using (var br = new BinaryReader(fs)) { for (int i = 0; i < K; ++i) { templatehistograms[f][i] = br.ReadInt32(); } } } } Debug("打开完成,用时{0}ms.", timer.Stop()); #endregion #region 打开Shapeme Debug("打开{0}个Shapeme.", K); timer.Restart(); double[][] shapemes = new double[K][]; using (var fs = new FileStream(Path.Combine(@"D:\Play Data\my_template_data\sm-" + K, m + ".sm"), FileMode.Open)) { using (var br = new BinaryReader(fs)) { for (int i = 0; i < K; ++i) { shapemes[i] = new double[60]; for (int k = 0; k < 60; ++k) { shapemes[i][k] = br.ReadDouble(); } } } } Debug("Shapeme读取完成,用时{0}ms.", timer.Stop()); #endregion #region 识别 foreach (var challengeFile in Directory.GetFiles(@"D:\Play Data\字符\", "*.jpg")) { timer.Restart(); string filename = Path.GetFileNameWithoutExtension(challengeFile); Image<Gray, Byte> img = new Image<Gray, byte>(challengeFile); var mmp = img.Convert<Bgr, Byte>(); Graphics g = Graphics.FromImage(mmp.Bitmap); double width_height_ratio = (double)img.Width / img.Height; int sq = (int)(s * width_height_ratio * 1.2); int randcount = (int)(width_height_ratio * 2); //int windowcount = (int)(width_height_ratio * 2), // windowstep = (int)(img.Width / windowcount), // windowwidth = (int)(img.Width * 1.5 / windowcount); //int maxrandcount = randcount * 3; //Console.WriteLine("宽高比{0:F2},采样{1},随机数{2},随机上限{3}.", // width_height_ratio, sq, randcount, maxrandcount); int slice = 16,//(int)(width_height_ratio * width_height_ratio), overlap = 4, windowcount = 7;//slice - (overlap - 1); double slice_width = (double)img.Width / slice; Console.WriteLine("宽高比{0:F2},切片数{1},切片宽度{2:F2},窗口数{3}.", width_height_ratio, slice, slice_width, windowcount); var edge = getEdge(img).Sample(sq); foreach (var p in edge) { mmp[p] = new Bgr(0, 0, 127); } bool[] edge_vi = Utils.InitArray(sq, false); #region 计算采样点之间的距离 ValueIndexPair<double>[][] edgedists = new ValueIndexPair<double>[sq][]; for (int i = 0; i < sq; ++i) { edgedists[i] = new ValueIndexPair<double>[sq]; for (int j = 0; j < sq; ++j) { double xi = edge[i].X, yi = edge[i].Y, xj = edge[j].X, yj = edge[j].Y; double d = Math.Sqrt((xi - xj) * (xi - xj) + (yi - yj) * (yi - yj)); edgedists[i][j] = new ValueIndexPair<double> { Value = d, Index = j }; } Array.Sort(edgedists[i], (a, b) => a.Value.CompareTo(b.Value)); } #endregion var charlist = new List<Tuple<string, int, PointF>>(); // <ch, count, center> //for (int rc = 0, rt = 0; rc < randcount && rt < maxrandcount; ++rt) { // #region 随机取一个中心点,并且取离他近的点计算形状上下文 //int center = rand.Next(sq); //if (edge_vi[center]) continue; //else rc++; //rc++; //var nearby = new List<Point>(); //foreach (var pair in edgedists[center].Take((int)(s * 1.5))) { // nearby.Add(edge[pair.Index]); // edge_vi[pair.Index] = true; //} //nearby = nearby.Sample(s); for (int wd = 0; wd < windowcount; ++wd) { #region 滑动窗口位置 //int window_center = wd * windowstep + (windowwidth / 2); double window_center = (wd * 2 + overlap / 2.0) * slice_width; g.DrawLine(Pens.Green, (float)window_center, 0, (float)window_center, img.Height); var nearby = edge.Where(p => Math.Abs(p.X - window_center) < img.Height) .OrderBy(p => Math.Abs(p.X - window_center)) .Take((int)(s * 1.2)) .ToList().Sample(s); if (nearby.Average(p => Math.Abs(p.X - window_center)) > img.Height) continue; var sc = Jim.OCR.ShapeContext2D.ShapeContext.ComputeSC2(nearby); #endregion #region 对待测图的形状上下文进行量化 int[] histogram = new int[K]; for (int i = 0; i < s; ++i) { double[] ds = new double[K]; for (int j = 0; j < K; ++j) ds[j] = Jim.OCR.ShapeContext2D.ShapeContext.HistCost(sc[i], shapemes[j]); int id = ds.Select((v, idx) => new ValueIndexPair<double> { Value = v, Index = idx }) .OrderBy(p => p.Value) .First().Index; ++histogram[id]; } #endregion #region 计算量化后的比较距离 double[] dists = new double[templatecount]; for (int i = 0; i < templatecount; ++i) { //dists[i] = Jim.OCR.ShapeContext2D.ShapeContext.ChiSquareDistance(histogram, templatehistograms[i]); dists[i] = Jim.OCR.ShapeContext2D.ShapeContext.HistCost( histogram.Select(d => (double)d).ToArray(), templatehistograms[i].Select(d => (double)d).ToArray()); } #endregion #region 对结果进行排序和统计 var arr = dists.Select((d, i) => new ValueIndexPair<double> { Value = d, Index = i }) .OrderBy(p => p.Value) .Select(p => new { Distance = p.Value, Char = templatechars[p.Index] }) .Where(p => "0123456789".IndexOf(p.Char) != -1) .ToArray(); Dictionary<string, int> matchcount = new Dictionary<string, int>(); int knn = 10; foreach (var pair in arr.Take(knn)) { string ch = pair.Char; matchcount[ch] = matchcount.ContainsKey(ch) ? matchcount[ch] + 1 : 1; } var match = matchcount.Select(pair => new { Count = pair.Value, Ch = pair.Key }) .Where(v => v.Count > 0) .OrderByDescending(v => v.Count).ToArray(); var firstmatch = match[0]; PointF newcenter = new PointF(nearby.Average(p => (float)p.X), nearby.Average(p => (float)p.Y)); charlist.Add(new Tuple<string, int, PointF> { First = firstmatch.Ch, Second = firstmatch.Count, Third = newcenter }); #endregion } foreach (var tp in charlist) { string ch = tp.First; int acc = tp.Second; PointF center = tp.Third; //g.DrawString(num.ToString(), new Font("Arial", 24), new SolidBrush(Color.FromArgb(40 + 20 * acc, 0, 0)), // new PointF(center.X - 12, center.Y - 12)); g.DrawString(ch, new Font("Arial", 24), (acc >= 5 ? Brushes.Red : Brushes.DarkGreen), new PointF(center.X - 12, center.Y - 12)); } mmp.Save(Path.Combine(@"D:\Play Data\测试玩意\", filename + ".jpg")); Debug("{0}-{1}ms", filename, timer.Stop()); } #endregion }
public Tuple <string, int> Recognize(Image <Gray, byte> src) { var list = src.getEdge().Sample(100); #region 计算形状上下文 int r = 15; var scall = Jim.OCR.ShapeContext2D.ShapeContext.ComputeSC(list); var scq = new double[r, 60]; for (int i = 0; i < r; ++i) { int pos = rand.Next(list.Count); for (int k = 0; k < 60; ++k) { scq[i, k] = scall[pos, k]; } } #endregion #region 计算距离 var dists = new ValueIndexPair <double> [SC.template_sc.Length]; for (int i = 0; i < SC.template_sc.Length; ++i) { double[,] sci = SC.template_sc[i]; double[,] costmat = Jim.OCR.ShapeContext2D.ShapeContext.HistCost(scq, sci); double cost = 0; for (int j = 0; j < r; ++j) { double min = double.MaxValue; for (int u = 0; u < 100; ++u) { double val = costmat[j, u]; if (val < min) { min = val; } } cost += min; } dists[i] = new ValueIndexPair <double> { Value = cost, Index = i }; } #endregion #region 对结果排序 var arr = dists .OrderBy(p => p.Value) .Select(p => new { Distance = p.Value, Char = SC.template_chars[p.Index] }) //.Where(p => "ABCDEFGHIJKLMNPQRSTUVWXYZ123456789".IndexOf(p.Char) != -1) .Where(p => Filter.IndexOf(p.Char) != -1) .ToArray(); Dictionary <string, int> matchcount = new Dictionary <string, int>(); foreach (var pair in arr.Take(Knn)) { string ch = pair.Char; matchcount[ch] = matchcount.ContainsKey(ch) ? matchcount[ch] + 1 : 1; } var match = matchcount.Select(pair => new { Count = pair.Value, Ch = pair.Key }) .Where(v => v.Count > 0) .OrderByDescending(v => v.Count).ToArray(); //string result = ""; //foreach (var m in match.Take(3)) { // result += String.Format("Char:'{0}',Accuracy:{1}/{2}\t", m.Ch, m.Count, knn); //} #endregion return(new Tuple <string, int> { First = match[0].Ch, Second = match[0].Count }); }
public void Run() { double totaltime = 0; int s = 100, r = 5; string[] templatefiles = Directory.GetFiles(@"D:\Play Data\train_data\sc\", "*.sc") .Take(100).ToArray(); #region 打开模板 string templatepath = @"D:\Play Data\template\"; int templatecount = templatefiles.Length; Debug("打开{0}个模板--------------------------------------------", templatecount); double[][,] templates = new double[templatecount][, ]; int[] templatenums = new int[templatecount]; timer.Restart(); for (int i = 0; i < templatefiles.Length; ++i) { string file = templatefiles[i]; string filename = Path.GetFileNameWithoutExtension(file); templatenums[i] = int.Parse(filename.Split('-')[1]); templates[i] = new double[s, 60]; using (var fs = new FileStream(file, FileMode.Open)) { using (var br = new BinaryReader(fs)) { for (int j = 0; j < s; ++j) { for (int k = 0; k < 60; ++k) { templates[i][j, k] = br.ReadDouble(); } } } } if (i % 100 == 0) { Debug("已完成{0}个", i); } } Debug("模板读取完成,用时{0}ms.", timer.Stop()); #endregion string[] testfiles = Directory.GetFiles(@"D:\Play Data\test\", "*.bmp") .Take(1000).ToArray(); #region 测试 int testcase = testfiles.Length, acc = 0; Debug("为{0}个对象寻找候选模板------------------------------------------", testcase); foreach (var file in testfiles) { timer.Restart(); string filenameext = Path.GetFileName(file); string filename = Path.GetFileNameWithoutExtension(file); int thisnum = int.Parse(filename.Split('-')[1]); Image <Gray, Byte> img = new Image <Gray, byte>(file); var list = getEdge(img.Resize(2.5, Emgu.CV.CvEnum.INTER.CV_INTER_LINEAR)).Sample(s); var sc100 = Jim.OCR.ShapeContext2D.ShapeContext.ComputeSC(list); double[,] scq = new double[r, 60]; for (int i = 0; i < 5; ++i) { int pos = rand.Next(s); for (int k = 0; k < 60; ++k) { scq[i, k] = sc100[pos, k]; } } var arr = new ValueIndexPair <double> [templatecount]; for (int i = 0; i < templatecount; ++i) { double[,] sci = templates[i]; double[,] costmat = Jim.OCR.ShapeContext2D.ShapeContext.HistCost(scq, sci); double cost = 0; for (int j = 0; j < 5; ++j) { double min = double.MaxValue; for (int u = 0; u < s; ++u) { double val = costmat[j, u]; if (val < min) { min = val; } } cost += min; } arr[i] = new ValueIndexPair <double> { Value = cost, Index = i }; } Array.Sort(arr, (a, b) => a.Value.CompareTo(b.Value)); int knn = 10; #region 进行精细匹配 var kmresults = new List <ValueIndexPair <double> >(); foreach (var pair in arr.Take(knn)) { int idx = pair.Index; var costmat = Jim.OCR.ShapeContext2D.ShapeContext.HistCost(templates[idx], sc100); var costmat_int = new int[s, s]; for (int ii = 0; ii < s; ++ii) { for (int jj = 0; jj < s; ++jj) { costmat_int[ii, jj] = (int)(costmat[ii, jj] * 10000); } } var km = new KM(s, costmat_int); km.Match(false); kmresults.Add(new ValueIndexPair <double> { Index = idx, Value = km.MatchResult / 10000.0 }); } kmresults.Sort((a, b) => a.Value.CompareTo(b.Value)); #endregion //int firstmatch = match[0].Num; int firstmatch = templatenums[kmresults[0].Index]; var fc = Console.ForegroundColor; Console.ForegroundColor = firstmatch == thisnum ? ConsoleColor.Green : ConsoleColor.Red; var timeused = timer.Stop(); totaltime += timeused; string info = String.Format("{0} {1}ms\t", filename, timeused); //foreach (var m in bestmatches.Take(4)) { foreach (var m in kmresults.Take(4)) { info += String.Format("{0}/{1:F2}\t", templatenums[m.Index], m.Value); } //Debug(info); if (firstmatch != thisnum) { Console.Write("."); } Console.ForegroundColor = fc; if (firstmatch == thisnum) { ++acc; } } Debug("\nRSC and KM 测试用例:{0}。正确率{1}。", testcase, acc); Console.WriteLine("总用时:{0}ms,平均用时:{1}ms。", totaltime, totaltime / testcase); #endregion }
public void Run() { double totaltime = 0; int s = 100, r = 5; string[] templatefiles = Directory.GetFiles(@"D:\Play Data\train_data\sc\", "*.sc") .Take(100).ToArray(); #region 打开模板 string templatepath = @"D:\Play Data\template\"; int templatecount = templatefiles.Length; Debug("打开{0}个模板--------------------------------------------", templatecount); double[][,] templates = new double[templatecount][, ]; int[] templatenums = new int[templatecount]; timer.Restart(); for (int i = 0; i < templatefiles.Length; ++i) { string file = templatefiles[i]; string filename = Path.GetFileNameWithoutExtension(file); templatenums[i] = int.Parse(filename.Split('-')[1]); templates[i] = new double[s, 60]; using (var fs = new FileStream(file, FileMode.Open)) { using (var br = new BinaryReader(fs)) { for (int j = 0; j < s; ++j) { for (int k = 0; k < 60; ++k) { templates[i][j, k] = br.ReadDouble(); } } } } if (i % 100 == 0) { Debug("已完成{0}个", i); } } Debug("模板读取完成,用时{0}ms.", timer.Stop()); #endregion string[] testfiles = Directory.GetFiles(@"D:\Play Data\test\", "*.bmp") .Take(1000).ToArray(); #region 测试 int testcase = testfiles.Length, acc = 0; Debug("为{0}个对象寻找候选模板------------------------------------------", testcase); foreach (var file in testfiles) { timer.Restart(); string filenameext = Path.GetFileName(file); string filename = Path.GetFileNameWithoutExtension(file); int thisnum = int.Parse(filename.Split('-')[1]); Image <Gray, Byte> img = new Image <Gray, byte>(file); var list = getEdge(img.Resize(2.5, Emgu.CV.CvEnum.INTER.CV_INTER_LINEAR)).Sample(s); var sc100 = Jim.OCR.ShapeContext2D.ShapeContext.ComputeSC(list); double[,] scq = new double[r, 60]; for (int i = 0; i < 5; ++i) { int pos = rand.Next(s); for (int k = 0; k < 60; ++k) { scq[i, k] = sc100[pos, k]; } } var arr = new ValueIndexPair <double> [templatecount]; for (int i = 0; i < templatecount; ++i) { double[,] sci = templates[i]; double[,] costmat = Jim.OCR.ShapeContext2D.ShapeContext.HistCost(scq, sci); double cost = 0; for (int j = 0; j < 5; ++j) { double min = double.MaxValue; for (int u = 0; u < s; ++u) { double val = costmat[j, u]; if (val < min) { min = val; } } cost += min; } arr[i] = new ValueIndexPair <double> { Value = cost, Index = i }; } Array.Sort(arr, (a, b) => a.Value.CompareTo(b.Value)); int[] matchcount = new int[10]; double[] matchcost = new double[10]; int knn = 10; foreach (var pair in arr.Take(knn)) { int num = templatenums[pair.Index]; matchcount[num]++; matchcost[num] += pair.Value; } var match = matchcount.Select((val, i) => new { Count = val, Num = i }) .Where(v => v.Count > 0) .OrderByDescending(v => v.Count).ToArray(); //var match = matchcost.Select((val, i) => new { Cost = val / matchcount[i], Num = i }) // .Where(v => !double.IsNaN(v.Cost)) // .OrderBy(v => v.Cost).ToArray(); #region 进行精细匹配,效果一般 //double[] matchrate = new double[10]; //foreach (var m in match) { // if (m.Count == 0) break; // string template = Path.Combine(templatepath, m.Num + ".bmp"); // Jim.OCR.ShapeContext2D.ShapeContext sc = new Jim.OCR.ShapeContext2D.ShapeContext(file, template); // sc.debug_flag = false; // sc.timer_flag = false; // sc.display_flag = false; // sc.n_iter = 3; // sc.matchScale = 2.5; // sc.maxsamplecount = 100; // matchrate[m.Num] = sc.MatchFile(); //} //var bestmatches = matchrate.Select((val, i) => new { Cost = val, Num = i }) // .Where(m => m.Cost > 0) // .OrderBy(m => m.Cost).ToArray(); //int firstmatch = bestmatches[0].Num; #endregion int firstmatch = match[0].Num; var fc = Console.ForegroundColor; Console.ForegroundColor = firstmatch == thisnum ? ConsoleColor.Green : ConsoleColor.Red; var timeused = timer.Stop(); totaltime += timeused; string info = String.Format("{0} {1}ms - {2}\t", filename, timeused, (firstmatch == thisnum ? "Right" : "Wrong")); //foreach (var m in bestmatches.Take(4)) { foreach (var m in match) { info += String.Format("{0}/{1}\t", m.Num, m.Count); //info += String.Format("{0}/{1:F3}\t", m.Num, m.Cost); //info += String.Format("{0}/{1:F3}\t", m.Num, m.Cost); } //Debug(info); if (firstmatch != thisnum) { Console.Write("."); } Console.ForegroundColor = fc; if (firstmatch == thisnum) { ++acc; } } Debug("\nRSC 测试用例:{0}。正确率{1}。", testcase, acc); Console.WriteLine("总用时:{0}ms,平均用时:{1}ms。", totaltime, totaltime / testcase); #endregion }
public void Run() { double totaltime = 0; int s = 100, r = 5; string[] templatefiles = Directory.GetFiles(@"D:\Play Data\train_data\sc\", "*.sc") .Take(100).ToArray(); #region 打开模板 string templatepath = @"D:\Play Data\template\"; int templatecount = templatefiles.Length; Debug("打开{0}个模板--------------------------------------------", templatecount); double[][,] templates = new double[templatecount][,]; int[] templatenums = new int[templatecount]; timer.Restart(); for (int i = 0; i < templatefiles.Length; ++i) { string file = templatefiles[i]; string filename = Path.GetFileNameWithoutExtension(file); templatenums[i] = int.Parse(filename.Split('-')[1]); templates[i] = new double[s, 60]; using (var fs = new FileStream(file, FileMode.Open)) { using (var br = new BinaryReader(fs)) { for (int j = 0; j < s; ++j) { for (int k = 0; k < 60; ++k) { templates[i][j, k] = br.ReadDouble(); } } } } if (i % 100 == 0) Debug("已完成{0}个", i); } Debug("模板读取完成,用时{0}ms.", timer.Stop()); #endregion string[] testfiles = Directory.GetFiles(@"D:\Play Data\test\", "*.bmp") .Take(1000).ToArray(); #region 测试 int testcase = testfiles.Length, acc = 0; Debug("为{0}个对象寻找候选模板------------------------------------------", testcase); foreach (var file in testfiles) { timer.Restart(); string filenameext = Path.GetFileName(file); string filename = Path.GetFileNameWithoutExtension(file); int thisnum = int.Parse(filename.Split('-')[1]); Image<Gray, Byte> img = new Image<Gray, byte>(file); var list = getEdge(img.Resize(2.5, Emgu.CV.CvEnum.INTER.CV_INTER_LINEAR)).Sample(s); var sc100 = Jim.OCR.ShapeContext2D.ShapeContext.ComputeSC(list); double[,] scq = new double[r, 60]; for (int i = 0; i < 5; ++i) { int pos = rand.Next(s); for (int k = 0; k < 60; ++k) { scq[i, k] = sc100[pos, k]; } } var arr = new ValueIndexPair<double>[templatecount]; for (int i = 0; i < templatecount; ++i) { double[,] sci = templates[i]; double[,] costmat = Jim.OCR.ShapeContext2D.ShapeContext.HistCost(scq, sci); double cost = 0; for (int j = 0; j < 5; ++j) { double min = double.MaxValue; for (int u = 0; u < s; ++u) { double val = costmat[j, u]; if (val < min) min = val; } cost += min; } arr[i] = new ValueIndexPair<double> { Value = cost, Index = i }; } Array.Sort(arr, (a, b) => a.Value.CompareTo(b.Value)); int knn = 10; #region 进行精细匹配 var kmresults = new List<ValueIndexPair<double>>(); foreach (var pair in arr.Take(knn)) { int idx = pair.Index; var costmat = Jim.OCR.ShapeContext2D.ShapeContext.HistCost(templates[idx], sc100); var costmat_int = new int[s, s]; for (int ii = 0; ii < s; ++ii) { for (int jj = 0; jj < s; ++jj) { costmat_int[ii, jj] = (int)(costmat[ii, jj] * 10000); } } var km = new KM(s, costmat_int); km.Match(false); kmresults.Add(new ValueIndexPair<double> { Index = idx, Value = km.MatchResult / 10000.0 }); } kmresults.Sort((a, b) => a.Value.CompareTo(b.Value)); #endregion //int firstmatch = match[0].Num; int firstmatch = templatenums[kmresults[0].Index]; var fc = Console.ForegroundColor; Console.ForegroundColor = firstmatch == thisnum ? ConsoleColor.Green : ConsoleColor.Red; var timeused = timer.Stop(); totaltime += timeused; string info = String.Format("{0} {1}ms\t", filename, timeused); //foreach (var m in bestmatches.Take(4)) { foreach (var m in kmresults.Take(4)) { info += String.Format("{0}/{1:F2}\t", templatenums[m.Index], m.Value); } //Debug(info); if (firstmatch != thisnum) Console.Write("."); Console.ForegroundColor = fc; if (firstmatch == thisnum) { ++acc; } } Debug("\nRSC and KM 测试用例:{0}。正确率{1}。", testcase, acc); Console.WriteLine("总用时:{0}ms,平均用时:{1}ms。", totaltime, totaltime / testcase); #endregion }
private void recognize_rsc() { if (template_histograms == null) { MessageBox.Show("尚未读取模板。"); return; } new Thread(new ThreadStart(() => { clearLog(); showStatus("搜索中"); foreach (var challenge in splitted_chars) { timer.Restart(); var list = challenge.getEdge().Sample(100); #region 计算形状上下文 int r = 15; var scall = Jim.OCR.ShapeContext2D.ShapeContext.ComputeSC(list); var scq = new double[r, 60]; for (int i = 0; i < r; ++i) { int pos = rand.Next(list.Count); for (int k = 0; k < 60; ++k) { scq[i, k] = scall[pos, k]; } } #endregion #region 计算距离 var dists = new ValueIndexPair<double>[template_sc.Length]; for (int i = 0; i < template_sc.Length; ++i) { double[,] sci = template_sc[i]; double[,] costmat = Jim.OCR.ShapeContext2D.ShapeContext.HistCost(scq, sci); double cost = 0; for (int j = 0; j < r; ++j) { double min = double.MaxValue; for (int u = 0; u < 100; ++u) { double val = costmat[j, u]; if (val < min) min = val; } cost += min; } dists[i] = new ValueIndexPair<double> { Value = cost, Index = i }; showProgress((i + 1.0) / template_histograms.Length); } #endregion #region 对结果排序 var arr = dists .OrderBy(p => p.Value) .Select(p => new { Distance = p.Value, Char = template_chars[p.Index] }) //.Where(p => "ABCDEFGHIJKLMNPQRSTUVWXYZ123456789".IndexOf(p.Char) != -1) .ToArray(); Dictionary<string, int> matchcount = new Dictionary<string, int>(); int knn = 10; foreach (var pair in arr.Take(knn)) { string ch = pair.Char; matchcount[ch] = matchcount.ContainsKey(ch) ? matchcount[ch] + 1 : 1; } var match = matchcount.Select(pair => new { Count = pair.Value, Ch = pair.Key }) .Where(v => v.Count > 0) .OrderByDescending(v => v.Count).ToArray(); string result = ""; foreach (var m in match.Take(3)) { result += String.Format("Char:'{0}',Accuracy:{1}/{2}\t", m.Ch, m.Count, knn); } appendLine(result); #endregion } appendLine("-----------------------------------------------------"); showStatus("搜索完成,共用时{0}ms。", timer.Stop()); })).Start(); }
private void recognize_rsc() { if (template_histograms == null) { MessageBox.Show("尚未读取模板。"); return; } new Thread(new ThreadStart(() => { clearLog(); showStatus("搜索中"); foreach (var challenge in splitted_chars) { timer.Restart(); var list = challenge.getEdge().Sample(100); #region 计算形状上下文 int r = 15; var scall = Jim.OCR.ShapeContext2D.ShapeContext.ComputeSC(list); var scq = new double[r, 60]; for (int i = 0; i < r; ++i) { int pos = rand.Next(list.Count); for (int k = 0; k < 60; ++k) { scq[i, k] = scall[pos, k]; } } #endregion #region 计算距离 var dists = new ValueIndexPair <double> [template_sc.Length]; for (int i = 0; i < template_sc.Length; ++i) { double[,] sci = template_sc[i]; double[,] costmat = Jim.OCR.ShapeContext2D.ShapeContext.HistCost(scq, sci); double cost = 0; for (int j = 0; j < r; ++j) { double min = double.MaxValue; for (int u = 0; u < 100; ++u) { double val = costmat[j, u]; if (val < min) { min = val; } } cost += min; } dists[i] = new ValueIndexPair <double> { Value = cost, Index = i }; showProgress((i + 1.0) / template_histograms.Length); } #endregion #region 对结果排序 var arr = dists .OrderBy(p => p.Value) .Select(p => new { Distance = p.Value, Char = template_chars[p.Index] }) //.Where(p => "ABCDEFGHIJKLMNPQRSTUVWXYZ123456789".IndexOf(p.Char) != -1) .ToArray(); Dictionary <string, int> matchcount = new Dictionary <string, int>(); int knn = 10; foreach (var pair in arr.Take(knn)) { string ch = pair.Char; matchcount[ch] = matchcount.ContainsKey(ch) ? matchcount[ch] + 1 : 1; } var match = matchcount.Select(pair => new { Count = pair.Value, Ch = pair.Key }) .Where(v => v.Count > 0) .OrderByDescending(v => v.Count).ToArray(); string result = ""; foreach (var m in match.Take(3)) { result += String.Format("Char:'{0}',Accuracy:{1}/{2}\t", m.Ch, m.Count, knn); } appendLine(result); #endregion } appendLine("-----------------------------------------------------"); showStatus("搜索完成,共用时{0}ms。", timer.Stop()); })).Start(); }
public void Run() { double totaltime = 0; int s = 100, r = 5; string[] templatefiles = Directory.GetFiles(@"D:\Play Data\train_data\sc\", "*.sc") .Take(100).ToArray(); #region 打开模板 string templatepath = @"D:\Play Data\template\"; int templatecount = templatefiles.Length; Debug("打开{0}个模板--------------------------------------------", templatecount); double[][,] templates = new double[templatecount][,]; int[] templatenums = new int[templatecount]; timer.Restart(); for (int i = 0; i < templatefiles.Length; ++i) { string file = templatefiles[i]; string filename = Path.GetFileNameWithoutExtension(file); templatenums[i] = int.Parse(filename.Split('-')[1]); templates[i] = new double[s, 60]; using (var fs = new FileStream(file, FileMode.Open)) { using (var br = new BinaryReader(fs)) { for (int j = 0; j < s; ++j) { for (int k = 0; k < 60; ++k) { templates[i][j, k] = br.ReadDouble(); } } } } if (i % 100 == 0) Debug("已完成{0}个", i); } Debug("模板读取完成,用时{0}ms.", timer.Stop()); #endregion string[] testfiles = Directory.GetFiles(@"D:\Play Data\test\", "*.bmp") .Take(100).ToArray(); #region 测试 int testcase = testfiles.Length, acc = 0; Debug("为{0}个对象寻找候选模板------------------------------------------", testcase); foreach (var file in testfiles) { timer.Restart(); string filenameext = Path.GetFileName(file); string filename = Path.GetFileNameWithoutExtension(file); int thisnum = int.Parse(filename.Split('-')[1]); Image<Gray, Byte> img = new Image<Gray, byte>(file); var list = getEdge(img.Resize(2.5, Emgu.CV.CvEnum.INTER.CV_INTER_LINEAR)).Sample(s); var scq = Jim.OCR.ShapeContext2D.ShapeContext.ComputeSC(list); var arr = new ValueIndexPair<double>[templatecount]; for (int i = 0; i < templatecount; ++i) { double[,] sci = templates[i]; double[,] costmat = Jim.OCR.ShapeContext2D.ShapeContext.HistCost(scq, sci); var costmat_int = new int[s, s]; for (int ii = 0; ii < s; ++ii) { for (int jj = 0; jj < s; ++jj) { costmat_int[ii, jj] = (int)(costmat[ii, jj] * 10000); } } var km = new KM(s, costmat_int); km.Match(false); arr[i] = new ValueIndexPair<double> { Index = i, Value = km.MatchResult / 10000.0 }; } Array.Sort(arr, (a, b) => a.Value.CompareTo(b.Value)); int[] matchcount = new int[10]; double[] matchcost = new double[10]; int knn = 10; foreach (var pair in arr.Take(knn)) { int num = templatenums[pair.Index]; matchcount[num]++; matchcost[num] += pair.Value; } var match = matchcount.Select((val, i) => new { Count = val, Num = i }) .Where(v => v.Count > 0) .OrderByDescending(v => v.Count).ToArray(); //var match = matchcost.Select((val, i) => new { Cost = val / matchcount[i], Num = i }) // .Where(v => !double.IsNaN(v.Cost)) // .OrderBy(v => v.Cost).ToArray(); #region 进行精细匹配,效果一般 //double[] matchrate = new double[10]; //foreach (var m in match) { // if (m.Count == 0) break; // string template = Path.Combine(templatepath, m.Num + ".bmp"); // Jim.OCR.ShapeContext2D.ShapeContext sc = new Jim.OCR.ShapeContext2D.ShapeContext(file, template); // sc.debug_flag = false; // sc.timer_flag = false; // sc.display_flag = false; // sc.n_iter = 3; // sc.matchScale = 2.5; // sc.maxsamplecount = 100; // matchrate[m.Num] = sc.MatchFile(); //} //var bestmatches = matchrate.Select((val, i) => new { Cost = val, Num = i }) // .Where(m => m.Cost > 0) // .OrderBy(m => m.Cost).ToArray(); //int firstmatch = bestmatches[0].Num; #endregion int firstmatch = match[0].Num; var fc = Console.ForegroundColor; Console.ForegroundColor = firstmatch == thisnum ? ConsoleColor.Green : ConsoleColor.Red; var timeused = timer.Stop(); totaltime += timeused; string info = String.Format("{0} {1}ms - {2}\t", filename, timeused, (firstmatch == thisnum ? "Right" : "Wrong")); //foreach (var m in bestmatches.Take(4)) { foreach (var m in match) { info += String.Format("{0}/{1}\t", m.Num, m.Count); //info += String.Format("{0}/{1:F3}\t", m.Num, m.Cost); //info += String.Format("{0}/{1:F3}\t", m.Num, m.Cost); } Debug(info); Console.ForegroundColor = fc; if (firstmatch == thisnum) { ++acc; } } Debug("测试用例:{0}。正确率{1}。", testcase, acc); Console.WriteLine("总用时:{0}ms,平均用时:{1}ms。", totaltime, totaltime / testcase); #endregion }