سؤال

تحفيز

أرغب في العثور على طريقة لأخذ لون عشوائي وتفتيحه ببعض الظلال، حتى أتمكن برمجيًا من إنشاء تدرج لطيف من لون واحد إلى إصدار أفتح.سيتم استخدام التدرج كخلفية في واجهة المستخدم.

الاحتمال 1

من الواضح أنه يمكنني فقط تقسيم قيم RGB وزيادتها بشكل فردي بمقدار معين.هل هذا فعلا ما أريد؟

الاحتمال 2

فكرتي الثانية كانت تحويل RGB إلى HSV/HSB/HSL (تدرج اللون والتشبع والقيمة/السطوع/الإضاءة)، وزيادة السطوع قليلاً، وتقليل التشبع قليلاً، ثم تحويله مرة أخرى إلى RGB.هل سيكون لهذا التأثير المطلوب بشكل عام؟

هل كانت مفيدة؟

المحلول

سأختار الخيار الثاني.بشكل عام، مساحة RGB ليست جيدة حقًا لمعالجة الألوان (إنشاء انتقال من لون إلى آخر، تفتيح/تغميق اللون، وما إلى ذلك).فيما يلي موقعان وجدتهما من خلال بحث سريع للتحويل من/إلى RGB إلى/من HSL:

نصائح أخرى

مثل قال إسفين, ، تريد المضاعفة لجعل الأشياء أكثر سطوعًا، لكن هذا لا يعمل إلا حتى يصبح أحد الألوان مشبعًا (أي.يضرب 255 أو أكبر).عند هذه النقطة، يمكنك فقط تثبيت القيم على 255، لكنك ستغير درجة اللون بمهارة عندما تصبح أفتح.للحفاظ على تدرج اللون، تحتاج إلى الحفاظ على نسبة (الأوسط-الأدنى)/(الأعلى-الأدنى).

فيما يلي وظيفتان في بايثون.الأول يطبق النهج الساذج الذي يربط قيم RGB بـ 255 في حالة تجاوزها.يقوم الثاني بإعادة توزيع القيم الزائدة للحفاظ على اللون سليمًا.

def clamp_rgb(r, g, b):
    return min(255, int(r)), min(255, int(g)), min(255, int(b))

def redistribute_rgb(r, g, b):
    threshold = 255.999
    m = max(r, g, b)
    if m <= threshold:
        return int(r), int(g), int(b)
    total = r + g + b
    if total >= 3 * threshold:
        return int(threshold), int(threshold), int(threshold)
    x = (3 * threshold - total) / (3 * m - total)
    gray = threshold - x * m
    return int(gray + x * r), int(gray + x * g), int(gray + x * b)

لقد قمت بإنشاء تدرج بدءًا من قيمة RGB (224,128,0) وضربها في 1.0، 1.1، 1.2، وما إلى ذلك.ما يصل إلى 2.0.النصف العلوي هو النتيجة باستخدام clamp_rgb والنصف السفلي هو النتيجة مع redistribute_rgb.أعتقد أنه من السهل أن نرى أن إعادة توزيع التدفقات الفائضة تعطي نتيجة أفضل بكثير، دون الحاجة إلى ترك مساحة ألوان RGB.

Lightness gradient with clamping (top) and redistribution (bottom)

للمقارنة، إليك نفس التدرج في مساحات الألوان HLS وHSV، كما تم تنفيذه بواسطة Python colorsys وحدة.فقط L تم تعديل المكون، وتم إجراء التثبيت على قيم RGB الناتجة.النتائج متشابهة، ولكنها تتطلب تحويلات مساحة اللون لكل بكسل.

Lightness gradient with HLS (top) and HSV (bottom)

شركة#:

public static Color Lighten(Color inColor, double inAmount)
{
  return Color.FromArgb(
    inColor.A,
    (int) Math.Min(255, inColor.R + 255 * inAmount),
    (int) Math.Min(255, inColor.G + 255 * inAmount),
    (int) Math.Min(255, inColor.B + 255 * inAmount) );
}

لقد استخدمت هذا في كل مكان.

تحتوي فئة ControlPaint في مساحة الاسم System.Windows.Forms على أساليب ثابتة Light وDark:

public static Color Dark(Color baseColor, float percOfDarkDark);

