Реферат по предмету "Информатика"


Система идентификации личности по отпечаткам пальцев Подсистема анализа изображения

--PAGE_BREAK--};
//класс для хранения _относительных_ параметров точки
typedef list listTRelDot;
//Шаблон для хранения пары значений {first, second}
template struct TPair{
  data_t1 first;
  data_t2 second;
  TPair(data_t1 _f, data_t2 _s){first = _f; second = _s;};
};
typedef TPair TPairAbsDot;
typedef TPair TPairSur;
//результат сравнения отпечатков
struct TCompareFing{
  double val;         //уровень схожести отпечатков
  short cDot;         //количество совпавших точек
  short nfng;         //номер отпечатка
  CString name;        //файл отпечатка
  list dots;      //first — совпавшие точки на отпечатке в базе
                             //second — совпавшие точки на открытом отпечатке
  list surdots;
  //окружения на одинаковых отпечатках должны быть одинаковыми,
  //на этом основано сравнение «роз»
};
//Описание отпечатка в _относительных_ параметрах
class TRelFing: public list{
private:
  inline double GetS(const CPoint A, const CPoint B);     //растояние между точками
  double GetAlpha(const CPoint A, const CPoint B);       //Направлени из точки А в В [-pi,pi)
public:
  TRelFing(){};
  ~TRelFing(){};
  TRelFing *Convert(TAbsFing &fng);      //конвертировать абсолютные параметры к относительным
  TCompareFing Compare(TRelFing &fng);  //сравнить отпечатки
};
П.1.7 ТЕКСТ МОДУЛЯ fing.cpp
#include «stdafx.h»
#include «fing.h»
bool TAbsFing::SaveFing(CString fsav)
//Сохранение отпечатка в файл *.sav
{
  if(!this->size()) return false;
  TAbsFing::iterator iter;
  FILE *fingfile = fopen(fsav, «wb»);
  if(fingfile == NULL)
  {
      MessageBox(NULL,«Невозможно создать файл: '»+fsav+"'", «Ошибка работы с файлом», MB_OK);
      return false;
  }
  for(iter = this->begin(); iter != this->end(); iter++)
  {
      TAbsDot dot = *iter;
      if(iter->show) fwrite((void *)&dot, 1, sizeof(dot), fingfile);
  }
  fclose(fingfile);
  return true;
}
bool TAbsFing::LoadFing(CString src)
//Загрузка отпечатка из файла *.sav
{
  TAbsDot dot;
  FILE *fingfile = fopen(src, «rb»);
  if(fingfile == NULL)
  {
      MessageBox(NULL,«Невозможно открыть файл: '»+src+"'", «Ошибка работы с файлом», MB_OK);
      return false;
  }
  this->clear();
  while(!feof(fingfile))
  {
      fread((void *)&dot, 1, sizeof(dot), fingfile);
      this->push_back(dot);
  }
  this->pop_back();
  fclose(fingfile);
  return true;
}
///////////////////////////////////////////////////////////////////////////////////////
///TRelFing//TRelFing/TRelFing/TRelFing/TRelFing/TRelFing/TRelFing/TRelFing/TRelFing///
///////////////////////////////////////////////////////////////////////////////////////
TRelFing *TRelFing::Convert(TAbsFing &fng)
//конвертировать абсолютные параметры к относительным
{
  if(fng.empty()) return this;
  this->clear();
  TAbsFing::iterator iterA1, iterA2;
  TRelDot tmpR;
  listTRelDot listDots;
  double tmpa, vecAB;
  for(iterA1 = fng.begin(); iterA1 != fng.end(); iterA1++)
  { 
      for(iterA2 = fng.begin(); iterA2 != fng.end(); iterA2++)
      {
          if(iterA2 == iterA1) continue;
          tmpR.l = (short)(GetS(iterA1->coord, iterA2->coord)+0.5);  //l — растояние между точками
          vecAB = GetAlpha(iterA2->coord, iterA1->coord);
          tmpa = iterA1->alpha — vecAB;
          if(tmpa
          tmpR.a1 = (short)(tmpa * 180.0/M_PI +0.5); //a1 — угол между собственным направлением точки А и направлением A -> B
          tmpa = iterA2->alpha — vecAB;
          if(tmpa
          tmpR.a2 = (short)(tmpa * 180.0/M_PI +0.5); //a2 — угол между собственным направлением точки В и направлением A -> B
          tmpR.absDot = *iterA1;           //Во всех точках хранятся одни и те же данные!(необходимо для отображения совпавших точек)
          listDots.push_back(tmpR);
      }
      listDots.sort();
      this->push_back(listDots);
      listDots.clear();
  }
  return this;
}
inline double TRelFing::GetS(const CPoint A, const CPoint B)
//растояние между точками
{
  return sqrt( (double)((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y)) );
}
double TRelFing::GetAlpha(const CPoint A, const CPoint B)
//Направлени из точки А в В [-pi,pi)
{
  if(A == B) return 0.0;
  double alpha;
  if (A.x — B.x == 0)
  {
      if (A.y > B.y) alpha = M_PI_2;
      else alpha = -M_PI_2;
  }else
  {
      double a = ((double)A.y-B.y)/((double)B.x-A.x);
      alpha = atan(a);
      if (A.x > B.x)
      {
          if (alpha
          else alpha -= M_PI;
          if (A.y == B.y) alpha = -M_PI;
      }
  }
  return alpha;
}
TCompareFing TRelFing::Compare(TRelFing &fng)
//сравнить отпечаток с отпечатком из файла
{
  TCompareFing ret;
  ret.nfng = (short)fng.size();
  const short CONFIRM_VAL = 9;
  const double DELTA_L = 10.0;           //ограничитель
  const double DELTA_A = 10.0;          //ограничитель
  short confirmDot = 0;       //количество совпавших СТ (спец точек)
  short confirmVal = 0;        //количество совпавших сопряженных СТ с текущей СТ
  short needVal = (short)(min(this->size(),fng.size())/3.0 +0.5);
    if(needVal > CONFIRM_VAL) needVal = CONFIRM_VAL;
  listTRelDot *surroundDots1, *surroundDots2;
  listTRelDot::iterator baseIter;
  for(TRelFing::iterator tekFing = this->begin();
      tekFing != this->end();
      tekFing++)
  {
      for(TRelFing::iterator baseFing = fng.begin();
          baseFing != fng.end();
          baseFing++)
      {
          confirmVal = 0;
          surroundDots1 = new(listTRelDot);
          surroundDots2 = new(listTRelDot);
          for(listTRelDot::iterator tekIter = (*tekFing).begin();
             tekIter != (*tekFing).end();
             tekIter++)
          {
             baseIter = (*baseFing).begin();
             short divv, next;
             divv = next = abs(baseIter->l — tekIter->l);
             while(
                 divv >= next &&
                 next >= DELTA_L &&
                 baseIter != (*baseFing).end())
             { 
                 divv = next;
                    baseIter++;
                 next = abs(baseIter->l — tekIter->l);
             }
             if(divv >= DELTA_L && divv = DELTA_L
             for(;
                 baseIter != (*baseFing).end();
                 baseIter++)
             {
                 int len = abs(tekIter->l — baseIter->l);
                 if(len >= DELTA_L) break;      //нет смысла сравнивать дальше т.к. всегда будет next >= DELTA_L
                 int delta_a = DELTA_A;
                 if(
                     ((abs(tekIter->a1 — baseIter->a1)a1 — baseIter->a1) > 360-delta_a))&&
                     ((abs(tekIter->a2 — baseIter->a2)a2 — baseIter->a2) > 360-delta_a)))
                 {
                     confirmVal++;
                     surroundDots1->push_back(*baseIter);
                     surroundDots2->push_back(*tekIter);
                     break;
                 }
             }
             if(confirmVal > needVal)
             { 
                 ///////////////////////////
                 //удалим эту точку из последующего перебора, т.к. она уже совпала
                 ret.dots.push_back(TPairAbsDot(baseFing->back().absDot, tekFing->back().absDot));
                 ret.surdots.push_back(TPairSur(surroundDots1,surroundDots2));
                 baseFing->clear();
                 fng.erase(baseFing);
                 confirmDot++;
                 break;
             }
          }
            if(confirmVal > needVal){break;}
          else{
             ret.dots.push_back(TPairAbsDot(baseFing->back().absDot, tekFing->back().absDot));
             ret.surdots.push_back(TPairSur(surroundDots1,surroundDots2));
             surroundDots1->clear();
             surroundDots2->clear();
          }
      }
  }
  ret.cDot = confirmDot;
  ret.val = 0;
  return ret;
}
П.1.8 ТЕКСТ МОДУЛЯ TAnalysePicture.h
#pragma once
#include «TFingPicture.h»
//MESSAGEOUT отображать отладочную информацию с помощью popup окон
//#define MESSAGEOUT true
#define MESSAGEOUT false
#define OUT_FILE «fingAnalyserOut.txt» //файл отчет
#define BLANK «blank.bmp»            //пустое изображение
///////////////////////////////////////////////////////////////////////////////////
//важные параметры для обхода изображения
#define LEN_S 3             //длина малого вектора (LEN_S точек)
#define LEN_L 4             //длина большого вектора (LEN_L малых векторов)
#define KOL_L 2             //необходимое количество больших векторов
#define KOL_S LEN_L*KOL_L //необходимое количество точек
#define TEST_ALPHA 130.0 //тест на разворот вектора. Указывается угол в градусах
///////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////
// Класс АНАЛИЗА ИЗОБРАЖЕНИЯ
///////////////////////////////////////////////////////////////////////////////////
class TAnalysePicture
{
private:
  TFingPicture *pic;     //Собственно сама картинка
  TFingPicture *tmpPic;   //копия картинки
  TFingPicture *pic2;       //изображение для отображения в окне
  int height, width;    //высота и ширина изображения
  CString srcImg;      //путь к изображению
  int err;        //Код состояния картинки
  TInfo info;          //сопроводительная информация
private:
  int ChangeLine(list::iterator _dot, list &_map);    //Обработка картинки, ее изменение
  TAbsFing ReadPic(list::iterator _dot);        //Нахождение на изображении спец точек
  list LookPic();                                  //Сканирование картинки и нахождение линий на ней
  inline double GetAlpha(const CPoint A, const CPoint B);     //Направлени из точки А в В [-pi,pi)
  inline double GetS(CPoint A, CPoint B);                    //растояние между точками
  CPoint FindAcceptDot(CPoint dot, double alpha, bool type);   //Поиск продолжения из окончания/раздвоения
  bool TestFindDot(int _x, int _y);//тест точки: Разность направлений вперед и назад должно быть меньше 110 градусов
  double ChangeAlphaInterval(double _alpha);     //Приведение итрервала к [-pi,pi)
  int DotsFilter(TAbsFing &_dots);   
/*Фильтрование полученных точек отсеиваются близкостоящие направленные в противоположные строки
а так же точки слева и справа от которых нет линий*/
  bool LeftDot(TAbsFing::iterator &iter); 
/*Если точка является окончанием, то слева и справа от нее должны быть линии
если это не так, то точку нужно исключить из дальнейшего анализа*/
public:
  TAnalysePicture(const CString src, CDC *screen);
  ~TAnalysePicture(void);
  int getErr();
  CString getErrMsg();
  CString getPathSrc(){return srcImg;};
  TAbsFing AnalysePicture();                        //Обработка загруженного изображения и получение образа
  bool Show(int x, int y, int xt=-1, int yt=-1);
  TFingPicture *GetPic1();
  TFingPicture *GetPic2();
};
П.1.9 ТЕКСТ МОДУЛЯ TAnalysePicture.cpp
#include «StdAfx.h»
#include «TAnalysePicture.h»
TAnalysePicture::TAnalysePicture(const CString src, CDC *screen)
{
  pic = new TFingPicture(screen);
  err = -1;
  if(!pic->Load(src)) err = 0;
  pic->Rectangle(CPoint(0, 0), pic->GetSize(), 10);
  srcImg = src;
  tmpPic = new TFingPicture(screen);
  tmpPic->Load(src);
  pic2 = new TFingPicture(screen);
  pic2->Load(BLANK);
}
TAnalysePicture::~TAnalysePicture(void)
{
  delete(tmpPic);
  delete(pic2);
  delete(pic);
}
//Код ошибки
int TAnalysePicture::getErr()
{
  return err;
}
//Сообщение ошибки
CString TAnalysePicture::getErrMsg()
{
  CString msg = "";
  switch (err)
  {
      case -1: {msg = «Ошибок при загрузке изображения нет»; break;}
      case 0: {msg = «Изображение не загружено»; break;}
      case 1: {msg = «Возникла ошибка при загрузке изображения»; break;}
      default: {msg = «Нераспознанная ошибка»;}
  }
  return msg;
}
// Обработка загруженного изображения и получение образа
TAbsFing TAnalysePicture::AnalysePicture()
{
  TAbsFing ret, ret2;
  if(err != -1)
  {
      if(MESSAGEOUT) MessageBox(NULL, getErrMsg(), «Ошибка», MB_OK);
      return ret;
  }
  int divvCol;
  int changeN = 0;                //Счетчик произведенных изменений на изображении
  list map;            //Карта точек принадлежащих линиям
  list::iterator imap;     //Итератор для map
  map = LookPic();                  //сканирование картинки и нахождение линий на ней
  do{
      changeN = 0;
      divvCol = (int)map.size();
      imap = map.begin();
      do{                                //Изображение можно модифицировать
          if(imap->pr1)     //Линия нуждается в обработке
             changeN += ChangeLine(imap, map);  //Обработка (преобразование) изображения
          imap++;                            //Переход для обработки следующей линии
      }while(imap != map.end());              //Изображение можно модифицировать
  }while(divvCol
  map = LookPic();                  //сканирование картинки и нахождение линий на ней
  imap = map.begin();
  do{                                //Изображение можно модифицировать
      ret.merge(ReadPic(imap));
      imap++;                         //Переход для обработки следующей линии
  }while(imap != map.end());          //Изображение можно модифицировать
////////////////////////////////////////////////////////////////////
/////////////////////Фильтрование полученных точек//////////////////
///отсеиваются близкостоящие направленные в противоположные строки//
//////////а так же точки слева и справа от которых нет линий////////
  int leftDots = 0;             //число отсеянных точек
  leftDots = DotsFilter(ret);     //Фильтрование полученных точек
////////////////////////////////////////////////////////////////////
  ret2.clear();
for(TAbsFing::iterator iter = ret.begin(); iter != ret.end(); iter++)
{   
  if(!iter->show) continue;
//рисование найденных точек (цвет окончания и раздвоения различный)
  COLORREF col = (iter->type)?0xFF0000:0x000000;
  pic2->Line(iter->coord, iter->coord, 5, col);
  pic2->Line(iter->coord,
             CPoint(iter->coord.x+(int)(10.0*cos(iter->alpha)),iter->coord.y-(int)(10.0*sin(iter->alpha))),
             2, col);
  ret2.push_back(*iter);
}
ret.clear();
  return ret2;
}
TAbsFing TAnalysePicture::ReadPic(list::iterator _dot)
//Нахождение на изображении спец точек
{
  TAbsFing retFing;     //Образ отпечатка в абсолютных координатах
  int kol = 0;         //количество пройденных точек
  int vec = 0;         //направление поиска очередной точки
  int tekS = 0;           //Текущее количество коротких векторов
  CPoint A,               //Начало вектора
          B;               //Конец вектора
  TAbsFing vecDotS;       //массив точек для коротких векторов
  TAbsFing vecDotL;       //массив точек для длинных векторов
  TAbsFing historyDotL;     //история точек для длинных векторов
    продолжение
--PAGE_BREAK--  TAbsDot _tmpDotFing, bestDot;
  TAbsFing::iterator iter;
  double alpha;             //направление вектора (в радианах)
  int stopKol = 2000;           //предел шагов
  int ret = 0;              //счетчик шагов после прохождения начальной точки
  bool homeOver = false;     //признак окончания обработки
 
  A = _dot->coord; B = _dot->coord;
  CPoint olddot, dot = _dot->coord;          //Текущая точка на линии
   
    do{
  //основной цикл обработки,
  //варианты завершения цикла
  //продолжается до тех пор пока вся линия не будет пройдена (нормальный вариант)
  //зацикливание (не нормальный вариант, их несколько)
  //
      olddot = dot;
      dot = pic->NextDotCW(dot, vec);        //Поиск следующей точки _по часовой_ стрелке
      if(dot.x == olddot.x && dot.y == olddot.y)
      {//положение точки не изменилось => выход//
          CString s;
          s.Format(«x = %d, y = %d, kol= %d», dot.x, dot.y, kol);
          if(MESSAGEOUT)MessageBox(0, «положение точки не изменилось => выход\n» + s, "", MB_OK);
          return retFing;
      }
      kol++;         //подсчет пройденных точек
      if(kol % LEN_S == 0)
      {//появился новый короткий вектор
          tekS++;
          A = B;
          B = dot;
pic2->Line(A,B, 1, 0x999999);
          _tmpDotFing.coord = A;
          alpha = GetAlpha(A, B);      //расчет локального направления между KOL_S пикселями (направление короткого вектора)//
          double dAlpha = 0.0;    //Разница углов
          if(vecDotS.size() > 0)     //в списке можно взять предыдущее значение
             dAlpha = alpha — vecDotS.begin()->alpha;
/**/        if (abs(dAlpha) >= M_PI) //разница между новым углом и предыдущим не нормальная!
          {//необходимо скорректировать текущую alpha
/**/            if (dAlpha
             {
                  while (abs(dAlpha) > M_PI)
                 {
                     alpha += 2.0 * M_PI;
                     dAlpha += 2.0 * M_PI;
                 }
             }else
             { 
                 while (dAlpha >= M_PI)
                 {
                     alpha -= 2.0 * M_PI;
                     dAlpha -= 2.0 * M_PI;
                 } 
             }
          }
          _tmpDotFing.alpha = alpha;     //запоминание направления из точки А//
          vecDotS.push_front(_tmpDotFing);
///////////////////////////////////////////////////////////////////////
///////проверяем два соседних длинных вектора при условии что//////////
///////пройдено достаточно точек, чтоб сравнивать длнинные вектора/////
          if(vecDotS.size()
//Вычисление среднего направления LEN_L коротких векторов//
//запись данных по длинному вектору////////////////////////
          double sumAlpha = 0.0;
          iter = vecDotS.begin();
          vecDotL.clear(); //пересчитаем длинные вектора
          for(int i = 0; i
          {
             sumAlpha += iter->alpha;
             if ((i+1) % LEN_L == 0)
             {
                 _tmpDotFing = *iter;
                 _tmpDotFing.alpha = sumAlpha / LEN_L;
                 vecDotL.push_back(_tmpDotFing);
                 sumAlpha = 0.0;
             }
             iter++;
          }
          if (abs(vecDotL.begin()->alpha) > 3*2*M_PI)
          {//слишком много оборотов//
             CString s;
             s.Format(«alpha = %.2f», vecDotL.begin()->alpha*180);
             if(MESSAGEOUT)MessageBox(0, «слишком много оборотов\n»+s, "", MB_OK);
             return retFing;
          }
//проверяем два соседних длинных вектора//
          dAlpha = vecDotL.begin()->alpha — (++vecDotL.begin())->alpha;
          if (abs(dAlpha) > (TEST_ALPHA / 180.0 * M_PI))   //сильный изгиб//
          {
             if (historyDotL.empty())
              { //сохранение состояния//
                 bestDot.alpha = 0.0;
             }
             if (dAlpha > 0)       //раздвоение
                 alpha = (vecDotL.begin()->alpha — M_PI + (++vecDotL.begin())->alpha) / 2.0;
             else             //окончание
                 alpha = (vecDotL.begin()->alpha + M_PI + (++vecDotL.begin())->alpha) / 2.0;
             _tmpDotFing = vecDotL.front();
             _tmpDotFing.alpha = alpha;        //направление в СТ (специфичная точка)//
             _tmpDotFing.type = dAlpha
             historyDotL.push_front(_tmpDotFing);
             if(bestDot.alpha
             { 
                 bestDot.coord = _tmpDotFing.coord;
                 bestDot.alpha = abs(dAlpha);
             }
          }
          else //сильный изгиб//
          {
             if (!historyDotL.empty())      //был _пройден_ сильный изгиб
             {
                 alpha = 0;
                 for(iter = historyDotL.begin(); iter != historyDotL.end(); iter++)
                     alpha += iter->alpha;
                 alpha /= historyDotL.size();      //среднее значение в пройденной СТ
                 iter = historyDotL.begin();
                 for(unsigned int i = 0; i
//                   CPoint wdot = iter->coord;          //наиболее вероятная точка для СТ
                 CPoint wdot = bestDot.coord;      //наиболее вероятная точка для СТ
//Если раскомментировать эти строки, то исключатся точки имеющие продолжение
//                   CPoint dotForAccept = FindAcceptDot(wdot, alpha, iter->type);
//                   if (dotForAccept.x == -1)
                 {  //точка не имеет продолжения, запомним ее//
                     _tmpDotFing.alpha = ChangeAlphaInterval(alpha);
                     _tmpDotFing.coord = wdot;
                     _tmpDotFing.show = true;
                     _tmpDotFing.type = historyDotL.begin()->type;
                     retFing.push_back(_tmpDotFing);
                 }
                 historyDotL.clear();
                 stopKol += (kol*1.5 > stopKol)?1000:0;
             }
          }
      }
      if (dot.x == _dot->coord.x && dot.y == _dot->coord.y)
      {//вероятно обход линии завершен
          if (kol
          {//Линия подозрительно короткая
             CString s;
             s.Format("%d", kol);
             if(MESSAGEOUT)MessageBox(0, «kol
             return retFing;
          }else
          {
             homeOver = true;   //пройти необходимо дальше начала
             stopKol = kol + KOL_L*LEN_L*LEN_S;
          }
      }
      if (homeOver) ret++;
  }while(ret
  _dot->pr1 = false;
  _dot->pr2 = false;
    return retFing;
}
list TAnalysePicture::LookPic()
//Попиксельное «пробегание» по картинке и
//запоминание черных точек, после нахождения черной точки
//заливка всей линии в цвет фона (удаление линии с картинки)
{
  list map;
  TMapElDot dot;
  tmpPic->Copy(*pic);
 
  for(int j = 0; j GetSize().y; j++)
      for(int i = 0; i GetSize().x; i++)
      {
          if(!tmpPic->GetPixel(i,j))      //найден черный пиксель
          {
             dot.coord.x = i; dot.coord.y = j;
             dot.pr1 = dot.pr2 = true;
             map.push_back(dot);
             tmpPic->FloodFill(i, j, 0xffffff);    //удаление линии
          }
      } 
  tmpPic->Copy(*pic);
  return map;
}
int TAnalysePicture::ChangeLine(list::iterator _dot, list &_map)
//Обработка картинки, ее изменение
//Обработка линии на которую указывает imap
//Исправление псевдо-раздвоений и псевдо-окончаний на указанной линии
{
  int changeN = 0;            //количество модификаций на линии
  int kol = 0;         //количество пройденных точек
  int vec = 0;         //направление поиска очередной точки
  int tekS = 0;           //Текущее количество коротких векторов
  CPoint A,               //Начало вектора
          B;               //Конец вектора
  TAbsFing vecDotS;       //массив точек для коротких векторов
  TAbsFing vecDotL;       //массив точек для длинных векторов
  TAbsFing historyDotL;     //история точек для длинных векторов
  TAbsDot _tmpDotFing;
  TAbsFing::iterator iter;
  TAbsDot resetDot, bestDot;
  double alpha;             //направление вектора (в радианах)
  int stopKol = 1500;           //предел шагов
  int ret = 0;              //счетчик шагов после прохождения начальной точки
  bool homeOver = false;     //признак окончания обработки
 
  _dot->pr1 = false;
  A = _dot->coord; B = _dot->coord;
  CPoint olddot, dot = _dot->coord;          //Текущая точка на линии
   
    do{
  //основной цикл обработки,
  //варианты завершения цикла
  //продолжается до тех пор пока вся линия не будет пройдена (нормальный вариант)
  //зацикливание (не нормальный вариант, их несколько)
  //
      olddot = dot;
      dot = pic->NextDotCW(dot, vec);        //Поиск следующей точки _по часовой_ стрелке
      if(dot.x == olddot.x && dot.y == olddot.y)
      {//положение точки не изменилось => выход//
          CString s;
          s.Format(«x = %d, y = %d, kol= %d», dot.x, dot.y, kol);
          if(MESSAGEOUT)MessageBox(0, «положение точки не изменилось => выход\n» + s, "", MB_OK);
          return changeN;
      }
      kol++;         //подсчет пройденных точек
      if(kol % LEN_S == 0)
      {//появился новый короткий вектор
          tekS++;
          A = B;
          B = dot;
//pic2->Line(A,B, 1, 0x999999);
          _tmpDotFing.coord = A;
          alpha = GetAlpha(A, B);      //расчет локального направления между KOL_S пикселями (направление короткого вектора)//
          double dAlpha = 0.0;    //Разница углов
          if(vecDotS.size() > 0)     //в списке можно взять предыдущее значение
             dAlpha = alpha — vecDotS.begin()->alpha;
/**/        if (abs(dAlpha) >= M_PI) //разница между новым углом и предыдущим не нормальная!
          {//необходимо скорректировать текущую alpha
/**/            if (dAlpha
             {
                 while (abs(dAlpha) > M_PI)
                 {
                     alpha += 2.0 * M_PI;
                     dAlpha += 2.0 * M_PI;
                 }
             }else
             { 
                 while (dAlpha >= M_PI)
                 {
                     alpha -= 2.0 * M_PI;
                     dAlpha -= 2.0 * M_PI;
                 } 
             }
          }
          _tmpDotFing.alpha = alpha;    //запоминание направления из точки А//
          vecDotS.push_front(_tmpDotFing);
///////////////////////////////////////////////////////////////////////
///////проверяем два соседних длинных вектора при условии что//////////
///////пройдено достаточно точек, чтоб сравнивать длнинные вектора/////
          if(vecDotS.size()
//Вычисление среднего направления LEN_L коротких векторов//
//запись данных по длинному вектору////////////////////////
          double sumAlpha = 0.0;
          iter = vecDotS.begin();
          vecDotL.clear(); //пересчитаем длинные вектора
          for(int i = 0; i
          {
             sumAlpha += iter->alpha;
             if ((i+1) % LEN_L == 0)
             {
                 _tmpDotFing = *iter;
                 _tmpDotFing.alpha = sumAlpha / LEN_L;
                 vecDotL.push_back(_tmpDotFing);
                 sumAlpha = 0.0;
             }
             iter++;
          }
          if (abs(vecDotL.begin()->alpha) > 3*2*M_PI)
          {//слишком много оборотов//
             CString s;
             s.Format(«alpha = %.2f», vecDotL.begin()->alpha*180);
             if(MESSAGEOUT)MessageBox(0, «слишком много оборотов\n»+s, "", MB_OK);
             return changeN;
          }
//проверяем два соседних длинных вектора//
          dAlpha = vecDotL.begin()->alpha — (++vecDotL.begin())->alpha;
          if (abs(dAlpha) > (TEST_ALPHA / 180.0 * M_PI))   //сильный изгиб//
          {
             if (historyDotL.empty())
             { //сохранение состояния//
                 resetDot = vecDotL.back();
                 bestDot.alpha = 0.0;
             }
             if (dAlpha > 0)       //раздвоение
                 alpha = (vecDotL.front().alpha — M_PI + (vecDotL.back().alpha)) / 2.0;
             else             //окончание
                 alpha = (vecDotL.front().alpha + M_PI + (vecDotL.back().alpha)) / 2.0;
             _tmpDotFing = vecDotL.front();
             _tmpDotFing.alpha = alpha;        //направление в СТ (специфичная точка)//
             _tmpDotFing.type = dAlpha
             historyDotL.push_front(_tmpDotFing);
             if(bestDot.alpha
             { 
                 bestDot.coord = _tmpDotFing.coord;
                 bestDot.alpha = abs(dAlpha);
             }
          }
          else //сильный изгиб//
          {
             if (!historyDotL.empty())      //был _пройден_ сильный изгиб
             {
                 alpha = 0.0;
                 for(iter = historyDotL.begin(); iter != historyDotL.end(); iter++)
                     alpha += iter->alpha;
                 alpha /= historyDotL.size();      //среднее значение в пройденной СТ
                 iter = historyDotL.begin();
                 for(unsigned int i = 0; i
                 CPoint wdot = bestDot.coord;      //наиболее вероятная точка для СТ
                 CPoint dotForAccept = FindAcceptDot(wdot, alpha, iter->type);
                 if (dotForAccept.x != -1)
                 {  //точка имеет продолжение//
                     COLORREF cl;
                     cl = (historyDotL.begin()->type)?0x000000:0xffffff;
//здесь можно поиграть с разной толщиной линии//
                     pic->Line(wdot, dotForAccept, 4, cl);
                     _dot->pr1 = true;   //эту линию необходио еще раз проанализировать
                     changeN++;
                     stopKol += (stopKol-kol
                     //stopKol += (kol*1.5 > stopKol)?500:0;
                     //загрузить начальное состояние
                     if(!historyDotL.begin()->type)
                     {  //если ликвидировано слипание то необходимо добавить новую точку на карту
                         _map.push_back(TMapElDot(dot));
                     }
//пройдена начальная точка, продлим анализ
//очень возможно, что начальную точку мы больше не попадем
                     if(ret-KOL_S*LEN_S
                     {
                         ret = 0;
                         homeOver = false;
                         stopKol = 500;
                     }
                     A = B = dot = resetDot.coord;
                     vecDotS.clear();    
                     vecDotL.clear();    
                     //------------------------------
                 }
                 historyDotL.clear();
             }
          }
      }
      if (dot.x == _dot->coord.x && dot.y == _dot->coord.y)
      {//вероятно обход линии завершен
          if (kol
          {//Линия подозрительно короткая
             CString s;
             s.Format("%d", kol);
             if(MESSAGEOUT)MessageBox(0, «kol
             return changeN;
          }else
          {
             homeOver = true;   //пройти необходимо дальше начала
             stopKol = kol + KOL_L*LEN_L*LEN_S;
          }
      }
      if (homeOver) ret++;
  }while(ret
    продолжение
--PAGE_BREAK--  _dot->pr2 = false;
    return changeN;
}
inline double TAnalysePicture::GetAlpha(const CPoint A, const CPoint B)
//Направлени из точки А в В [-pi,pi)
{
  if(A == B) return 0.0;
  double alpha;
  if (A.x — B.x == 0)
  {
      if (A.y > B.y) alpha = M_PI_2;
      else alpha = -M_PI_2;
  }else
  {
      double a = ((double)A.y-B.y)/((double)B.x-A.x);
      alpha = atan(a);
      if (A.x > B.x)
      {
          if (alpha
          else alpha -= M_PI;
          if (A.y == B.y) alpha = -M_PI;
      }
  }
  return alpha;
}
bool TAnalysePicture::TestFindDot(int _x, int _y)
//тест точки: Разность направлений вперед и назад должно быть меньше 110 градусов
{
  const int len = 7;
  CPoint A(_x, _y), B, C;
//первый вектор
  B = A;
  int vec = 0;
  for(int i = 1; i
      B = tmpPic->NextDotCW(B, vec);
  //------расчет угла-------//
  double alpha1 = GetAlpha(A, B);
//второй вектор
  C = B;
  B = A;
  vec = 0;
  for(int i = 1; i
  {
      B = tmpPic->NextDotCCW(B, vec);
      if(abs(B.x-C.x)
  }
  //------расчет угла-------//
  double alpha2 = GetAlpha(A, B);
//-----alpha1, alpha2------//
  alpha1 = abs(alpha2 — alpha1);
  if (alpha1 > M_PI) alpha1 = 2.0*M_PI — alpha1;
  return alpha1
}
CPoint TAnalysePicture::FindAcceptDot(CPoint dot, double alpha, bool type)
//Поиск продолжения из окончания/раздвоения
{
  const int maxL = 11;
  const int minL = 3;
  COLORREF color;
  color = (type)?0x000000:0xffffff;
      //окончание — ищем черную точку
      //раздвоение — ищем белую точку
  int i = 0;
  while (i
  {
      int l = minL;
      int k = (i+1) / 2;
      if (i % 2 == 1) k = -k;
      while (l
      {
          double arg = alpha + k * M_PI * 5.0/180.0;
          int x = dot.x + (int)(l*cos(arg)+0.5);
          int y = dot.y — (int)(l*sin(arg)+0.5);
          if (tmpPic->GetPixel(x, y) == color) //важное условие цвета точки!!!
          {
             if(TestFindDot(x,y))              //проверка найденной точки (на «вшивость» :) )
                 return CPoint(x, y);       //найденная точка
             else
                 break;
          }
          l++; //увеличение дальности поиска
      }
      i++;
  }
  return CPoint(-1, -1); //точка не найдена
}
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
                 ((abs(iter2->alpha — iter1->alpha) > (165.0/180.0*M_PI))&&(abs(iter2->alpha — iter1->alpha)
             )
              ||
             (  
             //или просто очень близкие точки (
                 (difL 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
  {
      l = minL;
      while(l
      {
          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
  {
      l= minL;
      while(l
      {
          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 вероятное направление поиска
{
  int i = 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]
      {
          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
  return dot;  //поиск ни к чему не привел
}
CPoint TFingPicture::NextDotCCW(const CPoint dot, int &vec)
//Поиск следующей точки "_против часовой_ стрелке"
//vec вероятное направление поиска
{
  int i = 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]
      {
          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
  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);
-          среда для разработки приложений Microsoft Visual Studio C++ 2003.
П.2.3. ХАРАКТЕРИСТИКА ПРОГРАММЫ
Программа FingerAnalyser требует для своего функционирования наличия в проекте файлов, содержащих растровые представления папиллярного узора.
В состав программы входят следующие файлы, необходимые для ее функционирования:
1)     FingerAnalyser.exe – исполняемый файл, содержащий основной интерфейс программы;
2)     MFC[1] – библиотеки для поддержки оконного среды;
3)     blank.bmp – пустое изображение;
    продолжение
--PAGE_BREAK--


    продолжение
--PAGE_BREAK--

    продолжение
--PAGE_BREAK--В большинстве случаев работа с важной информацией подразумевает также своевременное принятие решений и непрерывное управление ходом выполнения. В связи с этим существует необходимость непрерывного подтверждения личности (в случае если человек по какой-то причине покинет свое рабочее место, то любой в это время сможет задавать команды телеуправления или ответственные команды). Такое подтверждение личности метод «единого входа в сеть» предоставить не может, а вводить пароль после каждой команды – обременительно /4/.
Хотя на рынке существуют готовые системы, но на ряду со своими преимуществами они обладают рядом недостатков, таких как закрытость исходного кода и алгоритма, как следствие невозможность применения в своих системах, а также высокая цена. Вследствие чего есть смысл в разработке системы, которая бы предоставляла возможность всем разработчикам иметь готовую базу для разработки собственных проектов на основе биометрических технологий. А также предоставить объектное описание различных, не только папиллярного узора, изображений.
Целью данной работы является разработка и реализация такого преобразования изображения, при котором данные о расположение уникальных особенностей сохраняются наиболее полно и с наименьшим содержанием ложной информации.
Создаваемая система носит поисково-исследовательский характер и направлена на облегчение разработки алгоритмов обработки изображений, упрощение анализа экспериментальных данных и выявление общих закономерностей.
  1.1.4.  Обоснованиесоставаавтоматизируемыхзадач Реализация системы идентификации личности по отпечаткам позволит интегрировать в едином интерфейсе все этапы обработки изображения отпечатка пальца и сравнения его с другими отпечатками:
1)       анализ параметров изображения, выявление дефектов сканирования и их устранение;
2)       выделение локальных особенностей – минюций. формирование списка минюций в абсолютных параметрах;
3)       сортировка списка абсолютных параметров, исключение ложных  и ненадежных минюций;
4)       конвертирование абсолютных параметров в относительные, формирование списка относительных параметров;
5)       установка системы допусков для учета корреляции изображений;
6)       сравнение одного отпечатка с множеством других;
7)       способ хранения описания отпечатков позволяет применять результат работы программы для различных сфер деятельности.
1.2.         Аналитический обзор Как уже было указано во введении, метод опознавания личности по отпечаткам пальцев известен достаточно давно и с появлением электронно-вычислительной техники начали появляться программные продукты для анализа и сравнения изображений.
  1.2.1.  Фирма BioLink Ведущий поставщик технологий обеспечения безопасности, проектирует, производит и продает передовые биометрические продукты, основанные на принципе дактилоскопии. Предлагаемые решения составляют основу для систем аутентификации пользователей в компьютерных сетях, платформах электронной коммерции и системах обеспечения безопасности физического доступа.
BioLink предлагает гамму продуктов, основанных на фирменных технологиях сканирования отпечатков пальцев и обработки изображений, а также на алгоритме идентификации «один ко многим», решающих многие из существующих сегодня проблем безопасности /5/.
1.2.1.1.    Система управленияBioLinkBioTime2006 Система управления рабочим временем, являющаяся новейшей разработкой компании BioLink. Система BioTime 2006 упрощает обычные задачи учета и управления рабочим временем и обеспечивает простоту, легкость и удобство регистрации прихода и ухода сотрудников компании. Кроме того, система BioTime 2006 предоставляет различные виды отчетов по опозданиям, недоработкам и переработкам сотрудников, времени их прихода и ухода, а также автоматизирует создание табеля учета рабочего времени /5/.
1.2.1.2.    Программный сервер  BioLink Программный сервер BioLink Authenteon Software Appliance (ASA) — это программное обеспечение для сравнения шаблонов отпечатков пальцев BioLink. ASA объединяет в себе парольную защиту и клиент-серверную аутентификацию при входе в Windows, Novell и NFS при решении одной из самых актуальный на сегодняшний день проблем защиты — положительной идентификации пользователей корпоративной сети. Сервер поддерживает до 300 пользователей /5/.
1.2.2.  Microsoft IntelliMouse Explorer with Fingerprint Reader Анонсированная Microsoft осенью 2004 г. новая линейка продуктов с использованием биометрических технологий — сканер отпечатков пальцев, клавиатура со встроенным сканером и беспроводная оптическая мышь со сканером обладает возможностями /6/:
1)       снятие отпечатка пальца при кратковременном прикладывании пальца к сканеру;
2)       ведение менеджера паролей для веб интерфейсов;
3)       возможность идентификации личности для входа в систему одним приложением пальца.
Продукт подходит для применения за личным ПК. Программное обеспечение имеет очень ограниченную функциональность. Нет возможности получить параметры отсканированного отпечатка пальца, установить дополнительные действия от того какой палец был приложен.
1.2.3.  Сотовый телефон GI100 GI100 – первый телефон с функцией распознавания отпечатков пальцев. Отпечатки пальцев используются как для набора номера, так и для игр. Каждый из пальцев владельца телефона используются для быстрого набора одного из десяти введенных в память телефона номеров. Таким же образом и во время игр можно использовать вместо нажатия кнопок отпечатки пальцев.
Ограничение доступа – при включении телефона происходит сканирование отпечатка пальца включившего. Большим недостатком продукта является то, что в случае трехкратной неудачи при распознавании отпечатка пальца предлагается ввести пароль. Таким образом, доступ к телефону может получить не владелец, а просто знающий пароль человек /7/.
1.2.4.  РедакторAdobe Photoshop Профессиональный редактор растровых изображений. Основные возможности:
1)       контроль цвета и тона компонент изображения: возможность подбора палитры, замены цветов, поддержка 32-битного цвета (прозрачности), возможность построения гистограмм распределения цвета;
2)       интеллектуальное редактирование изображений: инструменты контекстной коррекции растра, позволяющие достичь фотореалистичности;
3)       широкий набор фильтров, позволяющих модифицировать и улучшить изображение;
4)       возможность создания многих независимых слоев в одном изображении.
Продукт предназначен для профессионального редактирования фотографических изображений, имеет мощный набор инструментов для улучшения их качества. В меньшей степени подходит для обработки искусственных изображений. Интерфейс обладает некоторой когнитивностью, которая, однако, ограничена сферой применения растровой модели /8/.
1.2.5.  Программа распознавания текста FineReader Профессиональная программа распознавания печатного текста. Основные возможности:
1)       загрузка изображения страницы из файла, получение изображения страницы со сканера;
2)       интеллектуальное определение расположения строк и символов в тексте, распознавание символов при их неточном сканировании или зашумлении;
3)       наличие возможности исправить неправильно распознанные символы;
4)       возможность сохранения распознанного текста в виде документа word или PDF.
Продукт предназначен для распознавания печатного текста различной сложности после сканирования, имеет мощный набор инструментов для улучшения качества распознавания, а также исправления неточно распознанных символов. Не имеет возможности дополнять набор распознаваемых символов, вследствие чего применение ограничивается только распознаванием печатного текста /9/.
1.2.6.  Вывод по аналитическому обзору Список программных продуктов, безусловно, может быть расширен, но все же самые характерные и популярные разработки в него включены.
Среди программных продуктов, посвященных идентификации по папиллярному узору, можно выделить основные возможности:
1)       программы реализуют возможность доступа по отпечаткам;
2)       возможна обработка стандартными функциями (яркость, контрастность, изменение размера);
3)       распознавание символов;
4)       ни одна программа не позволяет скорректировать изображение, основываясь на типичных характеристиках отпечатка, дать объектное описание отпечатка, а также дать возможность применить алгоритмы обработки в отдельности для собственных задач.
В связи с указанными особенностями существующих программных средств и в силу того, что применение биометрических способов позволяет увеличить защищенность и удобство пользования системами (см. п.п. 1.1.1) для большинства разработчиков будет удобным использование готового модуля работы с отпечатками пальцев. Поэтому актуальной является разработка системы, обладающая открытым кодом и позволяющая проводить структурное описание папиллярного узора. Возможность получать его объектное описание и сравнение. Применение алгоритма не только для описания изображения отпечатков пальцев, но и для объектного описания других битовых изображений, таких как символьная информация, шрифты и подписи.
Эту задачу решает система распознавания личности по отпечаткам пальцев.
1.3.         Основные требования к системе 1.3.1.  Основные цели создания системы и критерии эффективности ее функционирования Создание системы распознавания личности позволит получить новую возможность в сфере защиты и организации доступа к информации, а также разработке новых, эффективных алгоритмов по обработке растров и преобразованию их к структурному виду, разработать инструмент, улучшающий качество графической информации за счет снижения искажений и шумов.
Для оценки эффективности работы системы можно использовать качество получаемых на выходе изображений, и полноту их структурного описания. А также уровень правильного распознавания отпечатков, который можно судить по количеству отказов для правильного отпечатка, и количеству входов для неверного отпечатка /3/.
Разработанная система обладает открытым кодом, позволяет получать структурное описание папиллярного узора и его сравнение с другими папиллярными узорами. Алгоритм подходит для работы не только с изображениями отпечатков пальцев, но и для других битовых изображений, таких как символьная информация, шрифты и подписи.
1.3.2.  Функциональное назначение системы Реализация системы идентификации личности по отпечаткам позволит интегрировать в едином интерфейсе все этапы обработки изображения отпечатка пальца и сравнения его с другими отпечатками:
1)       модификация изображения, исправление искажений;
2)       выделение локальных особенностей – минюций. Формирование списка минюций в абсолютных параметрах;
3)       сортировка списка абсолютных параметров, исключение ложных  и ненадежных минюций;
4)       конвертирование абсолютных параметров в относительные, формирование списка относительных параметров;
5)       установка системы допусков для учета корреляции изображений;
6)       сравнение одного отпечатка с множеством других.
1.3.3.  Особенности системы и условия её эксплуатации Система идентификации личности по отпечаткам пальцев предназначена для работы с цифровыми изображениями, полученными посредством сканирования.
Получение электронного представления отпечатков пальцев с хорошо различимым папиллярным узором – достаточно сложная задача. Поскольку отпечаток пальца слишком мал, для получения его качественного изображения приходится использовать достаточно изощренные методы.
На сегодняшний момент можно выделить следующие сканеры отпечатков пальцев по используемым ими физическим принципам:
−         оптические;
−         кремниевые;
−         ультразвуковые.
Старейшей технологией сканирования отпечатка является – оптическая. Сканирование отпечатка пальца мини-камерами на ПЗС или КМОП-чипе позволило существенно уменьшить стоимость систем идентификации. Но этот способ снятия отпечатка сталкивается с некоторыми трудноразрешимыми проблемами: получаемый образ зависит от окружающего освещения, на границах образа возможны искажения, датчик может быть относительно легко «обманут» (некоторые дешевые датчики можно «дурачить» печатной копией, сделанной на обычном копире). Остаются проблемы и с размерами сканера. Датчик не может быть меньше, чем фокусное расстояние камеры. Среди главных преимуществ оптических систем можно еще раз упомянуть относительно низкую цену и практическую неуязвимость к воздействию электростатического разряда.
Абсолютно новой является технология использования электромагнитного поля. Датчик излучает слабый электромагнитный сигнал, который следует по гребням и впадинам отпечатка пальца и учитывает изменения этого сигнала для составления образа отпечатка. Такой принцип сканирования позволяет просматривать рисунок кожи под слоем омертвевших клеток, что приводит к хорошим результатам при распознавании бледных или стершихся отпечатков. Остается проблема отсутствия приемлемого соотношения между размером датчика и его разрешающей способностью.
Еще одна перспективная технология, которую следует упомянуть – ультразвуковая. Трехмерный ультразвуковой сканер измеряет пересеченную поверхность пальца своего рода радаром. Этот метод сканирования может быть особенно удобен, например, в здравоохранении. Он не требует касания каких-либо считывающих устройств датчика стерильными руками, а отпечаток легко считывается даже через резиновые или пластиковые перчатки хирурга. Главное неудобство ультразвуковой технологии — ее высокая стоимость и длительное время сканирования /10/.
Существуют и другие методы, либо использовавшиеся в прошлом, либо только разрабатываемые /11/.
1.3.4.  Требования к функциональной структуре Построение системы идентификации личности по отпечаткам пальцев предполагает модульную структуру. Общий интерфейс и возможность доступа ко всем модулям в составе системы должна обеспечивать оболочка. Из оболочки вызываются следующие модули: подсистема анализа изображения, подсистема сравнения одного отпечатка с множеством других. Обмен данными между подсистемами происходит через проект в рамках общей оболочки.
Подсистема анализа изображения должна обеспечивать возможность получения основных статистических характеристик папиллярного узора по ключевым участкам. Подсистема предполагает наличие средств для получения качественного образа отпечатка пальца.
Подсистема сравнения изображений отпечатков служит для автоматизированного выявления схожести различных изображений папиллярного узора.
1.3.5.  Требованияк техническомуобеспечению Задача обработки изображений в системе связана с автоматическим анализом больших массивов графической информации. Преобразования, проводимые в системе, должны проводиться в процессе интерактивного взаимодействия с пользователем, поэтому паузы на обработку не должны превышать нескольких секунд. Исходя из этого, сформулированы требования к техническим характеристикам персонального компьютера, на котором будет функционировать система. Требования сведены в табл. 1.1.
Таблица 1.1
Технические характеристики персонального компьютера
Наименование
Значение
Частота процессора, МГц
от 900
Объем оперативной памяти, Мб
от 64
Разрешение экрана монитора
не менее  1024x768
    продолжение
--PAGE_BREAK--

    продолжение
--PAGE_BREAK--
    продолжение
--PAGE_BREAK--Используемые переменные:
Dot0, dot1 – точки принадлежащие контуру обрабатываемой линии. Начальное значение dot0 = _dot;
vec0, vec1 – локальные направления;
step – шаг получения последующей точки;
alphaTest – предопределенная константа, определяющая сильное искривление контура папиллярной линии.
Используемые подпрограммы:
GetVec(dot0, dot1)– направление из точки dot0 в dot1;
NextDotCW(dot0, step) – получение координат точки следующей через step точек.
Раздвоение и окончание описаны в п.п. 2.3.4.
2.5.5.  ПодпрограммаDotsFilter Подпрограмма DotsFilter предназначена для сортировки списка найденных локальных особенностей и выделение списка минюций. Схема подпрограммы изображена на рис. 2.12.
Синтаксис:
int TAnalysePicture::DotsFilter(TAbsFing &_dots)
Входные данные для данной подпрограммы представлены:
TAbsFing &_dots – список точек найденный на растре, он содержит помимо нужных точек – минюций, лишние, непостоянные точки, которые не подходят для объектного описания папиллярного узора.
Выходные данные для данной подпрограммы представлены:
TAbsFing _dots – список параметров минюций, формат описан в
п.п. 2.1.3.
Используемые подпрограммы:
Порез(dot) – относится ли данная точка к точкам образованным порезами и инородными телами (см. п.п. 2.4.4);
Filter(dot1, dot2) – условие фильтрования (см. п.п. 2.4.4).
Схема подпрограммы «ReadPic»

Рис. 2.11

Схема подпрограммы «DotsFilter»
Рис. 2.12
2.5.6.  ПодпрограммаAnalysePicture Подпрограмма AnalysePicture предназначена для обработки загруженного изображения и получение из него объектного образа для последующего хранения и сравнения. Схема подпрограммы изображена на рис. 2.13.
Синтаксис:
TAbsFing TAnalysePicture::AnalysePicture()
Входные данные для данной подпрограммы представлены:
TFingPicture *pic – указатель на битовый образ в памяти, который был загружен для обработки.
Выходные данные для данной подпрограммы представлены:
TAbsFing Ret – список координат минюций в абсолютных параметрах, формат описан в п.п. 2.1.3.
Используемые переменные:
Map – список обрабатываемых линий на папиллярном узоре, каждой линии соответствует точка {x,y};
ChangeN – хранит количество сделанных изменений на растре.
Используемые подпрограммы:
LookPic – возвращает список линий на отпечатке;
ChangeLine(i, Map) – корректировка линии на растре, избавление от слипаний и обрывов;
ReadPic – возвращает список параметров специфических точек, см. формат в п.п. 2.1.3;
DotsFilter(Ret) – сортировка специфических точек, см. условия в п.п. 2.4.
2.6.         Описание контрольного примера 2.6.1.  Назначениепрограммы Основной целью работы программы является опознавание личности по отпечаткам пальцев на основе сравнения структурного представления папиллярных узоров. Контрольный пример должен содержать большое количество тестовых отпечатков пальцев, при этом отпечаток одного и того же пальца должен быть представлен как минимум в двух экземплярах для сравнения их между собой.
Схема подпрограммы «AnalysePicture».

Рис. 2.13
2.6.2.  Исходныеданные Для теста использовалось около 50 отпечатков разных людей и разного возраста. На рис. 2.14, 2.15, 2.16 приведены несколько изображений папиллярного узора, которые предполагается сравнить между собой и другими отпечатками в базе данных отпечатков. Данные изображения получены посредством зачернения пальца и приложения его к листу белой бумаги, после чего отпечатки были отсканированы и сохранены в виде bmp файлов на компьютере. Полученные таким образом отпечатки имеют не высокое качество, поэтому можно полностью проверить все этапы работы программы.
На рис. 2.14, 2.15 представлены отпечатки одного и того же пальца, а значит, в результате работы программы они должны совпасть. Рис. 2.16 это отпечаток другого пальца, нежели предыдущие два отпечатка.
Исходный образ A1

Рис. 2.14
Исходный образ A2

Рис. 2.15
Исходный образ B

Рис. 2.16
  2.6.3.  Контрольныйпример Результат работы подсистемы приведен на рис. 2.17, 2.18, 2.19 – это визуализированные структурные представления входных отпечатков.
Структурное представление A1

Рис. 2.17
Структурное представление A2

Рис. 2.18
Структурное представление B

Рис. 2.19
2.6.4.  Тестирование программного обеспечения системы распознавания личности по отпечаткам пальцев Для испытания программного обеспечения системы на вход были поданы тестовые образы, описанные в п.2.6.2. Испытания проводились согласно руководству программиста, приведенному в приложении 2, и руководству оператора, приведенному в приложении 3. В результате были получены структурные описания представленные на рис. 2.17, 2.18, 2.19.
Полученные структурные представления точно описывают входные образы, что не трудно проверить визуальным сравнением с входными образами. Статистически было выявлено, что на отпечатках имеется около 40..50 минюций, эта величина может варьироваться в больших пределах в зависимости от размеров пальца. На тестовых образах найдено 19, 40, 37 соответственно. Меньшее количество объясняется тем, что тестовые образы это лишь фрагменты полного отпечатка, а образ B это указательный палец, который меньше по размерам, чем большой.
В приложении 4 можно увидеть, что отпечатки A1 (1.bmp), A2 (R1_3rotate2.bmp) схожи между собой и схожи с отпечатком 1R1_1.bmp, что является верным, так как все они являются образами большого пальца правой руки одного и того же человека. Отпечаток B (3l2_2.bmp) не совпадает ни с одним из A1 и A2, но совпадает с 3l2_1.bmp, что является также верным результатом, это отпечатки указательного пальца правой руки другого человека.
Тестирование показало, что разработанное программное обеспечение способно сравнивать и отыскивать схожие отпечатки, а значит и есть возможность определить человека, которому принадлежит обрабатываемый отпечаток. Полученные результаты совпадают с ожидаемыми результатами и совпадают с ручным сравнением. Для проверки этого в приложении 4 приведено полное сравнение всех имеющихся отпечатков.
А также программа, после небольшой корректировки параметров анализа и сравнения, была настроена для распознавания символов алфавита. Для проверки был введен в базу данных набор символов изображенных на рис. 2.20, который в последующем сравнивался с алфавитом на рис. 2.21.
Алфавит для базы данных
                                                       Рис. 2.20
Алфавит для сравнения

                                              Рис. 2.21
В результате разработанный алгоритм, после минимальных изменений, стал пригоден для распознавания символов. Результаты работы приведены в приложении 5.

3.       ОРГАНИЗАЦИОННО-ЭКОНОМИЧЕСКАЯ ЧАСТЬ
3.1.         Обоснование необходимости разработки системы распознавания личности по отпечаткам пальцев Система распознавания личности по отпечаткам пальцев производит структурный анализ папиллярного узора посредством выделения на нем локальных особенностей. Разрабатываемая система носит исследовательский характер и предназначена для поиска и отладки наиболее эффективных алгоритмов обработки изображений. Реализация подсистемы позволит в значительной степени облегчить труд программиста-исследователя посредством автоматизации процесса поиска и выделения специфических точек на изображении.
Подсистема анализа изображения производит преобразование наиболее полно, с минимальным количеством недостоверных данных, в форму удобную для структурного анализа.
Установка защиты информации на основе дактилоскопии существенно усилит защиту от несанкционированного доступа и упростит этап идентификации пользователей и назначение им соответствующих прав доступа.
Таким образом, разработка системы позволит, помимо выполнения основной задачи – структурного анализа и идентификации, упростить работу с защитой данных и предоставлении доступа к ним.
3.2.         Расчет затрат на разработку системыраспознавания личности по отпечаткам пальцев Для определения величины расходов на создание подсистемы, используем прямой метод калькуляции.
Расчет сметы затрат осуществляется по следующим статьям
-        расходы на основные и вспомогательные материалы;
-        расходы на оплату труда исполнителей;
-        расходы на социальные программы;
-        расходы на содержание и амортизацию основных фондов;
-        накладные расходы;
-        прочие расходы.
К статье «Расходы на основные и вспомогательные материалы» относятся покупные изделия, необходимые для выполнения работы, перечисленные в табл. 3.1.
Таблица 3.1
Расходы на основные и вспомогательные материалы
Наименование материала
Количество
Стоимость, р.
Матрица CD-R
1 шт.
20
Матрица CD-RW
3 шт.
75
Бумага писчая 80 г.
250 листов
60
Тонер для принтера
1 шт.
70
Прочие канцелярские товары
25
Итого
250
Оклад инженера-программиста в период разработки составлял 5500 р. в месяц. Продолжительность разработки 3 месяца.
                                              ЗП = ЗПМ*ПМ                                                                (3.1)
ЗП = 5500 * 3 = 16500 руб.
К окладу начисляется премия. Процент премиальных составил 15% в месяц.
                                              ЗП,% = ЗП*1.15                                     (3.2)
ЗП,% = 16500 * 1.15 = 18975 руб.
Плановые накопления в фонд резерва отпусков (ЗД) рассчитывается в размере 10% от тарифной платы:
                                              ЗПД = ЗП * 0.10                                   (3.3)
ЗПД = 16500 * 0.10 = 1650 руб.
В расходы на оплату труда необходимо включить уральский коэффициент (15%). Районный коэффициент рассчитывается от оклада вместе с премиальными и дополнительной заработной платой.
КУР = (16500 + 1650) * 0.15 = 2722,50 руб.
Следовательно, расходы на оплату труда с учетом зонального коэффициента составят:
                                         ЗПОСН = ЗП,% + ЗПД + КУР                                       (3.4)
ЗПОСН = 18975 + 1650 + 2722.50 = 23347.50 руб.
Сумма налоговой базы не превышает 280000 руб., поэтому статья «Расходы на социальные налоги» включает в себя отчисления в пенсионный фонд (20%), на медицинское (3.1%) и социальное страхование (2.9%), отчисления в фонд страхования от несчастных случаев (0.2%), что составляет 26.2% /33/. Отчисления производятся от общих расходов на оплату труда и сумма отчислений составляет:
                                         СОТЧ = ЗПОСН * 0.262                              (3.5)
СОТЧ = 23347.50 * 0.262 = 3117.05 руб.
Статья «Расходы на амортизацию и содержание ВТ» включает расходы, связанные с эксплуатацией вычислительной техники. Стоимость одного машинного часа рассчитывается по формуле:
                                         АЧ = СИСП / (ЧМ * КЧ),                             (3.6)
где    АЧ – аренда за час использования;
СИСП – общая стоимость использования ЭВМ (рассчитывается по
формуле (3.7));
ЧМ – число месяцев в году;
КЧ – количество рабочих  часов  в  месяце.
                           СИСП = АКОМП + ЗПОБСЛ + СЗЧ + СЭЛ + АПО,          (3.7)
где    АКОМП – амортизация компьютера за год эксплуатации;
ЗПОБСЛ – расходы на оплату труда обслуживающего персонала за год эксплуатации;
ЗПОБСЛ = 1000 руб/мес
СЗЧ – стоимость запчастей для компьютера за год эксплуатации;
СЗЧ = 800 руб/год
СЭЛ – стоимость израсходованной электроэнергии за год эксплуатации;
СЭЛ = 1000 руб/год
АПО – годовая амортизация программного обеспечения.
                                           АКОМП = СКОМП / СПИ,                            (3.8)
где    СКОМП – стоимость компьютера;
СПИ – срок полезного использования (в годах);
АКОМП = 19000 / 5 = 3800 руб
                                         АПО = СТПО / СПИ,                                    (3.9)
где    СТПО – стоимость программного обеспечения;
СПИ – срок полезного использования (в годах);
АПО = 4000 / 5 = 800 руб
СИСП = 3800 + 1000*12 + 800 + 1000 + 800 = 18400 руб
АЧ = 18400 / (12 * 176) = 8,71 руб
ЭВМ использовалась на этапах проектирования (40 час), программирования (80 часов), отладки (320 часов) и документирования (160 часов), т.е. всего 600 часов. Следовательно, сумма амортизационных отчислений составит:
                                         САР = Эч * Ач                                          (3.10)
САР = 600 * 14.394 = 5227.40 руб.
Статья «Прочие расходы» содержит расходы, неучтенные в предыдущих статьях (до 50 % от расходов на оплату труда) :
                                       ПР = ЗПОСН * 0.5                                        (3.11)
ПР = 21337.50 * 0.5 = 10668.75 руб.
Статья «Накладные расходы» включает в себя расходы по управлению (заработная плата управления, расходы на все виды командировок управленческого аппарата), содержание пожарной и сторожевой охраны, содержание и текущий ремонт зданий, сооружений, инвентаря; содержание персонала, не относящегося к аппарату управления; расходы по изобретательству и рационализации; по подготовке кадров; расходы на содержание ВЦ; канцелярские, почтово-телеграфные расходы и др. общехозяйственные расходы; непроизводственные расходы. Накладные расходы составляют 130% от расходов на оплату труда, таким образом, получаем:
                                       НР = ЗПОСН * 1.3                                        (3.12)
НР = 23347.50 * 1.3 = 30351.75 руб.
Сумма затрат на разработку подсистемы в целом составила 76970 руб. Табл. 3.2 отражает затраты по статьям и структуру этих затрат в общей сумме.
Таблица 3.2
Смета затрат на разработку подсистемы
Статья затрат
Сумма затрат, руб.
Структура затрат, %
Расходы на материалы
250
0,3
Расходы на оплату труда
23350
30,3
Отчисления на социальные налоги
6120
8,0
Расходы на содержание и амортизацию ВТ
5230
6,8
Накладные расходы
30350
39,4
Прочие расходы
11670
15,2
Итого
76970
100
Округлим полученную сумму до тысяч для учета непредвиденных затрат. Получим, что сумма затрат на разработку системы составит 77000 руб.
Структура затрат на разработку ПО приведена на рис. 3.1.
Структура затрат на разработку ПО

Рис. 3.1

4.       БЕЗОПАСНОСТЬ И ЭКОЛОГИЧНОСТЬ ПРОЕКТА
4.1.         Анализ опасных и вредных факторов, возникающих при работе на компьютере Исследовательская работа в рамках данного проекта заключается в выполнении многих этапов, практически все из которых проходят в тесном контакте с ЭВМ. Длительная работа инженера-программиста с компьютером сопряжена с целым рядом вредных и опасных факторов. Рассмотрим некоторые из них.
Постоянное напряжение глаз
Работа с компьютером характеризуется высокой напряженностью зрительной работы. В выполняемом исследовании значительный объем информации на разных стадиях обработки представлен в графической форме с большим количеством мелких деталей, что дает серьезную нагрузку на зрение. Постоянное напряжение глаз может привести к снижению остроты зрения. Экран видеомонитора должен находиться от глаз пользователя на оптимальном расстоянии 600…700 мм, но не ближе 500 мм с учетом размеров алфавитно-цифровых знаков и символов. Также для снижения утомляемости рекомендуется делать 15-минутные перерывы в работе за компьютером в течение каждого часа.
Влияние электростатических и электромагнитных полей
    продолжение
--PAGE_BREAK--

    продолжение
--PAGE_BREAK--Температура воздуха является одним из основных параметров, характеризующих тепловое состояние микроклимата. Суммарное тепловыделение в помещении поступает от:
−         ЭВМ;
−         вспомогательного оборудования;
−         приборов освещения;
−         людей;
−         внешних источников.
Наибольшее количество теплоты выделяют ЭВМ и вспомогательное оборудование. Средняя величина тепловыделения от компьютеров колеблется до 100 Вт/м2. Тепловыделения от приборов освещения также велики. Удельная величина их составляет 35 Вт/м2.При этом, чем больше уровень освещенности, тем выше удельные величины тепловыделений. Количество теплоты от обслуживающего персонала незначительно. Оно зависит от числа работающих в помещении, интенсивности работы, выполняемой человеком.
К внешним источникам поступления теплоты относят теплоту, поступающую через окна от солнечной радиации, приток теплоты через непрозрачные ограждения конструкций. Интенсивность этих источников зависит от расположения здания, ориентации по частям света, цветовой гаммы и прочее.
С целью создания нормальных условий труда программиста, ГОСТом 12.1.005-88 установлены оптимальные и допустимые значения всех параметров микроклимата. Оптимальные параметры при длительном и систематическом воздействии на организм человека обеспечивают сохранение нормального функционирования и теплового состояния организма, создают ощущение теплового комфорта и являются предпосылкой высокого уровня работоспособности. Допустимые параметры микроклимата могут вызвать приходящие и быстро нормализующиеся изменения организма, не выходящие за пределы физиологически приспособительных возможностей, не создающие нарушений состояния здоровья, но вызывающие дискомфортные теплоощущения, ухудшение самочувствия и понижение работоспособности. Оптимальные и допустимые значения основных микроклиматических параметров представлены в табл. 4.5.
Для обеспечения нормальных условий труда необходимо придерживаться вышеуказанных данных. В целях поддержания температуры и влажности воздуха в помещении можно использовать системы отопления, вентиляции и кондиционирования воздуха.
Таблица 4.5
Параметры микроклимата производственных помещений
Параметры
Значения параметров
оптимальные
допустимые
Температура
20-22 °С
17-22 °С
Относительная влажность
40-60 %
до 75%
Скорость движения воздуха
0,1 м/с
не более 0,3 м/с
На исследуемом предприятии температура воздуха, влажность и скорость движения воздуха держится в рамках оптимальных параметров. Вредные вещества в воздухе рабочей зоны не превышают предельной допустимой концентрации.
4.5.         Требования к освещению и расчет искусственного освещения Организация рационального освещения рабочих мест является одним из основных вопросов охраны труда. Основные параметры освещения приведены в СНиП 23-05-95 «Естественное и искусственное освещение». Правильно спроектированное и выполненное производственное освещение сохраняет зрение рабочего, снижает утомляемость, способствует повышению производительности труда, качеству выпускаемой продукции, безопасности труда и снижению травматизма. Неправильно выбранные при проектировании осветительные приборы и аппаратура, а также нарушение правил их технической эксплуатации могут быть причиной пожара, взрыва, аварии на предприятии.
К современному освещению помещений, где работают с вычислительной техникой, предъявляют высокие требования как гигиенического, так и технического характера. Правильно спроектированное и выполненное освещение обеспечивает высокий уровень работоспособности, оказывает положительное психологическое воздействие, способствует повышению производительности труда. Условия деятельности пользователя в системе «человек-машина» связаны с явным преобладанием зрительной информации — до 90% общего объема.
В помещениях с компьютерной техникой применяется совмещенная система освещения. К таким системам предъявляют следующие требования:
1)     соответствие уровня освещенности рабочих мест характеру выполняемых зрительных работ;
2)     достаточно равномерное распределение яркости на рабочих поверхностях и в окружающем пространстве;
3)     отсутствие резких теней, прямой и отраженной блеклости.
4)     постоянство освещенности во времени;
5)     оптимальная направленность излучаемого осветительными приборами светового потока;
6)     долговечность, экономичность, пожаробезопасность, эстетичность, удобство и простота эксплуатации.
Искусственное освещение в помещениях эксплуатации ЭВМ должно осуществляться системой общего равномерного освещения. В производственных и административно-общественных помещениях, в случаях преимущественной работы с документами, допускается применение системы комбинированного освещения (к общему освещению дополнительно устанавливаются светильники местного освещения, предназначенные для освещения зоны расположения документов).
Согласно СНиП /34/ освещенность при системе общего освещения составляет 200 лк, а при системе комбинированного освещения 400 лк, в том числе от общего освещения 200 лк.
Для искусственного освещения помещений с вычислительной техникой следует использовать люминесцентные лампы, у которых высокая световая отдача (до 75 лм/Вт и более), продолжительный срок службы (до 10000 ч), малая яркость светящейся поверхности, близкий к естественному спектр излучения, что обеспечивает хорошую цветопередачу. Наиболее приемлемыми являются люминесцентные лампы белого света и тепло-белого света мощностью 40, 80 Вт.
Для исключения засветки экранов дисплеев прямым световым потоком, светильники общего освещения располагают сбоку от рабочего места, параллельно линии зрения пользователя и стене с окнами. Такое расположение светильников позволяет производить их последовательное включение по мере необходимости и исключает раздражение глаз чередующимися полосами света и тени, возникающее при поперечном расположении светильников.
При периметральном расположении компьютеров линии светильников должны располагаться локализовано над рабочим столом ближе к его переднему краю, обращенному к оператору.
Для обеспечения оптимальных условий зрительных работ для пользователей дисплейных устройств необходима определенная световая отделка помещения.
Следует ограничивать неравномерность распределения яркости в поле зрения пользователя ЭВМ, при этом соотношение яркости между рабочими поверхностями не должно превышать 3:1 - 5:1, а между рабочими поверхностями и поверхностями стен и оборудования – 10:1.
Освещенность рабочего места пользователя на исследуемом предприятии является совмещенной (искусственное + естественное), расположение рабочих мест исключает попадание прямых солнечных лучей на экран дисплея и в глаза. В качестве источника искусственного освещения используют люминесцентные лампы белого света  мощностью 40 Вт. Точность зрительной работы характеризуется размером объекта различения. Объект различения — это элемент рассматриваемого объекта минимального размера, который нужно узнавать и различать (элемент буквы или толщина ее начертания, размер отдельных деталей или расстояние между ними и т.п.). По степени точности все зрительные работы делятся на восемь разрядов.
Для естественного освещения нормируется коэффициент естественного освещения (КЕО), который определяется с помощью освещенности в данной точке внутри помещения и освещенности снаружи помещения. Причем нужно отметить, что КЕО при IV разряде зрительных работ должно быть не менее 1,2.
Для искусственного освещения нормируемым параметром является освещенность. В зависимости от контраста объекта с фоном и яркости фона каждый из восьми разрядов зрительных работ подразделяется на четыре подраздела, для каждого из которого нормируется освещенность. Например, при IV разряде зрительных работ нормированное значение освещенности принимает 400 лк.
Необходимый уровень освещенности тем выше, чем темнее фон, меньше объект различения и контраст объекта с фоном.
Наиболее часто для расчета искусственного освещения используется метод коэффициента использования осветительной установки, который сводится к определению светового потока:
,
где FЛ – световой поток источника света, лм;
ЕН – нормированное значение освещенности — ЕН=400 лк (разряд зрительной работы IV(в), комбинированное освещение);
кз – коэффициент запаса, кз=1.3;
Sn – площадь рабочей поверхности помещения, Sn=4´5=20 (м2);
Z – поправочный коэффициент, численно равный отношению средней освещенности к минимальной, Еср/Emin – Z=1,1;
n – количество источников света — n=12;
И – коэффициент использования осветительной установки, значение которого зависит от типа светильника, коэффициента отражения стен rс, потолка rп, рабочей поверхности rр, размеров освещаемого помещения (индекса помещения).
Для определения индекса помещения следует применять уравнение:
,
где b, ln – соответственно ширина и длина освещаемого помещения;
Нр – высота подвеса светильников над рабочей поверхностью.
Коэффициент использования светового потока светильников с лампами накаливания И определяем по таблице, приведенной в СНиП 23-05-95, с помощью следующих значений:
; rр=0,1; rс=0,2; rп=0,7.
В итоге И = 0,73.
Соответственно:

Для полученного значения светового потока источника света FЛ=3130 лм наиболее подходят два типа ламп накаливания: ЛБ40-М и ЛД65-7.
Все необходимые данные определены в СНиП 23-05-95.
4.6.         Пожарная безопасность Помещение, в котором установлено рабочее место инженера-программиста, относится к категории “Д” по взрывопожароопасности, так как не содержит горючих веществ, но лишь негорючие вещества и материалы в холодном состоянии.
Пожары в помещении, в котором находится ЭВМ, представляют особую опасность, так как сопряжены с большими материальными потерями. Площадь помещения, в котором ведется проектирование, невелика и составляет 8 м2. Как известно пожар может возникнуть при взаимодействии горючих веществ, окисления и источников зажигания. В помещении присутствуют все три основные фактора, необходимые для возникновения пожара. Горючими компонентами являются: строительные материалы для акустической и эстетической отделки помещений, двери, полы, бумага, изоляция кабелей и др.
Противопожарная защита — это комплекс организационных и технических мероприятий, направленных на обеспечение безопасности людей, на предотвращение пожара, ограничение его распространения, а также на создание условий для успешного тушения пожара.
Источниками зажигания в помещении, содержащем ЭВМ, могут быть электронные схемы от ЭВМ, приборы, применяемые для технического обслуживания, устройства электропитания, где в результате различных нарушений образуются перегретые элементы, электрические искры и дуги, способные вызвать загорания горючих материалов.
В современных ЭВМ очень высока плотность размещения элементов электронных схем. В непосредственной близости друг от друга располагаются соединительные провода, кабели. При протекании по ним электрического тока выделяется значительное количество теплоты. При этом возможно оплавление изоляции. Для отвода избыточной теплоты от ЭВМ служат системы вентиляции и кондиционирования воздуха. При постоянном действии эти системы представляют собой дополнительную пожарную опасность.
Одной из наиболее важных задач пожарной защиты является защита строительных помещений от разрушений и обеспечение их достаточной прочности в условиях воздействия высоких температур при пожаре. Учитывая высокую стоимость электронного оборудования, а также категорию его пожарной опасности, здания, в которых предусмотрено размещение ЭВМ должны быть 1 и 2 степени огнестойкости.
К средствам тушения пожара, предназначенных для локализации небольших возгорании, относятся пожарные стволы, внутренние пожарные водопроводы, огнетушители, сухой песок, асбестовые одеяла и т. п.
В соответствии с “Типовыми правилами пожарной безопасности для промышленных предприятий” залы ЭВМ, помещения для внешних запоминающих устройств, подготовки данных, сервисной аппаратуры, архивов, копировально-множительного оборудования и т.п. необходимо оборудовать дымовыми пожарными извещателями. В этих помещениях в начале пожара при горении различных пластмассовых, изоляционных материалов и бумажных изделий выделяется значительное количество дыма и мало теплоты.
Помещение, в котором производится разработка данного проекта, необходимо оборудовать средствами оповещения о пожаре, а также средствами для тушения пожара.
В данном разделе дипломной работы был проведен анализ вредных и опасных производственных факторов, действующих на рабочем месте инженера-программиста. Среди них были выделены: постоянное напряжение глаз, влияние электростатических и электромагнитных полей, длительное неизменное положение тела, шум. Был проведен анализ и указан комплекс мер по пожаробезопасности и электробезопасности. Проведен расчет эргономических требований к рабочему месту инженера-программиста. Созданные условия должны обеспечивать комфортную ра­бо­ту. На основании изученной литературы по данной проблеме, были указаны опти­маль­ные размеры рабочего стола и кресла, параметры рабочей поверхности, а также сформулированы предложения по улучшению параметров рабочего места. Соблюдение условий, определяющих оптимальную организацию рабочего места инженера-программиста, позволит сохранить хорошую работоспособность в течение всего рабочего дня, повысит как в количественном, так и в качественном отношениях производительность труда программиста, что в свою очередь будет способствовать быстрейшей разработке и отладке программного продукта.

ЗАКЛЮЧЕНИЕ В результате проделанной работы был разработан метод автоматизации поиска схожих отпечатков и реализована программа, для данного метода. Программа позволяет за приемлемое время автоматически определять личность по отпечатку пальца посредством выделения локальных особенностей. По сравнению с ручным определением получен значительный выигрыш в скорости и удобстве использования.
Разработанная подсистема является неотъемлемой частью системы идентификации личности. Обработка позволяет улучшить качество отпечатка. Получаемые характеристики достаточно полно описывают изображение, это представление удобно для хранения и позволяет провести распознавание с высокой степенью точности.
Созданную подсистему следует рассматривать как исследовательскую подсистему, предназначенную для преобразования растрового представления изображения к структурному представлению, которое пригодно для компактного хранения и дальнейшей разработки в направлении большей автоматизации и других сфер деятельности.
Разработанная система реализует новый вид функциональности – подготовку изображений к автоматизированному структурному анализу.

ЛИТЕРАТУРА 1)           Биометрические технологии – альтернатива персональным идентификационным номерам и паролям // k2kapital.com Аналитические обзоры 8 мая 2000. www.k2kapital.com/archives/research/rs20000508.html  Проверено: 16.05.06.
2)           Завгородний В.И. Комплексная защита информации в компьютерных системах // Учебное пособие. — М.: Мир, 2001. – 264 с.
3)           Виталий Задорожный. Области применения и принципы построения биометрических систем // PC Magazine/Russian Edition 21 апреля 2004. www.pcmag.ru/?ID=447314&4Print=1. Проверено 16.05.06.
4)           Долгий И.Д. Ковалев С.М., Кулькин С.А. К вопросу об идентификации личности в системе «Диспетчерской централизации» // Ростовский государственный университет путей сообщения, 2003. pitis.tsure.ru/files24/03.pdf. Проверено 16.05.06.
5)           ООО «Биолинк Технолоджис». Продукты: BioLink BioTime 2006; BioLink Authenteon Software Appliance (ASA) // BioLink, 2001. biolink.ru Проверено 16.05.06.
    продолжение
