Научная статья на тему 'Программная реализация системы анализа яркостных градаций изображений'

Программная реализация системы анализа яркостных градаций изображений Текст научной статьи по специальности «Компьютерные и информационные науки»

CC BY
96
27
i Надоели баннеры? Вы всегда можете отключить рекламу.
i Надоели баннеры? Вы всегда можете отключить рекламу.
iНе можете найти то, что вам нужно? Попробуйте сервис подбора литературы.
i Надоели баннеры? Вы всегда можете отключить рекламу.

Текст научной работы на тему «Программная реализация системы анализа яркостных градаций изображений»

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

К.Е. Косоруков,

студент 5-го курса, специальность «Информационные системы и технологии»

В.Н. Шурыгин,

к.т.н., доцент кафедры информационных систем

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

Система реализована в виде веб-приложения на двух языках высокого уровня: PHP и JavaScript. С серверной стороны приложения над «чистым» языком надстроен каркас Kohana, со стороны клиента -каркас ExtJS [1], позволяющий создать интерфейс, приближенный к оболочкам приложений операционной системы.

Прежде чем приступить к описанию программного решения означенной задачи, кратко остановимся на особенностях Kohana и ExtJS.

ExtJS - библиотека, написанная на языке JavaScript, задумывавшаяся изначально как расширение Yahoo UI Library, но со временем превратившаяся в отдельный проект. Имеет двойное лицензирование: есть возможность использовать как GPL v3, так и коммерческую лицензию компании Sencha. Основным ее направлением является создание клиент-серверных веб-приложений, похожих на desktop-приложения. Фреймворк характеризуется наличием огромного числа компонентов, похожих на стандартные элементы управления систем с графическим оконным интерфейсом.

Типичный компонент интерфейса описывается JavaScript-кодом. В основе каждого компонента лежит термин «конфигурацион-

16

ный объект». Это стандартный объект языка JavaScript, поля которого и их значения соответствуют таковым в документации ExtJS [1]. В листинге 1 представлен пример реализации компонента - панель для ввода исходных параметров, с которыми работает система.

