Приём заказов:
Круглосуточно
Москва
ул. Никольская, д. 10.
Ежедневно 8:00–20:00
Звонок бесплатный

Разработка системы для автоматического анализа цифровых изображений номерных знаков автомобилей

Диплом777
Email: info@diplom777.ru
Phone: +7 (800) 707-84-52
Url:
Логотип сайта компании Диплом777
Никольская 10
Москва, RU 109012
Содержание

Реферат

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

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

Разработано программное обеспечение системы автоматического выделения цифробуквенных символов номерного знака автомобиля по цифровым изображениям. Алгоритмы реализованы на языке С++ в среде MS Visual Studio .NET 2003 с использованием сторонних стандартных библиотек Qt by TrollTech v4.1.0 (VS2003). Разработанное программное обеспечение протестировано на значительном количестве реальных цифровых изображений номерных знаков автомобилей.

Содержание

  • Введение
  • 1. Разработка алгоритмов автоматического анализа цифровых изображений номерных знаков с целью сегментации цифробуквенных символов
  • 1.1 Общая структура алгоритма автоматического анализа цифровых изображений номерных знаков с целью сегментации цифробуквенных символов
  • 1.2 Выделение контуров на исходном изображении
  • 1.3 Выделение горизонтальной полосы, содержащей цифробуквенные символы
  • 1.3.1 Вычисление горизонтальной проекции
  • 1.3.2 Анализ горизонтальной проекции
  • 1.4 Сбор и анализ вертикальных проекций яркости и размаха яркости
  • 1.4.1 Вычисление вертикальной проекции яркости
  • 1.4.2 Вычисление вертикальной проекции размаха яркости
  • 1.5 Выделение цифробуквенных символов на исходном изображении
  • 2. Программная реализация системы автоматического выделения номерных знаков
  • 2.1 Средство разработки
  • 2.2 Программная реализация алгоритма автоматического анализа цифровых изображений номерных знаков с целью сегментации цифробуквенных символов
  • 2.2.1 Структура программной реализации
  • 2.2.2 Программная реализация обработки входного изображения
  • 2.2.3 Программная реализация графического пользовательского интерфейса
  • 3. Полученные результаты
  • Заключение
  • Приложение
  • Введение
  • В наше время, в связи с увеличением количества автомобилей, а, следовательно, с увеличением количества угонов, появилась острая необходимость автоматического контроля государственных номерных знаков на дорогах. Для этого может использоваться система машинного зрения для автоматического выделения и распознавания номерных знаков по цифровым изображениям автомобилей. Такая система необходима для отслеживания правонарушителей и нахождения автомобилей, числящихся в розыске. Эта система будет максимально эффективна, если ее использовать перед контрольными пунктами на въездах и выездах крупных городов, также можно оборудовать машины дорожно-постовой службы. Система будет оповещать пользователя, если будут выявлены правонарушители или автомобиль, числящийся в угоне. Такое оповещение возможно, если водитель нарушает правила дорожного движения или автомобиль числится в розыске.
  • Разрабатываемая система автоматического анализа цифровых изображений номерных знаков автомобилей с целью сегментации цифробуквенных символов (методом анализа проекций) является частью такой системы автоматического выделения и распознавания номерных знаков по цифровым изображениям
  • Требуется разработать систему машинного зрения для автоматического анализа цифровых изображений номерных знаков автомобилей с целью сегментации цифробуквенных символов (методом анализа проекций). Реализовать и исследовать различные методы выделения цифробуквенных символов. Система должна включать персональный компьютер, а также средства ввода и анализа цифровых изображений. Должна быть разработана структурная схема системы. Должно быть разработано алгоритмическое обеспечение системы. Должно быть разработано программное обеспечение системы. Программное обеспечение системы должно быть отработано на предоставленных экспериментальных регистрациях цифровых изображений номерных знаков автомобилей. Разработка системы должна осуществляться путем программирования на языке С++ с использованием стандартных библиотек.
  • Разработке подлежат следующие вопросы:
  • · разработка структуры системы;
  • · разработка алгоритмов автоматического анализа номерных знаков на изображениях с целью сегментации цифробуквенных символов;
  • · разработка программного обеспечения системы;
  • · отработка программного обеспечения системы на предоставленных экспериментальных регистрациях цифровых изображений номерных знаков.
  • Дипломный проект имеет следующую структуру:

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

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

В заключении перечислены основные результаты и выводы по работе.

В приложении приводится программный код разработанной программной реализации системы.

1. Разработка алгоритмов автоматического анализа цифровых изображений номерных знаков с целью сегментации цифробуквенных символов

1.1 Общая структура алгоритма автоматического анализа цифровых изображений номерных знаков с целью сегментации цифробуквенных символов

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

Таким образом, разработанный алгоритм имеет следующую структуру:

1. Выделение контуров на исходном изображении.

2. Выделение горизонтальной полосы, содержащей цифробуквенные символы.

3. Сбор и анализ вертикальных проекций яркости и размаха яркости.

4. Выделение цифробуквенных символов на исходном изображении.

Далее подробно описан каждый из этапов алгоритма.