تستخدم هذه الطرق تطبيقًا خاصًا لـ HLSColor.أتمنى أن يكون هذا الهيكل عامًا وفي System.Drawing.

وبدلاً من ذلك، يمكنك استخدام بنية GetHue وGetSaturation وGetBrightness on Color للحصول على مكونات HSB.للأسف لم أجد التحويل العكسي.

قم بتحويله إلى RGB وقم بالتحريف الخطي بين اللون الأصلي واللون المستهدف (غالبًا ما يكون أبيض).لذا، إذا كنت تريد 16 لونًا بين لونين، عليك القيام بما يلي:


for(i = 0; i < 16; i++)
{
  colors[i].R = start.R + (i * (end.R - start.R)) / 15;
  colors[i].G = start.G + (i * (end.G - start.G)) / 15;
  colors[i].B = start.B + (i * (end.B - start.B)) / 15;
}

للحصول على نسخة أفتح أو أغمق من لون معين، يجب عليك تعديل سطوعه.يمكنك القيام بذلك بسهولة حتى بدون تحويل اللون إلى لون HSL أو HSB.على سبيل المثال لجعل اللون أفتح يمكنك استخدام الكود التالي:

float correctionFactor = 0.5f;
float red = (255 - color.R) * correctionFactor + color.R;
float green = (255 - color.G) * correctionFactor + color.G;
float blue = (255 - color.B) * correctionFactor + color.B;
Color lighterColor = Color.FromArgb(color.A, (int)red, (int)green, (int)blue);

إذا كنت بحاجة إلى مزيد من التفاصيل، إقرأ القصة الكاملة على مدونتي.

تم طرح سؤال مشابه جدًا، مع إجابات مفيدة، سابقًا:كيف يمكنني تحديد متغير لون أغمق أو أفتح من لون معين؟

اجابة قصيرة:اضرب قيم RGB بثابت إذا كنت تحتاج فقط إلى "جيد بما فيه الكفاية"، وترجمها إلى HSV إذا كنت تريد الدقة.

لقد استخدمت إجابة أندرو وإجابة مارك هذا (اعتبارًا من 1/2013، لا يوجد إدخال للنطاق ff).

function calcLightness(l, r, g, b) {
    var tmp_r = r;
    var tmp_g = g;
    var tmp_b = b;

    tmp_r = (255 - r) * l + r;
    tmp_g = (255 - g) * l + g;
    tmp_b = (255 - b) * l + b;

    if (tmp_r > 255 || tmp_g > 255 || tmp_b > 255) 
        return { r: r, g: g, b: b };
    else 
        return { r:parseInt(tmp_r), g:parseInt(tmp_g), b:parseInt(tmp_b) }
}

enter image description here

إن التحويل إلى HS (LVB)، وزيادة السطوع ثم التحويل مرة أخرى إلى RGB هو الطريقة الوحيدة لتفتيح اللون بشكل موثوق دون التأثير على قيم الصبغة والتشبع (أي تفتيح اللون فقط دون تغييره بأي طريقة أخرى).

لقد قمت بذلك في كلا الاتجاهين - ستحصل على نتائج أفضل بكثير مع الإمكانية 2.

من المحتمل أن تعمل أي خوارزمية بسيطة تقوم بإنشائها للاحتمال 1 بشكل جيد فقط مع نطاق محدود من تشبع البداية.

قد ترغب في إلقاء نظرة على Poss 1 إذا (1) كان بإمكانك تقييد الألوان والسطوع المستخدم، و(2) كنت تقوم بإجراء العمليات الحسابية كثيرًا في العرض.

لن يحتاج إنشاء الخلفية لواجهة المستخدم إلى الكثير من حسابات التظليل، لذا أقترح Poss 2.

-آل.

إذا كنت تريد إنتاج تلاشي متدرج، فإنني أقترح عليك التحسين التالي:بدلاً من استخدام RGB->HSB->RGB لكل لون على حدة، يجب عليك حساب اللون المستهدف فقط.بمجرد معرفة RGB الهدف، يمكنك ببساطة حساب القيم المتوسطة في مساحة RGB دون الحاجة إلى التحويل ذهابًا وإيابًا.ما إذا كنت تحسب انتقالًا خطيًا لاستخدام نوع من المنحنى أم لا، فالأمر متروك لك.

طريقة 1:قم بتحويل RGB إلى HSL، واضبط HSL، ثم قم بالتحويل مرة أخرى إلى RGB.

