Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Соловьев.docx
Скачиваний:
49
Добавлен:
26.03.2016
Размер:
978.1 Кб
Скачать

4. Программная реализация

4.1 Схема программного обеспечения

Приложение разработано на языке программирования Java в среде разработки Android Studio. Android Studio распространяется компанией Google бесплатно для всех разработчиков, существуют версии для ОS Windows, OS Linux, Mac OS. В этом проекте разработка происходила под OS Windows. Завершенное приложение представляет из себя файл *.apk, который переносится на мобильное устройство под управлением OS Android и устанавливается на нем путем запуска указанного файла.

4.2 Описание функций и методов

  • MainActivity.java – класс активити, которую пользователь видит при запуске приложения. В нем реализованы стандартные методы, позволяющие отобразить необходимое содержимое, а также метод takeScreenshot(), который выполняет набор действий для получения скриншота с текстом и ключевым словом.

  • BinarizationActivity.java – класс активити, в котором по средствам выбора пользователем пунктов и параметров запускаются алогоритмы обработки изображения.

  • GystogramActivity.java – отвечает за отображение полученных гистограмм на весь экран.

  • Binarizer.java – содержит реализацию методов, которые позволяют получить из цветного изображения полутоновое, а далее бинарное.

  • ColorWordsProcessor.java – отвечает за сегментацию слов и перекрашивание их в разные цвета.

  • Recognizer.java – содержит реализацию распознавания ключевого слова среди претендентов, полученных на предыдущих этапах.

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

  • Кроме всего этого имеются файлы ресурсов, которые содержат верстку элементов пользовательского интерфейса.

Так, класс Binarizer содержит два public метода:

1) binarizeByThreshold(…), который выполняет бинаризацию изображения пороговым методом.

2) binarizeBy120Method(…), который выполняет бинаризацию изображения с использованием метода 120.

Исходный код класса Binarizer в приложении 2.

Класс GystogramBuilder реализует алгоритмы создания различных гистограмм, используемых для сегментации. Содержит следующие методы:

1) getImageGystogram(…) - позволяет получить гистограмму яркости изображения.

2) getRowsGystogram(…) - создает гистограмму количества черных пикселей в каждой однопиксельной строке. Количество градаций равно высоте изображения.

3) getColumnsGystogram(…) - создает гистограмму количества черных пикселей в каждом однопиксельном столбце изображения. Количеством градации является ширина изображения.

4) getSpacesInRowsGystogram(…) - получает гистограмму расстояний между символами. Количество градаций — количество различных расстояний между символами. Значение каждой градации — количество раз, сколько встречается такое расстояние. Данная гистограмма в дальнейшем обрабатывается методом мод.

Исходный код класса GystogramBuilder в приложении 3.

4.3Тестирование и руководство для пользователя

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

Рисунок 4.3.1 — Вид приложения после запуска, главный экран.

Рисунок 4.3.2 — Ввод ключевого слова

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

Рисунок 4.3.3 — Список кнопок для обработки изображения и отображения результата

Далее пользователю необходимо выбрать метод бинаризации. При выборе любого метода автоматически произойдет перевод из цветного изображения в полутоновое. При выборе метода порогового (кнопка «By user») пользователю необходимо будет ввести порог в появившемся диалоговом окне. Для запуска пороговой бинаризации с порогом по умолчанию без дополнительного ввода порога необходимо нажать на пункт «Default (128)». Если же пользователь выбрать метод 120, то нужно нажать на соответствующий пункт «Method 120».

После бинаризации необходимо выполнить сегментацию строк, т. е. построить гистограмму, для этого необходимо выбрать пункт «Rows». После чего на бинарном изображении сбоку появится миниатюрная гистограмма (см. рис. 4.3.4), в более крупном размере гистограмму можно вывести на весь экран, выбрав пункт «Rows – fullscreen».

Рисунок 4.3.4 — результат построения гистограммы строк.

Если необходимо избавиться от «хвостиков» букв, то можно вычесть из гистограммы 30% черных пикселей с помощью пункта «Substract 30%», дальнейшая обработка изображения будет учитывать полученный результат.

Для сегментации слов и букв нужно построить гистограммы строк и гистограмму расстояний, благодаря которой будут отделены пробелы между словами от межсимвольных. Отвечает за это пункт «Generate spaces». Если есть желание увидеть полученную гистограмму, то можно выбрать пункт «Show spaces gystogram», который выведет гистограмму на весь экран.

