استفاده از فضاهای رنگی مختلف برای مقایسه رنگ ها

در مقاله قبلی من یک تصویر پیکسلی گرفتم و هر یک از بلوک ها را با “نزدیک ترین” رنگ های موجود در فهرست رنگ هایم مطابقت دادم. اما همانطور که در تصاویر تمام شده دیدیم، تطابق رنگ ها کاملاً رضایت بخش نبود. اگر بخواهیم برای تطبیق رنگ بهتر تلاش کنیم، اولین چیزی که باید به آن توجه کنیم این است فضای رنگی که ما برای استفاده انتخاب می کنیم.
ما شروع به استفاده از یک مدل پایه RGB کردیم. این برای توسعه دهندگان وب شهودی است زیرا تقریباً همه رنگ هایی که با آنها سروکار داریم از یک مدل RGB پیروی می کنند. اما RGB تنها یکی از فضاهای رنگی مختلف است. و هر فضای رنگی متفاوت نتایج متفاوتی را ایجاد خواهد کرد.
برای مرجع، در اینجا تصویر پایه ما است که قبلاً پیکسل شده است، اما با رنگ های فیزیکی موجودی رنگ های من مطابقت ندارد:
و هنگامی که ما یک محاسبه اولیه RGB انجام دادیم، به این تبدیل رسیدیم:
آن نیست… ناگوار. ولی عالی هم نیست بنابراین بیایید به استفاده از برخی فضاهای رنگی بالقوه دیگر نگاه کنیم.
CMYK
CMYK فضای رنگی است که توسط چاپگرها استفاده می شود. از این منظر، ممکن است به نظر مناسبی برای نیازهای ما باشد، زیرا ما سعی می کنیم رنگ های دیجیتال را با آنهایی که در دنیای واقعی وجود دارند (مثلاً رنگ) مطابقت دهیم.
اول، ما باید خود را به روز کنیم getClosestColorInThePalette()
تابع. نسخه جدید به شکل زیر است:
const getClosestColorInThePalette = (referenceColor = rgbModel) => {
const key = `${referenceColor.red},${referenceColor.green},${referenceColor.blue}`;
if (closestColors[key])
return closestColors[key];
let closestColor = {
blue: -1,
green: -1,
name: '',
red: -1,
};
let shortestDistance = Number.MAX_SAFE_INTEGER;
const algorithm = local.getItem('algorithm');
palette.forEach(paletteColor => {
if (shortestDistance === 0)
return;
let distance;
switch (algorithm) {
case algorithms.CMYK:
const {cyan: paletteCyan, magenta: paletteMagenta, yellow: paletteYellow, key: paletteKey} = convertRgbToCmyk(paletteColor);
const {cyan: referenceCyan, magenta: referenceMagenta, yellow: referenceYellow, key: referenceKey} = convertRgbToCmyk(referenceColor);
distance = Math.sqrt(
Math.pow(referenceCyan - paletteCyan, 2)
+ Math.pow(referenceMagenta - paletteMagenta, 2)
+ Math.pow(referenceYellow - paletteYellow, 2)
+ Math.pow(referenceKey - paletteKey, 2)
);
break;
case algorithms.RGB:
default:
distance = Math.sqrt(
Math.pow(paletteColor.red - referenceColor.red, 2)
+ Math.pow(paletteColor.green - referenceColor.green, 2)
+ Math.pow(paletteColor.blue - referenceColor.blue, 2)
);
break;
}
if (distance < shortestDistance) {
shortestDistance = distance;
closestColor = paletteColor;
closestColors[key] = paletteColor;
}
});
return closestColor;
};
من دستورات مورد را اضافه کردم تا بتوانیم بسته به مدل رنگی که انتخاب کرده ایم از الگوریتم های مختلفی استفاده کنیم. تقریباً همه این محاسبات از یک محاسبه ریشه میانگین مربع (RMS) استفاده می کنند. RMS فرمولی است که برای یافتن فاصله بین دو نقطه مختلف در فضای سه بعدی استفاده می کنید. توجه داشته باشید که من الگوریتم RGB را نیز به استفاده از RMS تبدیل کردم. من متوجه شده ام که این تغییر تفاوت کمی در خروجی بصری محاسبه RGB ایجاد می کند، اما استفاده از RMS آن را با بقیه محاسبات فضای رنگ سازگارتر می کند.
همچنین توجه داشته باشید که ما همیشه از مقادیر RGB شروع می کنیم. این چیزی است که به تابع منتقل می شود. بنابراین اگر بخواهیم تفاوت ها را بر اساس فضای رنگی CMYK محاسبه کنیم، ابتدا باید مقدار RGB خود را به CMYK تبدیل کنیم. به همین دلیل است که ارزش ها ابتدا وارد می شوند convertRgbToCmyk()
قبل از اجرای الگوریتم
در اینجا چیزی است که convertRgbToCmyk()
تابع به نظر می رسد:
const convertRgbToCmyk = (rgbColor = rgbModel) => {
const {red, green, blue} = rgbColor;
let cyan = 255 - red;
let magenta = 255 - green;
let yellow = 255 - blue;
let key = Math.min(cyan, magenta, yellow);
const divider = key === 255 ? 1 : 255 - key;
cyan = ((cyan - key) / divider);
magenta = ((magenta - key) / divider);
yellow = ((yellow - key) / divider);
key = key / 255;
return {
cyan,
magenta,
yellow,
key,
};
};
و در اینجا این است که وقتی تطبیق رنگ خود را بر اساس CMYK انجام می دهیم، تصویر پیکسل شده چگونه به نظر می رسد:
خب…این با محاسبه RGB کمی متفاوت است. اما به سختی می توانم آن را “بهتر” بنامم. پس بیایید به جستجو در فضاهای رنگی مختلف ادامه دهیم.
HSL
اگر در ابزارهای گرافیکی مانند PaintShop کار کرده اید، احتمالاً با HSL آشنا هستید. این یک فضای رنگی مخروطی بر اساس رنگ، اشباع و روشنایی را نشان می دهد. این فضای رنگی نیز برای برخی از هنرمندان شهودی تر است.
بنابراین یک بار دیگر، ما خود را به روز می کنیم getClosestColorInThePalette()
تابع. نسخه جدید به شکل زیر است:
const getClosestColorInThePalette = (referenceColor = rgbModel) => {
const key = `${referenceColor.red},${referenceColor.green},${referenceColor.blue}`;
if (closestColors[key])
return closestColors[key];
let closestColor = {
blue: -1,
green: -1,
name: '',
red: -1,
};
let shortestDistance = Number.MAX_SAFE_INTEGER;
const algorithm = local.getItem('algorithm');
palette.forEach(paletteColor => {
if (shortestDistance === 0)
return;
let distance;
switch (algorithm) {
case algorithms.CMYK:
const {cyan: paletteCyan, magenta: paletteMagenta, yellow: paletteYellow, key: paletteKey} = convertRgbToCmyk(paletteColor);
const {cyan: referenceCyan, magenta: referenceMagenta, yellow: referenceYellow, key: referenceKey} = convertRgbToCmyk(referenceColor);
distance = Math.sqrt(
Math.pow(referenceCyan - paletteCyan, 2)
+ Math.pow(referenceMagenta - paletteMagenta, 2)
+ Math.pow(referenceYellow - paletteYellow, 2)
+ Math.pow(referenceKey - paletteKey, 2)
);
break;
case algorithms.HSL:
const {hue: paletteHue, saturation: paletteSaturation, lightness: paletteLightness} = convertRgbToHsl(paletteColor);
const {hue: referenceHue, saturation: referenceSaturation, lightness: referenceLightness} = convertRgbToHsl(referenceColor);
distance = Math.sqrt(
Math.pow(referenceHue - paletteHue, 2)
+ Math.pow(referenceSaturation - paletteSaturation, 2)
+ Math.pow(referenceLightness - paletteLightness, 2)
);
break;
case algorithms.RGB:
default:
distance = Math.sqrt(
Math.pow(paletteColor.red - referenceColor.red, 2)
+ Math.pow(paletteColor.green - referenceColor.green, 2)
+ Math.pow(paletteColor.blue - referenceColor.blue, 2)
);
break;
}
if (distance < shortestDistance) {
shortestDistance = distance;
closestColor = paletteColor;
closestColors[key] = paletteColor;
}
});
return closestColor;
};
محاسبه HSL اساساً با محاسبه RGB یکسان است. ما همچنان نتیجه RMS را از مقادیر موجود در رنگ پالت در مقابل رنگ مرجع می گیریم. اما به جای مقایسه قرمز، سبز و آبی بین هر دو رنگ، ما رنگ، اشباع و روشنایی را با هم مقایسه می کنیم.
همانطور که برای اجرای الگوریتم تطبیق CMYK باید مقادیر RGB را به CMYK تبدیل کنیم، برای اجرای الگوریتم تطبیق HSL جدید خود باید مقادیر RGB را به HSL تبدیل کنیم.
در اینجا چیزی است که convertRgbToHsl()
تابع به نظر می رسد:
const convertRgbToHsl = (rgbcolor = rgbModel) => {
let { red, green, blue } = rgbcolor;
red = red / 255;
green = green / 255;
blue = blue / 255;
const maximum = Math.max(red, green, blue);
const minimum = Math.min(red, green, blue);
const basis = (maximum + minimum) / 2;
let hue;
let saturation;
let lightness = basis;
if (maximum === minimum) {
hue = 0;
saturation = 0;
} else {
const difference = maximum - minimum;
saturation = lightness > 0.5 ? difference / (2 - maximum - minimum) : difference / (maximum + minimum);
switch (maximum) {
case red:
hue = (green - blue) / difference + (green < blue ? 6 : 0);
break;
case green:
hue = (blue - red) / difference + 2;
break;
case blue:
default:
hue = (red - green) / difference + 4;
break;
}
hue = hue / 6;
}
return {
hue,
saturation,
lightness,
};
}
و در اینجا این است که وقتی تطبیق رنگ خود را بر اساس HSL انجام می دهیم، تصویر پیکسل شده چگونه به نظر می رسد:
راستش را بخواهید، من این تبدیل را به نتایج RGB یا CMYK ترجیح می دهم. اما او هنوز هم به نظر می رسد که ماسک زده است. در این مرحله، زمان آن فراتر از این مدلهای رنگی «پایه» است.
XYZ
فضای رنگی XYZ (به طور رسمی به عنوان فضای رنگی CIE 1931 شناخته می شود) بسیار جذاب است. همانطور که از نام آن پیداست، در سال 1931 توسعه یافت. این اولین تلاش برای تولید یک فضای رنگی بر اساس اندازه گیری بود. درک رنگ انسان و اساس تقریباً تمام فضاهای رنگی دیگر است.
این چیزی است که ما واقعاً در اینجا به دنبال آن هستیم. ما می خواهیم دو رنگ RGB را بگیریم و تعیین کنیم که چقدر “نزدیک” هستند – بر اساس ادراک انسان.
دوباره، ما خود را به روز می کنیم getClosestColorInThePalette()
تابع. نسخه جدید به شکل زیر است:
const getClosestColorInThePalette = (referenceColor = rgbModel) => {
const key = `${referenceColor.red},${referenceColor.green},${referenceColor.blue}`;
if (closestColors[key])
return closestColors[key];
let closestColor = {
blue: -1,
green: -1,
name: '',
red: -1,
};
let shortestDistance = Number.MAX_SAFE_INTEGER;
const algorithm = local.getItem('algorithm');
palette.forEach(paletteColor => {
if (shortestDistance === 0)
return;
let distance;
switch (algorithm) {
case algorithms.CMYK:
const {cyan: paletteCyan, magenta: paletteMagenta, yellow: paletteYellow, key: paletteKey} = convertRgbToCmyk(paletteColor);
const {cyan: referenceCyan, magenta: referenceMagenta, yellow: referenceYellow, key: referenceKey} = convertRgbToCmyk(referenceColor);
distance = Math.sqrt(
Math.pow(referenceCyan - paletteCyan, 2)
+ Math.pow(referenceMagenta - paletteMagenta, 2)
+ Math.pow(referenceYellow - paletteYellow, 2)
+ Math.pow(referenceKey - paletteKey, 2)
);
break;
case algorithms.HSL:
const {hue: paletteHue, saturation: paletteSaturation, lightness: paletteLightness} = convertRgbToHsl(paletteColor);
const {hue: referenceHue, saturation: referenceSaturation, lightness: referenceLightness} = convertRgbToHsl(referenceColor);
distance = Math.sqrt(
Math.pow(referenceHue - paletteHue, 2)
+ Math.pow(referenceSaturation - paletteSaturation, 2)
+ Math.pow(referenceLightness - paletteLightness, 2)
);
break;
case algorithms.XYZ:
const {x: paletteX, y: paletteY, z: paletteZ} = convertRgbToXyz(paletteColor);
const {x: referenceX, y: referenceY, z: referenceZ} = convertRgbToXyz(referenceColor);
distance = Math.sqrt(
Math.pow(referenceX - paletteX, 2)
+ Math.pow(referenceY - paletteY, 2)
+ Math.pow(referenceZ - paletteZ, 2)
);
break;
case algorithms.RGB:
default:
distance = Math.sqrt(
Math.pow(paletteColor.red - referenceColor.red, 2)
+ Math.pow(paletteColor.green - referenceColor.green, 2)
+ Math.pow(paletteColor.blue - referenceColor.blue, 2)
);
break;
}
if (distance < shortestDistance) {
shortestDistance = distance;
closestColor = paletteColor;
closestColors[key] = paletteColor;
}
});
return closestColor;
};
درست مانند قبل، ما از یک محاسبه RMS برای تعیین فاصله بین رنگ مرجع و رنگ پالت استفاده می کنیم. اما این بار ما مقادیر فضای رنگ XYZ را با هم مقایسه می کنیم.
البته این بدان معناست که باید مقادیر RGB را به XYZ تبدیل کنیم. در اینجا چیزی است که convertRgbToXyz()
تابع به نظر می رسد:
const convertRgbToXyz = (rgbColor = rgbModel) => {
const convert = color => {
color = color / 255;
color = color > 0.04045 ? Math.pow(((color + 0.055) / 1.055), 2.4) : color / 12.92;
color = color * 100;
return color;
}
let {red, green, blue} = rgbColor;
red = convert(red);
green = convert(green);
blue = convert(blue);
const x = (red * 0.4124564) + (green * 0.3575761) + (blue * 0.1804375);
const y = (red * 0.2126729) + (green * 0.7151522) + (blue * 0.0721750);
const z = (red * 0.0193339) + (green * 0.1191920) + (blue * 0.9503041);
return {
x,
y,
z,
};
};
نه، من مطمئناً به تنهایی به این معادله نرسیدم. اما به این صورت است که یک مقدار RGB را به XYZ تبدیل می کنید.
و زمانی که تطبیق رنگ خود را بر اساس XYZ انجام میدهیم، تصویر پیکسلشده چگونه به نظر میرسد:
وای. حداقل به نظر من، این دگرگونی خاص است زیاد بهتر. هنوز مقداری حیرت وجود دارد. گروهبندیهای عجیب صورتی بالای چشمانش وجود دارد. اما به نظر می رسد بسیار نزدیکتر از هر چیزی است که با مقایسه RGB، CMYK یا HSL انجام دادیم.
Delta-E 2000
آخرین مدلی که می خواهیم با آن آزمایش کنیم Delta-E 2000 نام دارد. Delta-E 2000 یک فضای رنگی نیست. در عوض، این جدیدترین در یک خط طولانی از فرمول هایی است که برای تطبیق رنگ بر اساس فضای رنگی CIELAB یا L*a*b* ایجاد شده است.
در اینجا یک عکس فوری از محاسباتی است که در آن فرمول انجام می شود:
Dayyumm… خوب، بیایید به اجرای این کار بپردازیم. اول، ما خود را به روز می کنیم getClosestColorInThePalette()
عملکرد دوباره:
const getClosestColorInThePalette = (referenceColor = rgbModel) => {
const key = `${referenceColor.red},${referenceColor.green},${referenceColor.blue}`;
if (closestColors[key])
return closestColors[key];
let closestColor = {
blue: -1,
green: -1,
name: '',
red: -1,
};
let shortestDistance = Number.MAX_SAFE_INTEGER;
const algorithm = local.getItem('algorithm');
palette.forEach(paletteColor => {
if (shortestDistance === 0)
return;
let distance;
switch (algorithm) {
case algorithms.CMYK:
const {cyan: paletteCyan, magenta: paletteMagenta, yellow: paletteYellow, key: paletteKey} = convertRgbToCmyk(paletteColor);
const {cyan: referenceCyan, magenta: referenceMagenta, yellow: referenceYellow, key: referenceKey} = convertRgbToCmyk(referenceColor);
distance = Math.sqrt(
Math.pow(referenceCyan - paletteCyan, 2)
+ Math.pow(referenceMagenta - paletteMagenta, 2)
+ Math.pow(referenceYellow - paletteYellow, 2)
+ Math.pow(referenceKey - paletteKey, 2)
);
break;
case algorithms.HSL:
const {hue: paletteHue, saturation: paletteSaturation, lightness: paletteLightness} = convertRgbToHsl(paletteColor);
const {hue: referenceHue, saturation: referenceSaturation, lightness: referenceLightness} = convertRgbToHsl(referenceColor);
distance = Math.sqrt(
Math.pow(referenceHue - paletteHue, 2)
+ Math.pow(referenceSaturation - paletteSaturation, 2)
+ Math.pow(referenceLightness - paletteLightness, 2)
);
break;
case algorithms.XYZ:
const {x: paletteX, y: paletteY, z: paletteZ} = convertRgbToXyz(paletteColor);
const {x: referenceX, y: referenceY, z: referenceZ} = convertRgbToXyz(referenceColor);
distance = Math.sqrt(
Math.pow(referenceX - paletteX, 2)
+ Math.pow(referenceY - paletteY, 2)
+ Math.pow(referenceZ - paletteZ, 2)
);
break;
case algorithms.DELTA_E:
const paletteLabColor = convertRgbToLab(paletteColor);
const referenceLabColor = convertRgbToLab(referenceColor);
distance = calculateDeltaE2000(paletteLabColor, referenceLabColor);
break;
case algorithms.RGB:
default:
distance = Math.sqrt(
Math.pow(paletteColor.red - referenceColor.red, 2)
+ Math.pow(paletteColor.green - referenceColor.green, 2)
+ Math.pow(paletteColor.blue - referenceColor.blue, 2)
);
break;
}
if (distance < shortestDistance) {
shortestDistance = distance;
closestColor = paletteColor;
closestColors[key] = paletteColor;
}
});
return closestColor;
};
در این مورد، ما محاسبه را مستقیماً در این تابع انجام نمی دهیم زیرا از یک الگوریتم ساده RMS استفاده نمی کنیم. در عوض، ما ارزش ها را به جدید خود منتقل می کنیم calculateDeltaE2000()
تابع.
اما ابتدا باید مقادیر L*a*b* را از اشیاء RGB خود دریافت کنیم. در اینجا چیزی است که convertRgbToLab()
تابع به نظر می رسد:
const convertRgbToLab = (rgbColor = rgbModel) => {
const xyzColor = convertRgbToXyz(rgbColor);
return convertXyzToLab(xyzColor);
};
این واضح است که بسیار ساده است، زیرا تبدیل L*a*b* رنگ XYZ را انتظار دارد. البته قبلاً الف نوشتیم convertRgbToXyz()
تابع. زمانی که مقدار XYZ را بدست آوردیم، تماس می گیریم convertXyzToLab()
.
در اینجا چیزی است که convertXyzToLab()
تابع به نظر می رسد:
const convertXyzToLab = (xyzColor = xyzModel) => {
const adjust = value => value > 0.008856 ? Math.pow(value, (1 / 3)) : (7.787 * value) + (16 / 116);
let {x, y, z} = xyzColor;
x = x / 94.811;
y = y / 100;
z = z / 107.304;
x = adjust(x);
y = adjust(y);
z = adjust(z);
const lightness = (116 * y) - 16;
const redGreen = 500 * (x - y);
const blueYellow = 200 * (y - z);
return {
lightness,
redGreen,
blueYellow,
};
};
هنگامی که مقادیر L*a*b* را داشتیم، میتوانیم آنها را به خود متصل کنیم calculateDeltaE2000()
تابع به نظر می رسد:
const calculateDeltaE2000 = (labColor1 = labModel, labColor2 = labModel) => {
const {lightness: lightness1, redGreen: redGreen1, blueYellow: blueYellow1} = labColor1;
const {lightness: lightness2, redGreen: redGreen2, blueYellow: blueYellow2} = labColor2;
Math.rad2deg = function (rad) {
return 360 * rad / (2 * Math.PI);
};
Math.deg2rad = function (deg) {
return (2 * Math.PI * deg) / 360;
};
const avgL = (lightness1 + lightness2) / 2;
const c1 = Math.sqrt(Math.pow(redGreen1, 2) + Math.pow(blueYellow1, 2));
const c2 = Math.sqrt(Math.pow(redGreen2, 2) + Math.pow(blueYellow2, 2));
const avgC = (c1 + c2) / 2;
const g = (1 - Math.sqrt(Math.pow(avgC, 7) / (Math.pow(avgC, 7) + Math.pow(25, 7)))) / 2;
const a1p = redGreen1 * (1 + g);
const a2p = redGreen2 * (1 + g);
const c1p = Math.sqrt(Math.pow(a1p, 2) + Math.pow(blueYellow1, 2));
const c2p = Math.sqrt(Math.pow(a2p, 2) + Math.pow(blueYellow2, 2));
const avgCp = (c1p + c2p) / 2;
let h1p = Math.rad2deg(Math.atan2(blueYellow1, a1p));
if (h1p < 0)
h1p = h1p + 360;
let h2p = Math.rad2deg(Math.atan2(blueYellow2, a2p));
if (h2p < 0)
h2p = h2p + 360;
const avghp = Math.abs(h1p - h2p) > 180 ? (h1p + h2p + 360) / 2 : (h1p + h2p) / 2;
const t = 1 -
0.17 * Math.cos(Math.deg2rad(avghp - 30))
+ 0.24 * Math.cos(Math.deg2rad(2 * avghp))
+ 0.32 * Math.cos(Math.deg2rad(3 * avghp + 6))
- 0.2 * Math.cos(Math.deg2rad(4 * avghp - 63));
let deltahp = h2p - h1p;
if (Math.abs(deltahp) > 180) {
if (h2p <= h1p) {
deltahp += 360;
} else {
deltahp -= 360;
}
}
const deltalp = lightness2 - lightness1;
const deltacp = c2p - c1p;
deltahp = 2 * Math.sqrt(c1p * c2p) * Math.sin(Math.deg2rad(deltahp) / 2);
const sl = 1 + ((0.015 * Math.pow(avgL - 50, 2)) / Math.sqrt(20 + Math.pow(avgL - 50, 2)));
const sc = 1 + 0.045 * avgCp;
const sh = 1 + 0.015 * avgCp * t;
const deltaro = 30 * Math.exp(-(Math.pow((avghp - 275) / 25, 2)));
const rc = 2 * Math.sqrt(Math.pow(avgCp, 7) / (Math.pow(avgCp, 7) + Math.pow(25, 7)));
const rt = -rc * Math.sin(2 * Math.deg2rad(deltaro));
const kl = 1;
const kc = 1;
const kh = 1;
return Math.sqrt(Math.pow(deltalp / (kl * sl), 2)
+ Math.pow(deltacp / (kc * sc), 2)
+ Math.pow(deltahp / (kh * sh), 2)
+ rt * (deltacp / (kc * sc)) * (deltahp / (kh * sh)));
};
احتمالاً نمی خواهید زمان زیادی را صرف تماشای آن عملکرد کنید. بهت سر درد میده در حال حاضر، فقط میتوانیم راضی باشیم که بدانیم منطق را در اینجا در جاوا اسکریپت داریم.
و اکنون که میتوانیم مقادیر Delta-E 2000 را محاسبه کنیم، وقتی تطبیق رنگ خود را بر اساس آن الگوریتم انجام میدهیم، تصویر پیکسلشده چگونه به نظر میرسد:
صادقانه بگویم، من این یکی را تقریباً به اندازه محصولی که از محاسبه XYZ دریافت کردیم، دوست ندارم. اما همچنان به عنوان یک نقطه مرجع دیگر مفید است.
کدام الگوریتم “برنده” شد؟
بر اساس نتایج آزمایش از این یکی ممکن است وسوسه انگیز باشد که بگوییم الگوریتم XYZ “بهترین” است. اما این ارزیابی بیش از حد ساده خواهد بود.
ببینید، من بعد از بازی با صدها تصویر یاد گرفتم که هر الگوریتم (حتی مقایسه ساده RGB) نقاط قوت و ضعف خود را دارد. برای این تصویر خاص، ممکن است درست باشد که XYZ “برنده” است. اما وقتی تصاویر دیگر را بارگذاری میکنید، ممکن است متوجه شوید که از یکی از الگوریتمهای دیگر نتیجه رضایتبخشتری دریافت میکنید.
به همین دلیل، من به سادگی روی یک “برنده” و سپس هاردکد آن در Paint Map Studio اکتفا نکردم. در عوض، من یک فرم تعاملی ساختم که به شما امکان میدهد تنظیمات مختلف (از جمله الگوریتمهای مختلف) را آزمایش کنید تا بهترین تطابق ممکن را پیدا کنید.
صادقانه بگوییم، گاهی اوقات دیدن عملکرد یک الگوریتم خاص بر روی یک تصویر – و سپس عملکرد ضعیف آن در تصویر بعدی، ممکن است تعجب آور باشد. بنابراین بسیار ارزشمند است که بتوانیم بین آنها ورق بزنیم و نتایج را با هم مقایسه کنیم.
در قسط بعدی…
ما تمام الگوریتمهایی را که برای یافتن «بهترین» مورد نیاز داریم، پیادهسازی کردهایم. پس… همینه؟؟ به ندرت!
حتی زمانی که به تصویر تولید شده توسط XYZ در بالا نگاه می کنیم، ممکن است نسبت به الگوریتم های دیگر به تصویر اصلی نزدیک تر باشد، اما همچنان احساس می کند… خاموش است. صورتی وجود دارد که واقعاً نباید باشد. رنگ سبز تیره ای وجود دارد که خط موی او را هاله می کند. به طور خلاصه، ما هنوز می توانیم انجام دهیم بهتر.
اما اگر نخواهیم از طریق یک الگوریتم بعد از الگوریتم بعدی حرکت کنیم، چگونه تطابق رنگ را بهبود بخشیم؟
پاسخ از پالت رنگ های ما می آید. با وجود اینکه من بیش از 200 رنگ منحصر به فرد دارم که هر کدام رنگ متمایز خود را دارند، اما این رنگ ها هنوز برای به تصویر کشیدن وفادارانه تصویری مانند چهره این زن کافی نیستند. ما به رنگ های بیشتری نیاز داریم.
در قسمت بعدی نحوه ترکیب رنگ ها را نشان خواهم داد به صورت مجازی بنابراین می توانید بهترین پالت را برای تصویر خود تعیین کنید.