Работа с изображением в PHP

Введение: 

    В области программирования для сети PHP — один из популярных скриптовых языков (наряду с JSP, Perl и языками, используемыми в ASP.NET) благодаря своей простоте, скорости выполнения, богатой функциональности.  Популярность в области построения веб-сайтов определяется наличием большого набора встроенных средств для разработки веб-приложений. Основные из них: автоматическое извлечение POST и GET-параметров, а также переменных окружения веб-сервера в предопределённые массивы;

    Взаимодействие с большим количеством различных систем управления базами данных (MySQL, MySQLi, SQLite, PostgreSQL,Oracle (OCI8), Oracle, Microsoft SQL Server, Sybase, ODBC, mSQL, IBM DB2, Cloudscape и Apache Derby, Informix, Ovrimos SQL,Lotus Notes, DB++, DBM, dBase, DBX, FrontBase, FilePro, Ingres II, SESAM, Firebird / InterBase, Paradox File Access, MaxDB,Интерфейс PDO.

   В настоящее время PHP используется сотнями тысяч разработчиков. Согласно рейтингу корпорации TIOBE, базирующемся на данных поисковых систем, в апреле 2011 года PHP находился на 5 месте среди языков программирования. К крупнейшим сайтам, использующим PHP, относятся Facebook, ВКонтакте, Wikipedia. 
 
 
 
 
 
 

1.Работа с изображением в PHP 

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

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

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

Класс для работы с пикселом

    Для начала нам понадобится класс для работы с пикселом. Он очень прост – содержит в себе три значения: красного, зеленого и синего.

 
 
<?php  
class Pixel {  
    function 
Pixel($r, $g, $b)  
    {  
        
$this->r = ($r > 255) ? 255 : (($r < 0) ? 0 : (int)($r));  
        
$this->g = ($g > 255) ? 255 : (($g < 0) ? 0 : (int)($g));  
        
$this->b = ($b > 255) ? 255 : (($b < 0) ? 0 : (int)($b));  
    }  
}  
?>

 
 
 
 
 

    Этот  класс имеет только одну функцию  – конструктор, которая сохраняет RGB значения пикселя.

    Чтобы создать красный пиксел, вы просто делаете:

<?php  
$red 
= new Pixel(255, 0, 0);  
?> 

 
 

Класс манипуляций с  пикселами: главный  метод

    Далее мы создаем класс, который проделывает  фактические действия с изображением. Назовем его Image_PixelOperations(). Все, что мне было нужно – это более простой метод для открытия PNG файлов, который бы проходил по каждому пикселу файла, вызывает функцию, получает новый пиксел и присваивает его новому изображению. Далее приведу текст метода:

 
 
<?php  
class Image_PixelOperations {  
          
    function 
pixelOperation(  
            
$input_image,  
            
$output_image,  
            
$operation_callback,  
            
$factor = false  
            
)  
    {  
          
        
$image = imagecreatefrompng($input_image);  
        
$x_dimension = imagesx($image);  
        
$y_dimension = imagesy($image);  
        
$new_image = imagecreatetruecolor($x_dimension, $y_dimension);  
          
        if (
$operation_callback == 'contrast') {  
            
$average_luminance = $this->getAverageLuminance($image);  
        } else {  
            
$average_luminance = false;  
        }  
          
        for (
$x = 0; $x < $x_dimension; $x++) {  
            for (
$y = 0; $y < $y_dimension; $y++) {  
          
                
$rgb = imagecolorat($image, $x, $y);  
                
$r = ($rgb >> 16) & 0xFF;  
                
$g = ($rgb >> 8) & 0xFF;  
                
$b = $rgb & 0xFF;  
          
                
$pixel = new Pixel($r, $g, $b);  
                
$pixel = call_user_func(  
                    
$operation_callback,  
                    
$pixel,  
                    
$factor,  
                    
$average_luminance  
                
);  
          
                
$color = imagecolorallocate(  
                    
$image,  
                    
$pixel->r,  
                    
$pixel->g,  
                    
$pixel->b  
                
);  
                
imagesetpixel($new_image, $x, $y, $color);  
            }  
          
        }  
          
        
imagepng($new_image, $output_image);  
    }  
}  
          
?>

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

Добавляем шумов

    И так, пришло время, чтобы написать первую функцию обработки пиксела: addNoise(). Добавление шума к изображению означает добавление случайного значения к каждому каналу пикселя.  Что такое канал – уровень красного цвета в пикселе = канал, Тоже самое с зеленым и синим. Далее привожу функцию:

 
 
<?php  
    
function addNoise($pixel, $factor)  
    {  
        
$random = mt_rand(-$factor, $factor);  
        return new 
Pixel(  
                    
$pixel->r + $random,  
                    
$pixel->g + $random,  
                    
$pixel->b + $random  
                
);  
    }  
?> 

 

    Что представляет из себя функция? Она получает случайное число в указанном  пользователем диапазоне ($factor). И добавляет его к значению каналов пиксела. Пользователь указывает диапазон уровня шума: 0 – нет шума, 255 – очень много шума. 

<form method="get">  
    <input name="image" />  
    <input type="submit" />  
</form> 

 

    Она принимает параметр – названия файла с изображением. После получения этого параметра я создаю новый объект класса для работы с пикселами:

 
 
 
 
<?php  
if (!empty($_GET['image'])) {  
          
    
$po =& new Image_PixelOperations();  
          
}  
?> 

 
 
 

    Далее я показываю оригинальное изображение, а затем результат обработки.

 
 
 
 
<?php  
    
echo 'Оригинал: <br /><img src="'. $_GET['image'] .'" />';  
    echo 
'<hr />';  
          
    
// Шумы  
    
$noise = 100;  
    
$po->pixelOperation($_GET['image'], 'result_noise.png', array($po, 'addNoise'), $noise);  
    echo 
'<br />Добаляем шумы (factor '. $noise .'): <br /><img src="result_noise.png" />';  
    echo 
'<hr />';  
          
?> 

 
 
 
 
 
 
 
 
 
 
 
 
 
 

    Результат:

 
 
 
 

Управление  яркостью

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

 
 
<?php  
function adjustBrightness($pixel, $factor)  
{  
    return new 
Pixel(  
    
$pixel->r + $factor,  
    
$pixel->g + $factor,  
    
$pixel->b + $factor  
    
);  
}  
?> 

 

    Чтобы протестировать эту функцию выполните  следующий код:

 
<?php  
$brightness 
= 50;  
$po->pixelOperation($_GET['image'], 'result_bright.png', array($po, 'adjustBrightness'), $brightness);  
echo 
'<br />Ярче: <br /><img src="result_bright.png" />';  
$brightness = -50;  
$po->pixelOperation($_GET['image'], 'result_dark.png', array($po, 'adjustBrightness'), $brightness);  
echo 
'<br />Темнее: <br /><img src="result_dark.png" />';  
echo 
'<hr />';  
?> 

    Смотрим на результат:

 
 

Меняем  местами цвета

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

    Давайте посмотрим, как выглядит функция:

 
<?php  
function swapColors($pixel, $factor)  
{      
    switch (
$factor) {          
        case 
'rbg':          
        return new 
Pixel(          
        
$pixel->r,          
        
$pixel->b,          
        
$pixel->g          
        
);          
        break;          
        case 
'bgr':          
        return new 
Pixel(          
        
$pixel->b,          
        
$pixel->g,          
        
$pixel->r          
        
);          
        break;          
        case 
'brg':          
        return new 
Pixel(          
        
$pixel->b,          
        
$pixel->r,          
        
$pixel->g          
        
);          
        break;          
        case 
'gbr':          
        return new 
Pixel(          
        
$pixel->g,          
        
$pixel->b,          
        
$pixel->r          
        
);          
        break;          
        case 
'grb':          
        return new 
Pixel(          
        
$pixel->g,          
        
$pixel->r,          
        
$pixel->b          
        
);          
        break;          
        default:          
        return 
$pixel;          
    }          
}  
?> 

 

    Тестируем:

RGB -> RBG 
RGB -> BGR 
RGB -> BRG 
RGB -> GBR 
RGB -> GRB 
 

 
 
 
 
 
 
 
 
 
 
 
 
 
 

2.Удаление или насыщение цветов

    Далее рассматриваем еще 2 функции. Первая – устанавливает значение цвета в 0 (например, нет красного). Вторая – наоборот увеличивает колличество цвета до максимального значения, или сразу 2 канала. Таким образом, мы имеем 6 вариантов значений для каждого метода.

  • Удаление (или насыщение) красный
  • Удаление (или насыщение) зеленый
  • Удаление (или насыщение) синий
  • Удаление (или насыщение) красный и зеленый в то же самое время
  • Удаление (или насыщение) красный и синий
  • Удаление (или насыщение) зеленый и синий

    Код:

<?php  
function removeColor($pixel, $factor)  
{  
    if (
$factor == 'r' ) {  
        
$pixel->r = 0;  
    }  
    if (
$factor == 'g' ) {  
        
$pixel->g = 0;  
    }  
    if (
$factor == 'b' ) {  
        
$pixel->b = 0;  
    }  
    if (
$factor == 'rb' || $factor == 'br') {  
        
$pixel->r = 0;  
        
$pixel->b = 0;  
    }  
    if (
$factor == 'rg' || $factor == 'gr') {  
        
$pixel->r = 0;  
        
$pixel->g = 0;  
    }  
    if (
$factor == 'bg' || $factor == 'gb') {  
        
$pixel->b = 0;  
        
$pixel->g = 0;  
    }  
    return 
$pixel;  
}  
 
function 
maxColor($pixel, $factor)  
{  
    if (
$factor == 'r' ) {  
        
$pixel->r = 255;  
    }  
    if (
$factor == 'g' ) {  
        
$pixel->g = 255;  
    }  
    if (
$factor == 'b' ) {  
        
$pixel->b = 255;  
    }  
    if (
$factor == 'rb' || $factor == 'br') {  
        
$pixel->r = 255;  
        
$pixel->b = 255;  
    }  
    if (
$factor == 'rg' || $factor == 'gr') {  
        
$pixel->r = 255;  
        
$pixel->g = 255;  
    }  
    if (
$factor == 'bg' || $factor == 'gb') {  
        
$pixel->b = 255;  
        
$pixel->g = 255;  
    }  
    return 
$pixel;  
}  
?>

 
 

    Результаты:

Удаляем красный 
Удаляем зеленый 
Удаляем синий 
Удаляем красный  и зеленый 
Удаляем зеленый и  синий 
Удаляем красный и  синий 
Насыщаем  красный 
Насыщаем зеленый 
Насыщаем синий 
Насыщаем  красный и зеленый 
Насыщаем зеленый  и синий 
Насыщаем красный  и синий 

 

Делаем  негатив 
 

    Эта функция очень проста – у вас  много красного? Значит сделаем мало. И так далее.

 
 
 
<?php  
function negative($pixel)  
{  
    return new 
Pixel(  
    
255 - $pixel->g,  
    
255 - $pixel->r,  
    
255 - $pixel->b  
    
);  
}  
?> 

 

    Результат:                             

Оттенки серого (Grayscale)

    Не  знаю, в курсе вы или нет, но оттенок  серого получается уравниванием R, G, B каналов. Более темные участки имеют больше насыщения, светлые – меньше.

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

<?php  
function greyscale($pixel)  
{  
    
$pixel_average = ($pixel->r + $pixel->g + $pixel->b) / 3;  
 
    return new 
Pixel(  
    
$pixel_average,  
    
$pixel_average,  
    
$pixel_average  
    
);  
}  
?> 

    Результат:

 
 

Черно-белое

    В отличие от оттенков серого, черно-белое  изображение имеет только 2 цвета: черный (0,0,0) и белый (255,255,255). $factor мы будем использовать для определения границы того, что считать черным, а что – белым. Простота логики в том, что мы суммируем R+G+Bи смотрим, к чему значение ближе – к 255 или к 0. Использование $factor позволит нам внести некоторую гибкость в алгоритм (внести некоторую субъективность):

 
<?php  
function blackAndWhite($pixel, $factor)  
{  
    
$pixel_total = ($pixel->r + $pixel->g + $pixel->b);  
 
    if (
$pixel_total > (((255 + $factor) / 2) * 3)) {  
        
// белый  
        
$pixel->r = 255;  
        
$pixel->g = 255;  
        
$pixel->b = 255;  
    } else {  
        
$pixel->r = 0;  
        
$pixel->g = 0;  
        
$pixel->b = 0;  
    }  
 
    return 
$pixel;  
}  
 
?> 
Работа с изображением в PHP