//МЕТОДЫ, ИСПОЛЬЗУЕМЫЕ ДЛЯ СОЗДАНИЯ ЭТАЛОНОВ //---------------------------------------------------------------- //получить txt файлы для картинок с конкретными символами в папке private void CreateEtalonMatrix(object sender, EventArgs e) { //настроика диалога FolderBrowserDialog folderBrowserDialog = new FolderBrowserDialog(); DialogResult result = folderBrowserDialog.ShowDialog(); if (result == DialogResult.OK && !string.IsNullOrWhiteSpace(folderBrowserDialog.SelectedPath)) { string[] files = Directory.GetFiles(folderBrowserDialog.SelectedPath); foreach (string file in files) { //считываем изображение из файла System.Drawing.Bitmap image = new Bitmap(file); //произведем бинаризацию изображения BinarizedImage binarizedImage = new BinarizedImage(image); //матрица эталонная для символа byte[,] etalonArray = MyTextRecognizer.CreateMatrix_16X16(binarizedImage); string fileName = Path.GetFileName(file); fileName = fileName.Replace(".png", ""); MyArraySerializer.SerializeArray(etalonArray, new StreamWriter(txtPath + fileName + ".txt")); } } }
private static Tuple <int, int> GetDividersY(BinarizedImage binarizedImage, Tuple <int, int> xBoundaries) { byte[,] imageArray = binarizedImage.GetArray(); int yStart = binarizedImage.GetHeight(), yEnd = -1; for (int i = xBoundaries.Item1; i <= xBoundaries.Item2; ++i) { for (int j = 0; j < binarizedImage.GetHeight(); ++j) { if (imageArray[i, j] == 1) { if (yStart > j) { yStart = j; } if (yEnd < j) { yEnd = j; } } } } return(new Tuple <int, int>(yStart - 1, yEnd + 1)); //return new Tuple<int, int>(0, ImageBitmap.Height - 1); }
//выбрать из проводника изображение для распознавания private void chooseImageFromExplorer(object sender, EventArgs e) { //настроика диалога openFileDialog.InitialDirectory = "c:\\"; openFileDialog.Filter = "png files (*.png)|*.png|All files (*.*)|*.*"; openFileDialog.FilterIndex = 2; openFileDialog.RestoreDirectory = true; if (openFileDialog.ShowDialog() == DialogResult.OK) { //путь к файлу String filePath = openFileDialog.FileName; //считываем изображение из файла System.Drawing.Bitmap image = new Bitmap(filePath); //очистим полотно //canvas.Clear(Color.FromArgb(110, 110, 110)); //отрисуем картинку на полотне //canvas.DrawImage(image, new PointF(20, 20)); //бинаризация изображения BinarizedImage binarizedImage = new BinarizedImage(image); //отрисуем бинаризованную картинку на полотне //canvas.DrawImage(binarizedImageBitmap, new PointF(20, binarizedImageBitmap.Size.Height+40)); //imageSaver.Save(binarizedImage.GetBitmap(), "binarizedImage.png"); //моздаем объект - распознаватель MyTextRecognizer recognizer = new MyTextRecognizer(); //разделение изображения на отдельные символы List <Symbol> symbols = MyTextRecognizer.GetSymbols(binarizedImage); //результат распознавания recognitionResultTextbox.Text = ""; int count = 0; foreach (Symbol symbol in symbols) { symbol.Print(); Console.WriteLine(); recognizer.RecognizeSymbol(symbol); recognitionResultTextbox.Text = recognizer.; count += 1; } // //recognitionResultTextbox.Text = MyTextRecognizer.RecognizeSymbol(MyTextRecognizer.CreateMatrix_16X16(binarizedImage)); } }
public BinarizedImage(BinarizedImage image, int xLeft, int xRight, int yTop, int yBottom) { N = xRight - xLeft + 1; M = yBottom - yTop + 1; Console.WriteLine("Создается биткарта размерами " + N + " x " + M); binarizedImageArray = new byte[N, M]; for (int i = xLeft; i <= xRight; i++) { for (int j = yTop; j <= yBottom; j++) { binarizedImageArray[i - xLeft, j - yTop] = image.GetArray()[i, j]; } } }
//устарело //----------------------------------------------- //получит список всех символов на изображении private static List <int> GetDividersX(BinarizedImage binarizedImage) { List <int> resultDivivderIndexes = new List <int>(); byte[,] imageArray = binarizedImage.GetArray(); int N = binarizedImage.GetWidth(); int M = binarizedImage.GetHeight(); //первый разделитель в промежтуке bool previousOnlyWhite = false; for (int i = 0; i < N; ++i) { bool currentOnlyWhite = true; for (int j = 0; j < M; ++j) { currentOnlyWhite &= imageArray[i, j] == 0; } //переход с белого на чёрный if (currentOnlyWhite == false) { /*if (i == 0 || i == N - 1) { * resultDivivderIndexes.Add(i); * }*/ if (previousOnlyWhite == true) { resultDivivderIndexes.Add(i - 1); } } //переход с чёрного на белый else { //если первый столбец пикселей белый, значит мы не нашли изображение... пропускаем этот столбец if (previousOnlyWhite == false && i != 0) { resultDivivderIndexes.Add(i); } } previousOnlyWhite = currentOnlyWhite; } return(resultDivivderIndexes); }
//----------------------------------------------- //получить список символов на картинке public static List <Symbol> GetSymbols(BinarizedImage binarizedImage) { List <Symbol> symbols = new List <Symbol>(); List <Rectangle> symbolsBoundaries = GetSymbolsBoundaries(binarizedImage); foreach (Rectangle rect in symbolsBoundaries) { //Console.WriteLine("DividerX: "+dividerX.Item1+", "+dividerX.Item2); //Console.WriteLine("DividerY: " + dividerY.Item1 + ", " + dividerY.Item2); BinarizedImage image = new BinarizedImage(binarizedImage, rect.Left, rect.Right - 1, rect.Top, rect.Bottom); Symbol symbol = new Symbol(rect.Left, rect.Top, rect.Width, rect.Height, CreateMatrix_16X16(image)); symbols.Add(symbol); } return(symbols); }
//получить границы символов на изображении с множеством символов private static List <Rectangle> GetSymbolsBoundaries(BinarizedImage binarizedImage) { List <Rectangle> symbolsBoundaries = new List <Rectangle>(); byte[,] imageArray = binarizedImage.GetArray(); int N = binarizedImage.GetWidth(); int M = binarizedImage.GetHeight(); //первый разделитель в промежтуке bool previousOnlyWhite = false; int Left = -1, Right = -1, Top = -1, Bottom = -1, Counter = 0; for (int i = 0; i < N; ++i) { bool currentOnlyWhite = true; for (int j = 0; j < M; ++j) { currentOnlyWhite &= imageArray[i, j] == 0; } //переход с белого на чёрный if (currentOnlyWhite == false) { /*if (i == 0 || i == N - 1) { * resultDivivderIndexes.Add(i); * }*/ if (previousOnlyWhite == true) { Counter += 1; Left = i - 1; } } //переход с чёрного на белый else { //если первый столбец пикселей белый, значит мы не нашли изображение... пропускаем этот столбец if (previousOnlyWhite == false && i != 0) { Counter += 1; Right = i; } } previousOnlyWhite = currentOnlyWhite; if (Counter == 2) { Top = binarizedImage.GetHeight(); Bottom = -1; for (int k = Left; k <= Right; ++k) { for (int l = 0; l < binarizedImage.GetHeight(); ++l) { if (imageArray[k, l] == 1) { if (Top > l) { Top = l; } if (Bottom < l) { Bottom = l; } } } } Counter = 0; Console.WriteLine("l: " + Left + ", \tr: " + Right + ", \tt: " + Top + ", \tb: " + Bottom); symbolsBoundaries.Add(new Rectangle(Left, Top - 1, Right - Left + 1, Bottom - Top + 2)); } } return(symbolsBoundaries); }
//создать матрицу 16*16 для картинки с конкретным символом public static byte[,] CreateMatrix_16X16(BinarizedImage binarizedImage) { int N = binarizedImage.GetWidth(); int M = binarizedImage.GetHeight(); byte[,] binarizedImageArray = binarizedImage.GetArray(); //========================================================== //НАХОЖДЕНИЕ ГРАНИЦ СИМВОЛА //---------------------------------------------------------- //поиск верхней границы символа int yTop = -1; //цикл по вертикали(y) for (int j = 0; j < M; j++) { //цикл по горизонтали(x) for (int i = 0; i < N; i++) { //встретился черный пиксель - верхняя граница найдена if (binarizedImageArray[i, j] == 1) { yTop = j; break; } } if (yTop == j) { break; } } //---------------------------------------------------------- //---------------------------------------------------------- //поиск нижней границы символа int yBottom = -1; //цикл по вертикали(y) for (int j = M - 1; j >= 0; j--) { //цикл по горизонтали(x) for (int i = 0; i < N; i++) { //встретился черный пиксель - нижняя граница найдена if (binarizedImageArray[i, j] == 1) { yBottom = j + 1; break; } } if (yBottom == j + 1) { break; } } //---------------------------------------------------------- //---------------------------------------------------------- //поиск левой границы символа int xLeft = -1; //цикл по горизонтали(x) for (int i = 0; i < N; i++) { //цикл по вертикали(y) for (int j = 0; j < M; j++) { //встретился черный пиксель - левая граница найдена if (binarizedImageArray[i, j] == 1) { xLeft = i; break; } } if (xLeft == i) { break; } } //---------------------------------------------------------- //---------------------------------------------------------- //поиск правой границы символа int xRight = -1; //цикл по горизонтали(x) for (int i = N - 1; i >= 0; i--) { //цикл по вертикали(y) for (int j = 0; j < M; j++) { //встретился черный пиксель - правая граница найдена if (binarizedImageArray[i, j] == 1) { xRight = i + 1; break; } } if (xRight == i + 1) { break; } } //---------------------------------------------------------- //========================================================== //границы символа не найденв => ничего не нарисовано if (((yBottom - yTop) * (xRight - xLeft)) == 0) { Console.WriteLine("EtalonCreator: image has no symbol to bound it"); return(null); } //========================================================== // получаем процент заполнения как отношение кол-ва значимых пикселей к общему // кол-ву пикселей в границах образа // Percent будет необходим при анализе каждой ячейки в разбитом на 16х16 образе //количество черных пикселей на изображении int nSymbol = 0; for (int j = yTop; j <= yBottom; j++) { for (int i = xLeft; i <= xRight; i++) { if (binarizedImageArray[i, j] == 1) { nSymbol += 1; } } } double percent = (double)nSymbol / ((yBottom - yTop) * (xRight - xLeft)); // коэф-т влияет на формирование матрицы 16х16 // > 1 - учитывается меньше значимых пикселей // < 1 - учитывается больше значимых пикселей percent *= 0.99; //========================================================== //========================================================== // разбиваем прямоугольник образа на 16 равных частей путем деления сторон на 2 // и получаем относительные координаты каждой ячейки //ширина прямоугольника вокруг изображения int symbolWidth = xRight - xLeft; int[,] XY = new int[17, 2]; XY[0, 0] = 0; XY[16, 0] = symbolWidth; XY[8, 0] = XY[16, 0] / 2; XY[4, 0] = XY[8, 0] / 2; XY[2, 0] = XY[4, 0] / 2; XY[1, 0] = XY[2, 0] / 2; XY[3, 0] = (XY[4, 0] + XY[2, 0]) / 2; XY[6, 0] = (XY[8, 0] + XY[4, 0]) / 2; XY[5, 0] = (XY[6, 0] + XY[4, 0]) / 2; XY[7, 0] = (XY[8, 0] + XY[6, 0]) / 2; XY[12, 0] = (XY[16, 0] + XY[8, 0]) / 2; XY[10, 0] = (XY[12, 0] + XY[8, 0]) / 2; XY[14, 0] = (XY[16, 0] + XY[12, 0]) / 2; XY[9, 0] = (XY[10, 0] + XY[8, 0]) / 2; XY[11, 0] = (XY[12, 0] + XY[10, 0]) / 2; XY[13, 0] = (XY[14, 0] + XY[12, 0]) / 2; XY[15, 0] = (XY[16, 0] + XY[14, 0]) / 2; //высота образа int symbolHeight = yBottom - yTop; XY[0, 1] = 0; XY[16, 1] = symbolHeight; XY[8, 1] = XY[16, 1] / 2; XY[4, 1] = XY[8, 1] / 2; XY[2, 1] = XY[4, 1] / 2; XY[1, 1] = XY[2, 1] / 2; XY[3, 1] = (XY[4, 1] + XY[2, 1]) / 2; XY[6, 1] = (XY[8, 1] + XY[4, 1]) / 2; XY[5, 1] = (XY[6, 1] + XY[4, 1]) / 2; XY[7, 1] = (XY[8, 1] + XY[6, 1]) / 2; XY[12, 1] = (XY[16, 1] + XY[8, 1]) / 2; XY[10, 1] = (XY[12, 1] + XY[8, 1]) / 2; XY[14, 1] = (XY[16, 1] + XY[12, 1]) / 2; XY[9, 1] = (XY[10, 1] + XY[8, 1]) / 2; XY[11, 1] = (XY[12, 1] + XY[10, 1]) / 2; XY[13, 1] = (XY[14, 1] + XY[12, 1]) / 2; XY[15, 1] = (XY[16, 1] + XY[14, 1]) / 2; //========================================================== //========================================================== // анализируем каждую полученную ячейку в разбитом прямоугольнике образа // и создаем приведенную матрицу 16x16 // результат - приведенная матрица 16х16 byte[,] result = new byte[16, 16]; // пробегаемся по ячейкам уже // в абсолютных координатах // считаем кол-во значимых пикселей (=0 -> черный цвет) for (int kj = 0; kj < 16; kj++) { for (int ki = 0; ki < 16; ki++) { nSymbol = 0; for (int j = yTop + XY[kj, 1]; j <= yTop + XY[kj + 1, 1]; j++) { for (int i = xLeft + XY[ki, 0]; i <= xLeft + XY[ki + 1, 0]; i++) { if (binarizedImageArray[i, j] == 1) { nSymbol += 1; } } } // если отношение кол-ва знач. пикселей к общему кол-ву в ящейке > характерного процента заполнения то = 1 иначе = 0 if (nSymbol / Math.Max(1, ((XY[ki + 1, 0] - XY[ki, 0]) * (XY[kj + 1, 1] - XY[kj, 1]))) > percent) { result[kj, ki] = 1; } else { result[kj, ki] = 0; } } } //========================================================== return(result); }