CodeLab - первые шаги (Линогравюра)

Эта ветка форума посвящена инструкции по работе с лабораторией скриптов CodeLab от BoltBait. С её помощью можно делать свои плагины для Paint.NET. Все вопросы по CodeLab размещаются здесь.
Ответить
ReMake
Сообщения: 344
Зарегистрирован: 10 сен 2014, 01:25
Репутация: 108
Пол: Мужской
Откуда: Брест, Беларусь

CodeLab - первые шаги (Линогравюра)

Сообщение ReMake » 30 май 2015, 23:15

Возможно, вы знакомы с техникой создания изображений, именуемой линогравюра.

Давайте попробуем создать эффект, иммитирующий эту технику.

Итак, пошагово.

Шаг 1. Откройте какое-либо изображение.

Изображение

Шаг 2. Примените к нему эффект Эскиз (Эффекты -> Стилизация -> Эскиз) с параметрами по умолчанию.

Изображение

Шаг 3. Переведите получившееся изображение в черно-белый рисунок (Коррекция -> Сделать черно-белым).

Шаг 4. В меню Коррекция запустите эффект Кривые (Коррекция -> Кривые). Левую нижнюю точку кривой перетащите вправо, установив ее значения в (231,0). Правую верхнюю точку кривой перетащите влево, установив ее значения в (232,255).
Изображение
Шаг 5. Инвертируйте изображение (Коррекция -> Инвертировать цвета). В результате получится такое изображение.

Изображение

Вернитесь к шагу 4. Установите значения верхней точки кривой в (240,255), нижней - в (215,0). Попробуйте двигать левую точку вправо, до значений (239,0) - вы заметите, что это изменение приводит к детализации изображения.
Изображение
Теперь давайте будем создавать наш эффект. Запустите CodeLab (Эффекты -> Advanced -> Code Lab). В меню Файл выберите Новый. Выберите в выпадающем списке эффектов Эскиз. В верхнем выпадающем списке Обработка пикселя выберите Сделать черно-белым. В нижнем выпадающем списке Обработка пикселя выберите Инвертировать цвета. Нажмите кнопку Генерировать код. Мы получим следующий сценарий эффекта:

Код: Выделить всё

#region UICode
int Amount1=3; // [1,200] Толщина
int Amount2=50; // [0,100] Интенсивность
#endregion

// Настройки использования операций с пикселями
private UnaryPixelOps.Desaturate desaturateOp = new UnaryPixelOps.Desaturate();
private UnaryPixelOps.Invert invertOp = new UnaryPixelOps.Invert();

// Это основной цикл функции обработки
void Render(Surface dst, Surface src, Rectangle rect)
{
    // Настройки вызова эффекта Эскиз
    OutlineEffect outlineEffect = new OutlineEffect();
    PropertyCollection outlineProps = outlineEffect.CreatePropertyCollection();
    PropertyBasedEffectConfigToken outlineParameters = new PropertyBasedEffectConfigToken(outlineProps);
    outlineParameters.SetPropertyValue(OutlineEffect.PropertyNames.Thickness, Amount1);
    outlineParameters.SetPropertyValue(OutlineEffect.PropertyNames.Intensity, Amount2);
    outlineEffect.SetRenderInfo(outlineParameters, new RenderArgs(dst), new RenderArgs(src));
    // Вызов функции Эскиз
    outlineEffect.Render(new Rectangle[1] { rect }, 0, 1);

    // Теперь в основном цикле обработки холст назначения (dst) имеет эскизную версию холста источника (src)
    for (int y = rect.Top; y < rect.Bottom; y++)
    {
        if (IsCancelRequested) return;
        for (int x = rect.Left; x < rect.Right; x++)
        {
            ColorBgra CurrentPixel = dst[x,y];

            // ВЫПОЛНЕНИЕ: Добавьте здесь дополнительный код обработки пикселей
            CurrentPixel = desaturateOp.Apply(CurrentPixel);


            CurrentPixel = invertOp.Apply(CurrentPixel);

            dst[x,y] = CurrentPixel;
        }
    }
}
В строке

Код: Выделить всё

    outlineParameters.SetPropertyValue(OutlineEffect.PropertyNames.Intensity, Amount2);
замените Amount2 на 50.

Теперь давайте воспроизведем шаг 4. Между строкой

Код: Выделить всё

            CurrentPixel = desaturateOp.Apply(CurrentPixel);
и строкой

Код: Выделить всё

            CurrentPixel = invertOp.Apply(CurrentPixel);
поместите следующий код:

Код: Выделить всё

            int R = CurrentPixel.R;
            int G = CurrentPixel.G;
            int B = CurrentPixel.B;

           // Преобразование в контрастное черно-белое изображение
                if (R<232) {R=0;} 
                else R=255; 
                if (G<232) {G=0;} 
                else G=255; 
                if (B<232) {B=0;} 
                else B=255;  
            
		CurrentPixel.R = Int32Util.ClampToByte(R);
		CurrentPixel.G = Int32Util.ClampToByte(G);
		CurrentPixel.B = Int32Util.ClampToByte(B);