Ext.define('Img.view.ParamsPanel', { extend: 'Ext.panel.Panel', requires: ['Img.view.FilesGrid'], alias: 'widget.ParamsPanel', layout: 'auto', makeltems: function() {

this.logPanel = Ext.create('Img.view.LogPanel', { border: 0, height: 300, autoScroll: true

});

this.items = [

{

xtype: 'fieldset', width: 200, title: 'Параметры', style: 'margin-left: 10px', items: [ ... ]

},

{

xtype: 'button',

text: 'Запустить анализ',

handler: Ext.bind(function(btn, e) { ... }

}

]

},

}

Листинг 1. Пример реализации компонента интерфейса на ExtJS

Объявление компонента начинается с функции Ext.define, которая принимает два параметра: название создаваемого компонента в соответствии с конвенциями именования элементов в библиотеке (в данном случае - Img.view.ParamsPanel), а также конфигурационный объект со свойствами. Каждый компонент может включать свойство items, являющееся массивом объектов и позволяющее поместить внутрь

17

какого-либо элемента дополнительные компоненты, что показано в листинге 1. Там в компонент типа Img.view.ParamsPanel с помощью метода makeItems() включается группа элементов формы (fieldset) и простая кнопка (button).

Приведем еще некоторые из свойств и методов компонента Img.view.ParamsPanel:

- Свойство extend позволяет указать компонент, от которого будет наследоваться создаваемый элемент. Например, в листинге 1 панель пользовательского типа создается из предустановленной панели типа Ext.panel.Panel.

- Свойство requires используется для загрузки тех компонентов, которые не предустановлены каркасом ExtJS, но используются в текущем компоненте.

- Свойство alias позволяет задать псевдоним компонента. В данном случае, widget.ParamsPanel.

- Свойство layout задает расположение компонентов внутри элемента. Для компонента панели параметров это свойство стоит задать либо vbox, либо auto (что и сделано), что для конкретного случая означает расположение элементов друг под другом.

Полный перечень свойств и методов можно найти в официальной документации фреймворка [1].

Kohana - это объектно-ориентированный HMVC PHP5 фреймворк, предоставляющий средства для разработки web-приложений. Он распространяется по лицензии BSD, что дает право использовать его под коммерческие проекты. Благодаря своей каскадной файловой системе, большому количеству встроенных утилит и последовательному API, он идеально подходит для решения большинства задач, а высокая скорость выполнения и обширные возможности профилирования позволяют ускорить разработку и использовать менее мощные ресурсы для содержания конечного продукта.

Kohana обладает следующими возможностями:

- высокая скорость выполнения;

- использование всех объектных возможностей PHP5;

- большое количество встроенных инструментов, в том числе шаблон ORM (представление таблиц баз данных в виде объектов-моделей);

- малые системные требования;

- средства профилирования и отладки;

- поддержка кодировки UTF-8;

- проверки и фильтрация введенных данных;

- raokie, защищенные от изменения.

Более подробное описание можно найти в документации на официальном сайте [5].

18

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

Исходный макет интерфейса, реализованный с применением ExtJS, представлен на рис. 1.

Рис. 1. Макет интерфейса системы анализа документов

Условно интерфейс состоит из трех частей:

1. Панель с непосредственно анализируемым изображением.

2. Панель управления.

3. Панель информации и загрузки файлов.

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

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

19

Рис. 2. Отображение отдельной области похожих яркостей на изображении

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

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

Эта часть системы представляет собой унаследованный класс

контроллера фреймворка Kohana. Класс Controller___Files унаследован

от базового класса Controller каркаса не напрямую, а через дополнительный класс Controller_Extendcontroller, представляющий собой рас-

ширение базового класса для объединения операций, отсутствующих у фреймворка изначально, но необходимых для архитектуры конкретного приложения в каждом из контроллеров. Класс Controller_Files агрегирует два сторонних инструмента-оболочки: класс Memcache для управления сервером хранения хеш-таблиц данных Memcached и интерфейс взаимодействия с консольной утилитой Imagick, необходимой для конвертации документов различных форматов в изображения.

Одной из наиболее функционально важных частей системы является реализация алгоритма деления изображения на области, содержащаяся в классе Controller_Files в виде метода calcAreas() Его реа-

лизация представлена в листинге 2.

function calcAreas($width, $height) {

$pixels = array(); // Массив с пикселями текущего обхода $borders = array();

20

Gonti49ller_Fllei

4jplaad_dir

4jplMd_Drigjna Is_di г

-uplt>ad_pi'eYiews_d ir -upload jjrayscalesjflr -upload_map5_dlr 4jplnadJsQn_dir -N

-ilmageMap

-imageMapWallutd

-irmageWapAreaNunnber

+actiDn_uplDad() +action_j&etFilfrs() ■mnakePreviewD +actiDn_£etPrevie4^| igetNumbErDfPagEaJ) +actiDn_gett3raysi:ale^) +action_j£etAnMi() -raakeAre«[)

-getMemcai±iEd() +getNeiBh houri ng Aneas[) -eetBrighitl)

-caltAreasll

-getlengthO

-gerScaH)

-getl nterval^

] Ц

Класс фреймворка Itohana

Рис. 3. Диаграмма классов системы анализа документов

$numAreas = 0; for($x = 0; $x < $width; $x++) { for($y = 0; $y < $height; $y++) {

// Если рассматриваемый пиксель не посещен, делаем область

от него

if($this->imageMapWalked[$x][$y] == 0) {

$borders[$numAreas] = array('points' => array(), 'size' => 0);

// Его мы точно посетили.

$currentN = $this->imageMapAreaNumber[$x][$y];

$pixels[] = array($x, $y);

$this->imageMapWalked[$x][$y] = $numAreas + 1;

$size = $borderSize = $sumBright = 0;

21

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

while(count($pixels) > 0) { // Пока есть пиксели, от которых рассматривать область..

$arr = array_shift($pixels);

iНе можете найти то, что вам нужно? Попробуйте сервис подбора литературы.

$areaX = $arr[0];

$areaY = $arr[1 ];

$sumBright += $this->imageMap[$areaX][$areaY]; if($size == 0) { $borders[$numAreas]['center'] = array($areaX,

$areaY); }

// Смотрим клетки по сторонам света. Если следующая клетка не попадает в область хотя бы с одной стороны — это граница.

$border = false;

if($areaY + 1 < $height && $this-

>imageMapWalked[$areaX][$areaY + 1] == 0) { // SOUTH

if($currentN == $this-

>imageMapAreaNumber[$areaX][$areaY + 1] ) {

$pixels[] = array($areaX, $areaY + 1); $this->imageMapWalked[$areaX][$areaY + 1] = $numAreas + 1; // Помечаем сразу как пройденный, чтобы избежать мультивключения и лишних итераций } else {

$border = true;

}

} ...// Просмотр всех остальных направлений if($border) {

$borders[$numAreas]['points'][] = $arr;

$borderSize++;

}

$size++;

}

$borders[$numAreas]['size'] = $size; $borders[$numAreas]['bordersize'] = $borderSize; $borders[$numAreas]['brightness'] = $sumBright/ $size; $numAreas++;

}

}

}

