Флойд Стейнберг искажает Matlab — Что я делаю не так?

#matlab #image-processing #dithering

#matlab #обработка изображений #сглаживание

Вопрос:

Я пытаюсь реализовать сглаживание Флойда Стейнберга в MATLAB, используя псевдокод на странице Википедии https://en.wikipedia.org/wiki/Floyd–Steinberg_dithering

Мой код приведен ниже

 image = double(imread("dithering.jpg")) ./ 255;
levels = 2;

image_quantised = round(image .* (levels - 1)) ./ (levels - 1);
error = image - image_quantised;

height = size(image(:, :, 1), 1);
width = size(image(:, :, 1), 2);

image_dithered = image_quantised;

for y = 1:height - 1
    for x = 2:width - 1
                
        image_dithered(y    , x   1, :) = image_dithered(y    , x   1, :)   error(y, x, :) .* 7 / 16;
        image_dithered(y   1, x - 1, :) = image_dithered(y   1, x - 1, :)   error(y, x, :) .* 3 / 16;
        image_dithered(y   1, x    , :) = image_dithered(y   1, x    , :)   error(y, x, :) .* 5 / 16;
        image_dithered(y   1, x   1, :) = image_dithered(y   1, x   1, :)   error(y, x, :) .* 1 / 16;
        
    end
end

imshow(image_dithered)  % Image 1
imshow(dither(mean(image, 3)))  % Image 2
  

Изображение 1

Изображение 1, неправильно сглажено

Изображение 2

Изображение 2, правильный результат сглаживания

Я ожидаю результата на изображении 2, но получаю изображение 1. Похоже, что алгоритм ничего не делает. Есть идеи? 🙂

Редактировать: я пробовал инициализацию image_dithered с разными значениями; все нули, квантованное изображение и исходное изображение. Ни один из них не работает правильно

Редактирование 2: я приближаюсь к вычислению ошибки и квантованию в цикле. Однако все еще не на месте.

 for y = 1:height - 1
    for x = 2:width - 1
        new_pixel = round(image_dithered(y, x, :) .* (levels - 1)) ./ (levels - 1);
        image_dithered(y, x, :) = new_pixel;

        error = image(y, x, :) - new_pixel;

        image_dithered(y    , x   1, :) = image_dithered(y    , x   1, :)   error .* 7 / 16;
        image_dithered(y   1, x - 1, :) = image_dithered(y   1, x - 1, :)   error .* 3 / 16;
        image_dithered(y   1, x    , :) = image_dithered(y   1, x    , :)   error .* 5 / 16;
        image_dithered(y   1, x   1, :) = image_dithered(y   1, x   1, :)   error .* 1 / 16;
    end
end
  

Редактировать 3: Спасибо за @saastn и @Cris Luengo, оба ответа помогли мне понять, где я ошибался, и, похоже, теперь все работает так, как ожидалось!

Исправленный код приведен ниже для полноты.

 height = size(image(:, :, 1), 1);
width = size(image(:, :, 1), 2);

image_dithered = image;

for y = 1:height - 1
    for x = 2:width - 1
        old_pixel = image_dithered(y, x, :);
        new_pixel = round(image_dithered(y, x, :) .* (levels - 1)) ./ (levels - 1);
        
        image_dithered(y, x, :) = new_pixel;
        
        error = old_pixel - new_pixel;
        
        image_dithered(y    , x   1, :) = image_dithered(y    , x   1, :)   error .* 7 / 16;
        image_dithered(y   1, x - 1, :) = image_dithered(y   1, x - 1, :)   error .* 3 / 16;
        image_dithered(y   1, x    , :) = image_dithered(y   1, x    , :)   error .* 5 / 16;
        image_dithered(y   1, x   1, :) = image_dithered(y   1, x   1, :)   error .* 1 / 16;
        
    end
end

imshow(image_dithered)
imshow(dither(mean(image, 3)))
  

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

Ответ №1:

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

введите описание изображения здесь

Но даже после внесения изменений вы не можете ожидать, что результаты будут соответствовать выводам MATLAB, что может быть результатом различий в деталях двух реализаций. введите описание изображения здесь

Ответ №2:

Вы распространяете ошибки в image_quantized , а не в исходном изображении. Удалите это квантованное изображение, оно не является частью алгоритма.

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

Обратите внимание, что псевдокод Википедии делает это на месте, существует только одна копия изображения, которая работает как для ввода, так и для вывода.

В этом моем старом сообщении в блоге есть код MATLAB для сглаживания Флойда-Стейнберга.

Ответ №3:

Предполагая, что вы сначала следуете ответу saastn (и отвечаете на то, что в нем говорится о различиях между этими изображениями): я бы сказал, что, просто взглянув на них на изображении saastn, шаблоны Matlab выглядят так, как будто они представляют собой боковую версию Floyd-Steinberg здесь, либо путем поворота, либо, что более вероятно, с помощьютранспозиция (поменяйте местами x с y, что является отражением по диагональной оси x y). Это нельзя имитировать, просто изменяя коэффициенты, изображение должно обрабатываться по столбцам («для x» за пределами «для y» И т. Д.).