الطريقة الثانية: ليرب قيم ألوان RGB - http://en.wikipedia.org/wiki/Lerp_(الحوسبة)

يرى إجابتي على هذا السؤال المماثل لتطبيق C# للطريقة الثانية.

تظاهر بأنك ألفا ممزوجًا باللون الأبيض:

oneMinus = 1.0 - amount
r = amount + oneMinus * r
g = amount + oneMinus * g
b = amount + oneMinus * b

أين amount من 0 إلى 1، 0 يعيد اللون الأصلي و1 يعيد اللون الأبيض.

قد ترغب في المزج مع لون الخلفية مهما كان لونه إذا كنت تقوم بالتفتيح لعرض شيء معطل:

oneMinus = 1.0 - amount
r = amount * dest_r + oneMinus * r
g = amount * dest_g + oneMinus * g
b = amount * dest_b + oneMinus * b

أين (dest_r, dest_g, dest_b) هو اللون الذي يتم مزجه مع و amount من 0 إلى 1، مع عودة الصفر (r, g, b) و1 عائدين (dest.r, dest.g, dest.b)

ولم أجد هذا السؤال إلا بعد أن أصبح سؤالاً مرتبطًا بسؤالي الأصلي.

ومع ذلك، باستخدام البصيرة من هذه الإجابات الرائعة.لقد قمت بتجميع وظيفة لطيفة ذات خطين لهذا:

تفتيح اللون السداسي أو تغميقه برمجيًا (أو rgb، ومزج الألوان)

إنها نسخة من الطريقة 1.ولكن مع أخذ الإفراط في التشبع في الاعتبار.كما قال كيث في إجابته أعلاه؛استخدم Lerp لحل نفس المشكلة التي ذكرها مارك، ولكن بدون إعادة التوزيع.نتائج shadeColor2 يجب أن تكون أقرب إلى القيام بذلك بالطريقة الصحيحة مع HSL، ولكن دون تحمل أي تكاليف إضافية.

متأخرا قليلا للحزب، ولكن إذا كنت تستخدم javascript أو nodejs, ، يمكنك استخدام مكتبة tinycolor, وتلاعب باللون بالطريقة التي تريدها:

tinycolor("red").lighten().desaturate().toHexString() // "#f53d3d" 

كنت سأجرب الرقم 1 أولاً، لكن الرقم 2 يبدو جيدًا جدًا.حاول القيام بذلك بنفسك ومعرفة ما إذا كنت راضيًا عن النتائج، يبدو أن الأمر قد يستغرق 10 دقائق لإجراء الاختبار.

من الناحية الفنية، لا أعتقد أن أيًا منهما صحيح، ولكن أعتقد أنك تريد بديلاً للخيار رقم 2.تكمن المشكلة في أن استخدام RGB 990000 و"الإضاءة" سيضيف حقًا إلى القناة الحمراء (القيمة والسطوع والخفة) حتى تصل إلى FF.بعد ذلك (اللون الأحمر الثابت)، سيتم إزالة التشبع للذهاب إلى اللون الأبيض الصلب.

تصبح التحويلات مزعجة، خاصة أنه لا يمكنك الانتقال مباشرة من وإلى RGB وLab، ولكن أعتقد أنك تريد حقًا فصل قيم التلون والسطوع، وتعديل السطوع فقط لتحقيق ما تريده حقًا.

ستجد رمزًا للتحويل بين مساحات الألوان في ملف مكتبة روبي لأدوات الألوان

انا املك مشاركة مدونة يوضح كيفية القيام بذلك في دلفي.الأمر بسيط جدًا لأن الوظائف ColorRGBToHSL وColorHLSToRGB جزء من المكتبة القياسية.

فيما يلي مثال لتفتيح لون RGB في بايثون:

def lighten(hex, amount):
    """ Lighten an RGB color by an amount (between 0 and 1),

    e.g. lighten('#4290e5', .5) = #C1FFFF
    """
    hex = hex.replace('#','')
    red = min(255, int(hex[0:2], 16) + 255 * amount)
    green = min(255, int(hex[2:4], 16) + 255 * amount)
    blue = min(255, int(hex[4:6], 16) + 255 * amount)
    return "#%X%X%X" % (int(red), int(green), int(blue))
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top