Далее для выполнения сегментации слов и отображении их разноцветными, а также для нахождения претендентов, выбираем пункт «Color words». Результат работы на рисунке 4.3.5.

Рисунок 4.3.5 — результат сегментации слов разным цветом.

Для получения конечного результата — выделенных красным цветом слов на изображении (рис. 4.3.6), нажимаем на «Recognize».

Рисунок 4.3.6 — отображение результата работы на изображении.

ЗАКЛЮЧЕНИЕ

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

Было разработано приложение под OS Android с помощью среды разработки Android Studio на объекто-ориентированном языке программирования Java, реализующее алгоритм сегментации ключевого слова на изображении текста с экрана смартфона. Проанализировав полученные результаты, можно сделать вывод о том, что данная программа позволяет распознавать изображение ключевого слова на изображении текста с экрана смартфона, а значит цель проекта достигнута.

Тестирование приложения позволило сделать следующие выводы:

1. Метод бинаризации с заданием порога отлично подходит для перевода полутонового изображения в бинарное.

2. Метод 120 оставляет ненужные объекты фона.

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

Качество распознавания зависит от выбранного ключевого слова, а также выбранного метода бинаризации, и колеблется в диапазоне от 70 до 80%. Улучшить результат распознавания можно путем комбинирования характерных признаков, а также подбора порога бинаризации.

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

ЛИТЕРАТУРА

  • Горелик А.Л. Методы распознавания: учеб. пособие для вузов / А.Л.Горелик, В.А.Скрипкин. – 3-е изд., перераб. и доп. – М.: Высш.шк., 1989 – 234 с.

  • Гренандер У. Лекции по теории образов: в 3-х т./ У. Гренандер; под ред. Ю.И. Журавлева. – М.: Мир, 1979-1983 – 1267 с.

  • Конспект лекций по дисциплине «Методы распознавания образов». Ковалёва И.Л., 2011 г.

  • Документация по Android, http://developer.android.com

  • Документация по Java, http://docs.oracle.com

Приложение 1. Схема IDEF трех уровней и UML диаграмма классов.

Рисунок 1 – Схема IDEF (первый уровень)

Рисунок 2 – Схема IDEF (второй уровень)

Рисунок 3 – Схема IDEF (третий уровень)

Рисунок 4 — UML диаграмма классов

Приложение 2. Исходный код класса Binarizer

