PHP

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

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

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

Научившись применять основные из функций php библиотеки GD (Graphics Draw) я нашел ей применение в решении одной задачи, суть которой сводится к выравниванию масштаба всех изображений в наборе.

Дано: набор изображений для товаров интернет магазина.



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

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



Получившиеся изображения товаров должны быть, все одного разрешения и одного масштаба.

Решение задачи ( PHP работа с изображениями )

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

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

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

Как вычислить размеры внутреннего рисунка на холсте

Самой сложной из подзадач является, поиск габаритов изображения:


На приведенном рисунке

P0 – точка начала области изображения товара
H1- высота товара
W1- ширина товара
H2- расстояние от верхней границы холста до точки P0
W2- расстояние от левой границы холста до точки P0
H3- высота всего изображения картинки товара
W3- ширина всего изображения картинки товара
Чтобы определить все неизвестные нам параметры, мы воспользуемся как встроенными средствами PHP по работе с изображениями, так и собственным "велосипедом".

Найти H3 и W3 можно php функцией getimagesize(), но как бы нам вычислить H1 и W1? Что если мы вернемся к статье по распознаванию капчи? Возьмем из этой статьи алгоритм преобразования изображения в бинарную матрицу.

Бинарная матрица – это представления изображения в виде единиц и нулей, все пикселы изображения отличающиеся от фонового цвета получат значение = 0 , а пикселы составляющие само изображение будут равны 1, в итоге мы получим такую матрицу:



Теперь мы можем запросто вычислить интервалы, в которых находятся 1-цы.

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

В готовом виде PHP скрипт будет выглядеть так:
<?php
/**
 * Класс нормальзующий картинку по заданному разрешению
 */
class imageWorker {

  public $baseWidth = 150;  // длина эталонного изображения (именно товара внутри картинки)
  public $baseHeight = 119; // высота эталонного изображения (именно товара внутри картинки)
  public $outImageWidth = 600;  // длина изображения после обработки
  public $outImageHeight = 400; // высота изображения после обработки
  public $im = null;  // дескриптор картитнки
  public $binaryMartix = null; // матричное представление картитнки
  public $saveBinaryMartixTofile = false; // сохранять матричное представление картитнки в файл
  public $dir = 'image/source/';  // расположения набора картинок
  public $saveMartix = false; // сохранять матричное представление картитнок
  public $extensions = array("", "gif", "jpeg", "png"); // допустимые картинки
  public $curImageWidth = 1;  // ширина обрабатываемого изображения
  public $curImageHeight = 1; // высота обрабатываемого изображения
  public $imgFunctionProcess = "imagecreatefromjpeg"; // функция для работы с изображением
  public $curExt = ""; // расширение картинки
  public $curImageName = ""; // расширение картинки
  public $dirUpload = 'image/result/'; // папка для выгрузки (должна быть создана)


  function __construct($path, $w, $h) {
    $this->outImageWidth = $w;
    $this->outImageHeight = $h;
    $this->curImageName = $path;

    list($this->curImageWidth, $this->curImageHeight, $type) = getimagesize($this->dir.$path); // Получаем размеры и тип изображения (число)
    $ext = $this->extensions[$type];
    if ($ext) {
      $this->imgFunctionProcess = 'imagecreatefrom'.$ext; // Получаем название функции, соответствующую типу, для создания изображения
      $func = $this->imgFunctionProcess;
      $this->curExt = $ext;
      $this->im = $func($this->dir.$path); // Создаём дескриптор для работы с исходным изображением
      if (!$this->im) {
        return false;
      }
    } else {
      echo 'Ошибка: Неизвестный формат изображения!';
      return false;
    }

    $this->binaryMartix = $this->imageToMatrix($this->im, false);

    if ($this->saveBinaryMartixTofile) {
      $this->printMatrix($this->binaryMartix);
    }

    $res = $this->explodeMatrix($this->binaryMartix);
    $width = $res['resultInterval'];
    $cropX = $res['startInterval'];

    $this->binaryMartix = $this->imageToMatrix($this->im, true);
    $res = $this->explodeMatrix($this->binaryMartix);
    $height = $res['resultInterval'];
    $cropY = $res['startInterval'];

    $result = "Размеры изображения (".$path.") <br/>width=".$this->curImageWidth."px; <br/>   height=".$this->curImageHeight."px;";
    $result .= "<br/>Размеры изделия внутри изображения <br/>width=".$width."px; <br/>   height=".$height."px;";
    $result .= "<br/>Коэффициенты сжатия <br/>width=".$this->baseWidth / $width."px; <br/>    height=".$this->baseHeight / $height."px;";
    $result .= "<br/>Отрезать картинку с точки <br/>cropX=".$cropX." <br/>    cropY=".$cropY." ";

    //$this->crop("2.png", $cropY, $cropX, $width, $height); // Вызываем функцию
    //$this->reSizeImage($name, $ext, $tmp, 0.3);
    echo $result;
    if ($this->baseHeight < $height) {
      $this->resizeImage($this->baseHeight / $height);
    } else {
      $this->resizeImage(1);
    };

    imagedestroy($this->im);
  }


