}
bool TAnalysePicture::Show(int x, int y, int xt, int yt)
{
if(xt!=-1) pic2->Show(xt, yt);
return pic->Show(x, y);
}
TFingPicture *TAnalysePicture::GetPic1()
{
return pic;
}
TFingPicture *TAnalysePicture::GetPic2()
{
return pic2;
}
double TAnalysePicture::ChangeAlphaInterval(double _alpha)
//Приведение итрервала к [-pi,pi)
{
double ret = abs(_alpha);
while(ret >= 2.0*M_PI) ret -= 2.0*M_PI;
if(ret > M_PI) ret = 2.0*M_PI - ret;
else ret = -ret;
if(_alpha > 0) ret = -ret;
return ret;
}
/*Фильтрование полученных точек
отсеиваются близкостоящие направленные в противоположные строки
а так же точки слева и справа от которых нет линий*/
int TAnalysePicture::DotsFilter(TAbsFing &_dots)
{
int leftDots = 0;
TAbsFing::iterator iter1;
TAbsFing::iterator iter2;
for(iter1 = _dots.begin(); iter1 != _dots.end(); iter1++)
{
if(!iter1->show) continue;
//отсев точек сложным условием (условие окружения)
iter1->show = LeftDot(iter1);
}
for(iter1 = _dots.begin(); iter1 != _dots.end(); iter1++)
{
if(!iter1->show) continue;
//отсевблизкостоящихточек
for(iter2 = iter1, ++iter2; iter2 != _dots.end(); iter2++)
{
if(!iter2->show) continue;
double difL = GetS(iter1->coord,iter2->coord);
if( //условия отсева
(
//на близком растоянии (15) находятся два окончания/раздвоения направленных друг на друга
(difL < 15)&&
((abs(iter2->alpha - iter1->alpha) > (165.0/180.0*M_PI))&&(abs(iter2->alpha - iter1->alpha)<(195.0/180.0*M_PI)))
)
||
(
//или просто очень близкие точки (<5..10)
(difL < 10)&&(iter1->type == iter2->type)
)
)
{
iter1->show = false;
iter2->show = false;
}
}
}
return leftDots;
}
inline double TAnalysePicture::GetS(CPoint A, CPoint B)
//растояниемеждуточками
{
return sqrt( (double)((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y)) );
}
/*Если точка является окончанием, то слева и справа от нее должны быть линии если это не так, то точку нужно исключить из дальнейшего анализа*/
bool TAnalysePicture::LeftDot(TAbsFing::iterator &iter)
{
COLORREF color = 0x000000; //ищем черную точку для окончаний
if(!iter->type) color = 0xffffff;; //ищем белую точку для раздвоений
int l, k = 35;
const int minL = 4, maxL = 12;
bool find = false;
while(k <= 55)
{
l = minL;
while(l <= maxL)
{
int x = iter->coord.x + (int)(l*cos(iter->alpha + k/180.0*M_PI)+0.5);
int y = iter->coord.y - (int)(l*sin(iter->alpha + k/180.0*M_PI)+0.5);
if(pic->GetPixel(x,y) == color) // важноеусловие!!!
{ find = true; break;} //нашлиточкуслева
l++;
}
if(find) break;
k += 10; //Поисксшагом 10гр
}
if(!find) return false;
k = 35;
while(k <= 55)
{
l= minL;
while(l <= maxL)
{
int x = iter->coord.x + (int)(l*cos(iter->alpha - k/180.0*M_PI)+0.5);
int y = iter->coord.y - (int)(l*sin(iter->alpha - k/180.0*M_PI)+0.5);
if(pic->GetPixel(x,y) == color) // важноеусловие!!!
return true; //нашлиточкусправа
l++;
}
k += 10;
}
return false;
}
П.1.10. ТЕКСТ МОДУЛЯTFingPicture.h
#pragma once
#include "Fing.h"
///////////////////////////////////////////////////////////////////////////////
//Класс изображения.
//Хранение изображения, выполнение простейших операции над ним
///////////////////////////////////////////////////////////////////////////////
class TFingPicture
{
private:
CDC pic; //указатель на изображение
BITMAP bmp; //изображение
bool IsLoad; //изображение загружено
CDC *Screen; //указатель на окно программы
public:
TFingPicture(CDC *_Screen); //_Screen - указательнаокно
~TFingPicture(void);
bool Load(const CString src); //загрузитьизображениеизфайла src
bool Show(int X, int Y); //отобразить изображение на окне в координатах (X,Y)
bool SetPixel(CPoint dot, COLORREF color); //установка цвета пикселя dot
bool SetPixel(int x, int y, COLORREF color); //установкацветапикселя (x,y)
COLORREF GetPixel(CPoint dot); //взятиецветапикселя dot
COLORREF GetPixel(int x, int y); //взятиецветапикселя (x,y)
bool FloodFill(CPoint dot, COLORREF color=0xffffff); //заливкаобласти (поумолчаниючернымцветом)
bool FloodFill(int x, int y, COLORREF color=0xffffff); //заливкаобласти (поумолчаниючернымцветом)
bool Line(CPoint from, CPoint to, int width, COLORREF color);//рисованиелинии
bool Rectangle(CPoint from, CPoint to, int width=2, COLORREF color=0xffffff); //рисованиепрямоугольника
bool Copy(TFingPicture &from); //копированиеизображения
CPoint NextDotCW(const CPoint dot, int &vec); //Поискследующейточки "_почасовой_ стрелке"
CPoint NextDotCCW(const CPoint dot, int &vec); //Поискследующейточки "_противчасовой_ стрелке"
CPoint GetSize(); //получение размера изображения
};
П.1.11. ТЕКСТ МОДУЛЯTFingPicture.cpp
#include "StdAfx.h"
#include "TFingPicture.h"
///////////////////////////////////////////////////////////////////////////////
//Класс изображения.
//Хранение изображения, выполнение простейших операции над ним
///////////////////////////////////////////////////////////////////////////////
//координаты окружающих точек
const CPoint incXY[8]=
{
CPoint(-1, -1),
CPoint(0, -1),
CPoint(1, -1),
CPoint(1, 0),
CPoint(1, 1),
CPoint(0, 1),
CPoint(-1, 1),
CPoint(-1, 0)};
TFingPicture::TFingPicture(CDC *_Screen)
{
Screen = _Screen;
pic.CreateCompatibleDC(Screen);
IsLoad = false;
}
TFingPicture::~TFingPicture(void){}
//отобразить изображение на окне в координатах (X,Y)
bool TFingPicture::Show(int X, int Y)
{
if (!IsLoad) return false;
int kx = bmp.bmWidth;
int ky = bmp.bmHeight;
return Screen->StretchBlt(X, Y, bmp.bmWidth, bmp.bmHeight, &pic, 0, 0, kx, ky, SRCCOPY)>0;
}
//загрузитьизображениеизфайла src
bool TFingPicture::Load(const CString src)
{
IsLoad = false;
CBitmap bm;
bm.Detach();
IsLoad = bm.Attach(LoadImage(0, src, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE))>0;
bm.GetObject(sizeof(BITMAP), &bmp);
pic.SelectObject(&bm);
return IsLoad;
}
// color = BGR;
bool TFingPicture::SetPixel(CPoint dot, COLORREF color)
{
if (!IsLoad) return false;
pic.SetPixel(dot.x, dot.y, color);
return true;
}
bool TFingPicture::SetPixel(int x, int y, COLORREF color)
{
if (!IsLoad) return false;
pic.SetPixel(x, y, color);
return true;
}
// color = BGR;
COLORREF TFingPicture::GetPixel(CPoint dot)
{
if (!IsLoad) return false;
return pic.GetPixel(dot.x, dot.y);
}
COLORREF TFingPicture::GetPixel(int x, int y)
{
if (!IsLoad) return false;
return pic.GetPixel(x, y);
}
bool TFingPicture::FloodFill(CPoint dot, COLORREF color)
{
if(!IsLoad) return false;
COLORREF col = GetPixel(dot);
CBrush br(color);
pic.SelectObject(&br);
pic.ExtFloodFill(dot.x, dot.y, col, FLOODFILLSURFACE);
return true;
}
bool TFingPicture::FloodFill(int x, int y, COLORREF color)
{
if(!IsLoad) return false;
COLORREF col = GetPixel(x, y);
CBrush br(color);
pic.SelectObject(&br);
pic.ExtFloodFill(x, y, col, FLOODFILLSURFACE);
return true;
}
bool TFingPicture::Line(CPoint from, CPoint to, int width, COLORREF color)
{
if(!IsLoad) return false;
CPen pen(PS_SOLID, width, color);
pic.SelectObject(&pen);
pic.MoveTo(from.x, from.y);
pic.LineTo(to.x, to.y);
return true;
}
bool TFingPicture::Rectangle(CPoint from, CPoint to, int width, COLORREF color)
{
if(!IsLoad) return false;
Line(from, CPoint(from.x, to.y), width, color);
Line(CPoint(from.x, to.y), to, width, color);
Line(to, CPoint(to.x, from.y), width, color);
Line(CPoint(to.x, from.y), from, width, color);
return true;
}
bool TFingPicture::Copy(TFingPicture &from)
{
bmp = from.bmp;
IsLoad = from.IsLoad;
Screen = from.Screen;
return pic.BitBlt(0, 0, bmp.bmWidth, bmp.bmHeight, &from.pic, 0, 0, SRCCOPY)>0;
}
CPoint TFingPicture::NextDotCW(const CPoint dot, int &vec)
//Поиск следующей точки "_по часовой_ стрелке"
//vec вероятное направление поиска
{
inti = vec,
step = 0;
CPoint newdot = dot;
COLORREF clMas[9];
clMas[8] = clMas[0] = GetPixel(dot.x-1, dot.y-1);
clMas[1] = GetPixel(dot.x, dot.y-1);
clMas[2] = GetPixel(dot.x+1, dot.y-1);
clMas[3] = GetPixel(dot.x+1, dot.y);
clMas[4] = GetPixel(dot.x+1, dot.y+1);
clMas[5] = GetPixel(dot.x, dot.y+1);
clMas[6] = GetPixel(dot.x-1, dot.y+1);
clMas[7] = GetPixel(dot.x-1, dot.y);
do{
if(clMas[i+1] < clMas[i])
{
vec = (i + 1) % 8;
newdot.x = dot.x + incXY[vec].x;
newdot.y = dot.y + incXY[vec].y;
if(vec % 2 == 0) SetPixel(dot.x + incXY[vec+1].x, dot.y + incXY[vec+1].y, 0x000000);
vec = (vec + 5) % 8;
return newdot; //найденановаяточка
}
i = (i + 1) % 8;
step++;
}while(step <= 8);
return dot; //поиск ни к чему не привел
}
CPoint TFingPicture::NextDotCCW(const CPoint dot, int &vec)
//Поиск следующей точки "_против часовой_ стрелке"
//vec вероятное направление поиска
{
inti = vec,
step = 0;
CPoint newdot = dot;
COLORREF clMas[9];
clMas[8] = clMas[0] = GetPixel(dot.x-1, dot.y-1);
clMas[1] = GetPixel(dot.x-1, dot.y);
clMas[2] = GetPixel(dot.x-1, dot.y+1);
clMas[3] = GetPixel(dot.x, dot.y+1);
clMas[4] = GetPixel(dot.x+1, dot.y+1);
clMas[5] = GetPixel(dot.x+1, dot.y);
clMas[6] = GetPixel(dot.x+1, dot.y-1);
clMas[7] = GetPixel(dot.x, dot.y-1);
do{
if(clMas[i+1] < clMas[i])
{
vec = (i + 1) % 8;
newdot.x = dot.x + incXY[(8-vec)%8].x;
newdot.y = dot.y + incXY[(8-vec)%8].y;
if(vec % 2 == 0) SetPixel(dot.x + incXY[8-vec-1].x, dot.y + incXY[8-vec-1].y, 0x000000);
vec = (vec + 5) % 8;
return newdot; //найденановаяточка
}
i = (i + 1) % 8;
step++;
}while(step <= 8);
return dot; //поиск ни к чему не привел
}
CPoint TFingPicture::GetSize()
//получение размера изображения
{ if(!IsLoad) return false;
return CPoint(bmp.bmWidth, bmp.bmHeight);}
ПРИЛОЖЕНИЕ 2 РУКОВОДСТВО ПРОГРАММИСТА
П.2.1. НАЗНАЧЕНИЕ ПРОГРАММЫ
Программа распознавания личности по отпечаткам пальцев имеет идентификатор FingerAnalyser и предназначена для автоматической идентификации личности по папиллярному узору. Программа FingerAnalyser выполняет следующие функции:
1) модификация изображения, исправление искажений;
2) выделение локальных особенностей – минюций. Формирование списка минюций в абсолютных параметрах;
3) сортировка списка абсолютных параметров, исключение ложных и ненадежных минюций;
4) конвертирование абсолютных параметров в отностительные, формирование списка относительных параметров;
5) установка системы допусков для учета корреляцции изображений
6) сравнение одного отпечатка с множеством других.
Данная работа реализует такое преобразование изображения, при котором данные о расположение уникальных особенностей сохраняются наиболее полно и с наименьшим содержанием ложной информации.
Создаваемая система облегчит разработку алгоритмов обработки изображений, упростит анализ экспериментальных данных и выявление общих закономерностей.
П.2.2. УСЛОВИЯ ПРИМЕНЕНИЯ ПРОГРАММЫ
Программа FingerAnalyser предъявляет следующие требования к техническим средствам:
- стандартный x86-совместимый ПК;
- тактовая частота процессора 900 МГц или более;
- объем оперативной памяти не менее 64 Мб;
- разрешение экрана монитора не менее 1024x768.
Программа FingerAnalyser предъявляет следующие требования к программным средствам:
- операционная система семейства Windows (Windows 9x/ME/NT/2000/XP);
- среда для разработки приложений MicrosoftVisualStudioC++ 2003.
Интерфейс программы представлен на рис. П.2.1.
Интерфейс программы FingerAnalyser
Рис. П.2.1
На форме программы в визуальном виде представляется, после открытия через пункт «Открыть», исходное изображение, после нажатия на кнопку «Анализ», скорректированное изображение и визуальное представление структурного вида отпечатка. После чего можно нажатием на кнопку «Сравнить» отыскать в базе схожие отпечатки.
При каждом анализе отпечатка создается файл с его структурным описанием. Для того чтобы поместить отпечаток в базу данных отпечатков, для последующего стравнения с ним, необходимо нажать на кнопку «Запомнить в базу». Для запоминания в базу можно выбирать группу файлов для применения операции записи в базу данных для всех выбранных файлов.