public class Binarizer {

public void binarizeByThreshold(String imagePath, int threshold) {

Bitmap bitmap = BitmapFactory.decodeFile(imagePath);

int width = bitmap.getWidth();

int height = bitmap.getHeight();

int size = width * height;

int[] pixels = new int[size];

bitmap.getPixels(pixels, 0, width, 0, 0, width, height);

bitmap.recycle();

for (int i = 0; i < size; i++) {

int color = pixels[i];

int r = Color.red(color);

int g = Color.green(color);

int b = Color.blue(color);

double luminance = (0.299 * r + 0.0f + 0.587 * g + 0.0f + 0.114 * b + 0.0f);

pixels[i] = luminance > threshold ? Color.WHITE : Color.BLACK;

}

Utils.saveBitmap(imagePath, width, height, pixels);

}

public int binarizeBy120Method(String imagePath) {

Bitmap bitmap = BitmapFactory.decodeFile(imagePath);

int width = bitmap.getWidth();

int height = bitmap.getHeight();

int size = width * height;

int[] pixels = new int[size];

bitmap.getPixels(pixels, 0, width, 0, 0, width, height);

bitmap.recycle();

int maxGray = Integer.MIN_VALUE;

for (int i = 0; i < size; i++) {

int color = pixels[i];

int r = Color.red(color);

int g = Color.green(color);

int b = Color.blue(color);

double luminance = (0.299 * r + 0.0f + 0.587 * g + 0.0f + 0.114 * b + 0.0f);

pixels[i] = ((int) luminance);

if (pixels[i] < 120 && pixels[i] > maxGray) {

maxGray = pixels[i];

}

}

for (int i = 0; i < size; i++) {

int luminance = pixels[i];

if (luminance < (maxGray + 12)) {

pixels[i] = Color.BLACK;

} else {

pixels[i] = Color.WHITE;

}

}

Utils.saveBitmap(imagePath, width, height, pixels);

return maxGray;

}

Приложение 3. Исходный код класса GystogramBuilder

public class GystogramBuilder {

public ArrayList<GystMember> getImageGystogram(String imagePath) {

Bitmap bitmap = BitmapFactory.decodeFile(imagePath);

int width = bitmap.getWidth();

int height = bitmap.getHeight();

int size = width * height;

int[] pixels = new int[size];

bitmap.getPixels(pixels, 0, width, 0, 0, width, height);

bitmap.recycle();

ArrayList<GystMember> gystogram = new ArrayList<>();

GystMember gm;

for (int i = 0; i < size; i++) {

int color = pixels[i];

int r = Color.red(color);

int g = Color.green(color);

int b = Color.blue(color);

int luminance = (int) (0.299 * r + 0.0f + 0.587 * g + 0.0f + 0.114 * b + 0.0f);

gm = new GystMember(luminance);

boolean success = false;

for (GystMember member : gystogram) {

if (member.grayValue == luminance) {

member.add();

success = true;

} }

if (!success) {

gm.add();

gystogram.add(gm);

} }

return gystogram;

}

public ArrayList<GystMember> getRowsGystogram(String imagePath) {

Bitmap bitmap = BitmapFactory.decodeFile(imagePath);

int width = bitmap.getWidth();

int height = bitmap.getHeight();

int size = width * height;

int[] pixels = new int[size];

bitmap.getPixels(pixels, 0, width, 0, 0, width, height);

bitmap.recycle();

ArrayList<GystMember> gystogram = new ArrayList<>();

for (int x = 0; x < height; x++) {

gystogram.add(new GystMember(x));

for (int y = 0; y < width; y++) {

int color = pixels[y + x * width];

if (color == Color.BLACK) {

gystogram.get(x).add();

} } }

return gystogram;

}

public ArrayList<GystMember> getColumnsGystogram(String imagePath) {

Bitmap bitmap = BitmapFactory.decodeFile(imagePath);

int width = bitmap.getWidth();

int height = bitmap.getHeight();

int size = width * height;

int[] pixels = new int[size];

bitmap.getPixels(pixels, 0, width, 0, 0, width, height);

bitmap.recycle();

ArrayList<GystMember> gystogram = new ArrayList<>();

for (int x = 0; x < width; x++) {

gystogram.add(new GystMember(x));

for (int y = 0; y < height; y++) {

int color = pixels[x + y * width];

if (color == Color.BLACK) {

gystogram.get(x).add();

} } }

return gystogram;

}

public ArrayList<GystMember> getSpacesInRowsGystogram(String imagePath, ArrayList<GystMember> rowsGystogram) {

Bitmap bitmap = BitmapFactory.decodeFile(imagePath);

int width = bitmap.getWidth();

int height = bitmap.getHeight();

int size = width * height;

int[] pixels = new int[size];

bitmap.getPixels(pixels, 0, width, 0, 0, width, height);

bitmap.recycle();

ArrayList<GystMember> oneRowGystogram = new ArrayList<>();

ArrayList<Integer> spaces = new ArrayList<>();

ArrayList<GystMember> spacesInRowsGystogram = new ArrayList<>();

int yStart = 0, yEnd = 0, yIter = -1;

boolean inLine = false;

for (GystMember gystMember : rowsGystogram) {

yIter++;

if (gystMember.count > 0 && !inLine) {

inLine = true;

yStart = yIter;

} else if (gystMember.count == 0 && inLine) {

inLine = false;

yEnd = yIter;

for (int x = 0; x < width; x++) {

GystMember member = new GystMember(x);

for (int y = yStart; y < yEnd; y++) {

int color = pixels[x + y * width];

if (color == Color.BLACK) {

member.add();

} }

oneRowGystogram.add(member);

}

int xStart = 0, xEnd = 0, xIter = -1;

boolean inRow = false;

for (GystMember oneRowMember : oneRowGystogram) {

xIter++;

if (oneRowMember.count == 0 && !inRow) {

inRow = true;

xStart = xIter;

} else if ((oneRowMember.count > 0 || xIter == oneRowGystogram.size()-1) && inRow) {

inRow = false;

xEnd = xIter;

int xValue = xEnd - xStart;

spaces.add(xValue);

} } } }

Collections.sort(spaces);

int lastSpace = -1;

GystMember gystMember = null;

for (Integer space : spaces) {

if (space > lastSpace) {

if (gystMember != null) {

spacesInRowsGystogram.add(gystMember);

}

gystMember = new GystMember(space);

}

gystMember.add();

lastSpace = space;

}

return spacesInRowsGystogram;

}