  function explodeMatrix($binaryMartix) {
    $temp = array();

    // сложение столбцов для выявления интервалов
    for ($i = 0; $i < count($binaryMartix); $i++) {
      $sum = 0;
      for ($j = 0; $j < count($binaryMartix[0]); $j++) {
        $sum += $binaryMartix[$i][$j];
      }
      $temp[] = $sum ? 1 : 0;
    }


    // вычисление интервалов по полученной строке
    $start = false;
    $countPart = 0;
    $arrayInterval = array();
    foreach ($temp as $k => $v) {

      if ($v == 1 && !$start) {
        $arrayInterval[$countPart]['start'] = $k;
        $start = true;
      }

      if ($v == 0 && $start) {
        $arrayInterval[$countPart]['end'] = $k - 1;
        $start = false;
        $countPart++;
      }
    }

    //отсеиваем помехи (мелкие интервалы), Большая картинка, всяко больше 20px. 

    $resultInterval = 1;
    $startInterval = 1; // начало интервала
    foreach ($arrayInterval as $key => $interval) {
      if (($interval['end'] - $interval['start']) > 20) {
        $resultInterval = $interval['end'] - $interval['start'];
        $startInterval = $interval['start'];
      }
    }
    return
      array(
        'resultInterval' => $resultInterval,
        'startInterval' => $startInterval
    );
  }


  /**
   * Конвертация рисунка в бинарную матрицу
   * Все пиксели отличные от фона получают значение 1
   * @param imagecreatefrompng $im - картинка в формате PNG
   * @param bool $rotate - горизонтальная или вертикальная матрица 
   */
  function imageToMatrix($im, $rotate = false) {
    $height = imagesy($im);
    $width = imagesx($im);

    if ($rotate) {
      $height = imagesx($im);
      $width = imagesy($im);
    }

    $background = 0;
    for ($i = 0; $i < $height; $i++)
      for ($j = 0; $j < $width; $j++) {

        if ($rotate) {
          $rgb = imagecolorat($im, $i, $j);
        } else {
          $rgb = imagecolorat($im, $j, $i);
        }

        //получаем индексы цвета RGB 
        list($r, $g, $b) = array_values(imageColorsForIndex($im, $rgb));

        //вычисляем индекс красного, для фона изображения
        if ($i == 0 && $j == 0) {
          $background = $r;
        }
        //echo "red=".$background;
        $sensitivity = 15;
        // если цвет пикселя не равен фоновому заполняем матрицу единицей     
        $binary[$i][$j] = ($r > $background - $sensitivity) ? 0 : 1;
      }
    return $binary;
  }


  /**
   * Выводит матрицу на экран
   * @param type $binaryMartix
   */
  function printMatrix($binaryMartix) {
    $return = '';
    for ($i = 0; $i < count($binaryMartix); $i++) {
      $return .= "\n";
      for ($j = 0; $j < count($binaryMartix[0]); $j++) {
        $return .= $binaryMartix[$i][$j]." ";
      }
    }
    file_put_contents($this->dirUpload.$this->curImageName.".txt", $return);
  }


  /**
   * Функция для ресайза картинки
   * @paramint $koef коэффициент сжатия изображения
   * @return void
   */
  public function resizeImage($koef) {
    // получение новых размеров  
    $newWidth = $koef * $this->curImageWidth;
    $newHeight = $koef * $this->curImageHeight;
    // ресэмплирование    
    $image_p = imagecreatetruecolor($this->outImageWidth, $this->outImageHeight);
    //делаем фон изображения белым, иначе в png при прозрачных рисунках фон черный
    $color = imagecolorallocate($image_p, 255, 255, 255);
    imagefill($image_p, 0, 0, $color);
    imagecopyresampled(
      $image_p, $this->im, ($this->outImageWidth - $newWidth) / 2, ($this->outImageHeight - $newHeight) / 2, 0, 0, $newWidth, $newHeight, $this->curImageWidth, $this->curImageHeight
    );
    $func = "image".$this->curExt;
    $func($image_p, $this->dirUpload.$this->curImageName);
    imagedestroy($image_p);
  }

}// конец тела класса

/**
 * Массив имен файлов
 */
$imagesName = array(
  'kameya_medium_1005858593.jpg',
  'kameya_medium_1005862834.jpg',
  'km0210-3_small.jpg',
  'sd0201966_small.jpg',
);

/**
 * Перебор массива имен файлов и нормализация изображений
 */
foreach ($imagesName  as $image) {
  if (file_exists('image/source/'.$image)) {
     // каждую картинку нормальзуем и приведем к разрешению 200x200 пикселей
     $encrypt = new imageWorker($image, 200, 200);
  } else {
    continue;
  }
}

Данный скрипт PHP работает с изображениями из папки image/source/ и по результату своего выполнения складывает нормализованные картинки в папку image/result/.

Выполнив поставленную задачу и на практике познакомившись с тем, как происходит в php работа с изображениями, мы получили опыт на основе, которого сможем приводить изображения товаров каталога в приятный вид.
Теги:
изображения
Добавлено: 24 Сентября 2013 02:40:39 Добавил: Андрей Ковальчук Нравится 0
Добавить
Комментарии:
Нету комментариев для вывода...