Смекни!
smekni.com

Распознавание графических символов (стр. 3 из 4)

{

r.Teach(Recognizer.NormalizeBitmap(word,imSize), 0);

r.Teach(Recognizer.InverseBitmap(Recognizer.NormalizeBitmap(word,imSize)), 1);

}

}

ButtonsEnabled(FormState.Teached);

}

private voidbuttonSaveTeaching_Click(object sender, EventArgs e)

{

r.SerializeParams();

ButtonsEnabled(FormState.Serialized);

}

private voidbuttonLoadTeaching_Click(object sender, EventArgs e)

{

r.DeserializeParams();

ButtonsEnabled(FormState.Deserialized);

}

private void FormMain_Load(object sender,EventArgs e)

{

this.ButtonsEnabled(FormState.Empty);

}

}

// <summary>

/// Состояния изображения

/// </summary>

enum FormState

{

/// <summary>

/// изображение не открыто

/// </summary>

Empty,

/// <summary>

/// Изображение открыто

/// </summary>

Open,

/// <summary>

/// Сегментировано

/// </summary>

Segmented,

/// <summary>

/// Персептрон обучен

/// </summary>

Teached,

/// <summary>

/// Параметры персептрона сохранены

/// </summary>

Serialized,

/// <summary>

/// Параметры персептрона загружены

/// </summary>

Deserialized,

/// <summary>

/// Распознано

/// </summary>

Recognized

}

}

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Drawing;

using System.Windows.Forms;

using System.IO;

usingSystem.Runtime.Serialization.Formatters.Binary;

namespace WordSearcher