Помните, мы изменяли пороговое значение кривой от 215 до 240? Давайте воспроизведем это в нашем сценарии. Добавьте в сценарий целочисленную переменную int T = Amount2 + 214. Замените в приведенном выше блоке кода значение 232 на переменную T.
В блоке кодов интерфейса переменную Amount1 переименуйте в Размер инструмента. Переменную Amount2 переименуйте в Детализация, установите ее значение по умолчанию в 17, минимальное значение в 1, максимальное - в 25.

Теперь наш сценарий будет выглядеть так:

Код: Выделить всё

#region UICode
int Amount1=3; // [1,200] Размер инструмента
int Amount2=17; // [1,25] Детализация
#endregion

// Настройки использования операций с пикселями
private UnaryPixelOps.Desaturate desaturateOp = new UnaryPixelOps.Desaturate();
private UnaryPixelOps.Invert invertOp = new UnaryPixelOps.Invert();

// Это основной цикл функции обработки
void Render(Surface dst, Surface src, Rectangle rect)
{
    // Настройки вызова эффекта Эскиз
    OutlineEffect outlineEffect = new OutlineEffect();
    PropertyCollection outlineProps = outlineEffect.CreatePropertyCollection();
    PropertyBasedEffectConfigToken outlineParameters = new PropertyBasedEffectConfigToken(outlineProps);
    outlineParameters.SetPropertyValue(OutlineEffect.PropertyNames.Thickness, Amount1);
    outlineParameters.SetPropertyValue(OutlineEffect.PropertyNames.Intensity, 50);
    outlineEffect.SetRenderInfo(outlineParameters, new RenderArgs(dst), new RenderArgs(src));
    // Вызов функции Эскиз
    outlineEffect.Render(new Rectangle[1] { rect }, 0, 1);

    // Теперь в основном цикле обработки холст назначения (dst) имеет эскизную версию холста источника (src)
    for (int y = rect.Top; y < rect.Bottom; y++)
    {
        if (IsCancelRequested) return;
        for (int x = rect.Left; x < rect.Right; x++)
        {
            ColorBgra CurrentPixel = dst[x,y];

            // ВЫПОЛНЕНИЕ: Добавьте здесь дополнительный код обработки пикселей
            CurrentPixel = desaturateOp.Apply(CurrentPixel);

            int R = CurrentPixel.R;
            int G = CurrentPixel.G;
            int B = CurrentPixel.B;
            int T = Amount2 + 214;

           // Преобразование в контрастное черно-белое изображение
                if (R<T) {R=0;} 
                else R=255; 
                if (G<T) {G=0;} 
                else G=255; 
                if (B<T) {B=0;} 
                else B=255;  
            
		CurrentPixel.R = Int32Util.ClampToByte(R);
		CurrentPixel.G = Int32Util.ClampToByte(G);
		CurrentPixel.B = Int32Util.ClampToByte(B);

            CurrentPixel = invertOp.Apply(CurrentPixel);

            dst[x,y] = CurrentPixel;
        }
    }
}
Сохраните получившийся сценарий с именем Linocut_1. Создайте одноименный файл DLL. Проверьте как он работает, применив различные параметры элементов управления. Заметьте, эффективное значение элемента управления Размер инструмента лежит в диапазоне от 1 до 10. Запомним это.

Возможно вы захотите получить инверсную версию изображения, полученную в результате работы эффекта. Тогда давайте изменим наш интерфейс. Откройте Конструктор интерфеса (Файл -> Конструктор интерфеса). В поле Тип элемента выберите Check Box, в поле Имя элемента впишите Инвертировать, в поле По умолчанию впишите 0. Нажмите кнопку Добавить и кнопку ОК.

Измените запись в строке

Код: Выделить всё

            CurrentPixel = invertOp.Apply(CurrentPixel);
на

Код: Выделить всё

            if (!Amount3) {CurrentPixel = invertOp.Apply(CurrentPixel);}
Измените максимальное значение для переменной Amount1 на 10. Осталось добавить некоторую информацию:

Код: Выделить всё

// Author: ReMake
// Submenu: Artistic
// Name: Линогравюра
// Title: Линогравюра
// Desc: Paint.Net эффект, имитирующий технику линогравюры
// Keywords: paint.net|эффект|линогравюра
// URL: http://www.getpaint.net/redirect/plugins.html
и наш окончательный будет выглядеть так:

Код: Выделить всё

// Author: ReMake
// Submenu: Artistic
// Name: Линогравюра
// Title: Линогравюра
// Desc: Paint.Net эффект, имитирующий технику линогравюры
// Keywords: paint.net|эффект|линогравюра
// URL: http://www.getpaint.net/redirect/plugins.html

#region UICode
int Amount1 = 3; // [1,10] Размер инструмента
int Amount2 = 17; // [1,25] Детализация
bool Amount3 = false; // [0,1] Инвертировать
#endregion

// Настройки использования операций с пикселями
private UnaryPixelOps.Desaturate desaturateOp = new UnaryPixelOps.Desaturate();
private UnaryPixelOps.Invert invertOp = new UnaryPixelOps.Invert();