1.2 Выделение контуров на исходном изображении

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

Рис.1. Входное изображение

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

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

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

Изображение, обработанное с помощью краевой фильтрации

1.3 Выделение горизонтальной полосы, содержащей цифробуквенные символы

1.3.1 Вычисление горизонтальной проекции

Следующий шаг – это вычисление горизонтальной проекции яркости. Данная операция нужна для того, чтобы по проекции определить наиболее выделившиеся объекты.

Горизонтальная проекция от контурного препарата

1.3.2 Анализ горизонтальной проекции

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

Исходное изображение с выделенной на нем горизонтальной полосой

Дальнейший анализ изображения проводится только в выделенной горизонтальной полосе.

1.4 Сбор и анализ вертикальных проекций яркости и размаха яркости

1.4.1 Вычисление вертикальной проекции яркости

На следующем шаге вычисляется вертикальная проекция яркости. Значением проекции является сумма значений яркости для всех точек столбца в выделенной полосе.

Вертикальная проекция яркости

1.4.2 Вычисление вертикальной проекции размаха яркости

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

Вертикальная проекция размаха яркости

1.4.2 Анализ вертикальных проекций яркости и размаха яркости

Исследование особенностей тестовых изображений позволило определить связи между экстремальными точками проекций и особенностями изображений, а именно:

Локальным минимумам проекции яркости соответствует положение вертикальных штрихов в начертании текстовых символов.

Локальным максимумам проекции яркости соответствуют промежутки между текстовыми символами (первичные максимумы), а также промежутки между двумя ярко выраженными вертикальными штрихами в середине символа (вторичные максимумы); вторичные максимумы имеют несколько меньшие абсолютные значения.

Локальным минимумам проекции размаха яркости также соответствуют промежутки между текстовыми символами.

Таким образом, для нахождения промежутка, разделяющего два соседних символа, необходимо найти такие максимумы проекции яркости, которым соответствуют минимумы проекции размаха яркости.

Таким образом, процедура анализа вертикальных проекций имеет следующие шаги:

Поиск локальных экстремумов проекций яркости и размаха яркости.

Удаление вторичных максимумов проекции яркости и вторичных минимумов проекции размаха яркости.

Определение локальных максимумов проекции яркости, имеющих соответствующие минимумы в проекции размаха яркости.

Вторичные максимумы и минимумы определяются на основе следующего простого правила:

вторичный максимум проекции яркости – максимум, который, по крайней мере, на 7% амплитуды меньше чем оба соседних к нему максимума

вторичный минимум проекция размаха яркости – минимум, который, по крайней мере, на 35% амплитуды больше чем оба соседних к нему минимума. Представленные значения были получены экспериментальным путем.

1.5 Выделение цифробуквенных символов на исходном изображении

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

Исходное изображение с выделенными на нем цифробуквенными символами

2. Программная реализация системы автоматического выделения номерных знаков

2.1 Средство разработки

Программа написана на языке С++ в среде Microsoft Visual Studio .NET 2003 с использованием набора инструментальных средств разработчика Qt by TrollTech v4.1.0 (VS2003). Основной отличительной особенностью этого набора является межплатформность приложений, разработанных с его помощью (single-source portability). Также использовалась интеграция этого пакета в среду Visual Studio – Qt Integration for Visual Studio .NET.

2.2 Программная реализация алгоритма автоматического анализа цифровых изображений номерных знаков с целью сегментации цифробуквенных символов

2.2.1 Структура программной реализации

Программная реализация алгоритма автоматического анализа цифровых изображений номерных знаков с целью сегментации цифробуквенных символов состоит из пяти основных файлов:

Main.cpp

Основной модуль, в котором создается объект приложения и объект класса ImageViewer

Imageviewer.cpp

Imageviewer.h

Модули, содержащие в себе описание и реализацию класса ImageViewer. Класс отвечает за работу всего приложения в целом и обеспечивает графический пользовательский интерфейс приложения.

Myimage.cpp

MyImage.h

Модули, содержащие в себе описание и реализацию класса MyImage. Класс отвечает за непосредственную обработку входного изображения: контурную фильтрацию, построение и анализ горизонтальной проекции яркости, вертикальной проекции яркости и вертикальной проекции размаха яркости.

2.2.2 Программная реализация обработки входного изображения

Обработка изображения реализована в классе MyImage. Этот класс наследован от стандартного класса библиотеки Qt QImage. Таким образом, он наследует все стандартные методы работы с изображениями. В дополнение он расширен следующими основными функциями:

void MyImage::Sobel()

Функция реализует контурную фильтрацию изображения с использованием вертикальной маски Собела. Таким образом, эта функция выделяет вертикальные контуры в исходном изображении. После фильтрации функция перерисовывает исходной изображение контурным препаратом.

void MyImage::hCollectData()

Функция вычисляет горизонтальную проекцию изображения (заполняет массив int *hHist), находит в полученной гистограмме экстремальные точки, которые потом используются для выделения горизонтальной полосы, формирует списки максимумов QList<int> hMaxList и минимумов QList<int> hMinList горизонтальной гистограммы яркости.