{

/// <summary>

/// Реализует распозноание изображений

/// на базе персептрона

/// </summary>

class Recognizer

{

/// <summary>

/// матрица знаков входов персептрона

/// </summary>

private int[,] xa;

/// <summary>

/// Массив лямд

/// </summary>

private int[,] l;

/// <summary>

/// Массив имен классов

/// </summary>

private string[] classes = {"Указ",

"Не указ"};

/// <summary>

/// Массив имен классов

/// </summary>

public string[] ClassesList

{

get { return classes; }

}

/// <summary>

/// Инициализирует xa-матрицу

/// </summary>

/// <param name="sz">размеризображения</param>

/// <param name="aCount">количесвтоа-элементов</param>

/// <param name="lCount">количесвтоклассов</param>

public Recognizer(Size sz, int aCount, intlCount)

{

Random r = new Random();

//Создание матрцы ха

xa = new int[sz.Height * sz.Width, aCount];

//Создание матрицы лямд

l = new int[lCount,aCount];

//Первоначальная

//иницализация лямд еденицами

for (int i = 0; i < l.GetLength(0); i++)

{

for (int j = 0; j < l.GetLength(1); j++)

{

l[i, j] = 1;

}

}

//заполнение матрицы

//для каждого рецептора(строчки)

//назначаетя только один а-элемент(столбец) со знаком+ или -

for (int i = 0; i < xa.GetLength(0);i++)

{

xa[i, r.Next(aCount)] = (int)Math.Pow(-1,r.Next(1, 3));

}

}

/// <summary>

/// Обучение персептрона

/// </summary>

/// <param name="b">битмап для обучения</param>

/// <param name="classindex">имякласса к ккоторому относиться изображение</param>

public void Teach(Bitmap b, int classindex)

{

int[] x = new int[b.Height * b.Width];

int k = 0;

//Инициализация входных рецепторов

for (int i = 0; i < b.Width; i++)

{

for (int j = 0; j < b.Height; j++)

{

if (b.GetPixel(i, j) == Color.FromArgb(0,0, 0))

x[k] = 1;

k++;

}

}

//Вектор сумм рецепторов

int[] sumx = new int[xa.GetLength(1)];

//Вектор выходов А-элементов

int[] outa = new int[xa.GetLength(1)];

//суммирование сигналов от рецепторов

for (int i = 0; i < xa.GetLength(1); i++)

{

for (int j = 0; j < xa.GetLength(0);j++)

{

sumx[i] += x[j] * xa[j, i];

}

//Если сумма больше нуля выход а элемента 1

if (sumx[i] > 0)

outa[i] = 1;

}

//изменение коэфициетов лямда

for (int i = 0; i < outa.Length; i++)

{

//Если а-элемент возбужден то изменяем лямды

if (outa[i] == 1)

{

//перебор всех классов

for (int j = 0; j < l.GetLength(0); j++)

{

//Увеличение на 1 лямд для класса который обучается

//и уменьшение для всех осатльных

if (classindex == j)

l[j, i]++;

else

l[j, i]--;

}

}

}

}

/// <summary>

/// Распознавание изобржения

/// </summary>

/// <param name="b">битмап изображения</param>

/// <returns>имя класса к которому отнесеноизображение</returns>

public string Recognize(Bitmap b)

{

int[] x = new int[b.Height * b.Width];

int k = 0;

//Инициализация входных рецепторов

for (int i = 0; i < b.Width; i++)

{

for (int j = 0; j < b.Height; j++)

{

if (b.GetPixel(i, j) == Color.FromArgb(0,0, 0))

x[k] = 1;

k++;

}

}

//Вектор суммрецепторов

int[] sumx = new int[xa.GetLength(1)];

//Вектор выходов А-элементов

int[] outa = new int[xa.GetLength(1)];

//суммирование сигналов от рецепторов

for (int i = 0; i < xa.GetLength(1); i++)

{

for (int j = 0; j < xa.GetLength(0);j++)

{

sumx[i] += x[j] * xa[j, i];

}

//Если сумма больше нуля выход а элемента 1

if (sumx[i] > 0)

outa[i] = 1;

}

//Создание масива значений сумматоров

//каждый для отдельного класса

int[] sum = new int[l.GetLength(0)];

//Нахождение значений сумматоров для каждого класса

for (int i = 0; i < sum.Length; i++)

{

for (int j = 0; j < xa.GetLength(1);j++)

{

sum[i] += outa[j] * l[i, j];

}

}

//нахождение максимального значения сумматор

//именно оно соответствует распознанному классу

int max = sum[0];

int maxindex = 0;

for (int i = 1; i < sum.Length; i++)

{

if (max < sum[i])

{

max = sum[i];

maxindex = i;

}

}

//Возвращается имя класса с максимальным значениемсумматора

return classes[maxindex];

}

/// <summary>

/// Сериализация массива лямд(сохранение в файл) длясохранения обученяи персептрона

/// </summary>

public void SerializeParams()

{

try

{

BinaryFormatter bf = new BinaryFormatter();

FileStream fs = newFileStream("l.dat", FileMode.Create);

bf.Serialize(fs, l);

fs.Close();

bf = new BinaryFormatter();

fs = new FileStream("xa.dat",FileMode.Create);

bf.Serialize(fs, xa);

fs.Close();

}

catch (Exception ex)

{

MessageBox.Show(ex.Message);

}

}

/// <summary>

/// Десериализация массива лямд(чтение из файла)

/// </summary>

public void DeserializeParams()

{

try

{

BinaryFormatter bf = new BinaryFormatter();

FileStream fs = newFileStream("l.dat", FileMode.Open);

l = (int[,])bf.Deserialize(fs);

fs.Close();

bf = new BinaryFormatter();

fs = new FileStream("xa.dat",FileMode.Open);

xa = (int[,])bf.Deserialize(fs);

fs.Close();

}

catch (Exception ex)

{

MessageBox.Show(ex.Message);

}

}

/// <summary>

/// Подгонка битмапа по размеру и его бинаризация

/// </summary>

/// <param name="b">входной битмап</param>

/// <param name="sz">новый размер битмапа</param>

/// <returns>нормализованный битмап</returns>

public static Bitmap NormalizeBitmap(Bitmapb, Size sz)

{

//Подгонка размера

Bitmap inImg = new Bitmap(b, sz);

//Создание выходного битмапа на основе подогнанного

Bitmap outImg = new Bitmap(inImg);

//находим среднее значение яркости

int sum = 0;

for (int i = 0; i < outImg.Width; i++)

{

for (int j = 0; j < outImg.Height; j++)

{

Color cl = ((Bitmap)inImg).GetPixel(i,j);

sum += (cl.R + cl.G + cl.B) / 3;

}

}

int sredn = sum / (inImg.Width *inImg.Height);

//Просматриваем изображнеи и бинаризуем его

for (int i = 0; i < outImg.Width; i++)

{

for (int j = 0; j < outImg.Height; j++)

{

Color cl = ((Bitmap)inImg).GetPixel(i,j);

int gray = (cl.R + cl.G + cl.B) / 3;

if (gray > sredn)

outImg.SetPixel(i, j, Color.FromArgb(255,255, 255));

else

outImg.SetPixel(i, j, Color.FromArgb(0, 0,0));

}

}

return outImg;

}

/// <summary>

/// Инверсия цвета битмапа

/// </summary>

/// <paramname="b"></param>

/// <returns></returns>

public static Bitmap InverseBitmap(Bitmapb)

{

Bitmap outImg = new Bitmap(b.Width,b.Height);

for (int i = 0; i < b.Width; i++)

{

for (int j = 0; j < b.Height; j++)

{

Color c = b.GetPixel(i,j);

outImg.SetPixel(i, j, Color.FromArgb(255 -c.R, 255 - c.G, 255 - c.B));

}

}

return outImg;

}

}

}

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Drawing;