// Это основной цикл функции обработки
void Render(Surface dst, Surface src, Rectangle rect)
{
    // Настройки вызова эффекта Эскиз
    OutlineEffect outlineEffect = new OutlineEffect();
    PropertyCollection outlineProps = outlineEffect.CreatePropertyCollection();
    PropertyBasedEffectConfigToken outlineParameters = new PropertyBasedEffectConfigToken(outlineProps);
    outlineParameters.SetPropertyValue(OutlineEffect.PropertyNames.Thickness, Amount1);
    outlineParameters.SetPropertyValue(OutlineEffect.PropertyNames.Intensity, 50);
    outlineEffect.SetRenderInfo(outlineParameters, new RenderArgs(dst), new RenderArgs(src));
    // Вызов функции Эскиз
    outlineEffect.Render(new Rectangle[1] { rect }, 0, 1);

    // Теперь в основном цикле обработки холст назначения (dst) имеет эскизную версию холста источника (src)
    for (int y = rect.Top; y < rect.Bottom; y++)
    {
        if (IsCancelRequested) return;
        for (int x = rect.Left; x < rect.Right; x++)
        {
            ColorBgra CurrentPixel = dst[x,y];

            // ВЫПОЛНЕНИЕ: Добавьте здесь дополнительный код обработки пикселей
            CurrentPixel = desaturateOp.Apply(CurrentPixel);

            int R = CurrentPixel.R;
            int G = CurrentPixel.G;
            int B = CurrentPixel.B;
            int T = Amount2 + 214;

           // Преобразование в контрастное черно-белое изображение
                if (R<T) {R=0;} 
                else R=255; 
                if (G<T) {G=0;} 
                else G=255; 
                if (B<T) {B=0;} 
                else B=255;  
            
		CurrentPixel.R = Int32Util.ClampToByte(R);
		CurrentPixel.G = Int32Util.ClampToByte(G);
		CurrentPixel.B = Int32Util.ClampToByte(B);

		if (!Amount3) {CurrentPixel = invertOp.Apply(CurrentPixel);}

            dst[x,y] = CurrentPixel;
        }
    }
}
Сохраните сценарий с именем Linocut. Создайте для нашего эффекта подходящий значок в виде PNG файла размером 16X16 пикселей, например как этот: Изображение.

Теперь давайте сохраним наш эффект как DLL файл: Файл -> Сохранить как DLL... В представленном вам диалоге сборки DLL есть почти вся необходимая информация. Щелкните по ссылке Выбор значка и выберите ваш значок. Нажмите кнопку Создать - ваш новый эффект готов!

Так выглядит интерфейс пользователя нашего нового эффекта.
Изображение
А так выглядит результат работы эффекта с отмеченным флажком Инвертировать.
Изображение
Надеюсь создание этого эффекта затруднений у вас не вызвало.

Аватара пользователя
xmario
Администратор
Сообщения: 3402
Зарегистрирован: 03 апр 2010, 20:12
Репутация: 45
Пол: Мужской
Откуда: Москва

Re: CodeLab - первые шаги (Линогравюра)

Сообщение xmario » 01 июн 2015, 18:04

Хм, симпатично! Только есть такой эффект набросок тушью. :-D
И мой эксперимент на эту темы - эффект контуры. :oops:

ReMake
Сообщения: 344
Зарегистрирован: 10 сен 2014, 01:25
Репутация: 108
Пол: Мужской
Откуда: Брест, Беларусь

Re: CodeLab - первые шаги (Линогравюра)

Сообщение ReMake » 01 июн 2015, 20:19

Результаты схожи, но все же разные.

Ваш (настройки по умолчанию)
Изображение
Мой (настройки по умолчанию, инверсия включена)
Изображение

Я ставил перед собой цель - имитировать технику линогравюры. Идея пришла от Фотошоповского фильтра Линогравюра. Это всего лишь учебник и, как следствие его написания, соответствующий эффект.

Аватара пользователя
xmario
Администратор
Сообщения: 3402
Зарегистрирован: 03 апр 2010, 20:12
Репутация: 45
Пол: Мужской
Откуда: Москва

Re: CodeLab - первые шаги (Линогравюра)

Сообщение xmario » 02 июн 2015, 17:35

Да, у вас результат почище. :good: Хотя еще могу посоветовать эффект Stencil, у него результат еще лучше.

ReMake
Сообщения: 344
Зарегистрирован: 10 сен 2014, 01:25
Репутация: 108
Пол: Мужской
Откуда: Брест, Беларусь

Re: CodeLab - первые шаги (Линогравюра)

Сообщение ReMake » 02 июн 2015, 20:02

xmario писал(а):...Хотя еще могу посоветовать эффект Stencil, у него результат еще лучше.
Да, эффект Stencil интересен как средство создания маски, что очень удачно описала Lynx в своем примере создания силуэта.
Я просмотрел код этого эффекта. С точки зрения кодирования эффект интересен тем, что авторский алгоритм применения пороговых значений натолкнул меня на мысль о создании еще одного аналога Фотошоповского фильтра - Аппликация. Спасибо за информацию.

Ответить

Вернуться в «CodeLab от BoltBait»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 1 гость