void MyImage::setMinMaxJ()

Функция выделяет горизонтальную полосу int jMin, jMax, содержащую в себе знако-буквенные символы, основываясь на данных, полученных предыдущей функцией.

void MyImage::hHistDraw()

Функция рисует горизонтальную гистограмму по массиву int *hHist, помечает горизонтальную полосу, выделенную функцией setMinMaxJ()

void MyImage::vCollectData()

Функция вычисляет вертикальные проекции яркости и размаха яркости в выделенной горизонтальной полосе изображения, соответственно заполняет массивы int *vHist и int *vDifHist, находит в полученных гистограммах экстремальные точки QList<int> maxList, minList, maxDifList, minDifList.

void MyImage::vHistDraw()

Функция рисует вертикальную гистограмму яркости по массиву int *vHist, помечает найденные максимумы гистограммы QList<int> maxList.

void MyImage::vDifHistDraw()

Функция рисует вертикальную гистограмму размаха яркости по массиву int *vDifHist, помечает найденные минимумы гистограммы QList<int> minDifList.

void MyImage::imageDraw()

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

2.2.3 Программная реализация графического пользовательского интерфейса

Графический интерфейс программной реализации реализован в классе ImageViewer. Этот класс наследован от стандартного класса библиотеки Qt QMainWindow. В классе реализованы следующие основные функции.

void open();

предоставляет пользователю диалог для указания файла, содержащего входное изображение.

Окно программы с диалогом ввода исходного файла изображения

После указания файла соответствующее изображение отображается в окне программы.

Окно программы, отображающее введенное изображение

проекция программный автоматический интерфейс

void print();

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

Окно программы с диалогом распечатывания основного изображения

void selectSigns();

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

Окно программы, отображающее выходное изображение

void detailedView();

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

Окно программы, показывающее детальный вид отображения

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

void createMenus();

Функция создает пользовательское меню в окне приложения.

Пользовательское меню

Пользовательское меню содержит в себе следующие пункты:

· File (Файл)

Open File (Открыть файл)

Print (Печать)

Exit (Выход)

· Edit (Изменить)

Select Signs (Выделить символы)

· View (Вид)

Detailed View (Делальный вид)

· Help (Помощь)

About(О программе)

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

3. Полученные результаты

В данном разделе приводятся примеры применения алгоритма для автоматического анализа цифровых изображений государственных номерных знаков автомобилей. На рисунках показаны предоставленные исходные изображения номерных знаков и изображения с выделенными цифробуквенными символами. Исходя из полученных результатов, можно сделать вывод, что данный алгоритм анализа изображений хорошо работает для большой части изображений, однако для некоторых изображений допускает характерные ошибки:

· Установка вертикального разделителя в центре символа, где ожидался вторичный максимум, несколько меньший по величине, чем соседние локальные максимумы вертикальной проекции яркости. (Пример 3)

· Потеря разделителя между символами, то есть объединение двух символов в один объемлющий прямоугольник. (Пример 4)

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

Рис.N. Пример изображения автомобильного номера с результатами сегментации.

Пример 2

Пример 3

Пример 4

Пример 5

Заключение

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

В ходе работы над дипломным проектом получены следующие основные результаты.

1. Разработано алгоритмическое обеспечение системы для автоматического анализа изображений номерных знаков с целью сегментации цифробуквенных символов. Разработанный алгоритм имеет следующую структуру:

· Выделение контуров на исходном изображении.

· Выделение горизонтальной полосы, содержащей цифробуквенные символы.

· Сбор и анализ вертикальных проекций яркости и размаха яркости.

· Выделение цифробуквенных символов на исходном изображении.

2. Разработано программное обеспечение системы автоматического анализа цифровых изображений номерных знаков с целью сегментации цифробуквенных символов. Алгоритмы реализованы на языке С++ в среде MS Visual Studio .NET 2003 с использованием сторонних стандартных библиотек Qt by TrollTech v4.1.0 (VS2003).

3. Разработанное программное обеспечение протестировано на значительном количестве реальных цифровых изображениях номерных знаков автомобилей. Эксперименты показали, что разработанные алгоритмы решения и программное обеспечение системы хорошо работают для большой части изображений, однако для некоторых изображений допускают характерные ошибки. В связи с этим предложены следующие меры по усовершенствованию алгоритмов:

· Усовершенствование алгоритма анализа вертикальных проекций яркости и размаха яркости

· Дополнительный анализ знакомест на основе постоянности отношения высоты символа к его ширине.

Приложение. Программный код разработанной программной реализации системы

Файл Main.cpp

#include <QApplication>

#include “imageviewer.h”

int main(int argc, char *argv[])

{

QApplication app(argc, argv);

ImageViewer imageViewer;

imageViewer.show();

return app.exec();

}

Файл MyImage.h

#ifndef MYIMAGE_H

#define MYIMAGE_H

#include <QImage>

#include <QList>

class MyImage : public QImage

