public void Recognize() { var width = _image.Width; var height = _image.Height; KeyValuePair <ulong[], ulong[]>[,] matrix = new KeyValuePair <ulong[], ulong[]> [width, height]; for (var y = 0; y < height; y++) { IndexRow(y, width); } for (int x = 0; x < width; x++) { IndexColumn(x, height); } for (var y = 0; y < height; y++) { if (y == 574) { var roww = GetRow(y, width); var levelss = _sequenceToItsLocalElementLevelsConverter.Convert(roww); var l276 = levelss[276]; var l277 = levelss[277]; var l278 = levelss[278]; } var row = SaveRow(y, width); var x = 0; var stack = new Stack <ulong>(); StopableSequenceWalker.WalkRight(row, _links.GetSource, _links.GetTarget, _links.IsPartialPoint, enteredElement => { stack.Push(enteredElement); }, exitedElement => { stack.Pop(); }, checkedElement => true, element => { stack.Push(element); var pair = new KeyValuePair <ulong[], ulong[]>(stack.ToArray(), default); stack.Pop(); matrix[x++, y] = pair; return(true); }); } for (int x = 0; x < width; x++) { var column = SaveColumn(x, height); var y = 0; var stack = new Stack <ulong>(); StopableSequenceWalker.WalkRight(column, _links.GetSource, _links.GetTarget, _links.IsPartialPoint, enteredElement => { stack.Push(enteredElement); }, exitedElement => { stack.Pop(); }, checkedElement => true, element => { var pair = matrix[x, y]; stack.Push(element); pair = new KeyValuePair <ulong[], ulong[]>(pair.Key, stack.ToArray()); stack.Pop(); matrix[x, y++] = pair; return(true); }); } // Sort sequences by usages and frequency var linksByUsages = new SortedDictionary <ulong, List <ulong> >(); var linksByFrequency = new SortedDictionary <ulong, List <ulong> >(); var any = _links.Constants.Any; var @continue = _links.Constants.Continue; var query = new Link <ulong>(any, any, any); _links.Each(link => { var linkIndex = _links.GetIndex(link); var usages = _links.Count(new ulong[] { any, linkIndex }); if (!linksByUsages.TryGetValue(usages, out List <ulong> linksByUsageList)) { linksByUsageList = new List <ulong>(); linksByUsages.Add(usages, linksByUsageList); } linksByUsageList.Add(linkIndex); ulong frequency = GetFrequency(link); if (!linksByFrequency.TryGetValue(frequency, out List <ulong> linksByFrequencyList)) { linksByFrequencyList = new List <ulong>(); linksByFrequency.Add(frequency, linksByFrequencyList); } linksByFrequencyList.Add(linkIndex); return(@continue); }, query); // Build matrix of levels on 2D plane (as in optimal variant algorithm) var levels = new ulong[width, height]; var topBottom = 0UL; var leftRight = 0UL; var bottomTop = 0UL; var rightLeft = 0UL; var lastX = width - 1; var lastY = height - 1; // We do not calculate edges to simplify the algorithm for (int y = 1; y < lastY; y++) { for (int x = 1; x < lastX; x++) { topBottom = GetFrequency(matrix[x, y - 1].Key[0], matrix[x, y].Key[0]); leftRight = GetFrequency(matrix[x - 1, y].Key[0], matrix[x, y].Key[0]); bottomTop = GetFrequency(matrix[x, y].Key[0], matrix[x, y + 1].Key[0]); rightLeft = GetFrequency(matrix[x, y].Key[0], matrix[x + 1, y].Key[0]); levels[x, y] = Math.Max(Math.Max(topBottom, leftRight), Math.Max(bottomTop, rightLeft)); } } // Print levels matrix //for (int y = 1; y < lastY; y++) //{ // for (int x = 1; x < lastX; x++) // { // Console.Write("{0:0000}", levels[x, y]); // Console.Write(' '); // } // Console.WriteLine(); //} // Black and white (split to two colors) var contrastedLevels = new ulong[width, height]; var minimum = ulong.MaxValue; var maximum = ulong.MinValue; for (int y = 1; y < lastY; y++) { for (int x = 1; x < lastX; x++) { var level = levels[x, y]; minimum = minimum > level ? level : minimum; } } for (int y = 1; y < lastY; y++) { for (int x = 1; x < lastX; x++) { var level = levels[x, y]; maximum = maximum < level ? level : maximum; } } var middle = (maximum + minimum) / 2; for (int y = 1; y < lastY; y++) { for (int x = 1; x < lastX; x++) { contrastedLevels[x, y] = levels[x, y] > middle ? 0UL : 1UL; // the most frequent should be background (zero) } } // Print contrasted levels matrix //for (int y = 1; y < lastY; y++) //{ // for (int x = 1; x < lastX; x++) // { // Console.Write("{0:0}", contrastedLevels[x, y]); // } // Console.WriteLine(); //} var outputImagePath = Path.ChangeExtension(_sourceImagePath, ".bf.png"); using (var outputImage = new MagickImage(MagickColor.FromRgba(0, 0, 0, 255), width, height)) { var pixels = outputImage.GetPixels(); for (int y = 1; y < lastY; y++) { for (int x = 1; x < lastX; x++) { if (contrastedLevels[x, y] > 0) { pixels.SetPixel(x, y, new byte[] { 255, 255, 255, 255 }); } } Console.WriteLine(); } outputImage.Write(outputImagePath); } // Get the largest repeated patterns with lowest frequency (level) }