return $borders;

}

Листинг 2. Реализация функции для подсчета областей

22

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

1. Текущий рассматриваемый пиксель проверяется на наличие отметки о посещении. Если она есть, вложенный цикл рассматривает следующий пиксель. Если нет - этот пиксель помещается в массив пикселей для анализа.

2. Следующим шагом запускается цикл, который рассматривает массив анализируемых пикселей в порядке LIFO («последний пришел - первый ушел»). Относительно этого пикселя проверяются четыре направления, в которые может распространиться область: верх, низ, лево и право. Критерием включения очередного соседнего пикселя в массив к рассматриваемым является попадание значения яркости в тот же интервал яркостей (значение интервала для текущего пикселя сохранено в свойстве-массиве imageMapAreaNumber), что и у рассматриваемого пикселя.

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

4. В том случае, если он является границей (условие границы: яркости соседних пикселей попадают в разные яркостные интервалы), об этом аналогично делается отметка ($border = true), пиксель помещается в массив граничных пикселей для текущей области, а размер границы (переменная $borderSize) увеличивается на единицу. Переменная $size - общий размер области - аналогично увеличивается на единицу.

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

6. На финальной стадии ключам массива $borders с первым ключом, являющимся номером текущей области, присваиваются данные о размере границы области, общем размере области и среднем значении яркости области.

7. Процесс повторяется с шага 1 для всех рассматриваемых во вложенном цикле пикселей, которые еще не были помечены как просмотренные.

23

После завершения работы циклов во внешний код возвращается переменная $borders со всей собранной информацией.

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

function getBright($im, $x, $y) {

// Делим все пространство на равные промежутки. Y = значение яркости // Y = 0.299 * R + 0.587 * G + 0.114 * B (Значение яркости)

$black = 0;

$white = 255;

$color = imagecolorat($im, $x, $y);

// Получаем составляющие цвета (red, green, blue)

$r = ($color >> 16) & 0xFF; // Красный

$g = ($color >> 8) & 0xFF; // Зеленый

$b = $color & 0xFF; // Синий

$current = 0.299 * $r + 0.587 * $g + 0.114 * $b;

return $current;

}

Листинг 3. Метод для получения значения яркости отдельного пикселя.

Значение яркости рассчитывается по формуле 1. [2]

Y= 0,299R+0,587G+ 0,114-B,

где

G

B - целочисленное значение цветовых составляющих пикселя.

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

24

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

public function makeResponse($data, $coded = true) {

$view = View::factory('default');

$view->response = $coded ? json_encode($data) : $data;

$view->render();

$this->response->body($view);

}

Листинг 4. Метод для генерации ответа от сервера

Функция принимает два параметра: данные в виде массива, которые необходимо закодировать и флаг, который позволяет просто отправить данные в выходной поток без кодирования (если, например, требуется передать клиентской стороне скалярную величину: число или строку). Далее вызывается метод View::factory() фреймворка Kohana, которому передается название файла шаблона в папке /templates/ приложения. Свойствами возвращенного объекта (в данном случае - свойство response) являются значения переменных, которые будут доступны в шаблоне для визуализации. Метод render() позволяет зафиксировать текущие значения переменных шаблона и, наконец, метод body() свойства response класса Controller, принимающий объект ранее сгенерированного шаблона, позволяет отобразить результаты на экран.

Таким образом, система для анализа яркостных градаций изображений может быть успешно реализована в качестве веб-приложения, что и описано в статье. За счет применения фреймворков ExtJS и Kohana она легко расширяема и позволяет добавить новые функции. Для улучшения общей производительности рекомендовано связать PHP и ускоритель для него, например, Zend Optimizer или Eaccelerator, за счет которых, как написано на сайтах производителей [3, 4], возможно ускорение выполнения исходного кода в 1,5-2 раза.

Библиографический список

1. Официальная документация фреймворка ExtJS v 4.1.3: http://docs.sencha.com/ext-js/4-1

2. Описание цветовой модели YUV: http://ru.wikipedia.org/

wiki/YUV

3. Ускоритель и оптимизатор PHP Eaccelerator: http:// eaccelerator.net

4. Ускоритель и оптимизатор PHP Zend Optimizer: http:// www.zend.com/en/products/guard/downloads

5. Официальная документация фреймворка Kohana: http:// kohanaframework.org/guide/kohana

25

i Надоели баннеры? Вы всегда можете отключить рекламу.