{

public:

MyImage( const QString & fileName, const char * format = 0 );

void hCollectData();

void vCollectData();

void vDifHistDraw();

void hHistDraw();

void vHistDraw();

void imageDraw();

void setMinMaxJ();

void Sobel();

void imageRestore();

QImage *pImage, *pBufImage;

private slots:

private:

int jMin, jMax;

int *hHist, *vHist;

int *hDifHist, *vDifHist;

QList<int> hMaxList, hMinList, maxList, minList, maxDifList, minDifList;

int vHistMax, hHistMax, vDifHistMax;

};

#endif

Файл MyImage.cpp

#include “myimage.h”

#include <QtGui>

#include <QMessageBox>

#include “math.h”

//конструктор

MyImage::MyImage( const QString & fileName, const char * format ) :QImage( fileName, format )

{

pImage = new QImage(fileName,format);

pBufImage = new QImage(fileName,format);

vHist = new int[this->width()];

hHist = new int[this->height()];

vDifHist = new int[this->width()];

hDifHist = new int[this->height()];

maxList.clear();

minList.clear();

hMinList.clear();

hMaxList.clear();

maxDifList.clear();

minDifList.clear();

jMin = 0;

jMax = this->height()-1;

vHistMax=0;

hHistMax=0;

vDifHistMax=0;

}

//горизонтальная проекция

void MyImage::hCollectData(){

int i,j,sum;

int width = this->width();

int height = this->height();

for (j=0; j<height; j++){

sum = 0;

for (i=0; i<width; i++){

sum = sum + qGray(this->pixel(i,j));

}

hHist[j] = sum;

if (hHist[j] > hHistMax) hHistMax = hHist[j];

}

for (j=1; j<height-1; j++){

if (( (width*hHist[j-1]/hHistMax) <= (width*hHist[j]/hHistMax) ) && ( (width*hHist[j]/hHistMax) >= (width*hHist[j+1]/hHistMax) ))

hMaxList.append(j);

if (( (width*hHist[j-1]/hHistMax) >= (width*hHist[j]/hHistMax) ) && ( (width*hHist[j]/hHistMax) <= (width*hHist[j+1]/hHistMax) ))

hMinList.append(j);

}

}

//выделение горизонтальной полосы

void MyImage::setMinMaxJ(){

int i,j;

double kMin=0.2;

double kMax=0.55;

int height = this->height();

int thresholdMin = (int)hHistMax*kMin;

int thresholdMax = (int)hHistMax*kMax;

for (j=0; j<height-1; j++){

if((hHist[j] > thresholdMax)&&(hHist[j+1] < thresholdMax)) jMax = j+1;

}

j = hMinList.size();

for (i=0; i<j; i++){

if (hHist[hMinList.at(i)]>thresholdMin){

break;

}

}

jMin = hMinList.at(i);

}

//вертикальная проекция

void MyImage::vCollectData(){

int i,j,sum,max,min;

int width = this->width();

int height = this->height();

int color;

vHistMax=0;

for (i=0; i<width; i++){

sum = 0;

max = qGray(this->pixel(i,0));

min = qGray(this->pixel(i,0));

for (j=jMin; j<=jMax; j++){

color = qGray(this->pixel(i,j));

if (max < color) max = color;

if (min > color) min = color;

sum = sum + color;

}

vDifHist[i] = max – min;

vHist[i] = sum;

if (vHist[i] > vHistMax) vHistMax = vHist[i];

if (vDifHist[i] > vDifHistMax) vDifHistMax = vDifHist[i];

}

//поиск максимумов вертикальной гистограммы яркости

if ( (height*vHist[0]/vHistMax) > (height*vHist[1]/vHistMax) ){

maxList.append(0);

}

for (i=1; i<width-1; i++){

if (( (height*vHist[i-1]/vHistMax) < (height*vHist[i]/vHistMax) ) && ( (height*vHist[i]/vHistMax) >= (height*vHist[i+1]/vHistMax) ))

maxList.append(i);

}

if ( (height*vHist[width-1]/vHistMax) < (height*vHist[width]/vHistMax) ){

maxList.append(width);

}

//поиск минимумов вертикальной гистограммы яркости

if ( (height*vHist[0]/vHistMax) < (height*vHist[1]/vHistMax) ){

minList.append(0);

}

for (i=1; i<width-1; i++){

if (( (height*vHist[i-1]/vHistMax) > (height*vHist[i]/vHistMax) ) && ( (height*vHist[i]/vHistMax) <= (height*vHist[i+1]/vHistMax) ))

minList.append(i);

}

if ( (height*vHist[width-1]/vHistMax) > (height*vHist[width]/vHistMax) ){

minList.append(width);

}

//поиск минимумов вертикальной гистограммы размаха яркости

if ( (height*vDifHist[0]/vDifHistMax) < (height*vDifHist[1]/vDifHistMax) ){

minDifList.append(0);

}

for (i=1; i<width-1; i++){

if (( (height*vDifHist[i-1]/vDifHistMax) > (height*vDifHist[i]/vDifHistMax) ) && ( (height*vDifHist[i]/vDifHistMax) <= (height*vDifHist[i+1]/vDifHistMax) ))

minDifList.append(i);

}

if ( (height*vDifHist[width-1]/vDifHistMax) > (height*vDifHist[width]/vDifHistMax) ){

minDifList.append(width);

}

//поиск максимумов вертикальной гистограммы размаха яркости

if ( (height*vDifHist[0]/vDifHistMax) > (height*vDifHist[1]/vDifHistMax) ){

maxDifList.append(0);

}

for (i=1; i<width-1; i++){

if (( (height*vDifHist[i-1]/vDifHistMax) < (height*vDifHist[i]/vDifHistMax) ) && ( (height*vDifHist[i]/vDifHistMax) >= (height*vDifHist[i+1]/vDifHistMax) ))

maxDifList.append(i);

}

if ( (height*vDifHist[width-1]/vDifHistMax) < (height*vDifHist[width]/vDifHistMax) ){

maxDifList.append(width);

}

}

