Есть небольшой скрипт, он прогоняет через себя все пиксели некоторого изображения, сохраняет в ассоциативный массив цвет пикселя и количество пикселей этого цвета.
Проблема в том что скрипт работает очень долго, потому что на картинке встречается огромное количество пикселей с таким цветом, который за всю картинку встречается всего один раз.
Можно ли перед прогонкой изображения или во время неё убрать эти ненужные пиксели что бы скрипт работал быстрее?
<?php
$image = 'img/rgb1.png';
$img = imagecreatefrompng($image);//открываем изображение
$sx = imagesx($img);//находим ширину
$sy = imagesy($img);//находим длину
$colors = array();//создаем массив в котором будем хранить все цвета которые есть на картинке
for ($y = 0; $y < $sy; $y++){
$y_arr = array();
for ($x = 0; $x < $sx; $x++){
$rgb = imagecolorat($img, $x, $y);
$r = ($rgb >> 16) & 0xFF;
$g = ($rgb >> 8) & 0xFF;
$b = $rgb & 0xFF;
$x_arr = array($r, $g, $b) ;
$y_arr[] = $x_arr;
}
$colors[] = $y_arr; //заполнить массив значениями цветов пикселей
}
//поиск количества пикселей одинакового цвета
$color = array();//создаем массив который будет хранить цвета и их количество
$tm1 = array();//цвет
for ($i = 0; $i < $sx; $i++)
{
for ($j = 0; $j < $sy; $j++)
{
$tmp = 0;//запоминаем количество цветов
foreach ($color as $value){
foreach ($value as $val) {
if ($val == $colors[$i][$j] ) { //проверка если в масcиве $color уже есть значение такого цвета
continue 3; //то вsходим из цикла и переходим к другому пикселю
} else {
$tm1 = $colors[$i][$j]; //если такого цвета еще нет запоминаем его значение
}
}
}
//поиск количества цветов
for ($ii = 0; $ii < $sx; $ii++) //если был найден новый цвет то прогоняется веся картинках в поисках
{ //пикселей с таким же цветом
for ($jj = 0; $jj < $sy; $jj++)
{
if ($colors[$ii][$jj] == $tm1)
{
$tmp++; // запоминается их количество
}
}
}
$color[] = [$tmp => $tm1]; //записывается в маcсив
}
}
print_r($color);
Задача решается за один проход, а тут проходов столько, сколько в картинке разных цветов: на каждый новый цвет вся картинка прогоняется заново в поисках этого цвета, хотя очевидно, что во все предыдущие пиксели не этого цвета.
Допустим, последний пиксель такого цвета, который еще не встречался. Так зачем же опять прогонять скрипт по все картинке, если пиксель последний и такого цвета еще не было? Очевидно, что пиксель такого цвета один.
Алгоритм должен быть такой:
Править код не буду, потому что тут надо заново писать, а не исправлять.
В дополнение соседнего ответа, если шибко не заботится о памяти, то весь алгоритм подсчета сколько пикселей какого цвета в картинке, будет выглядеть примерно так:
$img = imagecreatefrompng( 'sample.png' );
$w = imagesx($img);
$h = imagesy($img);
$colors = [];
for($x = 0; $x < $w; $x++){
for($y =0 ; $y < $h; $y++){
$colors[] = imagecolorat($img, $x, $y);
}
}
$result = array_count_values($colors);
arsort($result);
print_r($result);
Ключами будет цвет, значениями - сколько раз встречается. Отсортировано по частоте в порядке убывания. Чтобы получить составляющие цвета, можно использовать как битовые сдвиги (как у вас), либо imagecolorsforindex($img, $color)
.
Очевидно, что если у вас будет картинка на 20Мпикселей черного цвета, то начальный массив будет содержать 20М элементов, вместо одного. Если хотите память расходовать более экономно, то array_count_values
лесом, и считаем руками:
$c = imagecolorat($img, $x, $y);
if(array_key_exists($c, $colors)){
$colors[$c]++;
}
else { $colors[$c] = 1; }
Виртуальный выделенный сервер (VDS) становится отличным выбором
Подскажите, совсем новичкуНужно сделать исключение вызову функции, которое не поддерживается операционной системой
Аналог реальной программыКак переместить создание потоков (#pragma omp parallel) в main_, но оставить funcSerial однопоточным (последовательным)? funcSerial я распараллеливать...
Имеется один файл maincpp, в котором определены две глобальные функции getSomeResultFromSomeFunc(), processResult() и функция main():