[AI CC-CC2021] RECOLOR ENGINE v2 by S.H.

Станислав Хоффман

Участник
Топикстартер
Сообщения
277
Реакции
24
Всем привет.
Выкладываю свой скрипт "RECOLOR ENGINE v2", написанный год назад.

Автоматическое перекрашивание CMYK -> CMY в AI.

Сразу оговорюсь - работает только с заливками (FillColor), т.е. не работает с обводками - надо дописывать. Я разбивал все обводки и запускал скрипт.

В архиве 5 версий скрипта - отобраны самые рабочие, каждый даёт результат немного отличный от других. В архиве также лежит файл AI с тестами каждого скрипта.

ссылка: DropMeFiles – бесплатный файлообменник без регистрации
 
Потестировал на конкретных примерах, качество полученного преобразования не ахти (((
Действительно, если мало объектов то уж лучше всё ручками...
Примеры можно посмореть?
 
Квантовые эффекты однако. А если серьезно?
Честно говоря, понятия не имею, почему скрипт не может подбирать все цвета одинаково хорошо - он очень избирателен. Я потратил тогда много времени, чтобы во всём разобраться - пробовал разные цветовые модели(RGB, LAB, HSB), вводил корректирующие коэффициенты, ещё что-то. Подбор цвета идёт постепенно с каким-то шагом: +-0,5% или +-1% - в итоге вы получите разные цвета. Протестировав скрипт на одних цветах, я натыкался на проблемы при тестах с другими. Например, до сих пор осталась проблема с тёмно-синими - тёмно-фиолетовыми оттенками.
Можно ли довести скрипты до идеала? Приблизить можно, довести - нет. Меня результат вполне устроил, он вполне сопоставим с конвертацией в профиль в фотошоп.
 
Последнее редактирование:
Гм, глянул код, наверное нужно dE прикрутить и итерациями подбираться к результату, а не перебором в цикле.
К примеру прикинуть шесть вариантов +/-2% по CMY, высчитать лучшее dE для Lab и двинуться в эту сторону. Если dE маленькое, то приближаться по 1%. Остановиться если dE на следующем шаге нельзя сделать лучше.
 
Посмотри как работает код по мотивам первого варианта... с ошибками не боролся, интересно качество подбора.
Код:
var doc = app.activeDocument; 
var mSel = doc.selection;
var LL = new Array(6);
var AA = new Array(6);
var BB = new Array(6);
var DD = new Array(6);

function convertColor(src, dest, clrArr) 
{ 
    return app.convertSampleColor(ImageColorSpace[src], clrArr, ImageColorSpace[dest], ColorConvertPurpose.defaultpurpose); 
} 

function AddV(n,a){
    r=Math.round(n+a);
    if (r>100) {r=100}
    if (r<0) {r=0}
    return r;
}

function setval(lab,i,labs){
    LL[i]=lab[0];
    AA[i]=lab[1];
    BB[i]=lab[2];
    DD[i]=Math.sqrt(
    Math.pow(labs[0]-LL[i],2)+
    Math.pow(labs[1]-AA[i],2)+
    Math.pow(labs[2]-BB[i],2));
    return;
};

for (i=0; i < mSel.length; i++)
{

    if (mSel[i].filled == true)
    {

    var color = mSel[i].fillColor;

    var labs = convertColor("CMYK", "LAB", [
                    Math.round(color.cyan),
                    Math.round(color.magenta),
                    Math.round(color.yellow),
                    Math.round(color.black)]); 

    color.black = 0;

                    
                var goo = true;
                var maxDD=10000000000;
                while (goo){
                    goo=false;
                    var lab = convertColor("CMYK", "LAB", [AddV(color.cyan,1), AddV(color.magenta,0), AddV(color.yellow,0), 0]); 
                    setval(lab,0,labs);
                    if (maxDD>DD[0]){maxDD=DD[0]; goo=true; color.cyan=color.cyan+1}
                    var lab = convertColor("CMYK", "LAB", [AddV(color.cyan,-1), AddV(color.magenta,0), AddV(color.yellow,0), 0]); 
                    setval(lab,1,labs);
                    if (maxDD>DD[1]){maxDD=DD[1]; goo=true; color.cyan=color.cyan-1}
                    var lab = convertColor("CMYK", "LAB", [AddV(color.cyan,0), AddV(color.magenta,1), AddV(color.yellow,0), 0]); 
                    setval(lab,2,labs);
                    if (maxDD>DD[2]){maxDD=DD[2]; goo=true; color.magenta=color.magenta+1}
                    var lab = convertColor("CMYK", "LAB", [AddV(color.cyan,0), AddV(color.magenta,-1), AddV(color.yellow,0), 0]); 
                    setval(lab,3,labs);
                    if (maxDD>DD[3]){maxDD=DD[3]; goo=true; color.magenta=color.magenta-1}
                    var lab = convertColor("CMYK", "LAB", [AddV(color.cyan,0), AddV(color.magenta,0), AddV(color.yellow,1), 0]); 
                    setval(lab,4,labs);
                    if (maxDD>DD[4]){maxDD=DD[4]; goo=true; color.yellow=color.yellow+1}
                    var lab = convertColor("CMYK", "LAB", [AddV(color.cyan,0), AddV(color.magenta,0), AddV(color.yellow,-1), 0]); 
                    setval(lab,5,labs);
                    if (maxDD>DD[5]){maxDD=DD[5]; goo=true; color.yellow=color.yellow-1}
                    
                }
}}
 
Но ведь есть же еще, как это грустно звучит, полно вычметодов покоординатного спуска и т.д. Второй курс ВУЗа
 
Гм, глянул код, наверное нужно dE прикрутить и итерациями подбираться к результату, а не перебором в цикле.
К примеру прикинуть шесть вариантов +/-2% по CMY, высчитать лучшее dE для Lab и двинуться в эту сторону. Если dE маленькое, то приближаться по 1%. Остановиться если dE на следующем шаге нельзя сделать лучше.
Была, конечно, мысль прикрутить dE, но когда я посмотрел формулу её вычисления, понял, что это будет долго и сложно.
Я пошёл простым путём. Идея с нарастанием шага точности перебора тоже была - это грамотный подход. На тестах я этим пренебрёг для экономии кода - на стадии отладки чем меньше код, тем лучше. Это уже вопрос оптимизации скорости скрипта, но не точности.
 
Посмотри как работает код по мотивам первого варианта... с ошибками не боролся, интересно качество подбора.
Код:
var doc = app.activeDocument;
var mSel = doc.selection;
var LL = new Array(6);
var AA = new Array(6);
var BB = new Array(6);
var DD = new Array(6);

function convertColor(src, dest, clrArr)
{
    return app.convertSampleColor(ImageColorSpace[src], clrArr, ImageColorSpace[dest], ColorConvertPurpose.defaultpurpose);
}

function AddV(n,a){
    r=Math.round(n+a);
    if (r>100) {r=100}
    if (r<0) {r=0}
    return r;
}

function setval(lab,i,labs){
    LL[i]=lab[0];
    AA[i]=lab[1];
    BB[i]=lab[2];
    DD[i]=Math.sqrt(
    Math.pow(labs[0]-LL[i],2)+
    Math.pow(labs[1]-AA[i],2)+
    Math.pow(labs[2]-BB[i],2));
    return;
};

for (i=0; i < mSel.length; i++)
{

    if (mSel[i].filled == true)
    {

    var color = mSel[i].fillColor;

    var labs = convertColor("CMYK", "LAB", [
                    Math.round(color.cyan),
                    Math.round(color.magenta),
                    Math.round(color.yellow),
                    Math.round(color.black)]);

    color.black = 0;

                   
                var goo = true;
                var maxDD=10000000000;
                while (goo){
                    goo=false;
                    var lab = convertColor("CMYK", "LAB", [AddV(color.cyan,1), AddV(color.magenta,0), AddV(color.yellow,0), 0]);
                    setval(lab,0,labs);
                    if (maxDD>DD[0]){maxDD=DD[0]; goo=true; color.cyan=color.cyan+1}
                    var lab = convertColor("CMYK", "LAB", [AddV(color.cyan,-1), AddV(color.magenta,0), AddV(color.yellow,0), 0]);
                    setval(lab,1,labs);
                    if (maxDD>DD[1]){maxDD=DD[1]; goo=true; color.cyan=color.cyan-1}
                    var lab = convertColor("CMYK", "LAB", [AddV(color.cyan,0), AddV(color.magenta,1), AddV(color.yellow,0), 0]);
                    setval(lab,2,labs);
                    if (maxDD>DD[2]){maxDD=DD[2]; goo=true; color.magenta=color.magenta+1}
                    var lab = convertColor("CMYK", "LAB", [AddV(color.cyan,0), AddV(color.magenta,-1), AddV(color.yellow,0), 0]);
                    setval(lab,3,labs);
                    if (maxDD>DD[3]){maxDD=DD[3]; goo=true; color.magenta=color.magenta-1}
                    var lab = convertColor("CMYK", "LAB", [AddV(color.cyan,0), AddV(color.magenta,0), AddV(color.yellow,1), 0]);
                    setval(lab,4,labs);
                    if (maxDD>DD[4]){maxDD=DD[4]; goo=true; color.yellow=color.yellow+1}
                    var lab = convertColor("CMYK", "LAB", [AddV(color.cyan,0), AddV(color.magenta,0), AddV(color.yellow,-1), 0]);
                    setval(lab,5,labs);
                    if (maxDD>DD[5]){maxDD=DD[5]; goo=true; color.yellow=color.yellow-1}
                   
                }
}}
Напиши, пжлста, комментарии к коду. Я с функциями не особо дружу, программирование - хобби, начинаю разбираться в нём под конкретную задачу. В целом, красиво) Протестировать смогу в понедельник.
 
Я тоже
 
А какие там комментарии нужны?
самая идея простая,
Находится Lab для исходного цвета и хранится в labs
Затем убирается черный в ноль и в цикле делаются попытки добавлять/отнимать по единичке к CMY.
AddV - добавляет по единичке к CMY и проверяет выход за диапазон 0..100.
setval находит dE между исходным labs и получившимся. (DD - вычисляется по cie76 году, там формула простая, корень из сумм квадратов разности).
Если delta E получилось улучшить, то сохраняем значение CMY в качестве текущего и текущую delta E в качестве максимальной.
if (maxDD>DD[4]){maxDD=DD[4]; goo=true; color.yellow=color.yellow+1}
Цикл делается до тех пор пока есть улучшения.
К сожалению протестировать не удалось, под рукой только CS5.5, а файл с примерами не pdf-compatable.
 
Это както чересчур примитивно. А как же частные производные, вектор градиента? '))'
 
@_MBK_, всё ты хочешь свести к задаче линейных уравнений)
нормальная реализация у @splxgf,
не чета хоффманской.


между прочим, в линейном программировании на целочисленных множествах -
почти так и работает алгоритм. перебором соседних точек.
 
Последнее редактирование:
При чем тут линейные уравнения? Задача вовсе нелинейная, но таки классическая поиска многомерного экстремума, такие вовсю решали еще во времена когда компьютеры были большими и полумеханическими.
 
@_MBK_, на целочисленных множествах алгоритма лучше перебора соседних точек - до сих пор не придумано)
никакие векторы там не работают
 
поиска многомерного экстремума
В рамках моего понимания там только один экстремум, если бы был полноценный CMYK, тогда задача бы решалась другим способом.