--PAGE_BREAK--6)           Документация «Microsoft IntelliMouse Explorer with Fingerprint Reader» // Microsoft, 2004.
7)           Первый телефон с функцией распознавания отпечатков пальцев.  // ИА Клерк.Ру, 04.08.2004. www.klerk.ru/soft/n/?11433.  Проверено 16.05.06.
8)           Бойер, П. Флостер Д. Использование Adobe Photoshop 7. Специальное издание. – М.: Вильямс, 2004.
9)           Руководство пользователя для FineReader 8.0 // 1996-2006 ABBYY Software. www.abbyy.com/DLCenter/downloadcentermanager.aspx?file=/fr80/guides/Guide_Russian.pdf. Проверено 16.05.06.
10)      Сканеры отпечатков пальцев. // BIOMETRICS.RU 2002-2006,  http://cyberdefend.narod.ru/biometric_devices.htm Проверено 16.05.06.
11)      Задорожный В.В. Идентификация по отпечаткам пальцев. //  PC Magazine/Russian Edition №1, 2004, — C. 25 — 35.
12)      Геннадий Рябов. Современные технологии идентификации личности по отпечатку пальца с использованием емкостных датчиков. //  radioradar.net, 2004. www.radioradar.net/staty/identif_otpech.php.  Проверено 16.05.06.
13)      Гончаров Д., Салихов Т. DirectX 7.0 для программистов //  - С.-Пб.: Питер, 2001. — 528 с.
14)      Прэтт У. Цифровая обработка изображений. Т. 1. — М.: Мир, 1982. – 312 с.
15)      Дуда Р., Харт П. Распознавание образов и анализ сцен. — М.: Мир, 1976. – 511 с.
16)      Аммерал Л. Принципы программирования в машинной графике. — М.: Сол Систем, 1992.
17)      Анисимов Б.В., Курганов В.Д., Злобин В.К. Распознавание и цифровая обработка изображений. — М.: Высшая школа, 1983. — 256 с.
18)      Бутаков А., Островский В. И., Фадеев И.Л. Обработка изображений на ЭВМ. — М.: Радио и связь, 1987.
19)      Гренандер У. Лекции по теории образов. — М.: Мир, 1979. – Т. 1-3.
20)      Павлидис Т. Алгоритмы машинной графики и обработки изображений. — М.: Радио и связь, 1986.
21)      Ту Дж., Гонсалес Р. Принципы распознавания образов. — М.: Мир, 1976.
22)      Файн В.С. Опознавание изображений. – М.: Наука, 1970.
23)      Розенфельд А. Распознавание и обработка изображений с помощью ЭВМ. — М.: Мир, 1972.
24)      Строустрап Б. Язык программирования С++. – М.: Мир, 1994. – 278 с.
25)      Кнут Д. Искусство программирования для ЭВМ. — М.: Мир, 1976. – Т. 1-3.
26)      Шилдт Г. Самоучитель С++. — С-Пб.: БВХ-Петербург, 2002. 3 издание.
27)      Тихомиров Ю. OpenGL Программирование трехмерной графики.  - С-Пб.: БВХ-Петербург, 2002г. 2 издание.
28)      Шибаева И.В., Мурынов А.И., Пивоваров И.В. Математические и программные средства распознавания графических изображений для передачи по цифровым каналам связи // Информационные технологии в науке, образовании, телекоммуникациях и бизнесе: Материалы 31 Междунар. конф. – Украина, Крым, Ялта–Гурзуф: Ж. «Успехи современного естествознания» №5, 2004, Прилож. №1. – 114 c.
29)      Соболева В.П. Методические указания по оформлению курсовых работ, курсовых и дипломных проектов. – Ижевск: Издательство ИМИ, 2003.
30)      Эйнджел Э. Интерактивная компьютерная графика. – М.: Вильямс, 2001. – 592 с.
31)      ГОСТ 12.1.006–84. ССБТ. Электромагнитные поля радиочастот. Допустимые уровни  на рабочих местах и требования к проведению контроля. – М.: Издательство стандартов, 1985.
32)      СанПиН 2.2.2.542-96. Гигиенические требования к видео-дисплейным терминалам, персонально-вычислительным машинам и организация работ. – М.: Госкомсанэпиднадзор России, 1996.
33)      Налоговый кодекс РФ. – М.: ГроссМедиа Ферлаг, 2004. – 432 с.
34)      ГОСТ 12.1.009-76. ССБТ. Электробезопасность. Термины и определения.
– М.: Издательство стандартов, 1985.
35)      ГОСТ 19.505-79 ЕСПД. Руководство оператора. Требования к содержанию и оформлению. – М.: Издательство стандартов, 1979.
36)      ГОСТ 19.504-79 ЕСПД. Руководство программиста. Требования к содержанию и оформлению. – М.: Издательство стандартов, 1979.
37)      ГОСТ 19.701-90 ЕСПД. Схемы алгоритмов и программ. Правила выполнения. – М.: Издательство стандартов, 1991.
38)      Технико-экономическое обоснование дипломных проектов при разработке приборов и методов контроля качества. Методические указания для студентов. – Ижевск: Издательство ИжГТУ, 2001.
39)      Почерняев С.В., Килин И.В. Методические указания по дипломному  проектированию. – Ижевск: Издательство ИжГТУ, 1994.

