Убрать ненужные пиксели

109
03 сентября 2019, 06:30

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

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

Можно ли перед прогонкой изображения или во время неё убрать эти ненужные пиксели что бы скрипт работал быстрее?

<?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);
Answer 1

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

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

Алгоритм должен быть такой:

  1. взяли пиксель,
  2. определили цвет,
  3. увеличили значение в таблице цветов или добавили, если еще не было,
  4. перешли к следующему.

Править код не буду, потому что тут надо заново писать, а не исправлять.

Answer 2

В дополнение соседнего ответа, если шибко не заботится о памяти, то весь алгоритм подсчета сколько пикселей какого цвета в картинке, будет выглядеть примерно так:

$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; }
READ ALSO
Исключение на не известную функцию в С++

Исключение на не известную функцию в С++

Подскажите, совсем новичкуНужно сделать исключение вызову функции, которое не поддерживается операционной системой

115
OpenMP. Нетривиальный случай

OpenMP. Нетривиальный случай

Аналог реальной программыКак переместить создание потоков (#pragma omp parallel) в main_, но оставить funcSerial однопоточным (последовательным)? funcSerial я распараллеливать...

86
Запуск сервера на C++ Visual Studio [закрыт]

Запуск сервера на C++ Visual Studio [закрыт]

Запускаю локальный отладчик Windows(x86)

123
std::move для объекта, возвращенного функцией

std::move для объекта, возвращенного функцией

Имеется один файл maincpp, в котором определены две глобальные функции getSomeResultFromSomeFunc(), processResult() и функция main():

99