# Дизеринг с распределением коррекции

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

1. Количество передаваемых оттенков ограничено размером матрицы
2. Каждый оттенок создается хорошо различимым регулярным узором, что может не очень хорошо смотреться на фотографиях
3. На изображениях с плавным переходом полутонов будут видны четкие границы узоров
4. Тонкие линии контрастного цвета могут пропасть полностью, если попадутся на неудачный участок шаблона

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

За основу возьмем то же самое изображение 16x16 клеточек из предыдущей части:

[![image.png](https://docs.mosaic-crochet.ru/uploads/images/gallery/2024-04/scaled-1680-/IJzimage.png)](https://docs.mosaic-crochet.ru/uploads/images/gallery/2024-04/IJzimage.png)

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

Фильтров придумано огромное множество и они создают разные эффекты. Одним из самых распространенных фильтров является фильтр Флойда-Штейнберга, который выглядит следующим образом:

<table border="1" id="bkmrk--1--1-7%2F16-3%2F16-5%2F16" style="border-collapse: collapse; width: 24.321%;"><colgroup><col style="width: 33.1878%;"></col><col style="width: 33.1878%;"></col><col style="width: 33.1878%;"></col></colgroup><tbody><tr><td style="background-color: rgb(224, 62, 45);">-1  
</td><td style="background-color: rgb(53, 152, 219);">-1  
</td><td style="background-color: rgb(45, 194, 107);">7/16  
</td></tr><tr><td style="background-color: rgb(45, 194, 107);">3/16  
</td><td style="background-color: rgb(45, 194, 107);">5/16  
</td><td style="background-color: rgb(45, 194, 107);">1/16  
</td></tr></tbody></table>

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

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

Как мы видим из таблички, в фильтре Флойда-Штейнберга распространение коррекции происходит вправо, вниз, по диагонали вправо-вниз и влево-вниз. Есть фильтры, которые распространяют коррекцию не только на непосредственно соседние клеточки, но и через одну или даже дальше. Например, фильтр Сьерры выглядит следующим образом:

<table border="1" id="bkmrk--1--1--1-5%2F32-3%2F32-2" style="border-collapse: collapse; width: 100%; height: 89.4px;"><colgroup><col style="width: 20%;"></col><col style="width: 20%;"></col><col style="width: 20%;"></col><col style="width: 20%;"></col><col style="width: 20%;"></col></colgroup><tbody><tr style="height: 29.8px;"><td style="background-color: rgb(224, 62, 45); height: 29.8px;">-1  
</td><td style="background-color: rgb(224, 62, 45); height: 29.8px;">-1  
</td><td style="height: 29.8px; background-color: rgb(53, 152, 219);">-1  
</td><td style="height: 29.8px; background-color: rgb(45, 194, 107);">5/32  
</td><td style="height: 29.8px; background-color: rgb(45, 194, 107);">3/32  
</td></tr><tr style="height: 29.8px;"><td style="height: 29.8px; background-color: rgb(45, 194, 107);">2/32  
</td><td style="height: 29.8px; background-color: rgb(45, 194, 107);">4/32  
</td><td style="height: 29.8px; background-color: rgb(45, 194, 107);">5/32  
</td><td style="height: 29.8px; background-color: rgb(45, 194, 107);">4/32  
</td><td style="height: 29.8px; background-color: rgb(45, 194, 107);">2/32  
</td></tr><tr style="height: 29.8px;"><td style="height: 29.8px; background-color: rgb(224, 62, 45);">-1  
</td><td style="height: 29.8px; background-color: rgb(45, 194, 107);">2/32  
</td><td style="height: 29.8px; background-color: rgb(45, 194, 107);">3/32  
</td><td style="height: 29.8px; background-color: rgb(45, 194, 107);">2/32  
</td><td style="height: 29.8px; background-color: rgb(224, 62, 45);">-1  
</td></tr></tbody></table>

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

Итак, давайте попробуем обработать нашу картинку алгоритмом дизеринга с распространением коррекции, используя фильтр Флойда-Штейнберга.

[![image.png](https://docs.mosaic-crochet.ru/uploads/images/gallery/2024-04/scaled-1680-/baXimage.png)](https://docs.mosaic-crochet.ru/uploads/images/gallery/2024-04/baXimage.png)

Берем первую клеточку. Она уже черного цвета, поэтому делать тут нечего.

[![image.png](https://docs.mosaic-crochet.ru/uploads/images/gallery/2024-04/scaled-1680-/KpBimage.png)](https://docs.mosaic-crochet.ru/uploads/images/gallery/2024-04/KpBimage.png)

У следующей клеточки оттенок серого с яркостью 11. Это меньше порогового значения 128, поэтому мы приведем ее к черному, т.е. к 0. В результате у нас возникнет значение коррекции в 11 единиц, которое нам нужно распределить на соседние клеточки в соответствии с фильтром. Знаменатель дроби (количество долей) у нас 16, поэтому делим 11 на 16 и получаем размер одной доли - 0,6875. Вправо мы должны распределить 7 долей, т.е. 4,8125. Яркость правой клеточки у нас 19, прибавим к ней 4,8125, округлим математически до целого значения и получится новое значение яркости - 24:

[![image.png](https://docs.mosaic-crochet.ru/uploads/images/gallery/2024-04/scaled-1680-/YfDimage.png)](https://docs.mosaic-crochet.ru/uploads/images/gallery/2024-04/YfDimage.png)

Вправо и вниз мы распределяем 1 долю, т.е. 0,6875, или округленно 1:

[![image.png](https://docs.mosaic-crochet.ru/uploads/images/gallery/2024-04/scaled-1680-/6P8image.png)](https://docs.mosaic-crochet.ru/uploads/images/gallery/2024-04/6P8image.png)

Вниз распределяем 5 долей, т.е. 3,4375, округленно 3:

[![image.png](https://docs.mosaic-crochet.ru/uploads/images/gallery/2024-04/scaled-1680-/9Xrimage.png)](https://docs.mosaic-crochet.ru/uploads/images/gallery/2024-04/9Xrimage.png)

И влево-вниз 3 доли, т.е. 2,0625, округленно 2:

[![image.png](https://docs.mosaic-crochet.ru/uploads/images/gallery/2024-04/scaled-1680-/zydimage.png)](https://docs.mosaic-crochet.ru/uploads/images/gallery/2024-04/zydimage.png)

Переходим ко второй клеточке. Ее значение яркости уже не 19, а 24, но это все еще меньше 128, поэтому клеточку приводим к черному цвету (0) и получаем значение коррекции 24, которое нужно распределить вправо, вправо-вниз, вниз и влево-вниз соответственно на 11, 2, 8 и 5 значений:

[![image.png](https://docs.mosaic-crochet.ru/uploads/images/gallery/2024-04/scaled-1680-/Cw1image.png)](https://docs.mosaic-crochet.ru/uploads/images/gallery/2024-04/Cw1image.png)

Четвертую клеточку мы тоже приводим к черному и распределяем уже 38 пунктов коррекции:

[![image.png](https://docs.mosaic-crochet.ru/uploads/images/gallery/2024-04/scaled-1680-/m05image.png)](https://docs.mosaic-crochet.ru/uploads/images/gallery/2024-04/m05image.png)

Пройдем до конца ряда:

[![image.png](https://docs.mosaic-crochet.ru/uploads/images/gallery/2024-04/scaled-1680-/Nuyimage.png)](https://docs.mosaic-crochet.ru/uploads/images/gallery/2024-04/Nuyimage.png)

[![image.png](https://docs.mosaic-crochet.ru/uploads/images/gallery/2024-04/scaled-1680-/RMJimage.png)](https://docs.mosaic-crochet.ru/uploads/images/gallery/2024-04/RMJimage.png)

[![image.png](https://docs.mosaic-crochet.ru/uploads/images/gallery/2024-04/scaled-1680-/1AZimage.png)](https://docs.mosaic-crochet.ru/uploads/images/gallery/2024-04/1AZimage.png)

[![image.png](https://docs.mosaic-crochet.ru/uploads/images/gallery/2024-04/scaled-1680-/IABimage.png)](https://docs.mosaic-crochet.ru/uploads/images/gallery/2024-04/IABimage.png)

[![image.png](https://docs.mosaic-crochet.ru/uploads/images/gallery/2024-04/scaled-1680-/oSWimage.png)](https://docs.mosaic-crochet.ru/uploads/images/gallery/2024-04/oSWimage.png)

[![image.png](https://docs.mosaic-crochet.ru/uploads/images/gallery/2024-04/scaled-1680-/lqcimage.png)](https://docs.mosaic-crochet.ru/uploads/images/gallery/2024-04/lqcimage.png)

Обратите внимание, как постепенно накапливается значение коррекции, высветляя соседние клеточки все больше и больше, пока не приводит к тому, что очередную клеточку мы уже приводим не к черному, а к белому: 143 -&gt; 255. При этом значение коррекции у нас уже становится отрицательным: 143 - 255 = -112, соответственно соседние клеточки мы уже будем распределением коррекции не высветлять, а затемнять, отнимая яркость в соответствии с долями распределения коррекции:

[![image.png](https://docs.mosaic-crochet.ru/uploads/images/gallery/2024-04/scaled-1680-/DTwimage.png)](https://docs.mosaic-crochet.ru/uploads/images/gallery/2024-04/DTwimage.png)

Теперь посмотрим на видео, как происходит обработка картинки от начала до конца:

<video controls="controls" height="320" poster="" width="320"><source src="https://mosaic-crochet.ru/public/docs/dither-fs-16.mp4" type="video/mp4"></source></video>

Конечно, на маленьком изображении результат не так очевиден, но вот как этот алгоритм выглядит на изображении 300x300 точек:

[![dither-fs-300.png](https://docs.mosaic-crochet.ru/uploads/images/gallery/2024-04/scaled-1680-/dither-fs-300.png)](https://docs.mosaic-crochet.ru/uploads/images/gallery/2024-04/dither-fs-300.png) <video controls="controls" height="300" poster="" width="300"><source src="https://mosaic-crochet.ru/public/docs/dither-fs-300.mp4" type="video/mp4"></source></video>

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

Ниже приведены результаты преобразования той же картинки размером 300x300 точек с использованием разных фильтров:

<table border="1" id="bkmrk--19" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 33.3333%;"></col><col style="width: 33.3333%;"></col><col style="width: 33.3333%;"></col></colgroup><tbody><tr><td>[![DitherFloydSteinbergSimplified.png](https://docs.mosaic-crochet.ru/uploads/images/gallery/2024-04/scaled-1680-/ditherfloydsteinbergsimplified.png)](https://docs.mosaic-crochet.ru/uploads/images/gallery/2024-04/ditherfloydsteinbergsimplified.png)  
</td><td>[![DitheringAtkinson.png](https://docs.mosaic-crochet.ru/uploads/images/gallery/2024-04/scaled-1680-/ditheringatkinson.png)](https://docs.mosaic-crochet.ru/uploads/images/gallery/2024-04/ditheringatkinson.png)  
</td><td>[![DitheringBurkes.png](https://docs.mosaic-crochet.ru/uploads/images/gallery/2024-04/scaled-1680-/ditheringburkes.png)](https://docs.mosaic-crochet.ru/uploads/images/gallery/2024-04/ditheringburkes.png)  
</td></tr><tr><td>[![DitheringJJN.png](https://docs.mosaic-crochet.ru/uploads/images/gallery/2024-04/scaled-1680-/ditheringjjn.png)](https://docs.mosaic-crochet.ru/uploads/images/gallery/2024-04/ditheringjjn.png)  
</td><td>[![DitheringOstromukhov.png](https://docs.mosaic-crochet.ru/uploads/images/gallery/2024-04/scaled-1680-/ditheringostromukhov.png)](https://docs.mosaic-crochet.ru/uploads/images/gallery/2024-04/ditheringostromukhov.png)  
</td><td>[![DitheringShiauFan.png](https://docs.mosaic-crochet.ru/uploads/images/gallery/2024-04/scaled-1680-/ditheringshiaufan.png)](https://docs.mosaic-crochet.ru/uploads/images/gallery/2024-04/ditheringshiaufan.png)  
</td></tr><tr><td>[![DitheringSierra.png](https://docs.mosaic-crochet.ru/uploads/images/gallery/2024-04/scaled-1680-/ditheringsierra.png)](https://docs.mosaic-crochet.ru/uploads/images/gallery/2024-04/ditheringsierra.png)  
</td><td>[![DitheringSierra2Rows.png](https://docs.mosaic-crochet.ru/uploads/images/gallery/2024-04/scaled-1680-/ditheringsierra2rows.png)](https://docs.mosaic-crochet.ru/uploads/images/gallery/2024-04/ditheringsierra2rows.png)  
</td><td>[![DitheringSierraLite.png](https://docs.mosaic-crochet.ru/uploads/images/gallery/2024-04/scaled-1680-/ditheringsierralite.png)](https://docs.mosaic-crochet.ru/uploads/images/gallery/2024-04/ditheringsierralite.png)  
</td></tr><tr><td>[![DitheringStuki.png](https://docs.mosaic-crochet.ru/uploads/images/gallery/2024-04/scaled-1680-/ditheringstuki.png)](https://docs.mosaic-crochet.ru/uploads/images/gallery/2024-04/ditheringstuki.png)  
</td><td>  
</td><td>  
</td></tr></tbody></table>

В [генераторе схем](https://mosaic-crochet.ru/generator2) для платных подписчиков на [Бусти](https://boosty.to/mosaic-crochet) и в [ВК](https://vk.com/donut/mosaic_crochet) доступны все эти фильтры и другие настройки, а также возможность составить собственный фильтр.