namespace WordSearcher

{

class Segmentation

{

/// <summary>

/// Разбиение битмапа с текстоми на строки

/// </summary>

/// <param name="b">исходный битмап</param>

/// <returns>коллекция строк</returns>

public static List<Bitmap>GetStrings(Bitmap text)

{

List<Bitmap> strs = newList<Bitmap>();

List<int> whiteLineIndexes = newList<int>();

//Находим все белые горзонатльные линии на ихображении

//и запоминаем их индексы

for (int j = 0; j < text.Height; j++)

{

bool whiteLineFound = true;

for (int i = 0; i < text.Width; i++)

{

if (text.GetPixel(i, j) !=Color.FromArgb(255, 255, 255))

{

whiteLineFound = false;

break;

}

}

if (whiteLineFound)

whiteLineIndexes.Add(j);

}

//Выделение строк между белыми несоседними линиями

for (int i = 0; i <whiteLineIndexes.Count-1; i++)

{

if (whiteLineIndexes[i + 1] -whiteLineIndexes[i] > 4)

{

strs.Add(text.Clone(

new Rectangle(

0,

whiteLineIndexes[i],

text.Width,

whiteLineIndexes[i + 1] -whiteLineIndexes[i]+1),

System.Drawing.Imaging.PixelFormat.Format24bppRgb));

}

}

return strs;

}

/// <summary>

/// Получить список слов отдельной строки

/// </summary>

/// <param name="str">битмап сострокой текста</param>

/// <returns>спсиок слов строки</returns>

public static List<Bitmap>GetStringWords(Bitmap str)

{

List<Bitmap> words = newList<Bitmap>();

List<int> whiteLineIndexes = newList<int>();

//Находим все белые вертикальные линии на изображении

//и запоминаем их индексы

for (int i = 0; i < str.Width; i++)

{

bool whiteLineFound = true;

for (int j = 0; j < str.Height; j++)

{

if (str.GetPixel(i, j).R < 100)

{

whiteLineFound = false;

break;

}

}

if (whiteLineFound)

whiteLineIndexes.Add(i);

}

//Ширина пробела

int spaceWidth = 0;

int sum = 0;

int n = 0;

//Вычисление ширины пробела

for (int i = 0; i <whiteLineIndexes.Count - 1; i++)

{

int d = whiteLineIndexes[i + 1] -whiteLineIndexes[i];

if (d > 1)

{

sum += d;

n++;

}

}

//Ширина пробела необходимо при дальнейшем выделениислов

//коэф. подобран вручную

spaceWidth = (int)Math.Round(sum * 0.45 / n+ 0.1);

//начальная координата слова

int wordBegin = 0;

//конечная координат слова

int wordEnd = 0;

//флаг указывающий на то найденно ли начало слова или нет

//перволдится обратно в фолс после нахождения концаслова

bool wordFound = false;

//Счетчик ширины белой полоски

int whiteWidth = 0;

//Выделение слов

for (int i = 0; i <whiteLineIndexes.Count - 1; i++)

{

//если линии не соседние и флаг wordFound фолс т.е.

//слово еще не найдено

//запоминаем координату певрой линии это будет

//координатой началом слова

if ((whiteLineIndexes[i + 1] -whiteLineIndexes[i] > 1) &&

!wordFound)

{

//обнуление счетчика идущих подряд белыхз линий

whiteWidth = 0;

//флаг найденного слова в тру

wordFound = true;

//инициализируем начальную координату слова

wordBegin = whiteLineIndexes[i];

}

//инициализируем конечную координату слова

//если найдены не сосдение линии

//но не обрезаем битмап и не добавлям его в коллекцию

//т.к. необходисмо зделать проверку на ширину пробела

if ((whiteLineIndexes[i + 1] -whiteLineIndexes[i] > 1) &&

wordFound)

{

whiteWidth = 0;

wordEnd = whiteLineIndexes[i + 1];

}

//Если найденны соседние белые линии

//инкремируем счетчик белых линий и сравниваем ширинуидущих подрд белых линий

//с ранее высчитаной средней шириной пробела

if (whiteLineIndexes[i + 1] -whiteLineIndexes[i] == 1)

{

whiteWidth++;

if ((whiteWidth >= spaceWidth)&&

(wordEnd - wordBegin > 1))

{

//Обрезаем и добавляем слово в коллекцию

words.Add(TrimBitmap(

str.Clone(

new Rectangle(

wordBegin,

0,