Очистить картинку от шума. GD. Возможно?

ksnk

прохожий
При загрузке картинок, иногда, требуется очистить картинку от артефактов пережатия jpeg, которые выглядят как шум. Картинки небольшого размера, превьюшки и накладные расходы даже на попиксельный просмотр картинки будут не очень страшны.
Выглядит это как дополнительный сервис в админке, когда после загрузки превьюшки, будет предложено пользователю выбрать наиболее удачный вариант обработки.
По идее, любой фильтр для очистки шума с этим справляется относительно разумно, однако потребовалось это сделать на сервере, без Image Magick.
Возможно ли это сделать с помощью фильтров GD или как нибудь еще?
 

WMix

герр M:)ller
Партнер клуба
не знаю как на счет jpeg шум но подход такой,
1. копия -> ч/б
2. все что черное уменьшить на 1px
3. все что черное увеличить на 1px
4. использовать как маску для оригинала
 

ksnk

прохожий
@WMix, маска в каком смысле, все что вне маски - выкидываем? При этом фон со светлым рисунком потеряется. Или я что-то не понял?
 

ksnk

прохожий
O! Все что вне маски делаем размытым... Вроде так более разумно выглядит. Правда что делать со светлым рисунком на темном фоне - нипанятна...
Спасибо за идею, буду думать.
 

WMix

герр M:)ller
Партнер клуба
Правда что делать со светлым рисунком на темном фоне
можно и инвертить, а вообще внутри как и снаружи... но яб на твоем месте не парился с попиксельной обработкой... не тот язык, долго будет
 

ksnk

прохожий
На первый взгляд - конволюшн с гауссовой матрицей дал неплохой результат.

PHP:
$img=imagecreatefromjpeg($imgfile);
$emboss = array(array(1/16, 1/8, 1/16), array(1/8, 1/4, 1/8), array(1/16, 1/8, 1/16));
        // calculate the sharpen divisor
$divisor = array_sum(array_map('array_sum', $emboss));
imageconvolution($img, $emboss, $divisor, 0);
В общем-то, практически блур, но для грязных и небольших превьюшек получается неплохо.

Хотя я уже почти созрел для вычисления маски по IMG_FILTER_EDGEDETECT, потом зарядить там контраст, результирующую картинку заблурить и по маске, там где пиксели достаточно черные или белые - скопировать старое изображение... Может еще доделаю :)
 

флоппик

promotor fidei
Команда форума
Партнер клуба
Хотя я уже почти созрел для вычисления маски по IMG_FILTER_EDGEDETECT, потом зарядить там контраст, результирующую картинку заблурить и по маске, там где пиксели достаточно черные или белые - скопировать старое изображение... Может еще доделаю :)
Там по идее в более качественных фильтрах так и делают, low pass + high pass + всякие угадайки
 

ksnk

прохожий
Да, как и ожидалось, решение с попиксельной работой оказалось медленным. Впрочем вся работа с GD не быстра...
Вдруг кому понадобится - тут есть некоторые цифры и слова.
PHP:
    /**
     * шумодав на коленке для маленьких жипегчиков .
     * @param file $imgfile :select[~dir(*.jpg)]  имя файла для обработки
     * @param string $tmpname :text имя файла с результатом, без расширения
     */
    function do_convert($imgfile,$tmpname='tmp'){
        $orig=imagecreatefromjpeg($imgfile);
        $width = imagesx($orig);
        $height = imagesy($orig);
        $mask=imagecreatetruecolor($width,$height);
        $img=imagecreatetruecolor($width,$height);
        // копируем оригинал
        imagecopy($mask,$orig,0,0,0,0,$width,$height);
        imagecopy($img,$orig,0,0,0,0,$width,$height);
        // делаем маску
        imagefilter($mask,IMG_FILTER_EDGEDETECT);
        imagefilter($mask,IMG_FILTER_GRAYSCALE);
        // imagefilter($img,IMG_FILTER_CONTRAST,-100); // не надо, становится хуже :(

        // Гаусс блур для  $img
        //imagefilter($img,IMG_FILTER_GAUSSIAN_BLUR);
        // или сильный блур для остальной картинки
        imagefilter($img,IMG_FILTER_SELECTIVE_BLUR);

        for($i=0;$i<$width;$i++)for($j=0;$j<$height;$j++){
            $rgb=imagecolorat($mask,$i,$j);
            $r = ($rgb >> 16) & 0xFF;
            $g = ($rgb >> 8) & 0xFF;
            $b = $rgb & 0xFF;
            $col=abs(128-($r+$g+$b)/3);
            if($col>110){
                $c=imagecolorat($orig,$i,$j);
                imagesetpixel($img,$i,$j,$c);
            }
        }
        // $img - готовая картинка с уменьшеным шумом
        imagepng($img,dirname($imgfile).'/'.$tmpname.'.png');
        imagedestroy($mask);
        imagedestroy($orig);
        imagedestroy($img); // порядок прежде всего
        //echo dirname($imgfile).'/'.$tmpname.'.png';
    }
Не то, что он убирает артефакты на картинке, но делает их не такими заметными. На первый взгляд, получился почти обычный мыльный шумодав...
 

WMix

герр M:)ller
Партнер клуба
Эх, попьет из тебя крови твой шумодав, говнецо еще то! Чес слово простой exec для imagic логичнее и проще поддерживаемо! Ну поиграйся... Задачка для понимания мира больше
 
  • Like
Реакции: ksnk
Сверху