ПРИЛОЖЕНИЕ 1   ТЕКСТ ПРОГРАММЫ П.1.1. ТЕКСТ МОДУЛЯ Resource.h
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by FingerAnalyser.rc
//
#define IDM_ABOUTBOX                    0x0010
#define IDD_ABOUTBOX                    100
#define IDS_ABOUTBOX                    101
#define IDD_FINGERANALYSER_DIALOG       102
#define IDR_MAINFRAME                   128
#define IDR_TOOLBAR                     130
#define IDI_FING_ICON                   135
#define IDR_MENU1                       138
#define IDC_OPEN_FILE                   1000
#define IDC_ANALYSE                     1001
#define IDC_COMPARE                     1002
#define IDC_EXIT                        1003
#define IDC_SAVE_TO_DB                  1004
#define IDC_SPEC_DOT                    1005
#define IDC_LOAD_PROGRESS               1006
#define IDC_WORK_FILE                   1007
#define IDC_LOAD_COMPARE_PROGRESS       1008
#define IDC_TEMESCAN                    1009
#define IDC_BUTTON_PREV                 1012
#define IDC_BUTTON_NEXT                 1013
#define IDC_SHOW_BASE                   1014
#define IDC_EDIT1                       1015
#define ID_BASE                         32771
#define ID_PROPERTY                     32772
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE        139
#define _APS_NEXT_COMMAND_VALUE         32774
#define _APS_NEXT_CONTROL_VALUE         1016
#define _APS_NEXT_SYMED_VALUE           101
#endif
#endif
П.1.2. ТЕКСТ МОДУЛЯ FingAnalyser.h
// FingerAnalyser.h: main header file for the PROJECT_NAME application
//
#pragma once
#ifndef __AFXWIN_H__
  #error include 'stdafx.h' before including this file for PCH
