Рабочее место должно быть оборудовано подставкой для
ног, имеющей ширину не менее 300 мм, глубину не менее 400 мм, регулировку по
высоте в пределах до 150 мм и по углу наклона опорной поверхности подставки до
20 градусов. Поверхность подставки должна быть рифленой и иметь по переднему
краю бортик высотой 10 мм. На рабочем месте подставка для ног отсутствует.
Исходя из эргономических требований, пространство
рабочего места можно разделить на несколько частей:
1)
моторное поле - пространство рабочего
места, в котором могут осуществляться двигательные действия человека;
2)
максимальная зона досягаемости рук - это
часть моторного поля рабочего места, ограниченного дугами, описываемыми
максимально вытянутыми руками при движении их в плечевом суставе;
3) оптимальная
зона - часть моторного поля рабочего места,
ограниченного дугами, описываемыми предплечьями при движении в локтевых
суставах с опорой в точке локтя и с относительно неподвижным плечом.
д - оптимальное пространство для тонкой ручной
работы.
Рис. 4.1
ДОКУМЕНТАЦИЯ: необходимая при работе - в зоне легкой
досягаемости ладони – в, а в выдвижных ящиках стола - литература,
неиспользуемая постоянно.
На рис. 4.2 показан образец размещения основных и
периферийных составляющих ПК на рабочем столе инженера-программиста.
Рис. 4.2
На рис. 4.3 показана схема реального размещения
основных и периферийных составляющих ПК на рабочем столе инженера-программиста.
Рис. 4.3
Положение экрана определяется расстоянием
считывания (0,6…0,7м), углом считывания, направлением взгляда на 20° ниже
горизонтали к центру экрана, причем экран перпендикулярен этому
направлению. Должна также предусматриваться возможность регулирования экрана по
высоте +3 см, по наклону от -10° до +20° относительно
вертикали, в левом и правом направлениях.
Большое значение также
придается правильной рабочей позе пользователя. При неудобной рабочей позе
могут появиться боли в мышцах, суставах и сухожилиях. Требования к рабочей позе
пользователя видеотерминала следующие:
Причина неправильной позы пользователей обусловлена
следующими факторами: нет хорошей подставки для документов, клавиатура
находится слишком высоко, а документы - низко, некуда положить руки и кисти,
недостаточно пространство для ног.
В целях преодоления указанных недостатков даются
общие рекомендации: лучше передвижная клавиатура; должны быть предусмотрены
специальные приспособления для регулирования высоты стола, клавиатуры и экрана,
а также подставка для рук.
Существенное значение для производительной и
качественной работы на компьютере имеют размеры знаков, плотность их
размещения, контраст и соотношение яркостей символов и фона экрана. Если расстояние
от глаз оператора до экрана дисплея составляет 60…80 см, то высота знака должна
быть не менее 3мм, оптимальное соотношение ширины и высоты знака составляет
3:4, а расстояние между знаками – 15…20% их высоты. Соотношение яркости фона
экрана и символов - от 1:2 до 1:15.
Во время пользования компьютером медики советуют устанавливать
монитор на расстоянии 50-60 см от глаз. Специалисты также считают, что верхняя
часть видеодисплея должна быть на уровне глаз или чуть ниже. Когда человек
смотрит прямо перед собой, его глаза открываются шире, чем когда он смотрит
вниз. За счет этого площадь обзора значительно увеличивается, вызывая
обезвоживание глаз. К тому же если экран установлен высоко, а глаза широко
открыты, нарушается функция моргания. Это значит, что глаза не закрываются
полностью, не омываются слезной жидкостью, не получают достаточного увлажнения,
что приводит к их быстрой утомляемости.
Рабочее место инженера-программиста в составе
данного проекта в целом соответствует предъявляемым к нему эргономическим
требованиям, связанным с параметрами мебели и размещением предметов труда в
рабочих зонах. При этом можно сформулировать следующие рекомендации: установить
на рабочее место подставку для ног.
Под метеорологическими условиями (ГОСТ 12.1.005-88)
понимают сочетание температуры, относительной влажности, скорости движения и
запыленности воздуха. Перечисленные параметры оказывают огромное влияние на
функциональную деятельность человека, его самочувствие и здоровье и на
надежность средств вычислительной техники. Эти микроклиматические параметры
влияют как каждый в отдельности, так и в различных сочетаниях.
Температура воздуха является одним из основных
параметров, характеризующих тепловое состояние микроклимата. Суммарное тепловыделение
в помещении поступает от:
-
внешних источников.
Наибольшее количество теплоты выделяют ЭВМ и
вспомогательное оборудование. Средняя величина тепловыделения от компьютеров
колеблется до 100 Вт/м2. Тепловыделения от приборов освещения также
велики. Удельная величина их составляет 35 Вт/м2. При
этом, чем больше уровень освещенности, тем выше удельные величины
тепловыделений. Количество теплоты от обслуживающего персонала незначительно.
Оно зависит от числа работающих в помещении, интенсивности работы, выполняемой
человеком.
К внешним источникам поступления теплоты относят
теплоту, поступающую через окна от солнечной радиации, приток теплоты через непрозрачные
ограждения конструкций. Интенсивность этих источников зависит от расположения
здания, ориентации по частям света, цветовой гаммы и прочее.
С целью создания нормальных условий труда
программиста, ГОСТом 12.1.005-88 установлены оптимальные и допустимые значения
всех параметров микроклимата. Оптимальные параметры при длительном и
систематическом воздействии на организм человека обеспечивают сохранение
нормального функционирования и теплового состояния организма, создают ощущение
теплового комфорта и являются предпосылкой высокого уровня работоспособности.
Допустимые параметры микроклимата могут вызвать приходящие и быстро
нормализующиеся изменения организма, не выходящие за пределы физиологически
приспособительных возможностей, не создающие нарушений состояния здоровья, но
вызывающие дискомфортные теплоощущения, ухудшение самочувствия и понижение
работоспособности. Оптимальные и допустимые значения основных
микроклиматических параметров представлены в табл. 4.5.
Параметры
|
Значения параметров
|
оптимальные
|
допустимые
|
Температура
|
20-22 °С
|
17-22 °С
|
Относительная влажность
|
40-60 %
|
до 75%
|
Скорость движения воздуха
|
0,1 м/с
|
не более 0,3 м/с
|
Для обеспечения нормальных условий труда необходимо
придерживаться вышеуказанных данных. В целях поддержания температуры и
влажности воздуха в помещении можно использовать системы отопления, вентиляции
и кондиционирования воздуха.
На исследуемом предприятии температура воздуха,
влажность и скорость движения воздуха держится в рамках оптимальных параметров.
Вредные вещества в воздухе рабочей зоны не превышают предельной допустимой концентрации.
Организация рационального освещения рабочих мест
является одним из основных вопросов охраны труда. Основные параметры освещения
приведены в СНиП 23-05-95 "Естественное и искусственное освещение".
Правильно спроектированное и выполненное производственное освещение сохраняет
зрение рабочего, снижает утомляемость, способствует повышению
производительности труда, качеству выпускаемой продукции, безопасности труда и
снижению травматизма. Неправильно выбранные при проектировании осветительные
приборы и аппаратура, а также нарушение правил их технической эксплуатации
могут быть причиной пожара, взрыва, аварии на предприятии.
К современному освещению помещений, где работают с
вычислительной техникой, предъявляют высокие требования как гигиенического, так
и технического характера. Правильно спроектированное и выполненное освещение
обеспечивает высокий уровень работоспособности, оказывает положительное
психологическое воздействие, способствует повышению производительности труда.
Условия деятельности пользователя в системе «человек-машина» связаны с явным
преобладанием зрительной информации - до 90% общего объема.
В помещениях с компьютерной техникой применяется
совмещенная система освещения. К таким системам предъявляют следующие требования:
1)
соответствие уровня освещенности рабочих мест
характеру выполняемых зрительных работ;
2)
достаточно равномерное распределение яркости на
рабочих поверхностях и в окружающем пространстве;
3)
отсутствие резких теней, прямой и отраженной
блеклости;
4)
постоянство освещенности во времени;
5)
оптимальная направленность излучаемого
осветительными приборами светового потока;
6)
долговечность, экономичность, пожаробезопасность,
эстетичность, удобство и простота эксплуатации.
Искусственное освещение в помещениях эксплуатации
ЭВМ должно осуществляться системой общего равномерного освещения. В
производственных и административно-общественных помещениях, в случаях
преимущественной работы с документами, допускается применение системы
комбинированного освещения (к общему освещению дополнительно устанавливаются
светильники местного освещения, предназначенные для освещения зоны расположения
документов).
Согласно СНиП /10/ освещенность при системе общего
освещения составляет 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.
Помещение, в котором установлено рабочее место инженера-программиста,
относится к категории “Д” по взрывопожароопасности, так как не содержит горючих
веществ, но лишь негорючие вещества и материалы в холодном состоянии.
Пожары в помещении, в котором находится ЭВМ,
представляют особую опасность, так как сопряжены с большими материальными
потерями. Площадь помещения, в котором ведется проектирование, невелика и
составляет 8 м2. Как известно пожар может возникнуть при
взаимодействии горючих веществ, окисления и источников зажигания. В помещении
присутствуют все три основные фактора, необходимые для возникновения пожара.
Горючими компонентами являются: строительные материалы для акустической и
эстетической отделки помещений, двери, полы, бумага, изоляция кабелей и др.
Противопожарная защита - это комплекс организационных
и технических мероприятий, направленных на обеспечение безопасности людей, на
предотвращение пожара, ограничение его распространения, а также на создание
условий для успешного тушения пожара.
Источниками зажигания в помещении, содержащем ЭВМ,
могут быть электронные схемы от ЭВМ, приборы, применяемые для технического
обслуживания, устройства электропитания, где в результате различных нарушений
образуются перегретые элементы, электрические искры и дуги, способные вызвать
загорания горючих материалов.
В современных ЭВМ очень высока плотность размещения
элементов электронных схем. В непосредственной близости друг от друга
располагаются соединительные провода, кабели. При протекании по ним
электрического тока выделяется значительное количество теплоты. При этом
возможно оплавление изоляции. Для отвода избыточной теплоты от ЭВМ служат
системы вентиляции и кондиционирования воздуха. При постоянном действии эти
системы представляют собой дополнительную пожарную опасность.
Одной из наиболее важных задач пожарной защиты
является защита строительных помещений от разрушений и обеспечение их
достаточной прочности в условиях воздействия высоких температур при пожаре.
Учитывая высокую стоимость электронного оборудования, а также категорию его
пожарной опасности, здания, в которых предусмотрено размещение ЭВМ должны быть
1 и 2 степени огнестойкости.
К средствам тушения пожара, предназначенных для
локализации небольших возгорании, относятся пожарные стволы, внутренние
пожарные водопроводы, огнетушители, сухой песок, асбестовые одеяла и т. п.
В соответствии с “Типовыми правилами пожарной
безопасности для промышленных предприятий” залы ЭВМ, помещения для внешних
запоминающих устройств, подготовки данных, сервисной аппаратуры, архивов,
копировально-множительного оборудования и т.п. необходимо оборудовать дымовыми
пожарными извещателями. В этих помещениях в начале пожара при горении различных
пластмассовых, изоляционных материалов и бумажных изделий выделяется
значительное количество дыма и мало теплоты.
Помещение, в котором производится разработка данного
проекта, необходимо оборудовать средствами оповещения о пожаре, а также
средствами для тушения пожара.
В данном разделе дипломной работы был проведен
анализ вредных и опасных производственных факторов, действующих на рабочем
месте инженера-программиста. Среди них были выделены: постоянное напряжение
глаз, влияние электростатических и электромагнитных полей, длительное неизменное
положение тела, шум. Был проведен анализ и
указан комплекс мер по пожаробезопасности и электробезопасности.
Проведен расчет эргономических требований к рабочему месту
инженера-программиста. Созданные условия должны обеспечивать комфортную работу.
На основании изученной литературы по данной проблеме, были указаны оптимальные
размеры рабочего стола и кресла, параметры рабочей поверхности, а также
сформулированы предложения по улучшению параметров рабочего места. Соблюдение
условий, определяющих оптимальную организацию рабочего места инженера -
программиста, позволит сохранить хорошую работоспособность в течение всего
рабочего дня, повысит как в количественном, так и в качественном отношениях
производительность труда программиста, что в свою очередь будет способствовать
быстрейшей разработке и отладке программного продукта.
В результате проделанной работы был разработан метод
автоматизации поиска схожих отпечатков и реализована программа, для реализации
данного метода. Программа позволяет за приемлемое время автоматически
определять личность по отпечатку пальца посредством выделения локальных
особенностей. По сравнению с ручным определением «на глаз» по ключевым участкам
исходного изображения получен значительный выигрыш в скорости и удобстве
использования. Получаемые статистические характеристики достаточно полно
описывают изображение и позволяют провести распознавание с высокой степенью
точности.
Разработанная подсистема является неотъемлемой частью
системы идентификации личности по отпечаткам пальцев, предназначенной для обнаружения
сходства между двумя изображениемя отпечатка пальца. В результате распознавания
можно установить личность человека, приложившего палец, что может
использоваться при входе в систему. Посредством подсистемы распознавания
удается значительно понизить уровень влияния смещения и переноса отпечатка
пальцев, а также шумов и искажений в изображении.
Созданную систему следует рассматривать как
исследовательскую систему, предназначенную для выявления эмпирических
закономерностей в предметной области и дальнейшую разработку в направлении
большей автоматизации процесса идентификации личности.
Разработанная система реализует новый вид
функциональности – подготовку изображений к автоматизированному структурному
анализу.
1.
10. ГОСТ
12.1.009-76 ССБТ Электробезопасность. Термины и определения. – М.: Издательство стандартов, 1985.
11.
Прэтт У. Цифровая обработка изображений. Т. 1. -
М.: Мир, 1982. – 312 с.
12.
Дуда Р., Харт П. Распознавание образов и анализ
сцен. - М.: Мир, 1976. – 511 с.
13.
Аммерал Л. Принципы программирования в машинной графике.
- М.: Сол Систем, 1992.
14.
Анисимов Б.В., Курганов В.Д., Злобин В.К.
Распознавание и цифровая обработка изображений. - М.: Высшая школа, 1983. - 256
с.
15.
Бутаков А., Островский В. И., Фадеев И.Л. Обработка
изображений на ЭВМ. - М.: Радио и связь, 1987.
16.
Гренандер У. Лекции по теории образов. - М.: Мир,
1979. – Т. 1-3.
17.
Павлидис Т. Алгоритмы машинной графики и обработки
изображений. - М.: Радио и связь, 1986.
18.
Ту Дж., Гонсалес Р. Принципы распознавания образов.
- М.: Мир, 1976.
19.
Файн В.С. Опознавание изображений. – М.: Наука,
1970.
20.
Розенфельд А. Распознавание и обработка изображений
с помощью ЭВМ. - М.: Мир, 1972.
21.
Хуанг Г.С. Быстрые алгоритмы цифровой обработки
изображений. – М.: Радио и связь, 1984.
22.
Крамер Г. Математические методы статистики. – М.:
Мир, 1975.
23.
Патрик Э. Основы теории распознавания образов. –
М.: Советсткое радио, 1980.
24.
Строустрап Б. Язык программирования С++. – М.: Мир,
1994. – 278 с.
25.
Кнут Д. Искусство программирования для ЭВМ. - М.:
Мир, 1976. – Т. 1-3.
26.
Лялин В.Е., Мурынов А.И., Шибаева И.В. Модели
представления и кодирования пространственных объектов для передачи изображений
сцен по цифровым каналам связи // Информационные технологии в науке,
образовании, телекоммуникациях и бизнесе: Материалы 31 Междунар. конф. –
Украина, Крым, Ялта–Гурзуф: Ж. «Успехи современного естествознания», №5, 2004,
Прилож. №1. - С. 123-125.
27.
Шибаева И.В., Мурынов А.И., Пивоваров И.В.
Математические и программные средства распознавания графических изображений для
передачи по цифровым каналам связи // Информационные технологии в науке,
образовании, телекоммуникациях и бизнесе: Материалы 31 Междунар. конф. –
Украина, Крым, Ялта–Гурзуф: Ж. «Успехи современного естествознания» №5, 2004,
Прилож. №1. - С. 114-117.
28.
Гусейнов П.М. Методы статистической классификации
многозональной видеоинформации с обучением по тестовому участку // Исследование
Земли из космоса. - 1987. - № 4. - С. 21-28.
29.
Корн Г., Корн Т. Справочник по математике для
научных работников и инженеров. - М.: Наука, 1979. – 720с.
30.
Эйнджел Э. Интерактивная компьютерная графика. –
М.: Вильямс, 2001. – 592 с.
31.
Левкович О.А., Шелкоплясов Е.С., Шелкоплясов Т.Н.
Основы компьютерной грамотности: Учебное пособие. – М.: ТетраСистемс, 2004.
- 528 с.
32.
ГОСТ 19.505-79 ЕСПД. Руководство оператора.
Требования к содержанию и оформлению. – М.: Издательство стандартов, 1979.
33.
ГОСТ 19.504-79 ЕСПД. Руководство программиста.
Требования к содержанию и оформлению. – М.: Издательство стандартов, 1979.
34.
ГОСТ 19.701-90 ЕСПД. Схемы алгоритмов и программ.
Правила выполнения. – М.: Издательство стандартов, 1991.
35.
Технико-экономическое обоснование дипломных
проектов при разработке приборов и методов контроля качества. Методические
указания для студентов. – Ижевск: Издательство ИжГТУ, 2001.
36.
Соболева В.П. Методические указания по оформлению
курсовых работ, курсовых и дипломных проектов. – Ижевск: Издательство ИМИ,
2003.
П.1.1. ТЕКСТ МОДУЛЯ 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<TMapElDot>
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 <(const TAbsDot &f){return (alpha < f.alpha);};
bool
operator >(const TAbsDot &f){return (alpha > f.alpha);};
bool
operator!=(const TAbsDot &f){return false;};
bool
operator<=(const TAbsDot &f){return false;};
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<TAbsDot>
{
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
operator<(const TRelDot &f){return this->l < f.l;}
bool
sortByA1(TRelDot &f){return a1 < f.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;}
};
//класс
для хранения _относительных_ параметров точки
typedef
list<TRelDot> listTRelDot;
//Шаблон
для хранения пары значений {first, second}
template
<class data_t1, class data_t2> struct TPair{
data_t1
first;
data_t2
second;
TPair(data_t1
_f, data_t2 _s){first = _f; second = _s;};
};
typedef
TPair<TAbsDot, TAbsDot> TPairAbsDot;
typedef
TPair<listTRelDot*, listTRelDot*> TPairSur;
//результат
сравнения отпечатков
struct
TCompareFing{
double
val; //уровень схожести отпечатков
short
cDot; //количество совпавших точек
short
nfng; //номер отпечатка
CString
name; //файл отпечатка
list<TPairAbsDot>
dots; //first - совпавшие точки на отпечатке в базе
//second
- совпавшие точки на открытом отпечатке
list<TPairSur>
surdots;
//окружения
на одинаковых отпечатках должны быть одинаковыми,
//на
этом основано сравнение "роз"
};
//Описание
отпечатка в _относительных_ параметрах
class
TRelFing: public list<listTRelDot>{
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.2.
ТЕКСТ МОДУЛЯ
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
< 0) tmpa = 2*M_PI + tmpa;
tmpR.a1
= (short)(tmpa * 180.0/M_PI +0.5); //a1 - угол между собственным направлением
точки А и направлением A -> B
tmpa =
iterA2->alpha - vecAB;
if(tmpa
< 0) tmpa = 2*M_PI + 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 < 0) alpha += M_PI;
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++)
{
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
prev, next;
prev =
next = abs(baseIter->l - tekIter->l);
while(
prev
>= next &&
next
>= DELTA_L &&
baseIter
!= (*baseFing).end())
{
prev =
next;
baseIter++;
next =
abs(baseIter->l - tekIter->l);
}
if(prev
>= DELTA_L && prev < next) continue; //нет
смысла
сравнивать
дальше
т.к. всегда
будет next
>= 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)<delta_a)||(abs(tekIter->a1 - baseIter->a1) >
360-delta_a))&&
((abs(tekIter->a2
- baseIter->a2)<delta_a)||(abs(tekIter->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.3.
ТЕКСТ МОДУЛЯ
FINGERANALYSERDLG.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<TCompareFing>::iterator
i = compareResult->begin();
i !=
compareResult->end();
i++)
{
list<TPairSur>::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
< 0xF000);
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);
}
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<HCURSOR>(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
CString
fileName = dlg.GetFileName();
delete(picture);
picture
= new TAnalysePicture(fileName, this->GetDC());
m_workFile
= fileName;
if(compareResult)
{
for(list<TCompareFing>::iterator
i = compareResult->begin();
i !=
compareResult->end();
i++)
{
list<TPairSur>::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<0)?60000+workTime:workTime;
delete(mTime);
m_scantime
= workTime;
Invalidate();
}
void
CFingerAnalyserDlg::OnBnClickedCompare()
{
if(fingA.size()
== 0)
{
MessageBox("Отпечаток
не
обработан",
"Ошибка");
return;
}
fingR.Convert(fingA);
if(compareResult)
{
for(list<TCompareFing>::iterator
i = compareResult->begin();
i !=
compareResult->end();
i++)
{
list<TPairSur>::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<TCompareFing>::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",
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()
< MIN_SIZE)
{
MessageBox("Отпечаток
не пригоден для сохраниения в базу!", fileName);
continue;
}
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<TInfo>::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<TCompareFing>
*CFingerAnalyserDlg::CompareWithBase()
//сравнить
точку с точками в БД
{
listTInfo
*bse;
list<TCompareFing>
*cFng;
cFng =
new list<TCompareFing>;
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<TInfo>::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<TPairSur>::iterator
is = showIter->surdots.begin();
list<TPairAbsDot>::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)<6 &&
abs(mouse_pos.y-id->first.coord.y)<6 )
{
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.4.
ТЕКСТ МОДУЛЯ
FINGERANALYSERDLG.H
//
FingerAnalyserDlg.h : header file
//
#pragma
once
#include
"TFingPicture.h"
#include
"afxcmn.h"
typedef
list<TInfo> 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<TCompareFing>
*CompareWithBase();
CString
m_workFile;
CProgressCtrl
compare_progress;
long
m_scantime;
afx_msg
void OnBnClickedButtonPrev();
list<TCompareFing>
*compareResult;
list<TCompareFing>::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. ТЕКСТ МОДУЛЯ 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.6. ТЕКСТ МОДУЛЯ 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
};
extern
CFingerAnalyserApp theApp;
П.1.7. ТЕКСТ
МОДУЛЯ 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.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<TMapElDot>::iterator _dot, list<TMapElDot>
&_map);//Обработка картинки, ее
изменение
TAbsFing
ReadPic(list<TMapElDot>::iterator _dot); //Нахождение
на
изображении
спец
точек
list<TMapElDot>
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
prevCol;
int
changeN = 0; //Счетчик произведенных изменений на изображении
list<TMapElDot>
map; //Карта точек принадлежащих линиям
list<TMapElDot>::iterator
imap; //Итератор для map
map
= LookPic(); //сканирование картинки и нахождение линий на ней
do{
changeN
= 0;
prevCol
= (int)map.size();
imap
= map.begin();
do{ //Изображение
можно модифицировать
if(imap->pr1) //Линия
нуждается в обработке
changeN
+= ChangeLine(imap, map); //Обработка (преобразование) изображения
imap++; //Переход
для обработки следующей линии
}while(imap
!= map.end()); //Изображение можно модифицировать
}while(prevCol<0.1*map.size()); //Изображение
можно модифицировать
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<TMapElDot>::iterator _dot)
//Нахождение
на изображении спец точек
{
TAbsFing
retFing; //Образ отпечатка в абсолютных координатах
int
kol = 0; //количество пройденных точек
int
vec = 0; //направление поиска очередной точки
int
tekS = 0; //Текущее количество коротких векторов
CPoint A, //Начало
вектора
B; //Конец
вектора
TAbsFing
vecDotS; //массив точек для коротких векторов
TAbsFing
vecDotL; //массив точек для длинных векторов
TAbsFing
historyDotL; //история точек для длинных векторов
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 < 0.0)
{
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()
< KOL_S) continue;
//Вычисление
среднего направления LEN_L коротких векторов//
//запись
данных по длинному вектору////////////////////////
double
sumAlpha = 0.0;
iter =
vecDotS.begin();
vecDotL.clear(); //пересчитаем
длинные
вектора
for(int
i = 0; i < KOL_S; 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<0; //тип СТ//
historyDotL.push_front(_tmpDotFing);
if(bestDot.alpha
<= abs(dAlpha))
{
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<(historyDotL.size()/2); i++) iter++;
//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 <= 2)
{//Линия
подозрительно короткая
CString
s;
s.Format("%d",
kol);
if(MESSAGEOUT)MessageBox(0,
"kol<=2 kol = " + s, "", MB_OK);
return
retFing;
}else
homeOver
= true; //пройти необходимо
дальше
начала
stopKol
= kol + KOL_L*LEN_L*LEN_S;
}
}
if
(homeOver) ret++;
}while(ret
< (LEN_L*LEN_S*KOL_L) && ret < stopKol && kol <=
stopKol);
_dot->pr1
= false;
_dot->pr2
= false;
return
retFing;
}
list<TMapElDot>
TAnalysePicture::LookPic()
//Попиксельное
"пробегание" по картинке и
//запоминание
черных точек, после нахождения черной точки
//заливка
всей линии в цвет фона (удаление линии с картинки)
{
list<TMapElDot>
map;
TMapElDot
dot;
tmpPic->Copy(*pic);
for(int
j = 0; j < pic->GetSize().y; j++)
for(int
i = 0; i < pic->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<TMapElDot>::iterator _dot,
list<TMapElDot> &_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 < 0.0)
{
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()
< KOL_S) continue;
//Вычисление
среднего направления LEN_L коротких векторов//
//запись
данных по длинному вектору////////////////////////
double
sumAlpha = 0.0;
iter =
vecDotS.begin();
vecDotL.clear(); //пересчитаем
длинные
вектора
for(int
i = 0; i < KOL_S; 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<0; //тип СТ//
historyDotL.push_front(_tmpDotFing);
if(bestDot.alpha
<= abs(dAlpha))
{
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<(historyDotL.size()/2); i++) iter++;
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 < 200)?200:0;
//stopKol
+= (kol*1.5 > stopKol)?500:0;
//загрузить
начальное состояние
if(!historyDotL.begin()->type)
{ //если
ликвидировано слипание то необходимо добавить новую точку на карту
_map.push_back(TMapElDot(dot));
}
//пройдена
начальная точка, продлим анализ
//очень
возможно, что начальную точку мы больше не попадем
if(ret-KOL_S*LEN_S
< 0)
{
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 <= 2)
{//Линия
подозрительно короткая
CString
s;
s.Format("%d",
kol);
if(MESSAGEOUT)MessageBox(0,
"kol<=2 kol = " + s, "", MB_OK);
return
changeN;
}else
{
homeOver
= true; //пройти необходимо
дальше
начала
stopKol
= kol + KOL_L*LEN_L*LEN_S;
}
}
if
(homeOver) ret++;
}while(ret
< (LEN_L*LEN_S*KOL_L) && ret < stopKol && kol <= stopKol);
_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 < 0) alpha += M_PI;
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<=len; i++)
B =
tmpPic->NextDotCW(B, vec);
//------расчет
угла-------//
double
alpha1 = GetAlpha(A, B);
//второй
вектор
C = B;
B = A;
vec =
0;
for(int
i = 1; i<=len; i++)
{
B =
tmpPic->NextDotCCW(B, vec);
if(abs(B.x-C.x)
< 3 && abs(B.y-C.y) < 3) return true;
}
//------расчет
угла-------//
double
alpha2 = GetAlpha(A, B);
//-----alpha1,
alpha2------//
alpha1
= abs(alpha2 - alpha1);
if
(alpha1 > M_PI) alpha1 = 2.0*M_PI - alpha1;
return
alpha1 < (110.0/180.0 * M_PI);
}
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<=6) //разброс поиска в указанном направлении alpha
{
int l =
minL;
int k =
(i+1) / 2;
if (i %
2 == 1) k = -k;
while
(l<=maxL)
{
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
< 15)&&
((abs(iter2->alpha
- iter1->alpha) > (165.0/180.0*M_PI))&&(abs(iter2->alpha -
iter1->alpha)<(195.0/180.0*M_PI)))
||
(
//или
просто очень близкие точки (<5..10)
(difL
< 10)&&(iter1->type == iter2->type)
)
)
{
iter1->show
= false;
iter2->show
= false;
}
}
}
return
leftDots;
}
inline
double TAnalysePicture::GetS(CPoint A, CPoint B)
//растояние
между
точками
{
return
sqrt( (double)((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y)) );
}
/*Если
точка является окончанием, то слева и справа от нее должны быть линии если это
не так, то точку нужно исключить из дальнейшего анализа*/
bool
TAnalysePicture::LeftDot(TAbsFing::iterator &iter)
{
COLORREF
color = 0x000000; //ищем черную точку для окончаний
if(!iter->type)
color = 0xffffff;; //ищем белую точку для раздвоений
int l,
k = 35;
const
int minL = 4, maxL = 12;
bool
find = false;
while(k
<= 55)
{
l =
minL;
while(l
<= maxL)
{
int x
= iter->coord.x + (int)(l*cos(iter->alpha + k/180.0*M_PI)+0.5);
int y =
iter->coord.y - (int)(l*sin(iter->alpha + k/180.0*M_PI)+0.5);
if(pic->GetPixel(x,y)
== color) // важное условие!!!
{ find
= true; break;} //нашли точку
слева
l++;
}
if(find)
break;
k +=
10; //Поиск с
шагом 10гр
}
if(!find)
return false;
k = 35;
while(k
<= 55)
{
l=
minL;
while(l
<= maxL)
{
int x =
iter->coord.x + (int)(l*cos(iter->alpha - k/180.0*M_PI)+0.5);
int y =
iter->coord.y - (int)(l*sin(iter->alpha - k/180.0*M_PI)+0.5);
if(pic->GetPixel(x,y)
== color) // важное условие!!!
return
true; //нашли точку
справа
l++;
}
k +=
10;
}
return
false;
}
П.1.10. ТЕКСТ МОДУЛЯ TFingPicture.h
#pragma
once
#include
"Fing.h"
///////////////////////////////////////////////////////////////////////////////
//Класс
изображения.
//Хранение
изображения, выполнение простейших операции над ним
///////////////////////////////////////////////////////////////////////////////
class
TFingPicture
{
private:
CDC
pic; //указатель на изображение
BITMAP
bmp; //изображение
bool
IsLoad; //изображение загружено
CDC
*Screen; //указатель на окно программы
public:
TFingPicture(CDC
*_Screen); //_Screen - указатель на
окно
~TFingPicture(void);
bool
Load(const CString src); //загрузить изображение
из
файла src
bool
Show(int X, int Y); //отобразить изображение на окне в координатах (X,Y)
bool
SetPixel(CPoint dot, COLORREF color); //установка цвета пикселя dot
bool
SetPixel(int x, int y, COLORREF color); //установка
цвета
пикселя (x,y)
COLORREF
GetPixel(CPoint dot); //взятие цвета
пикселя dot
COLORREF
GetPixel(int x, int y); //взятие цвета
пикселя (x,y)
bool
FloodFill(CPoint dot, COLORREF color=0xffffff); //заливка
области (по
умолчанию
черным
цветом)
bool FloodFill(int
x, int y, COLORREF color=0xffffff); //заливка
области (по
умолчанию
черным
цветом)
bool
Line(CPoint from, CPoint to, int width, COLORREF color);//рисование
линии
bool
Rectangle(CPoint from, CPoint to, int width=2, COLORREF color=0xffffff); //рисование
прямоугольника
bool
Copy(TFingPicture &from); //копирование
изображения
CPoint
NextDotCW(const CPoint dot, int &vec); //Поиск
следующей
точки
"_по часовой_ стрелке"
CPoint
NextDotCCW(const CPoint dot, int &vec); //Поиск
следующей
точки
"_против часовой_ стрелке"
CPoint
GetSize(); //получение размера изображения
};
П.1.11. ТЕКСТ МОДУЛЯ TFingPicture.cpp
#include
"StdAfx.h"
#include
"TFingPicture.h"
///////////////////////////////////////////////////////////////////////////////
//Класс
изображения.
//Хранение
изображения, выполнение простейших операции над ним
///////////////////////////////////////////////////////////////////////////////
//координаты
окружающих точек
const
CPoint incXY[8]=
{
CPoint(-1,
-1),
CPoint(0,
-1),
CPoint(1,
-1),
CPoint(1,
0),
CPoint(1,
1),
CPoint(0,
1),
CPoint(-1,
1),
CPoint(-1,
0)};
TFingPicture::TFingPicture(CDC
*_Screen)
{
Screen
= _Screen;
pic.CreateCompatibleDC(Screen);
IsLoad
= false;
}
TFingPicture::~TFingPicture(void){}
//отобразить
изображение на окне в координатах (X,Y)
bool
TFingPicture::Show(int X, int Y)
{
if
(!IsLoad) return false;
int kx
= bmp.bmWidth;
int ky
= bmp.bmHeight;
return
Screen->StretchBlt(X, Y, bmp.bmWidth, bmp.bmHeight, &pic, 0, 0, kx, ky,
SRCCOPY)>0;
}
//загрузить
изображение
из
файла src
bool
TFingPicture::Load(const CString src)
{
IsLoad
= false;
CBitmap
bm;
bm.Detach();
IsLoad
= bm.Attach(LoadImage(0, src, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE))>0;
bm.GetObject(sizeof(BITMAP),
&bmp);
pic.SelectObject(&bm);
return
IsLoad;
}
//
color = BGR;
bool
TFingPicture::SetPixel(CPoint dot, COLORREF color)
{
if
(!IsLoad) return false;
pic.SetPixel(dot.x,
dot.y, color);
return
true;
}
bool
TFingPicture::SetPixel(int x, int y, COLORREF color)
{
if
(!IsLoad) return false;
pic.SetPixel(x,
y, color);
return
true;
}
//
color = BGR;
COLORREF
TFingPicture::GetPixel(CPoint dot)
{
if
(!IsLoad) return false;
return
pic.GetPixel(dot.x, dot.y);
}
COLORREF
TFingPicture::GetPixel(int x, int y)
{
if
(!IsLoad) return false;
return
pic.GetPixel(x, y);
}
bool
TFingPicture::FloodFill(CPoint dot, COLORREF color)
{
if(!IsLoad)
return false;
COLORREF
col = GetPixel(dot);
CBrush
br(color);
pic.SelectObject(&br);
pic.ExtFloodFill(dot.x,
dot.y, col, FLOODFILLSURFACE);
return
true;
}
bool
TFingPicture::FloodFill(int x, int y, COLORREF color)
{
if(!IsLoad)
return false;
COLORREF
col = GetPixel(x, y);
CBrush
br(color);
pic.SelectObject(&br);
pic.ExtFloodFill(x,
y, col, FLOODFILLSURFACE);
return
true;
}
bool
TFingPicture::Line(CPoint from, CPoint to, int width, COLORREF color)
{
if(!IsLoad)
return false;
CPen
pen(PS_SOLID, width, color);
pic.SelectObject(&pen);
pic.MoveTo(from.x,
from.y);
pic.LineTo(to.x,
to.y);
return
true;
}
bool
TFingPicture::Rectangle(CPoint from, CPoint to, int width, COLORREF color)
{
if(!IsLoad)
return false;
Line(from,
CPoint(from.x, to.y), width, color);
Line(CPoint(from.x,
to.y), to, width, color);
Line(to,
CPoint(to.x, from.y), width, color);
Line(CPoint(to.x,
from.y), from, width, color);
return
true;
}
bool
TFingPicture::Copy(TFingPicture &from)
{
bmp =
from.bmp;
IsLoad
= from.IsLoad;
Screen
= from.Screen;
return
pic.BitBlt(0, 0, bmp.bmWidth, bmp.bmHeight, &from.pic, 0, 0, SRCCOPY)>0;
}
CPoint
TFingPicture::NextDotCW(const CPoint dot, int &vec)
//Поиск
следующей точки "_по часовой_ стрелке"
//vec
вероятное направление поиска
{
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]
< clMas[i])
{
vec =
(i + 1) % 8;
newdot.x
= dot.x + incXY[vec].x;
newdot.y
= dot.y + incXY[vec].y;
if(vec
% 2 == 0) SetPixel(dot.x + incXY[vec+1].x, dot.y + incXY[vec+1].y, 0x000000);
vec =
(vec + 5) % 8;
return
newdot; //найдена новая
точка
}
i = (i
+ 1) % 8;
step++;
}while(step
<= 8);
return
dot; //поиск ни к чему не привел
}
CPoint
TFingPicture::NextDotCCW(const CPoint dot, int &vec)
//Поиск
следующей точки "_против часовой_ стрелке"
//vec
вероятное направление поиска
{
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]
< clMas[i])
{
vec =
(i + 1) % 8;
newdot.x
= dot.x + incXY[(8-vec)%8].x;
newdot.y
= dot.y + incXY[(8-vec)%8].y;
if(vec
% 2 == 0) SetPixel(dot.x + incXY[8-vec-1].x, dot.y + incXY[8-vec-1].y,
0x000000);
vec =
(vec + 5) % 8;
return
newdot; //найдена новая
точка
}
i = (i
+ 1) % 8;
step++;
}while(step
<= 8);
return
dot; //поиск ни к чему не привел
}
CPoint
TFingPicture::GetSize()
//получение
размера изображения
{ if(!IsLoad)
return false;
return
CPoint(bmp.bmWidth, bmp.bmHeight);}
ПРИЛОЖЕНИЕ 2 РУКОВОДСТВО ПРОГРАММИСТА
П.2.1.
НАЗНАЧЕНИЕ ПРОГРАММЫ
Программа распознавания личности по отпечаткам
пальцев имеет идентификатор FingerAnalyser и предназначена
для автоматической идентификации личности по папиллярному узору. Программа FingerAnalyser выполняет следующие функции:
1)
модификация изображения, исправление искажений;
2)
выделение локальных особенностей – минюций.
Формирование списка минюций в абсолютных параметрах;
3)
сортировка списка абсолютных параметров, исключение
ложных и ненадежных минюций;
4)
конвертирование абсолютных параметров в
отностительные, формирование списка относительных параметров;
5)
установка системы допусков для учета корреляцции
изображений
6)
сравнение одного отпечатка с множеством других.
Данная работа реализует такое преобразование
изображения, при котором данные о расположение уникальных особенностей
сохраняются наиболее полно и с наименьшим содержанием ложной информации.
Создаваемая система облегчит разработку алгоритмов
обработки изображений, упростит анализ экспериментальных данных и выявление
общих закономерностей.
П.2.2.
УСЛОВИЯ ПРИМЕНЕНИЯ ПРОГРАММЫ
Программа FingerAnalyser
предъявляет следующие требования к техническим средствам:
-
стандартный x86-совместимый
ПК;
-
тактовая частота процессора 900 МГц или более;
-
объем оперативной памяти не менее 64 Мб;
-
разрешение экрана монитора не менее 1024x768.
Программа FingerAnalyser
предъявляет следующие требования к программным средствам:
-
операционная система семейства Windows (Windows 9x/ME/NT/2000/XP);
-
среда для разработки приложений Microsoft Visual
Studio C++ 2003.
Интерфейс программы представлен на рис. П.2.1.
Интерфейс программы FingerAnalyser
Рис. П.2.1
На форме программы в визуальном виде
представляется, после открытия через пункт «Открыть», исходное изображение,
после нажатия на кнопку «Анализ», скорректированное изображение и визуальное
представление структурного вида отпечатка. После чего можно нажатием на кнопку
«Сравнить» отыскать в базе схожие отпечатки.
При каждом анализе отпечатка создается файл с его
структурным описанием. Для того чтобы поместить отпечаток в базу данных
отпечатков, для последующего стравнения с ним, необходимо нажать на кнопку
«Запомнить в базу». Для запоминания в базу можно выбирать группу файлов для
применения операции записи в базу данных для всех выбранных файлов.
П.2.3.
ХАРАКТЕРИСТИКА ПРОГРАММЫ
Программа FingerAnalyser
требует для своего функционирования наличия в проекте файлов, содержащих
растровые представления папиллярного узора.
В состав программы входят следующие файлы,
необходимые для ее функционирования:
1)
FingerAnalyser.exe –
исполняемый файл, содержащий основной интерфейс программы;
2)
MFC – библиотеки для поддержки оконного среды;
3)
blank.bmp – пустое изображение;
4)
report.txt – файл отчет в который записываются все
результаты сравнения
5)
sav/*.sav – файлы со структурным представлением
отпечатков
6)
sav/fingbase.bse – база данных отпечатков
7)
dll библиотеки MFC
Программа является интерактивной, требующей
взаимодействия с пользователем, поэтому время выполнения отдельных этапов
обработки не превышает 0.5 с. при использовании требуемых технических средств.
П.2.4. ОБРАЩЕНИЕ К ПРОГРАММЕ
Для запуска программы необходимо убедиться в том,
что необходимые библиотеки MFC находятся в том же
каталоге, что и исполняемый файл или в каталоге Windows/System32.
Для корректной работы программы она должна
находиться в каталоге, к которому есть права на чтение и запись.
Для запуска подсистемы
необходимо в оболочке системы на главном окне нажать на кнопку «Анализ» - для
сравнения нужного отпечатка с набором имеющимся в базе данных, или «Запомнить в
базу» - для внесения указанных отпечатков в базу данных.
П.2.5.
ВХОДНЫЕ И ВЫХОДНЫЕ ДАННЫЕ
Входными и выходными данными для программы
является файл базы данных отпечатков sav/fingbase.bse. Структура файла:
src
[kol] [dpi] [date] [description]
src
[kol] [dpi] [date] [description]
src
[kol] [dpi] [date] [description]
В каждой строке файла базы данных отпечатков содержится
описание одного отпечатка. В табл. П.2.1 приведен формат записи в файле базы
данных.
Таблица П.2.1
Формат записи файла базы данных
Поле
|
Формат
|
Описание
|
src
|
Строка
|
путь к образу из
которого была получена информация
|
kol
|
Целое
|
количество точек
|
dpi
|
Целое
|
качество исходного
отпечатка (dot per inch)
|
date
|
Дата
|
дата отпечатка
|
description
|
строка
|
описание
|
Выходными данными для программы является файл sav/*.sav со структурным представлением, содержащий
статистические характеристики минюций на отпечатке. Этот файл имеет следующий
формат:
x
y
alpha
type
[
show
]
x
y alpha type [show]
x
y alpha type [show]
В каждой строке файла структурного представления
содержится описание одной минюции. В табл. П.2.2 приведен формат строки со
структурным описанием минюции в абсолютных параметрах.
Таблица П.2.2
Формат строки
файла со структурным описанием
Поле
|
Формат
|
Описание
|
x
|
Целое
|
Абцисса минюции на растре
|
y
|
Целое
|
alpha
|
Целое
|
Ориентация минюции на растре
|
type
|
Байт
|
Тип минюции. Раздвоение или окончание
|
Кроме того, выходной информацией для данной
подсистемы является файл отчет report.txt, содержащий отпечатки из базы данных, в которых были обнаружены
сходства с обрабатываемым отпечатком.
В каждой строке отчета содержится описание
отпечатка, его имя, количество совпавших точек при распознавании и степень
сходства.
В табл. П.2.3 приведен формат данных. На рис. П.2.2 приведен пример файла
отчета.
report.txt имеет следующий
формат:
------ Namei ------
Counti1 Pcti1 Sourcei1
Counti2 Pcti2 Sourcei2
Countik Pctik Sourceik
Всего в базе: NN
Таблица П.2.3
Формат данных файла-отчета
Поле
|
Формат
|
Описание
|
Name
|
Строка
|
Имя отпечатка
|
Count
|
Целое
|
Абсцисса минюции на растре
|
Pct
|
Целое
|
Степень сходства отпечатков в процентах, принимает значения
(0, 100]
|
Source
|
Строка
|
Путь к файлу, из которого были взяты параметры
|
NN
|
Целое
|
Количество отпечатков имеющихся в базе данных
|
Файл-отчет
------ hedgeR1_2.bmp ------
7 70 с:\мои документы\fing\fingc\fingeranalyser\pic\base\hedger1_1.bmp
Всего в базе: 58
------ starkyR2_2.bmp ------
5 50 с:\мои документы\fing\fingc\fingeranalyser\pic\base\starkyr2_1.bmp
Всего в базе: 58
------ karR2_2.bmp ------
3 30 с:\мои документы\fing\fingc\fingeranalyser\pic\base\karr2_1.bmp
Всего в базе: 58
------ vasL1_2.bmp ------
21 100 с:\мои документы\fing\fingc\fingeranalyser\pic\vasl1_1.bmp
56 100 с:\мои документы\fing\fingc\fingeranalyser\pic\vasl1_2.bmp
12 100 с:\мои документы\fing\fingc\fingeranalyser\pic\vasl1_3.bmp
Всего в базе: 58
------ tatL1_2.bmp ------
Ни одного
отпечатка не найдено!
|
Рис. П.2.2
П.2.6.
СООБЩЕНИЯ
Сообщения, выдаваемые программисту, приведены в
табл. П.2.4.
Таблица П.2.4
Сообщения программисту
Сообщение
|
Действие программиста
|
Отпечаток не обработан
|
Прежде чем запускать сравнение необьходимо провести анализ
|
База данных пуста
|
В базе данных нет информации ни об одном отпечатке.
Необходимо заполнить базу данных отпечатков
|
Отпечаток не пригоден для сохранения в базу
|
На отпечатке либо слишком мало обнаружено минюций, менее
10, либо слишком много, более 80
|
Ни одного отпечатка не найдено
|
В результате поиска не совпало ни одного отпечтака
|
Невозможно создать базу данных с отпечатками
|
Возможно нет прав на запись или нет свободного места на
носителе
|
Невозможно создать файл
|
Возможно нет прав на запись или нет свободного места на
носителе
|
Невозможно открыть файл
|
Возможно нет прав на чтение или не сеществует
запрашиваемого файла на носителе
|
Обнаружены сходства
|
В базе данных были обнаружены отпечатки, имеющие схожее
представление.
|
Визуализация результатов проведения анализа
приведена на рис. П.2.2.
ПРИЛОЖЕНИЕ 3 РУКОВОДСТВО ОПЕРАТОРА
П.3.1. НАЗНАЧЕНИЕ ПРОГРАММЫ
Программа распознавания личности по отпечаткам
пальцев имеет идентификатор FingerAnalyser и предназначена
для автоматической идентификации личности по папиллярному узору. Программа FingerAnalyser выполняет следующие функции:
1)
модификация изображения, исправление искажений;
2)
выделение локальных особенностей – минюций.
Формирование списка минюций в абсолютных параметрах;
3)
сортировка списка абсолютных параметров, исключение
ложных и ненадежных минюций;
4)
конвертирование абсолютных параметров в
отностительные, формирование списка относительных параметров;
5)
установка системы допусков для учета корреляцции
изображений;
6)
сравнение одного отпечатка с множеством других.
Данная работа реализует такое преобразование
изображения, при котором данные о расположение уникальных особенностей
сохраняются наиболее полно и с наименьшим содержанием ложной информации.
Создаваемая система облегчит разработку алгоритмов
обработки изображений, упростит анализ экспериментальных данных и выявление
общих закономерностей.
П.3.2.
УСЛОВИЯ ВЫПОЛНЕНИЯ ПРОГРАММЫ
Программа FingerAnalyser
предъявляет следующие требования к техническим средствам:
-
стандартный x86-совместимый
ПК;
-
тактовая частота процессора 900 МГц или более;
-
объем оперативной памяти не менее 64 Мб;
-
разрешение экрана монитора не менее 1024x768.
Программа FingerAnalyser
предъявляет следующие требования к программным средствам:
-
операционная система семейства Windows (Windows 9x/ME/NT/2000/XP);
-
dll библиотеки MFC
П.3.3.
ВЫПОЛНЕНИЕ ПРОГРАММЫ
Интерфейс программы представлен на рис. П.3.1.
Интерфейс программы FingerAnalyser
Рис. П.3.1
На форме программы в визуальном виде
представляется, после открытия через пункт «Открыть», исходное изображение,
после нажатия на кнопку «Анализ», скорректированное изображение и визуальное
представление структурного вида отпечатка. Для вызова работы подсистемы
необходимо в оболочке системы на главном окне нажать на кнопку «Сравнить».
При каждом анализе отпечатка создается файл с его
структурным описанием. Для того чтобы поместить отпечаток в базу данных
отпечатков, для последующего стравнения с ним, необходимо нажать на кнопку
«Запомнить в базу». Для запоминания в базу можно выбирать группу файлов для
применения операции записи в базу данных для всех выбранных файлов.
П.3.4.
СООБЩЕНИЯ ОПЕРАТОРУ
Сообщения, выдаваемые оператору, приведены в табл.
П.3.1.
Таблица П.3.1
Сообщения оператору
Сообщение
|
Действие оператора
|
Отпечаток не обработан
|
Прежде чем запускать сравнение необьходимо провести анализ
|
База данных пуста
|
В базе данных нет информации ни об одном отпечатке.
Необходимо заполнить базу данных отпечатков
|
Отпечаток не пригоден для сохранения в базу
|
На отпечатке либо слишком мало обнаружено минюций, менее
10, либо слишком много, более 80
|
Ни одного отпечатка не найдено
|
В результате поиска не совпало ни одного отпечтака
|
Невозможно создать базу данных с отпечатками
|
Возможно нет прав на запись или нет свободного места на
носителе
|
Невозможно создать файл
|
Возможно нет прав на запись или нет свободного места на
носителе
|
Невозможно открыть файл
|
Возможно нет прав на чтение или не сеществует запрашиваемого
файла на носителе
|
Обнаружены сходства
|
В базе данных были обнаружены отпечатки, имеющие схожее
представление.
|
Визуализация результатов проведения сравнения
приведена на рис. П.3.1.
В табл. П.4.1 приведены результаты сравнения всех
отпечатков полученных при испытаниях. Для проверки правильности работы имена
файлам давались таким образом, что бы можно было определить принадлежность
отпечатка.
Формат результата сравнения: A/B,
где A – количество
совпавших минюций;
B – процент совпадения.
Формат имени файла: <Name><R|L><C>_<E>.bmp
где Name – имя
человека, которому принадлежит отпечаток;
R – отпечаток с правой руки, L – отпечаток с левой руки;
С – порядковый номер пальца, начиная с
большого;
E – экземпляр отпечатка.
Таблица П.4.1
Результаты сравнения
|
vovR2_1.bmp
|
1L1_1.BMP
|
1L2_1.BMP
|
1L3_1.BMP
|
1R1_1.BMP
|
1R2_1.BMP
|
1R3_1.BMP
|
1R4_1.bmp
|
2l1_1.bmp
|
2l2_1.bmp
|
2r1_0.bmp
|
2r2_0.bmp
|
1L1_2.bmp
|
|
24/100
|
|
|
|
|
|
|
|
|
|
|
1L2_2.BMP
|
|
|
9/90
|
|
|
|
|
|
|
|
|
|
1R1_2.BMP
|
|
|
|
|
23/100
|
|
|
|
|
|
|
|
1R2_1rotate2.bmp
|
|
|
|
|
|
23/100
|
|
|
|
|
|
|
1R2_2.BMP
|
|
|
|
|
|
16/100
|
|
|
|
|
|
|
1R3_2.BMP
|
|
|
|
|
|
|
1/10
|
3/30
|
|
|
|
|
1R4_2.bmp
|
|
|
|
|
|
|
|
15/100
|
|
|
|
|
2l1_2.bmp
|
|
|
|
|
|
|
|
|
14/100
|
|
|
|
2l2_2.bmp
|
|
|
|
|
|
|
|
|
|
8/80
|
|
|
2r1_1.bmp
|
|
|
|
|
|
|
|
|
|
|
|
|
2r2_1.bmp
|
|
1/10
|
|
|
|
|
|
|
|
|
|
|
2r3_1.bmp
|
|
|
|
|
|
|
|
|
|
|
|
|
3l1_2rotate.bmp
|
|
|
|
|
|
|
|
|
|
|
|
|
3l2_2.bmp
|
|
|
|
|
|
|
|
|
|
|
|
|
alexR1_3.bmp
|
|
|
|
|
|
|
|
|
|
|
|
|
alexR2_3.bmp
|
|
|
|
|
|
|
|
|
|
|
|
1L1_2.bmp
|
|
|
|
|
|
|
|
|
|
|
|
|
1L2_2.BMP
|
|
|
|
|
|
|
|
|
|
|
|
|
1R1_2.BMP
|
|
|
|
|
|
|
|
|
|
|
|
|
1R2_1rotate2.bmp
|
|
|
|
|
|
|
|
|
|
|
|
|
1R2_2.BMP
|
|
|
|
|
|
|
|
|
|
|
|
|
1R3_2.BMP
|
|
|
|
|
|
|
|
|
|
|
|
|
1R4_2.bmp
|
|
|
|
|
|
|
|
|
|
|
|
|
2l1_2.bmp
|
|
|
|
|
|
|
|
|
|
|
|
|
2l2_2.bmp
|
|
|
|
|
|
|
|
|
|
|
|
|
2r1_1.bmp
|
|
|
|
2/20
|
|
|
|
|
|
|
|
|
2r2_1.bmp
|
|
|
|
|
|
|
|
|
|
|
|
|
2r3_1.bmp
|
48/100
|
|
|
|
|
|
|
|
|
|
|
|
3l1_2rotate.bmp
|
|
24/100
|
|
|
1/10
|
|
|
|
|
|
|
|
3l2_2.bmp
|
|
|
21/100
|
|
|
|
|
|
|
|
|
|
alexR1_3.bmp
|
|
|
|
|
|
4/40
|
|
|
|
|
|
|
alexR2_3.bmp
|
|
|
|
|
|
|
4/40
|
|
|
|
|
|
apmAR1_2.bmp
|
|
|
|
|
|
|
|
4/40
|
|
|
|
|
apmAR2_2.bmp
|
|
|
|
|
|
|
|
|
9/90
|
|
|
|
apmAR3_2.bmp
|
|
|
|
|
|
|
|
|
|
|
|
|
apmBR1_2.bmp
|
|
|
|
|
|
|
|
|
|
|
12/100
|
|
apmBR2_2.bmp
|
|
|
|
|
|
|
|
|
|
|
|
20/100
|
apmBR3_2.bmp
|
|
|
|
|
|
|
|
|
|
|
|
|
hedgeR1_2.bmp
|
|
|
|
|
|
|
|
|
|
|
|
|
hedgeR2_3.bmp
|
|
|
|
|
|
|
|
|
|
|
|
|
karR1_2.bmp
|
|
|
|
|
|
|
|
|
|
|
|
|
karR2_2.bmp
|
|
|
|
|
|
|
|
|
|
|
|
|
starkyR1_2.bmp
|
|
|
|
|
|
|
|
|
|
|
|
|
starkyR2_2.bmp
|
|
|
|
|
|
|
|
|
|
|
|
|
starR1_2.bmp
|
|
|
|
|
|
|
|
|
|
|
|
|
vasL1_2.bmp
|
|
|
|
|
|
|
|
|
|
|
|
|
vasL2_2.bmp
|
|
|
|
|
|
|
|
|
|
|
|
|
vasR1_2.bmp
|
|
|
|
|
|
|
|
|
|
|
|
|
vovR1_2.bmp
|
|
|
|
|
|
|
|
|
|
|
|
|
1L1_2.bmp
|
|
|
|
|
|
|
|
|
|
|
|
|
1L2_2.BMP
|
|
|
|
|
|
|
|
|
|
|
|
|
1R1_2.BMP
|
|
|
|
|
|
|
|
|
|
|
|
|
1R2_1rotate2.bmp
|
|
|
|
|
|
|
|
|
|
|
|
|
1R2_2.BMP
|
|
|
|
|
|
|
|
|
|
|
|
|
1R3_2.BMP
|
|
|
|
|
|
|
|
|
|
|
|
|
1R4_2.bmp
|
|
|
|
|
|
|
|
|
|
|
|
|
2l1_2.bmp
|
|
|
|
|
|
|
|
|
|
|
|
|
2l2_2.bmp
|
|
|
|
|
|
|
|
1/10
|
|
|
|
|
2r1_1.bmp
|
|
|
|
|
|
|
|
|
|
|
|
|
2r2_1.bmp
|
|
|
|
|
|
|
|
|
|
|
|
|
2r3_1.bmp
|
|
|
|
|
|
|
|
|
|
|
|
|
3l1_2rotate.bmp
|
|
|
|
|
|
|
|
|
|
|
|
|
3l2_2.bmp
|
|
|
|
|
|
|
|
|
|
|
|
|
alexR1_3.bmp
|
|
|
|
|
|
|
|
|
|
|
|
|
alexR2_3.bmp
|
|
|
|
|
|
|
|
|
|
|
|
|
apmAR1_2.bmp
|
|
|
|
|
|
|
|
|
|
|
|
|
apmAR2_2.bmp
|
|
|
|
|
|
|
|
|
|
|
|
|
apmAR3_2.bmp
|
|
|
|
|
|
|
|
|
|
|
|
|
apmBR1_2.bmp
|
|
|
|
|
|
|
|
|
|
|
|
|
apmBR2_2.bmp
|
|
|
|
|
|
|
|
|
|
|
|
|
apmBR3_2.bmp
|
14/100
|
|
|
|
|
|
|
|
|
|
|
|
hedgeR1_2.bmp
|
|
7/70
|
|
|
|
|
|
|
|
|
|
|
hedgeR2_3.bmp
|
|
|
6/60
|
|
|
|
|
|
|
|
|
|
karR1_2.bmp
|
|
|
|
15/100
|
|
|
|
|
|
|
|
|
karR2_2.bmp
|
|
|
|
|
2/20
|
|
|
|
|
|
|
|
starkyR1_2.bmp
|
|
|
|
|
|
12/100
|
|
|
|
|
|
|
starkyR2_2.bmp
|
|
|
|
|
|
|
6/60
|
|
|
|
|
|
starR1_2.bmp
|
|
|
|
|
|
|
|
22/100
|
|
|
|
|
vasL1_2.bmp
|
|
|
|
|
|
|
|
|
20/100
|
|
|
|
vasL2_2.bmp
|
|
|
|
|
|
|
|
|
|
10/100
|
|
|
vasR1_2.bmp
|
|
|
|
|
|
|
|
|
|
|
15/100
|
|
vovR1_2.bmp
|
|
|
|
|
|
|
|
|
|
|
|
49/100
|
Для тестирования программы было использовано 2
метода распознавания. Метод 1 не зависит от ориентации буквы на плоскости,
метод 2 имеет привязанность к вертикальному положению буквы. При распознавании
символьной информации было не распознано около 18% по методу 2 и 22% по методу
1. Результат сравнения приведен в табл. П.5.1.
Формат результата сравнения: A/B,
где A – количество
совпавших минюций;
B – процент совпадения.
Таблица П.5.1
Результат распознавания символов
Открытый образ
|
Результат сравнения (метод
2)
|
Открытый образ
|
Результат сравнения (метод
1)
|
|
|
Первое обнаруженное
значение
|
Второе
обнаруженное
значение
|
|
Первое обнаруженное
значение
|
Второе
обнаруженное
значение
|
|
_a1.bmp
|
А (4/80)
|
Н (5/62)
|
_a1.bmp
|
Н (2 25)
|
Ы (1 20)
|
|
_a2.bmp
|
А (5/100)
|
Н (3/37)
|
_a2.bmp
|
А (2 40)
|
Ц (1 11)
|
|
_б1.bmp
|
Б (5/100)
|
Г (3/60)
|
_б1.bmp
|
Б (5 100)
|
Ш (4 44)
|
|
_б2.bmp
|
Б (5/83)
|
Е (5/55)
|
_б2.bmp
|
Б (5 83)
|
Ш (4 44)
|
|
_в1.bmp
|
В (3/100)
|
|
_в1.bmp
|
В (3 100)
|
Е (1 11)
|
|
_в2.bmp
|
В (3/100)
|
|
_в2.bmp
|
В (3 100)
|
Б (1 20)
|
|
_г1.bmp
|
Г (3/75)
|
Б (3/60)
|
_г1.bmp
|
Г (3 75)
|
Б (3 60)
|
|
_г2.bmp
|
Г (4/66)
|
Е (5/55)
|
_г2.bmp
|
Г (4 66)
|
Щ (3 20)
|
|
_д1.bmp
|
Д (8/80)
|
Щ (7/46)
|
_д1.bmp
|
Д (8 80)
|
Г (3 30)
|
|
_д2.bmp
|
Д (8/80)
|
Щ (5/33)
|
_д2.bmp
|
Д (9 90)
|
Щ (3 20)
|
|
_е1.bmp
|
Е (7/70)
|
Ы (8/61)
|
_е1.bmp
|
Е (7 70)
|
Э (5 50)
|
|
_ж1.bmp
|
Ж (10/83)
|
Х (7/58)
|
_ж1.bmp
|
Ж (10 83)
|
Х (7 58)
|
|
_ж2.bmp
|
Ж (10/83)
|
Ж (6/50)
|
_ж2.bmp
|
Ж (10 83)
|
Х (7 58)
|
|
_з1.bmp
|
З (5/55)
|
Д (4/40)
|
_з1.bmp
|
З (5 55)
|
Э (4 44)
|
|
_з2.bmp
|
Э (4/57)
|
Щ (3/20)
|
_з2.bmp
|
Е (5 55)
|
Ю (1 14)
|
|
_и1.bmp
|
И (5/83)
|
Х (4/57)
|
_и1.bmp
|
И (4 66)
|
К (4 57)
|
|
_и2.bmp
|
И (4/66)
|
Ы (3/50)
|
_и2.bmp
|
И (4 66)
|
М (5 62)
|
|
_к1.bmp
|
К (7/100)
|
Ж (6/54)
|
_к1.bmp
|
К (7 100)
|
Ж (6 54)
|
|
_к2.bmp
|
К (7/100)
|
М (4/50)
|
_к2.bmp
|
К (7 100)
|
Ж (7 63)
|
|
_л1.bmp
|
П (5/83)
|
Л (4/57)
|
_л1.bmp
|
П (4 66)
|
Л (4 57)
|
|
_л2.bmp
|
П (5/83)
|
Л (4/57)
|
_л2.bmp
|
П (5 83)
|
Л (4 57)
|
|
_м1.bmp
|
М (6/75)
|
Ж (7/63)
|
_м1.bmp
|
М (7 87)
|
Ж (3 27)
|
|
_м2.bmp
|
М (8/100)
|
И (6/75)
|
_м2.bmp
|
М (8 100)
|
Ъ (2 25)
|
|
_н1.bmp
|
Н (8/100)
|
Ю (6/66)
|
_н1.bmp
|
Н (8 100)
|
Ч (6 75)
|
|
_н2.bmp
|
Н (8/100)
|
Ч (6/75)
|
_н2.bmp
|
Н (8 100)
|
Ч (6 75)
|
|
_о1.bmp
|
|
|
_о1.bmp
|
|
|
_о2.bmp
|
|
|
_о2.bmp
|
|
|
_п1.bmp
|
П (6/100)
|
Л (5/71)
|
_п1.bmp
|
П (6 100)
|
Ш (6 66)
|
_п2.bmp
|
П (6/100)
|
Г (3/50)
|
_п2.bmp
|
П (6 100)
|
Ш (6 66)
|
_р1.bmp
|
Д (3/30)
|
Г (1/25)
|
_р1.bmp
|
Р (1 25)
|
П (1 16)
|
_р2.bmp
|
Х (3/42)
|
Н (3/37)
|
_р2.bmp
|
Р (3 75)
|
Х (3 42)
|
_с1.bmp
|
С (2/40)
|
Ц (2/22)
|
_с1.bmp
|
С (3 60)
|
Ц (2 22)
|
_с2.bmp
|
К (1/14)
|
Ж (1/9)
|
_с2.bmp
|
Щ (1 6)
|
|
_т1.bmp
|
Т (5/100)
|
Г (3/60)
|
_т1.bmp
|
Т (5 100)
|
Г (2 40)
|
_т2.bmp
|
Т (5/100)
|
Г (3/60)
|
_т2.bmp
|
Т (4 80)
|
Г (3 60)
|
_у1.bmp
|
У (5/83)
|
Ч (5/71)
|
_у1.bmp
|
Ю (4 44)
|
Ш (4 44)
|
_у2.bmp
|
У (4/80)
|
Щ (4/26)
|
_у2.bmp
|
У (1 20)
|
К (1 14)
|
_ф1.bmp
|
Ф (3/100)
|
П (3/50)
|
_ф1.bmp
|
П (3 37)
|
Ц (3 33)
|
_ф2.bmp
|
Ф (3/100)
|
П (3/50)
|
_ф2.bmp
|
Ф (3 100)
|
Ц (3 33)
|
_х1.bmp
|
Х (7/87)
|
Ж (7/63)
|
_х1.bmp
|
Х (7 87)
|
Ч (4 50)
|
_х2.bmp
|
Х (7/87)
|
К (6/75)
|
_х2.bmp
|
К (5 62)
|
_ц1.bmp
|
Ц (8/88)
|
Ш (5/55)
|
_ц1.bmp
|
Ц (8 88)
|
П (4 50)
|
_ц2.bmp
|
Ц (9/100)
|
Ш (6/66)
|
_ц2.bmp
|
Ц (7 77)
|
Ш (6 66)
|
_ч1.bmp
|
Ч (7/100)
|
Ц (7/77)
|
_ч1.bmp
|
Ч (7 100)
|
Н (5 62)
|
_ч2.bmp
|
Ч (7/100)
|
Ц (7/77)
|
_ч2.bmp
|
Ч (7 100)
|
П (5 71)
|
_ш1.bmp
|
Ш (6/66)
|
Ц (5/55)
|
_ш1.bmp
|
Ш (6 66)
|
П (5 62)
|
_ш2.bmp
|
Ш (6/66)
|
Ц (5/55)
|
_ш2.bmp
|
П (5 62)
|
Ы (3 37)
|
_щ1.bmp
|
Ц (9/81)
|
Ю (8/72)
|
_щ1.bmp
|
Ц (6 54)
|
Щ (7 46)
|
_ъ1.bmp
|
Ъ (5/83)
|
Д (3/30)
|
_ъ1.bmp
|
Ъ (4 66)
|
Г (3 60)
|
_ъ2.bmp
|
Ъ (5/83)
|
З (2/33)
|
_ъ2.bmp
|
Ъ (5 83)
|
Ы (4 30)
|
_ы1.bmp
|
Ы (4/66)
|
Ч (4/57)
|
_ы1.bmp
|
Ь (3 50)
|
Ы (2 33)
|
_ы2.bmp
|
Ы (4/66)
|
Ь (3/50)
|
_ы2.bmp
|
Ы (5 83)
|
Ь (3 50)
|
_ь1.bmp
|
Ь (3/75)
|
Ы (3/60)
|
_ь2.bmp
|
Ь (3 60)
|
Н (2 25)
|
_ь2.bmp
|
Ю (2/22)
|
Щ (2/13)
|
_ь1.bmp
|
Ь (3 75)
|
Я (3 42)
|
_э1.bmp
|
Э (3/50)
|
Л (1/14)
|
_э1.bmp
|
Э (3 50)
|
Ш (1 11)
|
_э2.bmp
|
Э (5/100)
|
Щ (1/6)
|
_э2.bmp
|
Е (5 55)
|
Э (1 20)
|
_ю1.bmp
|
Ю (8/88)
|
Н (7/77)
|
_ю1.bmp
|
Ю (7 77)
|
Ч (6 66)
|
_ю2.bmp
|
Н (7/77)
|
Ю (6/66)
|
_ю2.bmp
|
Н (6 66)
|
Ю (5 55)
|
_я1.bmp
|
Я (5/71)
|
Ж (4/36)
|
_я1.bmp
|
Я (5 71)
|
Ж (1 9)
|
_я2.bmp
|
Я (4/57)
|
Ю (4/44)
|
_я2.bmp
|
Я (3 42)
|
Ь (2 33)
|
Тестирование на чувствительность к
ориентации образа на плоскости:
|
_А_10.bmp
|
А (4 80)
|
Х (3 42)
|
_А_10.bmp
|
А (1 20)
|
Р (1 20)
|
_А_90.bmp
|
Е (3 33)
|
Б (2 33)
|
_А_90.bmp
|
А (4 80)
|
Ж (3 27)
|
_А_30.bmp
|
Ю (4 66)
|
Ч (3 50)
|
_А_30.bmp
|
А (4 80)
|
Ж (3 25)
|
_А_15.bmp
|
Ю (3 50)
|
Ц (3 42)
|
_А_15.bmp
|
А (3 60)
|
Щ (4 26)
|
|
|
|
|
|
|
|
|
|
|
|
|
Итого по методу 2: 11 нераспознано и 15
распознано лучше, чем метод 1.
Итого по методу 1: 13 нераспознано и 6 распознано
лучше, чем метод 2.