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