//рисование исходного изображения, рисование разделителей

void MyImage::imageDraw(){

int i,j,l;

int width = this->width();

int height = this->height();

int borderColor = 250;

int color;

if (this->isGrayscale()){

for (j=0; j<height; j++){

for (i=0; i<width; i++){

this->setPixel(i,j,qGray(pImage->pixel(i,j)));

}

}

}

else

{

for (j=0; j<height; j++){

for (i=0; i<width; i++){

color = qGray(pImage->pixel(i,j));

this->setPixel(i, j, qRgb(color, color, color));

}

}

}

if( (jMin == 0) && (jMax == this->height()-1) ){

return;

}

else

{

//анализ максимумов и минимумов, рисование вертикальных разделителей между символами

double kMax = 0.93;

double kMin = 1.35;

int q,w,e;

if (!maxList.isEmpty() && !minDifList.isEmpty()){

//удаление вторичных максимумов

j = maxList.size();

if( vHist[maxList.value(0)] < kMax * vHist[maxList.value(1)] ){

maxList.removeAt(0);

j–;

}

for (i=1; i<j-1; i++){

q = maxList.value(i-1);

w = maxList.value(i);

e = maxList.value(i+1);

if( (vHist[w] < kMax * vHist[q]) && (vHist[w] < kMax * vHist[e]) ){

maxList.removeAt(i);

j–;

}

}

if( vHist[maxList.value(j-2)] * kMax > vHist[maxList.value(j-1)] ){

maxList.removeAt(j-1);

j–;

}

//удаление вторичных минимумов

j = minDifList.size();

if( vDifHist[minDifList.value(0)] > kMin * vDifHist[minDifList.value(1)] ){

minDifList.removeAt(0);

j–;

}

for (i=1; i<j-1; i++){

q = minDifList.value(i-1);

w = minDifList.value(i);

e = minDifList.value(i+1);

if( (vDifHist[w] > kMin * vDifHist[q]) && (vDifHist[w] > kMin * vDifHist[e]) ){

minDifList.removeAt(i);

j–;

}

}

if( vDifHist[minDifList.value(j-2)] * kMin < vDifHist[minDifList.value(j-1)] ){

minDifList.removeAt(j-1);

j–;

}

//выбор максимумов гист. яркости соответствующих минимумам гист. размаха яркости

j = maxList.size();

for (i=0; i<j; i++){

w = maxList.value(i);

if ( minDifList.contains(w-1) || minDifList.contains(w) || minDifList.contains(w+1) ){

//

}

else{

maxList.removeAt(i);

}

}

//рисование вертикальных разделителей

j = maxList.size();

if (this->isGrayscale()){

for (i=0; i<j; i++){

w = maxList.value(i);

for (l=0; l<height; l++){

this->setPixel(w, l, borderColor);

}

}

}

else{

for (i=0; i<j; i++){

w = maxList.value(i);

for (l=0; l<height; l++){

this->setPixel(w, l, qRgb(borderColor, borderColor, borderColor));

}

}

}

}

//рисование горизонтальной полосы

if (this->isGrayscale()){

for (i=0; i<width; i++){

this->setPixel(i, jMin, borderColor);

this->setPixel(i, jMax, borderColor);

}

}

else

{

for (i=0; i<width; i++){

this->setPixel(i, jMin, qRgb(borderColor,borderColor,borderColor));

this->setPixel(i, jMax, qRgb(borderColor,borderColor,borderColor));

}

}

}

}

//восстановление оригинальной картинки из буфера

void MyImage::imageRestore(){

int i,j;

int width = this->width();

int height = this->height();

int color;

if (this->isGrayscale()){

for (j=0; j<height; j++){

for (i=0; i<width; i++){

this->setPixel(i,j,qGray(pImage->pixel(i,j)));

}

}

}

else

{

for (j=0; j<height; j++){

for (i=0; i<width; i++){

color = qGray(pImage->pixel(i,j));

this->setPixel(i, j, qRgb(color, color, color));

}

}

}

maxList.clear();

minList.clear();

hMinList.clear();

hMaxList.clear();

maxDifList.clear();

minDifList.clear();

jMin = 0;

jMax = this->height()-1;

vHistMax=0;

hHistMax=0;

vDifHistMax=0;

}

