Смекни!
smekni.com

Программная система обработки и анализа изображений (стр. 2 из 3)

* Вначале на всем изображении выделяется область, ограничивающая отдельный символ.

* Затем эта область делится на 9 равных частей ( рис. 2 ).

рис. 2

* В каждом из 9 квадратов подсчитывается число черных пикселов и делится на площадь данного квадрата, т.е. определяется плотность заполнения в каждом квадрате.

* Все 9 определенных плотностей преобразуются в формат Х.ХХХ и далее в строку типа Х.ХХХ Х.ХХХ Х.ХХХ Х.ХХХ Х.ХХХ Х.ХХХ Х.ХХХ Х.ХХХ Х.ХХХ.

Преобразование в строку производится для более удобного хранения данных в базе данных ( структура базы описана в приложении ), так как это намного удобнее, чем делать в базе 9 полей для хранения 9 значений плотности.

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

Описание программы

Все операции осуществляются посредством главного меню программы. Главное меню состоит из следующих пунктов:

1) Файл

· Открыть файл

Открывается окно выбора файла. Возможные маски для выбора ( BMP, PCX, JPG ).

Если выбранный файл является правильным графическим файлом, то хранимое в нем изображение выводится в окно программы.

· Выделить линии

..... Перед пользователем появляется диалоговое окно, в котором ему предоставляется возможность выбрать какие линии выделять ( вертикальные или горизонтальные ).

1) Операции

· Очистить

........... Тот файл, который был открыт открывается снова и все линии появившиеся в процессе работы удаляются.

· Определить плотность ( учеба )

Этот пункт меню предназначен для обучения системы. В окне должен находится эталонный текст. С помощью “мышки” выделяется нужный символ и выбирается данный пункт. Вслед за этим пользователю предоставляется возможность указать уникальный код для выбранного символа. Определенная плотность и код записываются в базу данных.

· Распознать

........... Этот пункт противоположен предыдущему. С помощью “мышки” выделяется нужный символ и выбирается данный пункт. Происходит определение плотности выбранного символа и далее в базе осуществляется поиск записи, у которой поле с эталонной строкой более сходно с плотностью выделенного символа.

........... Сравнение происходит следующим образом:

........... Определяется и складываются между собой разности между плотностями эталонного и выделенного символами для каждого квадрата. Тот эталонный символ, у которого полученная сумма окажется наименьшей считается эквивалентом для выделенного.

1) Преобразования

..... Эти преобразования являются экспериментальными и не являются целью поставленной задачи. Полученные результаты при более глубоком исследовании могут быть в дальнейшем использованы для обработки изображений.

· Афинное преобразование

· Узоры

........... Эти два пункта строят изображение пользуясь афинными преобразованиями с различными коэффициентами. В зависимости от этих коэффициентов изображения получаются различными.

· Лист папоротника

........... Опять же основываясь на афинных преобразованиях строится лист папоротника. Данное преобразование имеет огромное практическое значение, так как относительно сложное изображение ( лист папоротника ) строится с помощью одной формулы.

1) Выход

Выход из программы.


Приложение

Структура базы для хранения эталонных символов

Код символа

Эталонная строка

Код символа - однозначно идентифицирует хранимый символ. Так как в базе хранятся эталоны иероглифов, для которых в русском алфавите нет примера начертания, то для замены распознанного символа нужно еще хранить и его эталонное изображение. Но так как целью данной работы является не замена распознанных символов на эталонные, а только соотнесение с эталоном, то для экономии дискового пространства решено хранить не эталонное изображение символа, а только его уникальный код, с помощью которого можно однозначно идентифицировать символ.

Эталонная строка - строка, содержащая в себе все 9 плотностей выделенной области.




Текст программы

{$I CdBase.inc}

{$I CdComp.inc}

unit Main;

interface

uses

SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,

Forms, Dialogs, Reg_imag, Menus, Options, CmplSign, DBTables, DB;

type

TMainForm = class(TForm)

MainMenu: TMainMenu;

N1: TMenuItem;

N2: TMenuItem;

Image: TMultiImage;

N3: TMenuItem;

NFileOpen: TMenuItem;

OpenDialog: TOpenDialog;

NSelect: TMenuItem;

N4: TMenuItem;

N5: TMenuItem;

N6: TMenuItem;

N7: TMenuItem;

Onemore1: TMenuItem;

N8: TMenuItem;

N9: TMenuItem;

DataTable: TTable;

N10: TMenuItem;

DataTableOpis: TStringField;

DataTableID: TFloatField;

procedure N2Click(Sender: TObject);

procedure NFileOpenClick(Sender: TObject);