#endif
#include «resource.h»      // main symbols
// CFingerAnalyserApp:
// See FingerAnalyser.cpp for the implementation of this class
//
class CFingerAnalyserApp: public CWinApp
{
public:
  CFingerAnalyserApp();
// Overrides
  public:
  virtual BOOL InitInstance();
// Implementation
  DECLARE_MESSAGE_MAP()
};
extern CFingerAnalyserApp theApp;
П.1.3. ТЕКСТ МОДУЛЯ FingAnalyser.cpp
// FingerAnalyser.cpp: Defines the class behaviors for the application.
//
#include «stdafx.h»
#include «FingerAnalyser.h»
#include «FingerAnalyserDlg.h»
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CFingerAnalyserApp
BEGIN_MESSAGE_MAP(CFingerAnalyserApp, CWinApp)
  ON_COMMAND(ID_HELP, CWinApp::OnHelp)
END_MESSAGE_MAP()
// CFingerAnalyserApp construction
CFingerAnalyserApp::CFingerAnalyserApp()
{
  // TODO: add construction code here,
  // Place all significant initialization in InitInstance
}
// The one and only CFingerAnalyserApp object
CFingerAnalyserApp theApp;
// CFingerAnalyserApp initialization
BOOL CFingerAnalyserApp::InitInstance()
{
  CWinApp::InitInstance();
  // Standard initialization
  // If you are not using these features and wish to reduce the size
  // of your final executable, you should remove from the following
  // the specific initialization routines you do not need
  // Change the registry key under which our settings are stored
  // TODO: You should modify this string to be something appropriate
  // such as the name of your company or organization
  SetRegistryKey(_T(«Local AppWizard-Generated Applications»));
  CFingerAnalyserDlg dlg;
  m_pMainWnd = &dlg;
  INT_PTR nResponse = dlg.DoModal();
  if (nResponse == IDOK)
  {
      // TODO: Place code here to handle when the dialog is
      //  dismissed with OK
  }
  else if (nResponse == IDCANCEL)
  {
      // TODO: Place code here to handle when the dialog is
      //  dismissed with Cancel
  }
  // Since the dialog has been closed, return FALSE so that we exit the
  //  application, rather than start the application's message pump.
  return FALSE;
}
П.1.4. ТЕКСТ МОДУЛЯ FingAnalyserDlg.h
// FingerAnalyserDlg.h: header file
//
#pragma once
#include «TFingPicture.h»
#include «afxcmn.h»
typedef list listTInfo;
// CFingerAnalyserDlg dialog
class CFingerAnalyserDlg: public CDialog
{
// Construction
public:
  CFingerAnalyserDlg(CWnd* pParent = NULL); // standard constructor
  ~CFingerAnalyserDlg();    // деструктор
// Dialog Data
  enum { IDD = IDD_FINGERANALYSER_DIALOG };
  protected:
  virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
// Implementation
protected:
  HICON m_hIcon;
  CDC memDC;
  CBitmap bm;
  BITMAP bmp;
  UINT timer;
  TFingPicture *fp;
  // Generated message map functions
  virtual BOOL OnInitDialog();
  afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
  afx_msg void OnPaint();
  afx_msg HCURSOR OnQueryDragIcon();
  DECLARE_MESSAGE_MAP()
public:
  afx_msg void OnBnClickedOpenFile();
  afx_msg void OnBnClickedExit();
  afx_msg void OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized);
  afx_msg void OnBnClickedAnalyse();
  afx_msg void OnBnClickedCompare();
  afx_msg void OnTimer(UINT nIDEvent);
  afx_msg void OnEnChangeSpecDot();
  int m_kolDots;
  afx_msg void OnBnClickedSaveToDb();
  CProgressCtrl loadProgress;
