Білоруський Державний Університет Інформатики і радіоелектроніки. P>
Контрольна робота з дисципліни p>
«БАГІ» p>
«Програма розпізнавання символів» p>
Виконав студент групи 500501 p>
Балахонов Е.В. p>
Завдання. p>
Потрібно написати програму, здатну розпізнавати графічнопредставлені символи у вигляді растрового зображення і перетворювати взвичайний текст. p>
- платформа: Win32, p>
- формат графічного зображення: Windows Bitmap (BMP), 8 біт, p>
- шрифт для розпізнавання: Arial, 16 p>
Вибір засобів розробки. p>
Як середовище розробки буде використовуватися Borland C + + Builder
5. P>
Розпізнавання символів. P>
Етап 1. Виділення контуру об'єкта, визначення його меж. P>
Як алгоритму виділення контурів будемо використовувати алгоритмжука. p>
Загальний опис алгоритму. p>
відстежують алгоритми грунтуються на тому, що на зображеннівідшукується об'єкт (перший зустрілася точка об'єкта) і контур об'єктавідстежується і векторізуется. Перевагою даних алгоритмів є їхпростота, до недоліків можна віднести їх послідовну реалізацію тадеяку складність в процесі пошуку та обробки внутрішніх контурів. Прикладвідслідковує алгоритму - "алгоритму жука" - наведено на рис. 5.12. Жукпочинає рух з білою області у напрямку до чорної, Як тільки вінпотрапляє на чорний елемент, він повертає ліворуч і переходить до наступногоелементу. Якщо цей елемент білий, то жук повертається направо, інакше --наліво. Процедура повторюється до тих пір, поки жук не повернеться у вихіднукрапку. Координати точок переходу з чорного на біле і з білого на чорне іописують кордон об'єкта. p>
На рис. 1 показана схема роботи такого алгоритму.
p>
Рис. 1. Схема роботи відслідковує алгоритму «жука». P>
Етап 2. Побудова на основі контуру об'єкта скелетної лінії. P>
При знаходженні нової точки контуру, розраховується відстань міжпопередньої знайденої точкою і нової. Якщо воно перевищує деяку кордон
(за замовчуванням в 5 одиниць), вона запам'ятовується. До кінця побудови скелетноїлінії програма має масив координат вершин ламаної, яка єскелетної лінією об'єкта. p>
Етап 3. Порівняння отриманої скелетної лінії з списком шаблонів. P>
Після побудови скелетної лінії проводиться порівняння її з спискомшаблонів відомих символів. При знаходженні збіги, програмазаписує в рядок знайдений символ. p>
Оригінальний текст програми. p>
//------------------------------------------------ --------------------------< br>- p>
# include
# pragma hdrstop p>
# include
# include p>
# include "ChildFormUnit.h"
# include "MainFormUnit.h"
# include "AverageFilterDialogFormUnit.h"
# include "OSRFormUnit.h" p>
//---------------------------------- ----------------------------------------< br>-
# pragma package (smart_init)
# pragma resource "*. dfm"
TChildForm * ChildForm;
TTemplates Templates;
//------------------------------------------------ --------------------------< br>-
__fastcall TChildForm:: TChildForm (TComponent * Owner) p>
: TForm (Owner)
(
)
//------------------------------------------------ --------------------------< br>--bool __fastcall TChildForm:: LoadImage (AnsiString FileName)
(Try
(
Image1-> Picture-> LoadFromFile (FileName);
) catch (EInvalidGraphic & Exception)
(
AnsiString Error = "Помилка завантаження файлу зображення! Помилка системи:";
Error + = Exception.Message;
MessageBox (this-> Handle, Error.c_str (), "Помилка", MB_OK | MB_ICONERROR); return false;
) p>
if (Image1-> Picture-> Bitmap-> PixelFormat! = pf8bit)
(
MessageBox (Handle, "Такий формат файлу поки не підтримують ...", p>
" Слабенько я поки що. .. ", MB_OK | MB_ICONSTOP |
MB_APPLMODAL); return false;
) p>
return true;
)
//------------------------------------------------ --------------------------< br>--void __fastcall TChildForm:: FormClose (TObject * Sender, p>
TCloseAction & Action)
(
MainForm-> DeleteActiveChildForm ();
)
//------------------------------------------------ --------------------------< br>--void __fastcall TChildForm:: AverageFilter ()
(
AverageFilterDialogForm = new TAverageFilterDialogForm (this); if (AverageFilterDialogForm-> ShowModal () == mrCancel)
(delete AverageFilterDialogForm; return;
) p>
int Value = atoi (AverageFilterDialogForm -> Edit1-> Text.c_str ()); p>
delete AverageFilterDialogForm; p>
Byte * PrevisionLine = NULL;
Byte * CurrentLine = NULL;
Byte * NextLine = NULL; int I = 0, J = 0; int Summ = 0; p>
for (I = 0; I Picture-> Bitmap-> Height - 1; I + +)
(
CurrentLine = (Byte *) Image1-> Picture-> Bitmap-> ScanLine [I]; for (J = 0; J Picture-> Bitmap-> Width - 1; J + +)
( p>
Summ = 0; p>
if (I> 0) p>
( p>
PrevisionLine = (Byte *) Image1-> Picture-> Bitmap-> ScanLine [I - 1]; if (J> 0) p>
( p>
Summ + = PrevisionLine [J - 1]; p>
) p>
Summ = Summ + PrevisionLine [J]; p>
if (J + 1 Picture-> Bitmap-> Width) p> ( p>
Summ + = PrevisionLine [J + 1]; p>
) p>
) p>
if (J> 0) p>
( p> < p> Summ + = CurrentLine [J - 1]; p>
) p>
Summ + = CurrentLine [J]; p>
if (J + 1 Picture-> Bitmap-> Width) p> ( p>
Summ + = CurrentLine [J + 1]; p>
) p>
if (I + 1 Picture-> Bitmap-> Height) p> ( p>
NextLine = (Byte *) Image1-> Picture-> Bitmap-> ScanLine [I + 1]; if (J> 0) p>
( p>
Summ + = NextLine [J - 1]; p>
) p>
Summ + = NextLine [J]; p>
if (J + 1 Picture-> Bitmap-> Width) p> ( p>
Summ + = NextLine [J + 1]; p>
) p>
) p>
if ((int) (Summ/9) Visible = false;
Image1-> Visible = true;
)
//------------------------------------------------ --------------------------< br>-
//Відстань між двома точкамиint Distance (TVertex & V1, TVertex & V2)
(Int a = abs (V1.Y - V2.Y); int b = abs (V1.X - V2.X); return sqrt (a * a + b * b);
) p>
//---------------------------------------- ----------------------------------< br>--void __fastcall TChildForm:: OSR ()
(
// Гранична відстань для простроенія спрощеної фігури const int Treshold = 5; p>
// Сюди зберігається результат розпізнання
AnsiString Result; p>
// Відлагоджувальна форма з зображенням для роботи
OSRForm = new TOSRForm (this); p>
// Напрямки руху жука typedef enum (North, East, South, West) TDirectional;
TDirectional Direct; p>
// Координати першій зустрічі з поточним об'єктом int X, Y; p>
// Тимчасово їх використовуємо для завдання нового розміру робочого зображення
X = OSRForm-> Width - OSRForm-> Image1-> Width;
Y = OSRForm-> Height - OSRForm-> Image1-> Height;
OSRForm-> Image1-> Picture-> Bitmap-> Assign (Image1-> Picture-> Bitmap);
OSRForm-> Width = OSRForm-> Image1-> Width + X;
OSRForm-> Height = OSRForm-> Image1-> Height + Y;
OSRForm-> Image1-> Canvas-> Rectangle (0, 0, OSRForm - > Image1-> Width - 1, p>
OSRForm-> Image1-> Height - 1); p>
Graphics:: TBitmap * FromImage = Image1-> Picture-> Bitmap;
Graphics:: TBitmap * ToImage = OSRForm-> Image1-> Picture-> Bitmap; p>
// Поточні координати маркера int cX, cY; p>
// Максимальні координати, які займає фігура int MaxX = 0; int MaxY = FromImage-> Height; p>
// Від цієї координати починається нове сканування за Y int BeginY = 0; p>
// Оброблювані лінії
Byte * Line, * ToLine; p>
char Symb = 'А'; p>
// Поточний байт
Byte B = 0; p>
bool SkipMode = false; while (true)
(
// Список координат поточного об'єкта
TShapeVector ShapeVector;
// Тимчасова структура координат точки
TVertex Vertex; p>
// Пошук будь-якого об'єкта
// Йдемо до тих пір, поки не зустрінемо чорну область for (X = MaxX; X Width; X + +)
(for (Y = BeginY; Y ( p>
Line = (Byte *) FromImage-> ScanLine [Y]; if (Line [X] <255) goto FindedLabel; p>
) p >
if ((X + 1 == FromImage-> Width) & & (Y == FromImage-> Height)) p>
( p>
X + +; goto FindedLabel; p>
) p>
// Якщо пройшли до самого правого краю, розширюємо межі пошуку до низу if (X + 1 == FromImage-> Width) p>
( p >
X = 0; p>
MaxX = 0; p>
BeginY = MaxY; p>
MaxY = FromImage-> Height; p>
) p>
)
FindedLabel: p>
// Якщо не знайшли жодного чорного піксела, то виходимо із процедури if ((X == FromImage-> Width) & & (Y == FromImage-> Height)) break; p >
// Спочатку завдання знайти максимальні межі виявленої фігури,
// щоб потім від неї починати будувати скелет
// Також шукаємо найвищу точку фігури, для початку побудови int MinX = Image1-> Picture-> Width;// Сама ліва координата p>
MaxX = 0;
MaxY = 0; p>
// Сама верхня точка
TVertex TopPoint;
TopPoint.Y = Image1-> Picture-> Height; p>
// Звертаємо ліворуч (новий напрямок - північ) cX = X; cY = Y - 1; p>
Direct = North;
Line = (Byte *) FromImage-> ScanLine [cY]; p>
// Ще не прийдемо у вихідну точку, виділяємо контур об'єкта while ((cX! = X) | | (cY! = Y)) < br> ( p>
// В залежності від поточного напрямку руху жука switch (Direct) p>
( p>
// Північ case North: p>
( p>
B = Line [cX]; p>
// Якщо елемент "чорний", повертаємо знову "наліво" if (B <255) p>
( p>
Direct = West; cX -; p>
// Може це сама ліва координата? if (MinX> cX) p>
MinX = cX; p>
) p>
// Інакше повертаємо "направо" else p>
( p>
Direct = East; cX + +; if (MaxX MaxX = cX; p>
) p>
) break; p>
// Схід case East: p>
( p>
B = Line [cX]; p>
// Якщо елемент "чорний", повертаємо знову "наліво "if (B <255) p>
( p>
Direct = North; cY -; p>
Line = (Byte *) FromImage-> ScanLine [cY] ; p>
// Може це сама верхня точка? if (TopPoint.Y> cY) p>
( p>
TopPoint.Y = cY; p>
TopPoint.X = cX; p>
) p>
) p>
// Інакше повертаємо "направо" else p>
( p>
Direct = South; cY ++; p>
Line = (Byte *) FromImage-> ScanLine [cY]; if (MaxY MaxY = cY; p>
) p>
) break; p>
// Південь case South: p>
( p>
B = Line [cX]; p>
// Якщо елемент "чорний", повертаємо знову "наліво" if (B <255) p>
( p>
Direct = East; cX + +; if (MaxX MaxX = cX;
) p>
// Інакше повертаємо "направо" else p>
( p>
Direct = West; cX -; p> < p>// Може це сама ліва координата? if (MinX> cX) p>
MinX = cX; p>
) p>
) break; p>
// Захід case West: p>
( p>
B = Line [cX]; p>
// Якщо елемент "чорний", повертаємо знову "наліво" if (B <255) p>
( p>
Direct = South; cY ++; p>
Line = (Byte *) FromImage-> ScanLine [cY]; if (MaxY MaxY = cY; p>
) p>
// Інакше повертаємо "направо" else p>
( p>
Direct = North; cY -- ; p>
Line = (Byte *) FromImage-> ScanLine [cY]; p>
// Може це сама верхня точка? if (TopPoint.Y> cY) p>
( p>
TopPoint.Y = cY; p>
TopPoint.X = cX; p>
) p>
) p>
) p>
)
) p>
TopPoint.X ++; p>
if ((! TopPoint.X) & & (! TopPoint.Y))
( p>
TopPoint.X = X; p>
TopPoint.Y = Y;
) else
( p>
X = TopPoint.X; p>
Y = TopPoint.Y;
) p>
// Будівництво скелета
ToLine = (Byte * ) ToImage-> ScanLine [Y];
ToLine [X] = 0; p>
// Звертаємо ліворуч (новий напрямок - південь) cX = X; cY = Y; p>
Vertex.X = X;
Vertex.Y = Y;
ShapeVector.push_back (Vertex); p>
Direct = East;
Line = (Byte *) FromImage-> ScanLine [cY]; p>
// Ще не прийдемо у вихідну точку, виділяємо контур об'єкта do
( p>
// В залежності від поточного напрямку руху жука switch (Direct) p>
( p>
// Північ case North: p>
( p>
B = Line [cX]; p>
// Якщо елемент "чорний", повертаємо знову "наліво" if (B <255) p>
( p>
ToLine = (Byte *) ToImage-> ScanLine [cY]; p>
ToLine [cX] = 0; p>
Vertex.X = cX; p>
Vertex.Y = cY; if (Distance (Vertex, ShapeVector [ShapeVector.size () -- 1])> =
Treshold) p>
ShapeVector.push_back (Vertex); p>
Direct = West; cX -; p>
) p>
// Інакше повертаємо "направо" else p>
( p>
Direct = East; cX ++; p>
) p>
) break; p>
// Схід case East: p>
( p>
B = Line [cX]; p>
// Якщо елемент "чорний", повертаємо знову "наліво" if ( B <255) p>
( p>
ToLine = (Byte *) ToImage-> ScanLine [cY]; p>
ToLine [cX] = 0; p >
Vertex.X = cX; p>
Vertex.Y = cY; if (Distance (Vertex, ShapeVector [ShapeVector.size () - 1])> =
Treshold) p>
ShapeVector.push_back (Vertex); p>
Direct = North; cY -; p>
Line = (Byte *) FromImage-> ScanLine [cY ]; p>
) p>
// Інакше повертаємо "направо" else p>
( p>
Direct = South; cY ++; p>
Line = (Byte *) FromImage-> ScanLine [cY]; p>
) p>
) break; p>
// Південь case South: p>
( p>
B = Line [cX]; p>
// Якщо елемент "чорний", повертаємо знову "наліво" if (B <255) p>
( p>
ToLine = (Byte *) ToImage-> ScanLine [cY]; p>
ToLine [cX] = 0; p>
Vertex.X = cX; p>
Vertex.Y = cY; if (Distance (Vertex, ShapeVector [ShapeVector.size () - 1])> =
Treshold) p>
ShapeVector.push_back (Vertex); p>
Direct = East; cX ++; p>
) p>
// Інакше повертаємо "направо "else p>
( p>
Direct = West; cX -; p>
) p>
) break; p>
// Захід case West: p>
( p>
B = Line [cX]; p>
// Якщо елемент "чорний", повертаємо знову "наліво" if ( B <255) p>
( p>
ToLine = (Byte *) ToImage-> ScanLine [cY]; p>
ToLine [cX] = 0; p >
Vertex.X = cX; p>
Vertex.Y = cY; if (Distance (Vertex, ShapeVector [ShapeVector.size () - 1])> =
Treshold) p>
ShapeVector.push_back (Vertex); p>
Direct = South; cY ++; p>
Line = (Byte *) FromImage-> ScanLine [cY]; p>
) p>
// Інакше повертаємо "направо" else p>
( p>
Direct = North; cY -; p>
Line = (Byte *) FromImage-> ScanLine [cY]; p>
) p>
) p>
)
) while ((cX! = X) | | (cY! = Y )); p>
Vertex.X = X;
Vertex.Y = Y;
ShapeVector.push_back (Vertex); p> < p> ToImage-> Canvas-> Pen-> Color = clRed;
ToImage-> Canvas-> MoveTo (ShapeVector [0]. X, ShapeVector [0]. Y); for (UINT i = 1; i < ShapeVector.size (); i + +)
( p>
ToImage-> Canvas-> LineTo (ShapeVector [i]. X, ShapeVector [i]. Y);
) p>
for (UINT i = 0; i ( p> ShapeVector [i]. X -= MinX; p>
ShapeVector [ i]. Y -= Y;
) p>
/* p>
if (Symb == 'Й')
( p>
Symb + +;
) p>
if (Symb == 'а')
( p>
// Symb = 'A'; break;
) p> < p> if ((Symb! = 'И') & & (! SkipMode))
( p>
AnsiString FileName = ExtractFilePath (Application-> ExeName) + "TPL"; p>
FileName + = Symb; p>
ofstream OutFile (FileName.c_str ()); for (UINT i = 0; i ( p>
OutFile p>