procedure NSelectClick(Sender: TObject);

procedure FormCreate(Sender: TObject);

procedure ImageMouseDown(Sender: TObject; Button: TMouseButton;

Shift: TShiftState; X, Y: Integer);

procedure ImageMouseUp(Sender: TObject; Button: TMouseButton;

Shift: TShiftState; X, Y: Integer);

procedure ImageMouseMove(Sender: TObject; Shift: TShiftState; X,

Y: Integer);

procedure N4Click(Sender: TObject);

procedure N7Click(Sender: TObject);

procedure Onemore1Click(Sender: TObject);

procedure N8Click(Sender: TObject);

procedure N9Click(Sender: TObject);

procedure N5Click(Sender: TObject);

procedure N10Click(Sender: TObject);

private

DetectRectX, DetectRectY: real; { Угол, под которым выделять линии }

xStart, xEnd, yStart, yEnd: word;

BegSelect: boolean;

procedure DefGradient(var Gx, Gy: real; x,y: word);

procedure SetRect;

procedure DefPlotn;

procedure AfinConvert;

procedure OneMore;

procedure Mandel;

procedure Paporotnik;

function GetDensity: string;

public

{ Public declarations }

end;

var

MainForm: TMainForm;

implementation

{$R *.DFM}

procedure TMainForm.N2Click(Sender: TObject);

begin

Application.Terminate;

end;

procedure TMainForm.NFileOpenClick(Sender: TObject);

begin

if OpenDialog.Execute then begin

Image.ImageName := OpenDialog.FileName;

NSelect.Enabled := True;

end

else NSelect.Enabled := False;

end;

procedure TMainForm.NSelectClick(Sender: TObject);

var

Result: word;

begin

OptionForm := nil;

try

OptionForm := TOptionForm.Create(Self);

with OptionForm do begin

RectXEdit.Text := FloatToStr(DetectRectX);

RectYEdit.Text := FloatToStr(DetectRectY);

X1Edit.Text := IntToStr(xStart);

X2Edit.Text := IntToStr(xEnd);

Y1Edit.Text := IntToStr(yStart);

Y2Edit.Text := IntToStr(yEnd);

Result := ShowModal;

DetectRectX := StrToInt(RectXEdit.Text);

DetectRectY := StrToInt(RectYEdit.Text);

xStart := StrToInt(X1Edit.Text);

xEnd := StrToInt(X2Edit.Text);

yStart := StrToInt(Y1Edit.Text);

yEnd := StrToInt(Y2Edit.Text);

end; { with }

finally

OptionForm.Free;

end; { try }

if Result = mrOK then SetRect;

end;

{ Определение градиентов Gx и Gy в точке [x,y] }

procedure TMainForm.DefGradient(var Gx, Gy: real; x,y: word);

var

a, b, c, d, e, g, h, i: byte;

begin

with Image.Canvas do begin

if Pixels[x-1,y-1] = clBlack then a := 0

else a := 1;

if Pixels[x,y-1] = clBlack then b := 0

else b := 1;

if Pixels[x+1,y-1] = clBlack then c := 0

else c := 1;

if Pixels[x-1,y] = clBlack then d := 0

else d := 1;

if Pixels[x+1,y] = clBlack then e := 0

else e := 1;

if Pixels[x-1,y+1] = clBlack then g := 0

else g := 1;

if Pixels[x,y+1] = clBlack then h := 0

else h := 1;

if Pixels[x+1,y+1] = clBlack then i := 0

else i := 1;

{ Градиент по X }

Gx := g + 2*h + i - a - 2*b - c;

if Gx < 0 then Gx := 0;

if Gx = 0 then Gx := 0.000001;

{ Градиент по Y }

Gy := c + 2*e + i - a - 2*d - g;

if Gy < 0 then Gy := 0;

end; { with Image }

end;

procedure TMainForm.SetRect;

var

x, y: word;

Gx, Gy, Qx, Qy: real;

OutF: TextFile;

S1,S2: string;

begin

AssignFile(OutF, 'tangs.000');

Rewrite(OutF);

{ Сканируем все изображение }

with Image.Canvas do begin

for y := yStart+1 to yEnd-1 do begin

for x := xStart+1 to xEnd-1 do begin

DefGradient(Gx,Gy,x,y); { Определить градиент в точке [x,y] }

{if Gx+Gy > 0 then Pixels[x,y+200] := clRed;}

Qx := ArcTan(Gy/Gx);

Qx := Round(Qx*180/Pi);

{ Qx := Round(90*Gx/4);

Qy := Round(90*Gy/4);}

Str(Qx:2:0, S1);