public:
  listTInfo *LoadDB(CString dbFile);
  list *CompareWithBase();
  CString m_workFile;
  CProgressCtrl compare_progress;
  long m_scantime;
  afx_msg void OnBnClickedButtonPrev();
  list *compareResult;
  list::iterator showIter;
  afx_msg void OnBnClickedButtonNext();
  void ShowBase(bool key, bool next = true);
  void PrintReport(CString file, CString report);
  CString GetSAV(CString srcName);        //получение пути к sav файлу
  BOOL m_show_base;
  afx_msg void OnBnClickedShowBase();
  afx_msg void OnMouseMove(UINT nFlags, CPoint point);
  CPoint mouse_pos;
  int m_mouse_x;
  int m_mouse_y;
  afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
};
П.1.5 ТЕКСТ МОДУЛЯ FingAnalyserDlg.cpp
// FingerAnalyserDlg.cpp: implementation file
//
#include «stdafx.h»
#include «FingerAnalyser.h»
#include «FingerAnalyserDlg.h»
#include «TAnalysePicture.h»
#include ".\fingeranalyserdlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
CString sav_path, db_file;
TAnalysePicture *picture;
TAbsFing fingA;
TRelFing fingR;
// CAboutDlg dialog used for App About
class CAboutDlg: public CDialog
{
public:
  CAboutDlg();
// Dialog Data
  enum { IDD = IDD_ABOUTBOX };
  protected:
  virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
// Implementation
protected:
  DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg(): CDialog(CAboutDlg::IDD)
{}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
  CDialog::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
END_MESSAGE_MAP()
// CFingerAnalyserDlg dialog
CFingerAnalyserDlg::CFingerAnalyserDlg(CWnd* pParent /*=NULL*/)
 : CDialog(CFingerAnalyserDlg::IDD, pParent)
 , m_kolDots(0)
 , m_workFile(_T(""))
 , m_scantime(0)
 , m_show_base(FALSE)
 , m_mouse_x(0)
 , m_mouse_y(0)
{
  m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
CFingerAnalyserDlg::~CFingerAnalyserDlg()
{
  delete(fp);
  delete(picture);
  if(compareResult)
  { 
      for(list::iterator i = compareResult->begin();
          i != compareResult->end();
          i++)
      { 
          list::iterator j;
          for(j=i->surdots.begin(); j!=i->surdots.end(); j++)
          {
             j->first->clear();  delete(j->first);
             j->second->clear(); delete(j->second);
          }
      }
      compareResult->clear();
      delete(compareResult);
      compareResult = NULL;
  }
}
void CFingerAnalyserDlg::DoDataExchange(CDataExchange* pDX)
{
  CDialog::DoDataExchange(pDX);
  DDX_Text(pDX, IDC_SPEC_DOT, m_kolDots);
  DDX_Control(pDX, IDC_LOAD_PROGRESS, loadProgress);
  DDX_Text(pDX, IDC_WORK_FILE, m_workFile);
  DDX_Control(pDX, IDC_LOAD_COMPARE_PROGRESS, compare_progress);
  DDX_Text(pDX, IDC_TEMESCAN, m_scantime);
  DDX_Check(pDX, IDC_SHOW_BASE, m_show_base);
}
BEGIN_MESSAGE_MAP(CFingerAnalyserDlg, CDialog)
  ON_WM_SYSCOMMAND()
  ON_WM_PAINT()
  ON_WM_QUERYDRAGICON()
  //}}AFX_MSG_MAP
  ON_BN_CLICKED(IDC_OPEN_FILE, OnBnClickedOpenFile)
  ON_BN_CLICKED(IDC_EXIT, OnBnClickedExit)
  ON_WM_CLOSE()
  ON_WM_ACTIVATE()
  ON_BN_CLICKED(IDC_ANALYSE, OnBnClickedAnalyse)
  ON_BN_CLICKED(IDC_COMPARE, OnBnClickedCompare)
  ON_WM_TIMER()
  ON_BN_CLICKED(IDC_SAVE_TO_DB, OnBnClickedSaveToDb)
  ON_BN_CLICKED(IDC_BUTTON_PREV, OnBnClickedButtonPrev)
  ON_BN_CLICKED(IDC_BUTTON_NEXT, OnBnClickedButtonNext)
  ON_BN_CLICKED(IDC_SHOW_BASE, OnBnClickedShowBase)
  ON_WM_MOUSEMOVE()
  ON_WM_LBUTTONDOWN()
END_MESSAGE_MAP()
// CFingerAnalyserDlg message handlers
BOOL CFingerAnalyserDlg::OnInitDialog()
{
  CDialog::OnInitDialog();
  ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
  ASSERT(IDM_ABOUTBOX
  CMenu* pSysMenu = GetSystemMenu(FALSE);
  if (pSysMenu != NULL)
  {
      CString strAboutMenu;
      strAboutMenu.LoadString(IDS_ABOUTBOX);
      if (!strAboutMenu.IsEmpty())
      {
          pSysMenu->AppendMenu(MF_SEPARATOR);
          pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
      }
  }
  // Set the icon for this dialog.  The framework does this automatically
  //  when the application's main window is not a dialog
  SetIcon(m_hIcon, TRUE);        // Set big icon
  SetIcon(m_hIcon, FALSE);       // Set small icon
  fp = new TFingPicture(this->GetDC());
  char fullpath[200];
  _fullpath(fullpath, NULL, 200);
  sav_path = fullpath;
  sav_path += "\\sav\\";
  db_file = sav_path + «fingbase.bse»;
  compareResult = NULL;
  return TRUE;  // return TRUE  unless you set the focus to a control
}
void CFingerAnalyserDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
  if ((nID & 0xFFF0) == IDM_ABOUTBOX)
  {
      CAboutDlg dlgAbout;
      dlgAbout.DoModal();
  }
  else
  {
      CDialog::OnSysCommand(nID, lParam);
  }
}
// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.
void CFingerAnalyserDlg::OnPaint()
{
  CPaintDC dc(this); // device context for painting
  if(m_show_base)
  {//режим просмотра базы
      ShowBase(true, false);
  }
  else
  {//режим просмотра открытого образа
      if (picture != NULL)
      {
          picture->GetPic1()->Show(110, 45);
          picture->GetPic2()->Show(545, 45);
      }
      m_kolDots = (int)fingA.size();
      UpdateData(false);
    продолжение
--PAGE_BREAK--  }
  CDialog::OnPaint();
}
// The system calls this function to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CFingerAnalyserDlg::OnQueryDragIcon()
{
  return static_cast(m_hIcon);
}
void CFingerAnalyserDlg::OnBnClickedOpenFile()
{
  char szFilters[]= «Образы (*.bmp)|*.bmp|All Files (*.*)|*.*||»;
  CFileDialog dlg(TRUE, «bmp», "*.bmp", OFN_FILEMUSTEXIST| OFN_HIDEREADONLY, szFilters, this);
  if(dlg.DoModal() != IDOK) return;      //никаких файлов не открыли
  if(dlg.GetFileExt().CompareNoCase(«bmp»)) return; //открытый файл не имеет расширеня .bmp
//    fp->Load(dlg.GetFileName());
  CString fileName = dlg.GetFileName();
  delete(picture);
  picture = new TAnalysePicture(fileName, this->GetDC());
  m_workFile = fileName;
  if(compareResult)
  {
      for(list::iterator i = compareResult->begin();
          i != compareResult->end();
          i++)
      { 
          list::iterator j;
          for(j=i->surdots.begin(); j!=i->surdots.end(); j++)
          {
             j->first->clear(); delete(j->first);
             j->second->clear(); delete(j->second);
      }  }
      compareResult->clear();
  }
  m_show_base = false;
  Invalidate();
}
void CFingerAnalyserDlg::OnBnClickedExit()
{
  CDialog::SendMessage(WM_CLOSE);
}
void CFingerAnalyserDlg::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized)
{
  CDialog::OnActivate(nState, pWndOther, bMinimized);
//    pWndOther->SetProperty(
}
void CFingerAnalyserDlg::OnBnClickedAnalyse()
{
  if(picture == NULL) return;
  LPSYSTEMTIME mTime;
  mTime = new SYSTEMTIME;
  GetSystemTime(mTime);
  long int workTime;
  workTime = mTime->wSecond*1000+mTime->wMilliseconds;
      fingA = picture->AnalysePicture();
      fingA.SaveFing(GetSAV(picture->getPathSrc()));
 
  GetSystemTime(mTime);
  workTime = mTime->wSecond*1000+mTime->wMilliseconds — workTime;
  workTime = (workTime
  delete(mTime);
    m_scantime = workTime;
  Invalidate();
}
void CFingerAnalyserDlg::OnBnClickedCompare()
{
  if(fingA.size() == 0)
  { 
      MessageBox(«Отпечаток не обработан», «Ошибка»);
      return;
  }
  fingR.Convert(fingA);
  if(compareResult)
  { 
      for(list::iterator i = compareResult->begin();
          i != compareResult->end();
          i++)
      { 
          list::iterator j;
          for(j=i->surdots.begin(); j!=i->surdots.end(); j++)
          {
             j->first->clear(); delete(j->first);
             j->second->clear(); delete(j->second);
          }
      }
      compareResult->clear();
      delete(compareResult);
      compareResult = NULL;
      showIter = NULL;
  }
  compareResult = CompareWithBase();
  if(compareResult->size() == 0) return;
  CString sOut="";
  for(list::iterator i = compareResult->begin();
      i != compareResult->end();
      i++)
  {
      CString s="";
      int mlevel = min(i->nfng,m_kolDots);
      int percent;
      if(mlevel > 10) mlevel = 10;
      if(i->cDot > mlevel) percent = 100;
      else percent = (int)(100.0*i->cDot/(double)mlevel + 0.5);
      if(percent == 0) continue;
      s.Format("%d %d %% %s\n", i->cDot, percent, i->name);
      sOut += s;
  }
  if(sOut.GetLength()==0) sOut = «Ни одного отпечатка не найдено!\n»;
  CString kol; kol.Format("\n Всего в базе: %d", compareResult->size());
  sOut += kol;
  PrintReport(picture->getPathSrc(), sOut);
  MessageBox(sOut, picture->getPathSrc());
}
void CFingerAnalyserDlg::OnTimer(UINT nIDEvent)
{
  Invalidate();
  CDialog::OnTimer(nIDEvent);
}
void CFingerAnalyserDlg::OnBnClickedSaveToDb()
{
  char szFilters[]=
      «Образы (*.bmp)|*.bmp|All Files (*.*)|*.*||»;
  CFileDialog dlg(TRUE, «bmp», "*.bmp", OFN_FILEMUSTEXIST| OFN_HIDEREADONLY| OFN_ALLOWMULTISELECT, szFilters, this);
  if(dlg.DoModal() == IDOK)
  {
      listTInfo *fingDB = LoadDB(db_file);
 
      FILE *fbse = fopen(db_file, «wb»);
      if(fbse == NULL)
      {
          MessageBox(«Невозможно создать базу данных с отпечатками», «Ошибка создания БД», MB_OK);
          return;
      }
     
      POSITION pos, posStart;
      TInfo newFingInDB;
      pos = posStart = dlg.GetStartPosition();
      int kolFile = 0;
      while(pos) {dlg.GetNextPathName(pos); kolFile++;}
      pos = posStart;
      loadProgress.SetRange(0, kolFile);
      int progressPos = 1;
      while(pos)
      {
          CString fileName = dlg.GetNextPathName(pos).MakeLower();
          if(fileName.Find(".bmp") == -1) continue;
          TAnalysePicture *loadingPic;
          loadingPic = new TAnalysePicture(fileName, this->GetDC());
          m_workFile = fileName;
          fingA = loadingPic->AnalysePicture();
          if(fingA.size()
          if(fingA.size() > MAX_SIZE) {MessageBox(«Отпечаток не пригоден для сохраниения в базу!», fileName); continue;}
          fingA.SaveFing(GetSAV(fileName));
          newFingInDB.src = fileName;
          fingDB->remove(newFingInDB);
          fingDB->push_back(newFingInDB);
          loadProgress.SetPos(progressPos);
          progressPos++;
          Invalidate();
          delete(loadingPic);
      }
      loadProgress.SetPos(0);
      int count = 0;
      fwrite((void*)&count, sizeof(count), 1, fbse);
      for(list::iterator iter = fingDB->begin(); iter != fingDB->end(); iter++)
      {
          iter->Printf(fbse);
          count++;
      }
      fseek(fbse, 0, SEEK_SET);
      fwrite((void*)&count, sizeof(count), 1, fbse);
      fingDB->clear();
      delete(fingDB);
      fclose(fbse);
  }
}
listTInfo *CFingerAnalyserDlg::LoadDB(CString dbFile)
//загрузить точки из БД
{
  listTInfo *bse = new listTInfo();
  TInfo finf;          //данные по отпечатку
  FILE *fbse = fopen(dbFile, «rb»);
  if(fbse == NULL)
  {
//        MessageBox(«Невозможно загрузить базу данных с отпечатками», «Ошибка загрузки БД», MB_OK);
      return bse;
  }
  int count = 0;
  fread((void*)&count, sizeof(count), 1, fbse);
  for(;count > 0; count--)
  {
      finf.Scanf(fbse);
      bse->push_back(finf);
  }
  fclose(fbse);
  return bse;
}
list *CFingerAnalyserDlg::CompareWithBase()
//сравнить точку с точками в БД
{
  listTInfo *bse;
  list *cFng;
  cFng = new list;
  bse = LoadDB(db_file);
  if(bse->empty())
  { 
      MessageBox(«База данных отпечатков пуста», «Сообщение», MB_OK);
      return cFng;
  }
  TAbsFing aFng;
  TRelFing baseFng;
  compare_progress.SetRange(0, (short)bse->size());
  for(list::iterator ibse = bse->begin();
      ibse != bse->end(); ibse++)
  {
      if(!aFng.LoadFing(GetSAV(ibse->src))) continue;
      baseFng.Convert(aFng);
      TCompareFing compareRes = fingR.Compare(baseFng);
      compareRes.name = ibse->src;
      cFng->push_back(compareRes);
      compare_progress.SetPos((int)cFng->size());
  }
  bse->clear();
  compare_progress.SetPos(0);
  delete(bse);
  return cFng;
}
void CFingerAnalyserDlg::OnBnClickedButtonPrev(){   ShowBase(false);}
void CFingerAnalyserDlg::OnBnClickedButtonNext(){   ShowBase(true);}
void CFingerAnalyserDlg::ShowBase(bool key, bool next)
//key — направление перемотки по базе (влево, вправо)
//next — нужно ли переходить к следующему отпечатку
{
  if(!compareResult) return;
  if(compareResult->size() == 0)
  { 
      MessageBox(«База данных отпечатков пуста», «Сообщение», MB_OK);
      return;
  }
  if(showIter == NULL) showIter = compareResult->begin();
  else
  { 
      if(next)
          if(key)
          {
             showIter++;
             if(showIter == compareResult->end())
                 showIter = compareResult->begin();
          }
          else
          {
             if(showIter == compareResult->begin())
                 showIter = compareResult->end();
             showIter--;
          }
  }
  TFingPicture *pic;
  pic = new TFingPicture(this->GetDC());
  if(!pic->Load(BLANK)) return;
         
  CPaintDC dc(this); // device context for painting
 
  list::iterator is = showIter->surdots.begin();
  list::iterator id = showIter->dots.begin();
  for(; id != showIter->dots.end(); id++, is++)
  { 
      COLORREF col;
      if(is->first->empty()) col = 0xBBBBBB;
      else                 col = (id->first.type)?0xff0000:0x000000;
      pic->Line(id->first.coord, id->first.coord, 5, col);
      pic->Line(id->first.coord,
                 CPoint(id->first.coord.x+(int)(10.0*cos(id->first.alpha)),id->first.coord.y-(int)(10.0*sin(id->first.alpha))),
                 2, col);
      if(is->first->empty()) continue; //окружения для этой точки нет
      //проверка, что «мышь» находится над точкой
      if( abs(mouse_pos.x-id->first.coord.x)first.coord.y)
      {
          TFingPicture pic2(this->GetDC());
          if(!pic2.Load(BLANK)) return;
          pic2.Copy(*picture->GetPic2());
          for(listTRelDot::iterator ii = is->first->begin(); ii != is->first->end(); ii++)
          { 
             COLORREF cl = 0x554444;
             CPoint cd;
             cd.x = (long)(id->first.coord.x — ii->l * cos(ii->a1*M_PI/180.0 — id->first.alpha));
             cd.y = (long)(id->first.coord.y — ii->l * sin(ii->a1*M_PI/180.0 — id->first.alpha));
             pic->Line(id->first.coord, cd, 1, cl);
          }
          for(listTRelDot::iterator ii = is->second->begin(); ii != is->second->end(); ii++)
          { 
             COLORREF cl = 0x554444;
             CPoint cd;
             cd.x = (long)(id->second.coord.x — ii->l * cos(ii->a1*M_PI/180.0 — id->second.alpha));
             cd.y = (long)(id->second.coord.y — ii->l * sin(ii->a1*M_PI/180.0 — id->second.alpha));
             pic2.Line(id->second.coord, cd, 1, cl);
          }
          pic2.Show(545, 45);
      }
  }
  if (pic != NULL)
  {
        pic->Show(110, 45);
      m_workFile = showIter->name;
  }
  UpdateData(false);
  delete(pic);
}
void CFingerAnalyserDlg::PrintReport(CString file, CString report)
{
  FILE *outf = fopen(«report.txt», «a»);
  CString msg = "\n------ "+file+" ------\n"+report;
  fprintf(outf, msg);
  fclose(outf);
}
CString CFingerAnalyserDlg::GetSAV(CString srcName)
{
  CString fsav = srcName.Left(srcName.GetLength() — 3) + «sav»;
  while(fsav.Find("\\") != -1){ fsav = fsav.Right(fsav.GetLength() — fsav.Find("\\")-1); }
  return sav_path + fsav;
}
void CFingerAnalyserDlg::OnBnClickedShowBase()
{
  m_show_base =! m_show_base;
  UpdateData(false);
  if(m_show_base)
  {
      ShowBase(true, false);
  }
  else
  {
      OnPaint();
  }
}
void CFingerAnalyserDlg::OnLButtonDown(UINT nFlags, CPoint point)
{
  if(!m_show_base) return;
  mouse_pos = point;
  mouse_pos.x -= 110;
  mouse_pos.y -= 45;
  ShowBase(true, false);
  CDialog::OnLButtonDown(nFlags, point);
}
П.1.6 ТЕКСТ МОДУЛЯ fing.h
#pragma once
#include «stdafx.h»
using namespace std;
//Элемент «карты точек»
//«Карта точек» — список точек для обработки
class TMapElDot{
public:
  CPoint coord;     //координаты точки
  bool pr1, pr2;    //признаки точки
public:
  TMapElDot(CPoint dot){pr1 = true; pr2 = true; coord = dot;};
  TMapElDot(){pr1 = true; pr2 = true;};
  ~TMapElDot(){};
};
//«Карта точек» — список точек для обработки
class TMapDot{
public:
  list map; //карта точек на изображении
  TMapDot(){};
  ~TMapDot(){map.clear();};
};
//сопроводительна информация
class TInfo{
public:
  short kol;           //количество точек
  short dpi;           //качество исходного отпечатка (dot per inch)
  CString src;            //путь к образу из которого была получена информация
  CTime date;               //дата отпечатка
  CString description;  //описание
  bool operator==(const TInfo &inf){return src == inf.src;};   //сравнение расположения изображений на диске
  TInfo(){kol = -1; dpi = -1; /*src = ""; description = "";*/};
    void Printf(FILE *fout)       //запись данных в файл
  {
      fwrite((void *)(&kol), sizeof(kol), 1, fout);
      fwrite((void *)(&dpi), sizeof(dpi), 1, fout);
      int strlen = src.GetLength();
      fwrite((void *)(&strlen), sizeof(int), 1, fout);
      fwrite((void *)(src.GetBuffer()), strlen, 1, fout);
  };
    void Scanf(FILE *fin)      //чтение данных из файла
  {
      fread((void *)(&kol), sizeof(kol), 1, fin);
      fread((void *)(&dpi), sizeof(dpi), 1, fin);
      int strlen;
      fread((void *)(&strlen), sizeof(int), 1, fin);
      char * text = new char[strlen+1];
      fread((void *)(text), strlen, 1, fin);
      text[strlen] = '\0';
      src = text;
      delete(text);
  };
};
//абсолютные параметры точки
class TAbsDot{
public:
  CPoint coord; //координаты
  double alpha; //направление в точке
  bool type;       //тип точки (1- окончание, 0- раздвоение)
  bool show;     //видимость точки (1- видима, 0- скрыта)
public:
  TAbsDot(){coord.x = -1; coord.y = -1; alpha = 0; type = false; show = false;};
  ~TAbsDot(){};
  bool operator==(const TAbsDot &f){return (coord.x == f.coord.x && coord.y == f.coord.y && alpha == f.alpha);};
  bool operator
  bool operator >(const TAbsDot &f){return (alpha > f.alpha);};
  bool operator!=(const TAbsDot &f){return false;};
  bool operator
  bool operator>=(const TAbsDot &f){return false;};
  CString toStr()
  { 
      CString str;
      str.Format("%d %d %f %d %d\n", coord.x, coord.y, alpha, type, show);
      return str;
  };
};
//класс для хранения точек в _абсолютных_ параметрах
//Описание отпечатка в абсолютных параметрах
class TAbsFing: public list
{
public:
  TAbsFing(){this->clear();};
  ~TAbsFing(){this->clear();};
  bool LoadFing(CString src);     //Загрузка отпечатка из файла *.sav
    bool SaveFing(CString fsav);     //Сохранение отпечатка в файл *.sav
};
//относительные параметры точки
class TRelDot{
public:
  short l,a1,a2;      //координаты точки
  //l — растояние между точками
  //a1 — угол между собственным направлением точки А и направлением A -> B [0, 2*M_PI)
  //a2 — угол между собственным направлением точки В и направлением A -> B  [0, 2*M_PI)
  TAbsDot absDot;  //ее абсолютные параметры (необходимо для отображения на экране совпавших точек)
public:
  bool operatorl
  bool sortByA1(TRelDot &f){return a1
  bool operator==(const TRelDot &f){return (this->l == f.l && this->a1 == f.a1 && this->a2 == f.a2);}
  CString toStr(){CString s; s.Format("%d %d %d\n", l, a1, a2); return s;}


Не сдавайте скачаную работу преподавателю!
Данный реферат Вы можете использовать для подготовки курсовых проектов.

Поделись с друзьями, за репост + 100 мильонов к студенческой карме :

Пишем реферат самостоятельно:
! Как писать рефераты
Практические рекомендации по написанию студенческих рефератов.
! План реферата Краткий список разделов, отражающий структура и порядок работы над будующим рефератом.
! Введение реферата Вводная часть работы, в которой отражается цель и обозначается список задач.
! Заключение реферата В заключении подводятся итоги, описывается была ли достигнута поставленная цель, каковы результаты.
! Оформление рефератов Методические рекомендации по грамотному оформлению работы по ГОСТ.

Читайте также:
Виды рефератов Какими бывают рефераты по своему назначению и структуре.