В этом учебном семестре у меня появился довольно интересный предмет «Методы распознавания образов».
Существуют такие предметы или явления, для которых характерно такое свойство, что ознакомившись с конечным представителем этих предметов или явлений люди оказываются способными узнавать сколь угодно большое число других представителей этих предметов или явлений. Предметы и явления — образы, а их отдельные представители — объекты. Воспринимая окружаюший мир, мы всегда проводим классификацию явлений, т.е. разбиваем все явления на группы похожих. Для принятия решения необходимо выполнить распознавание, т.е. отнести незнакомый объект (ситуацию) к классу (образу, группе) ранее известных и классифицированных.
Моим первым практическое задание, заключалось в написании программы, которая могла бы распознать буквы Y, R, N. Для этого нужно немножко окунуться в теорию. Распознавание выполняется попиксельно. Каждый пискель имеет 8 соседей.
Тип пикселя определяется из количества и вида его соедей, т.е. с точки зрения связности. Для определения типа пикселя введены понятия связности и характеристичесие числа
- количество единичных элементов по 4-х свзяности A4(аij) = ∑ а2k-1, k=1..4
- количество единичных элементов по 8-ми свзяности A8(аij) = ∑ аk, k=1..8
- количество единичных двоек B8(аij) = ∑ аk *аk+1, k=1..8
- количество единичных двоек в окреснтности пикселя Cn(аij) = A8(аij) -B8(аij)
Изолированный пиксель имеет А8=0, конечный писксель A8=1,
Cn=0 – изолированный пиксель, Сn=1 – конечный пиксель, Сn=2 – связующий пиксель, Сn≥3 – пиксель ветвления.
Помимо этого, мне нужно было осуществить возможность подгружать изображения, и выводить схему буквы. На данный момент программа распознаёт три буквы (Y, R, N), нарисованные однопиксельной кистью.
Приведу несколько строк из кода:
public int pixel_value(int X, int Y) { Color clr; byte val; clr = (pictureBox1.Image as Bitmap).GetPixel(X, Y); if ((clr.R.Equals(0)) && (clr.G.Equals(0)) && (clr.B.Equals(0))) val = 1; else val = 0; return val; }
static void Highlight(RichTextBox box, string phrase, Color color) { int pos = box.SelectionStart; string s = box.Text; for (int ix = 0; ; ) { int jx = s.IndexOf(phrase, ix, StringComparison.CurrentCultureIgnoreCase); if (jx < 0) break; box.SelectionStart = jx; box.SelectionLength = phrase.Length; box.SelectionColor = color; ix = jx + 1; } box.SelectionStart = pos; box.SelectionLength = 0; }
private void button1_Click(object sender, EventArgs e) { int pX, pY, A4 = 0, A8 = 0, B8 = 0, C8 = 0, NC4 = 0, CN = 0, pxKon = 0, pxNor = 0, pxVet = 0; Color clr; for (pY = 0; pY < pictureBox1.Height; pY++) { for (pX = 0; pX < pictureBox1.Width; pX++) { pictureBox1.Refresh(); clr = (pictureBox1.Image as Bitmap).GetPixel(pX, pY); if ((clr.R.Equals(0)) && (clr.G.Equals(0)) && (clr.B.Equals(0))) { A4 = 0; A8 = 0; A4 = pixel_value(pX - 1, pY) + pixel_value(pX + 1, pY) + pixel_value(pX, pY - 1) + pixel_value(pX, pY + 1); A8 = A4 + pixel_value(pX + 1, pY - 1) + pixel_value(pX - 1, pY - 1) + pixel_value(pX - 1, pY + 1) + pixel_value(pX + 1, pY + 1); B8 = pixel_value(pX + 1, pY) * pixel_value(pX + 1, pY - 1) + pixel_value(pX + 1, pY - 1) * pixel_value(pX, pY - 1) + pixel_value(pX, pY - 1) * pixel_value(pX - 1, pY - 1) + pixel_value(pX - 1, pY - 1) * pixel_value(pX - 1, pY) + pixel_value(pX - 1, pY) * pixel_value(pX - 1, pY - 1) + pixel_value(pX - 1, pY + 1) * pixel_value(pX, pY + 1) + pixel_value(pX, pY + 1) * pixel_value(pX + 1, pY + 1) + pixel_value(pX + 1, pY + 1) * pixel_value(pX + 1, pY); C8 = pixel_value(pX + 1, pY) * pixel_value(pX + 1, pY - 1) * pixel_value(pX, pY - 1) + pixel_value(pX, pY - 1) * pixel_value(pX - 1, pY - 1) * pixel_value(pX - 1, pY) + pixel_value(pX - 1, pY) * pixel_value(pX - 1, pY + 1) * pixel_value(pX, pY + 1) + pixel_value(pX, pY + 1) * pixel_value(pX + 1, pY + 1) * pixel_value(pX + 1, pY); NC4 = A4 - C8; CN = A8 - B8; if (A8 == 1) pxKon++; if (A8 == 2) pxNor++; if (A8 > 2) pxVet++; pCount++; } if (pixel_value(pX, pY) == 1) richTextBox1.Text += A8; else richTextBox1.Text += "_"; progressBar1.Value += 1; } richTextBox1.Text += "\n"; } if (/*(pxVet == 1) && */(pxKon == 3)) MessageBox.Show("Y", "Ваша буква", MessageBoxButtons.OK, MessageBoxIcon.Information); if ((pxVet > 4) && (pxKon == 2)) MessageBox.Show("R", "Ваша буква", MessageBoxButtons.OK, MessageBoxIcon.Information); if ((pxVet > 1) && (pxVet < 5) && (pxKon == 2)) MessageBox.Show("N", "Ваша буква", MessageBoxButtons.OK, MessageBoxIcon.Information); Highlight(richTextBox1, "_", Color.LightGray); Highlight(richTextBox1, "1", Color.White); Highlight(richTextBox1, "1", Color.Green); Highlight(richTextBox1, "2", Color.Orange); Highlight(richTextBox1, "3", Color.OrangeRed); Highlight(richTextBox1, "4", Color.Firebrick); richTextBox1.Visible = true; label3.Text = "Количество чёрных пикселей: " + pCount; pCount = 0; progressBar1.Value = 0; }
Ну, а вот и собственно исходник программы. Ах да, при запуске программы выскакивает окно, для выбора изображения из файла (3 файла изображения также в архиве с исходником), если хотите нарисовать букву самостоятельно, жмите отмена.
Надеюсь пригодилось?
Если вдруг Вы решили затеять ремонт, то Вам определённо стоит обратить внимание на металлопластиковые окна.
Вообще вещь!
Спасибо. Пример очень кстати пришёлся)
Мне бы не букв а целых слов… А так очень круто… Можешь сделать на целые слова…
Для целых слов — немного другой алгоритм, который потребует больших временных затрат. Это такой хороший курсовой проект получится. С радостью бы поделился, но тема моего проекта — распознавание рукописной подписи.