{ Str(Qy:2:0, S2); }

Write(OutF, S1+{' '+S2+}' | ');

{ if (Q <= -Pi/3) or (Q >= Pi/3) then Pixels[x,y+200] := clRed;}

if (Qx > { DetectRectX}80) and (Qx < 100){ and (Q > DetectRect*Pi/180) }then

Pixels[x,y+200] := clRed;

end; { for x }

WriteLn(OutF, 'End Line');

end; { for y }

end; { with Image.Canvas }

CloseFile(OutF);

end;

procedure TMainForm.DefPlotn;

var

i, j, x, y, dx, dy, Range, x1, y1: word;

Count: word;

begin

x := xStart; y := yStart;

dx := Round((xEnd-xStart+1) div 3);

dy := Round((yEnd-yStart+1) div 3);

x1 := x; y1 := y;

{ Три квадрата по вертикали }

for i := 1 to 3 do begin

if i = 2 then Range := (yEnd-yStart+1) - 2*dy

else Range := dy;

{ Три квадрата по горизонтали }

for j := 1 to 3 do begin

if j = 2 then Range := (xEnd-xStart+1) - 2*dx

else Range := dx;

{ Сканируем внутри квадрата по y }

for y := y1 to y1+Range do begin

{ Сканируем внутри квадрата по x }

for x := x1 to x1+Range do begin

{ Подсчитываем число не белых пикселов }

if Image.Canvas.Pixels[x,y] <> clWhite then Inc(Count);

end; { for x }

end; { for y }

x1 := x1+dx; { Следующий квадрат по горизонтали }

end; { for j }

y1 := y1+dy; { Следующий квадрат по вертикали }

end; { for i }

end;

procedure TMainForm.FormCreate(Sender: TObject);

begin

OpenDialog.FileName := 'c:&bsol;delphi&bsol;mydir&bsol;diplom&bsol;pict&bsol;pict1.bmp';

Image.ImageName := OpenDialog.FileName;

end;

procedure TMainForm.ImageMouseDown(Sender: TObject; Button: TMouseButton;

Shift: TShiftState; X, Y: Integer);

begin

if Button = mbRight then begin

Image.ImageName := OpenDialog.FileName;

Exit;

end;

BegSelect := True;

with Image.Canvas do begin

Pen.Mode := pmXor;

Pen.Color := clGreen;

Pen.Style := psDot;

Brush.Style := bsClear;

xStart := X; yStart := Y;

xEnd := X; yEnd := Y;

end; { with }

end;

procedure TMainForm.ImageMouseUp(Sender: TObject; Button: TMouseButton;

Shift: TShiftState; X, Y: Integer);

begin

BegSelect := False;

with Image.Canvas do begin

Pen.Mode := pmCopy;

Pen.Color := clBlack;

Pen.Style := psSolid;

Brush.Style := bsSolid;

end; { with }

end;

procedure TMainForm.ImageMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);

begin

if not BegSelect then Exit;

with Image.Canvas do begin

Rectangle(xStart, yStart, xEnd, yEnd);

xEnd := X; yEnd := Y;

Rectangle(xStart, yStart, xEnd, yEnd);

end; { with }

end;

procedure TMainForm.N4Click(Sender: TObject);

begin

Image.ImageName := OpenDialog.FileName;

end;

{ Афинное преобразование }

procedure TMainForm.AfinConvert;

var

dx, dy, Rand: word;

A, B, C, D, E, F: real;

x, y: word;

i: longint;

begin

A := 0.5; B := 0.5; E := 0;

C := 0.3; D := 0; F := 1;

dx := (xEnd-xStart+1) div 2; xEnd := xStart +2*dx - 1;

dy := (yEnd-yStart+1) div 2; yEnd := yStart +2*dy - 1;

x := xStart+dx; y := yStart+dy;

Randomize;

for i := 1 to 50000 do begin

Rand := Random(10);

Case Rand of

0..3: begin

x := xStart + 1 + (x-xStart+1) div 2;

y := yStart + 1 + (y-yStart+1) div 2;

end;

4: begin

x := xStart + dx + (x-xStart+1) div 2;

y := yStart + 1 + (y-yStart+1) div 2;

end;

5: begin

x := xStart + 1 + (x-xStart+1) div 2;

y := yStart + dy + (y-yStart+1) div 2;

end;

6..9: begin

x := xStart + dx + (x-xStart+1) div 2;

y := yStart + dy + (y-yStart+1) div 2;

end;

end; { Case }

Image.Canvas.Pixels[x,y] := clBlue;

end; { for i }

end;

procedure TMainForm.N7Click(Sender: TObject);

begin

AfinConvert;