//рисование вертикальной латеральной гистограммы размаха яркости

void MyImage::vDifHistDraw(){

int i,j;

int width = this->width();

int height = this->height();

int grayColor;

int columnHeight;

int length;

this->fill(qRgb(255,255,255));

length = minDifList.size();

if (this->isGrayscale())

{

for (i=0; i<width; i++){

grayColor = (int)vDifHist[i]*0.9;

columnHeight = height*vDifHist[i]/vDifHistMax;

for (j=0; j<columnHeight; j++){

this->setPixel(i,height-j-1,grayColor);

}

}

for (i=0; i<length; i++){

this->setPixel(minDifList.at(i), height-1, 0);

}

}

else{

QRgb rgbColor;

for (i=0; i<width; i++){

grayColor = (int)vDifHist[i]*0.9;

rgbColor = qRgb(grayColor, grayColor, grayColor);

columnHeight = height*vDifHist[i]/vDifHistMax;

for (j=0; j<columnHeight; j++){

this->setPixel(i,height-j-1,rgbColor);

}

}

rgbColor = qRgb(0, 0, 0);

for (i=0; i<length; i++){

this->setPixel(minDifList.at(i), height-1, rgbColor);

}

}

}

//рисование горизонтальной латеральной гистограммы яркости

void MyImage::hHistDraw(){

int i,j;

int width = this->width();

int height = this->height();

this->fill(qRgb(255,255,255));

for (j=0; j<height; j++){

for (i=0; i<width*hHist[j]/hHistMax; i++){

if (this->isGrayscale()){

this->setPixel(i,j,(int)hHist[j]/width);

}

else{

this->setPixel(i, j, qRgb((int)hHist[j]/width,(int)hHist[j]/width,(int)hHist[j]/width));

}

}

}

this->setPixel(0,jMin,255);

this->setPixel(0,jMax,255);

this->setPixel(1,jMin,255);

this->setPixel(1,jMax,255);

this->setPixel(2,jMin,255);

this->setPixel(2,jMax,255);

}

//рисование вертикальной латеральной гистограммы яркости

void MyImage::vHistDraw(){

int i,j;

int width = this->width();

int height = this->height();

int columnHeight;

int grayColor;

int length;

this->fill(qRgb(255,255,255));

length = maxList.size();

if (this->isGrayscale()){

for (i=0; i<width; i++){

grayColor = (int)vHist[i]/(jMax-jMin+1)*0.9;

columnHeight = height*vHist[i]/vHistMax;

for (j=0; j<columnHeight; j++){

this->setPixel(i, height-j-1, grayColor);

}

}

for (i=0; i<length; i++){

this->setPixel(maxList.at(i), height-1, 0);

}

}

else{

QRgb rgbColor;

for (i=0; i<width; i++){

grayColor = (int)vHist[i]/(jMax-jMin+1)*0.9;

rgbColor = qRgb(grayColor, grayColor, grayColor);

columnHeight = height*vHist[i]/vHistMax;

for (j=0; j<columnHeight; j++){

this->setPixel(i, height-j-1, rgbColor);

}

}

rgbColor = qRgb(0, 0, 0);

for (i=0; i<length; i++){

this->setPixel(maxList.at(i), height-1, rgbColor);

}

}

}

//оператор Собела

void MyImage::Sobel()

{

int i,j;

double vSum,hSum;

int width = this->width();

int height = this->height();

int grayColor;

if (pBufImage->isGrayscale()){

for (j=0; j<height; j++){

for (i=0; i<width; i++){

if((j==0)||(j==(height-1))||(i==0)||(i==(width-1))){

hSum = 0;

vSum = 0;

}

else{

vSum = -qGray(this->pixel(i-1,j-1)) – 2*qGray(this->pixel(i-1,j)) – qGray(this->pixel(i-1,j+1)) + qGray(this->pixel(i+1,j-1)) + 2*qGray(this->pixel(i+1,j)) + qGray(this->pixel(i+1,j+1));

//vSum = qGray(this->pixel(i,j)) – qGray(this->pixel(i+1,j));

hSum = 0;//qGray(this->pixel(i-1,j-1)) + 2*qGray(this->pixel(i,j-1)) + qGray(this->pixel(i+1,j-1)) – qGray(this->pixel(i-1,j+1)) – 2*qGray(this->pixel(i,j+1)) – qGray(this->pixel(i+1,j+1));

}

grayColor = (int)sqrt(hSum*hSum+vSum*vSum)/4;

pBufImage->setPixel(i,j,grayColor);

}

}

for (j=0; j<height; j++){

for (i=0; i<width; i++){

this->setPixel(i,j,qGray(pBufImage->pixel(i,j)));

}

}

}

else{

QRgb rgbColor;

for (j=0; j<height; j++){

for (i=0; i<width; i++){

if((j==0)||(j==(height-1))||(i==0)||(i==(width-1))){

hSum = 0;

vSum = 0;

}

else{

vSum = -qGray(this->pixel(i-1,j-1)) – 2*qGray(this->pixel(i-1,j)) – qGray(this->pixel(i-1,j+1)) + qGray(this->pixel(i+1,j-1)) + 2*qGray(this->pixel(i+1,j)) + qGray(this->pixel(i+1,j+1));

hSum = 0;// qGray(this->pixel(i-1,j-1)) + 2*qGray(this->pixel(i,j-1)) + qGray(this->pixel(i+1,j-1)) – qGray(this->pixel(i-1,j+1)) – 2*qGray(this->pixel(i,j+1)) – qGray(this->pixel(i+1,j+1));

}

grayColor = (int)sqrt(hSum*hSum+vSum*vSum);

rgbColor = qRgb(grayColor,grayColor,grayColor);

pBufImage->setPixel(i,j,rgbColor);

}

}

for (j=0; j<height; j++){

for (i=0; i<width; i++){

this->setPixel(i, j, pBufImage->pixel(i,j) );

}

}

}

}

