апреля
24
2011

В этом учебном семестре у меня появился довольно интересный предмет «Методы распознавания образов».

Существуют такие предметы или явления, для которых характерно такое свойство, что ознакомившись с конечным представителем этих предметов или явлений люди оказываются способными узнавать сколь угодно большое число других представителей этих предметов или явлений. Предметы и явления — образы, а их отдельные представители — объекты. Воспринимая окружаюший мир, мы всегда проводим классификацию явлений, т.е. разбиваем все явления на группы похожих. Для принятия решения необходимо выполнить распознавание, т.е. отнести незнакомый объект (ситуацию) к классу (образу, группе) ранее известных и классифицированных.

Моим первым практическое задание, заключалось в написании программы, которая могла бы распознать буквы Y, R, N. Для этого нужно немножко окунуться в теорию. Распознавание выполняется попиксельно. Каждый пискель имеет 8 соседей.

Тип пикселя определяется из количества и вида его соедей, т.е. с точки зрения связности. Для определения типа пикселя введены понятия связности и характеристичесие числа

  • количество единичных элементов по 4-х свзяности A4(аij) = ∑ а2k-1, k=1..4
  • количество единичных элементов по 8-ми свзяности A8(аij) = ∑ аk, k=1..8
  • количество единичных двоек  B8(аij) = ∑ аkk+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 файла изображения также в архиве с исходником), если хотите нарисовать букву самостоятельно, жмите отмена.

Надеюсь пригодилось?

Если вдруг Вы решили затеять ремонт, то Вам определённо стоит обратить внимание на металлопластиковые окна.

Не пропустите, это тоже интересно!

К этой записи 3 комментария

  • burito пишет:

    Вообще вещь!
    Спасибо. Пример очень кстати пришёлся)

  • Alex пишет:

    Мне бы не букв а целых слов… А так очень круто… Можешь сделать на целые слова…

    • Stafox пишет:

      Для целых слов — немного другой алгоритм, который потребует больших временных затрат. Это такой хороший курсовой проект получится. С радостью бы поделился, но тема моего проекта — распознавание рукописной подписи.

Добавить комментарий для Alex