Файл ImageViewer.h

#ifndef IMAGEVIEWER_H

#define IMAGEVIEWER_H

#include <QMainWindow>

#include <QPrinter>

class QAction;

class QLabel;

class QMenu;

class QScrollArea;

class QScrollBar;

class MyImage;

class ImageViewer : public QMainWindow

{

Q_OBJECT

public:

ImageViewer();

private slots:

void open();

void print();

void about();

void selectSigns();

void detailedView();

private:

void createActions();

void createMenus();

bool isDetailed;

QLabel *imageLabel, *imageLabel2, *imageLabel3, *imageLabel4, *imageLabel5, *imageLabel6;

MyImage *image;

QScrollArea *scrollArea;

QPrinter printer;

QAction *openAct;

QAction *printAct;

QAction *exitAct;

QAction *aboutAct;

QAction *selectSignsAct;

QAction *detailedViewAct;

QMenu *fileMenu;

QMenu *editMenu;

QMenu *viewMenu;

QMenu *helpMenu;

};

#endif

Файл ImageViewer.cpp

#include <QtGui>

#include <QImage>

#include <math.h>

#include “imageviewer.h”

#include “myimage.h”

ImageViewer::ImageViewer()

{

imageLabel = new QLabel;

imageLabel->setBackgroundRole(QPalette::Base);

imageLabel->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);

imageLabel->setScaledContents(true);

imageLabel2 = new QLabel;

imageLabel2->setBackgroundRole(QPalette::Base);

imageLabel2->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);

imageLabel2->setScaledContents(true);

imageLabel3 = new QLabel;

imageLabel3->setBackgroundRole(QPalette::Base);

imageLabel3->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);

imageLabel3->setScaledContents(true);

imageLabel4 = new QLabel;

imageLabel4->setBackgroundRole(QPalette::Base);

imageLabel4->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);

imageLabel4->setScaledContents(true);

imageLabel5 = new QLabel;

imageLabel5->setBackgroundRole(QPalette::Base);

imageLabel5->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);

imageLabel5->setScaledContents(true);

imageLabel6 = new QLabel;

imageLabel6->setBackgroundRole(QPalette::Base);

imageLabel6->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);

imageLabel6->setScaledContents(true);

scrollArea = new QScrollArea;

scrollArea->setBackgroundRole(QPalette::Dark);

setCentralWidget(scrollArea);

QHBoxLayout *topLayout = new QHBoxLayout;

topLayout->addWidget(imageLabel);

topLayout->addWidget(imageLabel2);

QHBoxLayout *middleLayout = new QHBoxLayout;

middleLayout->addWidget(imageLabel3);

middleLayout->addWidget(imageLabel4);

QHBoxLayout *bottomLayout = new QHBoxLayout;

bottomLayout->addWidget(imageLabel5);

bottomLayout->addWidget(imageLabel6);

QVBoxLayout *mainLayout = new QVBoxLayout(scrollArea);

mainLayout->addLayout(topLayout);

mainLayout->addLayout(middleLayout);

mainLayout->addLayout(bottomLayout);

mainLayout->setMargin(11);

isDetailed = false;

createActions();

createMenus();

setWindowTitle(“Automatic analysis of license plate digital images.”);

resize(1024, 768);

}

void ImageViewer::open()

{

QString fileName = QFileDialog::getOpenFileName(this, tr(“Open File”), QDir::currentPath());

if (!fileName.isEmpty()) {

image = new MyImage(fileName,0);

if (image->isNull()) {

QMessageBox::information(this, tr(“Image Viewer”), tr(“Cannot load %1.”).arg(fileName));

return;

}

imageLabel->clear();

imageLabel2->clear();

imageLabel3->clear();

imageLabel4->clear();

imageLabel5->clear();

imageLabel6->clear();

setWindowTitle(tr(“Automatic analysis of license plate digital images – “) + fileName);

imageLabel->setPixmap(QPixmap::fromImage(*image));

scaleFactor = 1.0;

printAct->setEnabled(true);

selectSignsAct->setEnabled(true);

}

}

void ImageViewer::selectSigns(){

if (isDetailed){

imageLabel4->setPixmap(QPixmap::fromImage(*image));

image->Sobel();

imageLabel6->setPixmap(QPixmap::fromImage(*image));

image->hCollectData();

image->setMinMaxJ();

image->hHistDraw();

imageLabel2->setPixmap(QPixmap::fromImage(*image));

image->imageDraw();

image->vCollectData();

image->vHistDraw();

imageLabel3->setPixmap(QPixmap::fromImage(*image));

image->vDifHistDraw();

imageLabel5->setPixmap(QPixmap::fromImage(*image));

image->imageDraw();

imageLabel->setPixmap(QPixmap::fromImage(*image));

image->imageRestore();

}

else

{

image->Sobel();

image->hCollectData();

image->setMinMaxJ();

image->hHistDraw();

image->imageDraw();

image->vCollectData();

image->vHistDraw();

image->vDifHistDraw();

image->imageDraw();

imageLabel->setPixmap(QPixmap::fromImage(*image));

image->imageRestore();

}

}

void ImageViewer::detailedView(){

if( detailedViewAct->isChecked()){

isDetailed = true;

if ( selectSignsAct->isEnabled() ){

selectSigns();

}

}

else

{

isDetailed = false;

imageLabel2->clear();

imageLabel3->clear();

imageLabel4->clear();

imageLabel5->clear();

imageLabel6->clear();

}

}

void ImageViewer::print()

{

Q_ASSERT(imageLabel->pixmap());

QPrintDialog dialog(&printer, this);

if (dialog.exec()) {

QPainter painter(&printer);

QRect rect = painter.viewport();

QSize size = imageLabel->pixmap()->size();

size.scale(rect.size(), Qt::KeepAspectRatio);

painter.setViewport(rect.x(), rect.y(), size.width(), size.height());

painter.setWindow(imageLabel->pixmap()->rect());

painter.drawPixmap(0, 0, *imageLabel->pixmap());

}

}

void ImageViewer::about()

{

QMessageBox::about(this, tr(“About Image Viewer”),

tr(“<p>This is about window for <b>Image Viewer</b>”

“</p>”));

}

void ImageViewer::createActions()

{

openAct = new QAction(tr(“Open &File”), this);

openAct->setShortcut(tr(“Ctrl+F”));

connect(openAct, SIGNAL(triggered()), this, SLOT(open()));

connect(openAct, SIGNAL(triggered()), this, SLOT(fitToWindow()));

printAct = new QAction(tr(“&Print…”), this);

printAct->setShortcut(tr(“Ctrl+P”));

printAct->setEnabled(false);

connect(printAct, SIGNAL(triggered()), this, SLOT(print()));

exitAct = new QAction(tr(“E&xit”), this);

exitAct->setShortcut(tr(“Ctrl+Q”));

connect(exitAct, SIGNAL(triggered()), this, SLOT(close()));

aboutAct = new QAction(tr(“&About”), this);

connect(aboutAct, SIGNAL(triggered()), this, SLOT(about()));

detailedViewAct = new QAction(tr(“&Detailed View”), this);

detailedViewAct->setShortcut(tr(“Ctrl+D”));

detailedViewAct->setEnabled(true);

detailedViewAct->setCheckable(true);

detailedViewAct->setChecked(false);

connect(detailedViewAct, SIGNAL(triggered()), this, SLOT(detailedView()));

selectSignsAct = new QAction(tr(“Select &Signs”), this);

selectSignsAct->setShortcut(tr(“Ctrl+S”));

selectSignsAct->setEnabled(false);

connect(selectSignsAct, SIGNAL(triggered()), this, SLOT(selectSigns()));

}

void ImageViewer::createMenus()

{

fileMenu = new QMenu(tr(“&File”), this);

fileMenu->addAction(openAct);

fileMenu->addAction(printAct);

fileMenu->addSeparator();

fileMenu->addAction(exitAct);

editMenu = new QMenu(tr(“&Edit”), this);

editMenu->addAction(selectSignsAct);

viewMenu = new QMenu(tr(“&View”), this);

viewMenu->addAction(detailedViewAct);

helpMenu = new QMenu(tr(“&Help”), this);

helpMenu->addAction(aboutAct);

menuBar()->addMenu(fileMenu);

menuBar()->addMenu(editMenu);

menuBar()->addMenu(viewMenu);

menuBar()->addMenu(helpMenu);

}

Леонид Федотов
Леонид Федотов
Окончил НИУ ВШЭ факультет компьютерных наук. Сам являюсь кандидатом наук. По специальности работаю 13 лет, за это время создал 8 научных статей и 2 диссертации. В компании подрабатываю в свободное от работы время уже более 5 лет. Нравится помогать школьникам и студентам в решении контрольных работ и написании курсовых проектов. Люблю свою профессию за то, что это направление с каждым годом становится все более востребованным и актуальным.
Поделиться дипломной работой:
Поделиться в telegram
Поделиться в whatsapp
Поделиться в skype
Поделиться в vk
Поделиться в odnoklassniki
Поделиться в facebook
Поделиться в twitter
Похожие статьи
Раздаточный материал для дипломной работы образец

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

Читать полностью ➜
Задание на дипломную работу образец заполнения

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

Читать полностью ➜