อัลกอริทึมในการปรับเปลี่ยนสีเพื่อให้คล้ายน้อยกว่าพื้นหลัง


23

ฉันกำลังสร้างตัวอย่างลูกบอล 20 ลูกที่กระเด้งกันโดยมีพื้นหลังที่เต็มไปด้วยสีทึบ สีสำหรับแต่ละลูกบอลจะถูกเลือกแบบสุ่มด้วยrandint(0, 255)สำหรับองค์ประกอบ Tuple R, G, B แต่ละชิ้น

ปัญหาคือลูกบอลบางส่วนจบลงด้วยสีที่คล้ายกับพื้นหลังทำให้ดูยาก ฉันต้องการหลีกเลี่ยงสิ่งนั้นไม่ว่าจะโดยการกลิ้งสีอื่นถ้าสีที่เลือกนั้นคล้ายกันเกินไป (ภายในขีด จำกัด ที่กำหนด) หรือโดยการเลื่อนออกไปจากสีพื้นหลัง

จะคำนวณดัชนีความคล้ายคลึงกันเพื่อใช้เป็นเกณฑ์ได้อย่างไร หรือวิธีการแปลงสีเพื่อให้พูดน้อยสีฟ้า ish ?

ข้อจำกัดความรับผิดชอบที่ชัดเจน: ฉันไม่รู้อะไรเลยเกี่ยวกับทฤษฎีสีดังนั้นฉันไม่รู้เลยว่าแนวคิดด้านบนยังคงมีอยู่!

ฉันกำลังเขียนโปรแกรมในหลาม แต่ฉันกำลังมองหาแนวคิดและกลยุทธ์ดังนั้นหลอกรหัสเป็นเรื่องดี (หรือเพียงแค่ทฤษฎี)

แก้ไข:

หากต้องการชี้แจงจุดสองสามข้อ:

  • ลูกบอลแต่ละลูกมีสีแบบสุ่มของตัวเอง ฉันต้องการให้พวกเขายังคงสุ่มให้มากที่สุดและสำรวจพื้นที่สีให้มากที่สุด (ไม่ว่าจะเป็น RGB หรือ HSV pygameยอมรับทั้งสองรูปแบบเพื่อกำหนดสี)

  • ฉันแค่ต้องการหลีกเลี่ยงการเป็นสี "ใกล้เกินไป" กับพื้นหลัง ปัญหาไม่ได้เป็นเพียงเกี่ยวกับเว้: ฉันตกลงอย่างสมบูรณ์แบบด้วยลูกบอลสีฟ้าอ่อนกับพื้นหลังสีน้ำเงินเข้ม (หรือ "สีฟ้าเต็ม" กับ "สีขาว - สีฟ้า" สีฟ้า ฯลฯ )

  • สำหรับตอนนี้ฉันไม่สนใจหรอกว่าลูกจะจบลงด้วยสีที่คล้ายกัน (หรือเหมือนกัน) กับลูกบอลอีกลูก การหลีกเลี่ยงสิ่งนั้นเป็นโบนัส แต่เป็นปัญหาเล็กน้อย

  • สีพื้นหลังเป็นสี RGB คงที่เดียว สำหรับตอนนี้ฉันใช้สีน้ำเงิน "พื้นฐาน" (0, 0, 255)แต่ฉันไม่ได้ใช้มัน ดังนั้นให้พิจารณาพื้นหลังให้เป็นสีตามอำเภอใจ (ด้วยเฉดสีโดยพลการความสว่างความอิ่มตัว ฯลฯ )

EDIT2:

TL, DR เวอร์ชั่น:เพียงแค่ให้วิธีการสร้างสีแบบสุ่ม X เพื่อให้ไม่มี "จางหายไปมากเกินไป" กับพื้นหลังของสีโดยพลการ (แต่อย่างเดียวและคงที่)



1
ทำไมไม่เพียงแค่วางเค้าโครงรอบ ๆ ลูกบอลแต่ละลูก
ashes999

1
จากนั้นอาจมีปัญหาในการสร้างสีเค้าร่างที่แตกต่างจากทั้งพื้นหลังและสีของลูก;)
Kromster พูดว่าสนับสนุน Monica

1
@AlexM: ยากที่จะเชื่อว่าไม่มีวิธีง่ายๆในการ "สร้างสีแบบสุ่มโดยหลีกเลี่ยงการใช้กฎเกณฑ์ใด ๆ "
MestreLion

1
@MestreLion เพียงใช้สีดำสำหรับเค้าร่างและสร้างสีที่มีค่า RGB ต่ำสุดที่ 128 มันเป็นเรื่องง่าย
ashes999

คำตอบ:


33

คุณสามารถใช้ความจริงที่ว่าสีประกอบขึ้นเป็นพื้นที่สี (สามมิติ) และคำนวณระยะทางในพื้นที่สีนี้ จากนั้นคุณต้องกำหนดเมตริกในพื้นที่สีนี้เพื่อค้นหาระยะห่างระหว่างสองสี

เช่นระยะทางในปริภูมิแบบยุคลิดระหว่างสองจุด x = (x1, x2, x3) และ y = (y1, y2, y3) มอบให้โดย d (x, y) = sqrt ((y1-x1) * (y1- x1) + (y2-x2) * (y2-x2) + (y3-x3) * (y3-x3))

ตอนนี้คุณสามารถคำนวณระยะห่างระหว่างสีลูกกับสีพื้นหลังของคุณและถ้ามันมีขนาดเล็กเกินไปให้สร้างสีแบบสุ่มใหม่และทดสอบอีกครั้ง

คุณจะพบว่าทั้ง RGB และ HSV นั้นไม่ใช่พื้นที่สีที่ดีสำหรับงานนี้ บทความวิกิพีเดียแตกต่างของสีพนักงานL ขพื้นที่สีและให้ตัวชี้วัดที่เป็นไปได้หลาย

นอกจากนี้ยังมีdiskussion บน stackoverflowในหัวข้อ


นั่นเป็นวิธีที่ดีมากฉันทำได้ :) ขอบคุณ! นอกจากนี้ยังสนใจที่จะอธิบายเพิ่มเติมเกี่ยวกับวิธีหาเกณฑ์ "ระยะทางขั้นต่ำ" อย่างเพียงพอหรือไม่ หาก RGB ไม่เพียงพอวิธีแปลงเป็น L a b? ฉันไม่ได้พยายามวัดการรับรู้ที่แม่นยำดังนั้นค่าเริ่มต้น "ดีพอ" จะทำ
MestreLion

1
รักคำตอบนี้ดีคิดออกคำอธิบายที่ดีของวิธีการทำงานในขณะที่ให้สมการและการอ้างอิงที่จำเป็น คำตอบแรกที่ดี
Tom 'Blue' Piddock

1
หากคุณกำลังมองหาการรับรู้ของมนุษย์ที่ "ดีพอ" คุณอาจต้องการตรวจสอบพื้นที่สีYUVซึ่งมีการแปลงโดยตรงจาก RGB
trm

5
ประหยัดเวลาและไม่ต้องใช้รากที่สอง (แพง) เพียงแค่ทำให้ค่าระยะห่างของสีต่ำสุดที่คุณเปรียบเทียบกับสี่เหลี่ยม
Chris Cudmore

1
@MestreLion พื้นที่สีL a b * ได้รับการคิดค้นให้มีความเหมือนกันซึ่งหมายความว่าระยะทางที่รับรู้ระหว่างสองสีนั้นเท่ากับระยะทางจริงในพื้นที่สี เนื่องจากสี RGB ขึ้นอยู่กับอุปกรณ์คุณจึงไม่สามารถแปลงระหว่าง Lab และ RGB ได้โดยตรง อย่างไรก็ตามหากคุณใช้พื้นที่สี RGB แน่นอนคุณสามารถแปลงได้ ดูบทความนี้: en.wikipedia.org/wiki/SRGB_color_spaceและบทความนี้: en.wikipedia.org/wiki/Lab_color_space
jwir3

8

หน้ามาตรฐานการเข้าถึงเว็บของสหประชาชาติ ( http://www.un.org/webaccessibility/1_visual/13_colourcontrast.shtml ) แสดงถึงมาตรฐานในการรับรองความคมชัดของข้อความที่เหมาะสมบนเว็บไซต์โดยคำนึงถึงผู้ใช้บางคนที่ตาบอดสี สิ่งนี้อาจมีความสำคัญอย่างยิ่งสำหรับคุณเนื่องจากผู้ใช้บางคนอาจเป็นคนตาบอดสี (ยากที่จะบอกลูกบอลสีแดงจากพื้นหลังสีเขียวหากพวกเขามีความสว่างเท่ากัน)

หน้า UN ชี้ไปที่ Juicy Studios Luminosity Color Contrast Ratio Analyzer ที่ ( http://juicystudio.com/services/luminositycontrastratio.php#specify ) ซึ่งระบุข้อความบนพื้นหลังจะต้องมีอัตราส่วนความคมชัด 4.5: 1 ยกเว้นสิ่งที่ฉัน เชื่อว่ามีความคล้ายคลึงกับกรณีของคุณ:

  • ข้อความขนาดใหญ่: ข้อความขนาดใหญ่และรูปภาพของข้อความขนาดใหญ่มีอัตราส่วนความคมชัดอย่างน้อย 3: 1

ทีนี้อัตราส่วนความคมชัดคืออะไร? ติดตามไฮเปอร์ลิงก์ต่อไปนี้ (นี่สนุกมาก!) เราไปที่หน้า W3 ซึ่งกำหนดอัตราส่วนคอนทราสต์เป็น:

Contrast Ratio = (L1 + 0.05)/(L2 + 0.05)

ที่ L1 และ L2 คือความสว่างสัมพัทธ์ของสี L1 เป็นสีที่ให้ความสว่างมากกว่า L2 เป็นสีที่มีความส่องสว่างน้อยกว่า อีกครั้งเราไปตามลิงก์ไปยังหน้า W3 เดียวกันกับที่ระบุ:

L = 0.2126 * R + 0.7152 * G + 0.0722 * B where R, G and B are defined as:

if RsRGB <= 0.03928 then R = RsRGB/12.92 else R = ((RsRGB+0.055)/1.055) ^ 2.4
if GsRGB <= 0.03928 then G = GsRGB/12.92 else G = ((GsRGB+0.055)/1.055) ^ 2.4
if BsRGB <= 0.03928 then B = BsRGB/12.92 else B = ((BsRGB+0.055)/1.055) ^ 2.4
and RsRGB, GsRGB, and BsRGB are defined as:

RsRGB = R8bit/255
GsRGB = G8bit/255
BsRGB = B8bit/255

หมายเหตุ : เครื่องหมายคาเร็ตสัญลักษณ์^ด้านบนอ้างถึงการยกกำลัง (x²)

เรามีกรอบที่ดีมากสำหรับอัลกอริทึมตัดกัน (นั่นเป็นมิตรกับตาบอดสี!)

  • กำหนดค่า R, G, B สำหรับแต่ละสี
  • กำหนดความส่องสว่างสำหรับแต่ละสี
  • หากอัตราส่วนความคมชัดของสีที่มีความสว่างมากกว่าไปยังสีที่มีความสว่างน้อยที่สุดนั้นน้อยกว่า 3 ให้ทำซ้ำ!

2
อาจต้องการทราบว่า ^ ควรจะเป็นการยกกำลัง สำหรับเราผู้ใช้ C-like ที่บ้าคลั่งนั่นหมายถึง xor (ฉันคิดว่าคุณกำลังพยายามที่จะทำบิตพอยต์บนค่าทศนิยมเป็นเวลาหนึ่งนาที)
Pharap

นั่นเป็นวิธีที่น่าทึ่งฉันชอบมัน! :)
MestreLion

และไม่ต้องกังวล^ฉันจะไม่คิดถึง XOR bitwise ในบริบทนี้ (หรือในความจริงใด ๆ C'mon C phreaks ^เป็น simbol de-พฤตินัยสำหรับการยกกำลังในรหัสหลอก (แม้ว่าภาษาน้อยมากจริง ๆ ใช้มัน ... ในหลามมัน**)
MestreLion

1
เพียงแก้ไขข้อผิดพลาด ยิ่งไปกว่านั้นหากคนคนหนึ่งมีปัญหากับ ^ โอกาสที่คนอื่นในอนาคตก็สามารถทำได้เช่นกัน ไม่เจ็บที่จะเจาะจง
จอห์น

1
@John ไม่ต้องกังวล ฉันไม่แน่ใจว่าความสับสนเกิดจากที่ใด (เช่นภาษาที่ใช้ ^ เพื่อจุดประสงค์แรก) บางครั้งฉันเท่านั้นที่รู้ว่า ^ ใช้สำหรับการยกกำลังเนื่องจากประสบการณ์ของฉันกับ VB (ฉันไม่รู้ภาษาอื่นที่ใช้เป็นการยกกำลัง แต่อาจมีบางอย่าง) เช่นเดียวกับเฮดอัพแม้ว่ามันจะเป็นสัญลักษณ์รูปหมวกไม่ใช่สัญลักษณ์ของแครอท อาจต้องการที่จะเปลี่ยนก่อนที่ใครบางคนทำให้เรื่องตลกที่น่ากลัวของพระเจ้าเกี่ยวกับการเขียนโปรแกรมกับผัก (โดยเฉพาะอย่างยิ่งหนึ่งที่เกี่ยวข้องกับรากที่สอง)
Pharap

2

การใช้ค่า RGB โดยการสร้าง0-255ค่าสุ่มสำหรับแต่ละองค์ประกอบอาจไม่เพียง แต่สร้างสีที่คล้ายกับพื้นหลังคุณยังสามารถจบลงด้วยสีที่คล้ายกันมากสำหรับลูกบอล

ฉันอาจเลือกวิธีสุ่มน้อยลงและสร้างสีที่รับประกันว่าจะแตกต่างกันแทน คุณสามารถสร้างสีสำหรับแต่ละ ~ 32 องศาในช่วงสีและสลับความสว่างหรือความอิ่มตัว (ใช้โมเดลสี HSV แทน RGB)

ดังนั้นสิ่งนี้:

numColors = 20;
stepSize = 360 / (numColors / 2 + 1); // hue step size
for(i = 0; i < numColors; i++){
    color = HSV(i / 2 * stepSize, 0.5 + (i % 2) * 0.5, 1.0) 
}

ซึ่งจะสร้าง 20 สีกระจายอย่างสวยงาม สิ่งนี้จะถือว่าคุณใช้เลขจำนวนเต็มดังนั้นi = 0และi = 1จะสร้างค่าฮิวเหมือนกัน

แน่นอนว่ามันไม่ได้ปรับขนาดได้ดีเกินไป .. หากคุณมีค่าสี 100 ค่าในการสร้างระยะห่างของสีอาจไม่เพียงพอและคุณจะได้สีที่คล้ายกันอีกครั้ง ในกรณีนี้คุณสามารถเปลี่ยนแปลงค่าV(ความสว่าง) ได้

ฉันไม่รู้ว่าสีพื้นหลังของคุณเป็นอย่างไร แต่ HSV ช่วยให้เปรียบเทียบสีได้ง่ายขึ้น (เพียงเปรียบเทียบส่วนประกอบ 3 ชิ้นและอย่าลืมว่า HUE เป็นวงกลม (0 == 360))

UPDATE:

เนื่องจากฉันไม่ได้ตอบคำถามของคุณ แต่ให้แนวทางอื่นนี่คือวิธีอัลกอริทึมสำหรับพื้นหลังโดยพลการและลูกบอลสีแบบสุ่มที่สมบูรณ์อาจมีลักษณะ (นี่เป็นวิธีการที่กำลังดุร้าย แต่ควรทำงานได้ดีสำหรับกรณีของคุณ):

// background color, currently equals RGB(0, 0, 255)
bg = HSV(240, 1.0, 1.0)

// number of colors to create is equal to the amount of balls
numColors = balls.length

// set threshold to compare colors. you can tweak this to your liking
threshold = 0.15

for(i = 0; i < numColors; i++){
    do {
        // assuming rnd returns a random float 0-1 inclusive
        color = HSV(rnd() * 360, rnd(), rnd())
        // calculate delta values, normalize hue to 0-1
        dH = (180 - abs(abs(bg.h - color.h) - 180)) / 360
        dS = bg.s - color.s
        dV = bg.v - color.v
        // "distance" between bg and color
        difference = sqrt(dH * dH + dS * dS + dV * dV)
    } while(difference < threshold)

    ball[i].color = color
}

เกี่ยวกับเครื่องคำนวณของคุณการคำนึงถึงสีพื้นหลังเป็นอย่างไร?
MestreLion

ขณะนี้ไม่ได้คำนึงถึงสีพื้นหลังไว้ในบัญชี ... คุณสามารถปรับแต่งได้โดยการเปรียบเทียบสีที่สร้าง (ตามที่อธิบายไว้ในย่อหน้าสุดท้าย) จากนั้นสร้างสีที่แตกต่างกันV(เนื่องจากอัลกอริทึมปัจจุบันไม่ได้เปลี่ยนแปลง)
bummzack

@MestreLion เพิ่มการอัปเดตด้วยอัลกอริธึมทางเลือก
bummzack

เยี่ยมมากนั่นเป็นกลยุทธ์ที่ดี กำลังดุร้ายก็โอเคสีจะสร้างเพียงครั้งเดียวเมื่อเริ่มต้นไม่ใช่ภายในลูปเกม ดูเหมือนว่าคุณกำลังใช้วิธีการเดียวกับRenéด้วยระยะทางแบบยุคลิดแบบธรรมดาใน HSV ใช่ไหม? การอ้างอิงใด ๆ ของเกณฑ์ที่เหมาะสมสำหรับ HSV H, S และ V มีน้ำหนักเท่ากันในระยะทางเหมือนใน RGB หรือไม่?
MestreLion

@MestreLion ใช่อัลกอริธึมที่สองของฉันนั้นเป็นสิ่งที่Renéอธิบายไว้ในคำตอบของเขา น่าเศร้าที่ไม่มีค่าที่แน่นอนสำหรับเกณฑ์ที่ดีเนื่องจากการเปลี่ยนแปลงสีไม่ได้รับการรับรู้อย่างสม่ำเสมอ เรารับรู้การเปลี่ยนแปลงในสีเขียวเร็วกว่าสีน้ำเงิน ... ดังนั้นสำหรับโทนสีเขียวขีด จำกัด ขนาดเล็กอาจทำงานได้ แต่จะไม่เพียงพอสำหรับสีอื่น ๆ เป็นต้นเท่าที่ฉันรู้แล็บสีพื้นที่นั้นใกล้เคียงกับการรับรู้สีของมนุษย์และ อาจเหมาะสมที่สุดหากคุณไม่ได้รับผลลัพธ์ที่ต้องการด้วย HSV colourspace
bummzack

1

เมื่อคุณพูดถึงคุณมีพื้นหลังนิ่งสีของลูกบอลยังคงเป็นแบบสุ่ม แต่พวกเขาจะต้องตกอยู่ในบางช่วงที่ยังคงชมพื้นหลัง

ข้อมูลพื้นฐานเกี่ยวกับ ก่อนที่เราจะทำอย่างนั้นคุณจำเป็นต้องรู้พื้นฐาน พิจารณาสีต่อไปนี้:

Black   #000000 rgb(0,0,0)
Red     #FF0000 rgb(255,0,0)
Green   #00FF00 rgb(0,255,0)
Blue    #0000FF rgb(0,0,255)
Yellow  #FFFF00 rgb(255,255,0)
Cyan    #00FFFF rgb(0,255,255)
Pink    #FF00FF rgb(255,0,255)
Gray    #C0C0C0 rgb(192,192,192)
White   #FFFFFF rgb(255,255,255)

การผสมสี RGB [(0..255), (0..255), (0..255)] สร้างสีใหม่ดังกล่าวข้างต้น

การคำนวณเพื่อลบสีการคำนวณเพื่อลบสีก็เหมือนกับการเปลี่ยนสีแดงเป็นสีฟ้าสีเขียวสีม่วงสีม่วงสีน้ำเงินสีเหลือง

Red     #FF0000 rgb(255,0,0) ->     Cyan    #00FFFF rgb(0,255,255)
Green   #00FF00 rgb(0,255,0) ->     Purple   #FF00FF    rgb(255,0,255)
Blue    #0000FF rgb(0,0,255) ->     Yellow  #FFFF00 rgb(255,255,0)

สีเสริม

ตามการอ้างอิงเกี่ยวกับการคำนวณสีเสริม: http://serennu.com/colour/rgbtohsl.php

เกี่ยวกับ HSL

HSL เป็นการแสดงออกถึงสีในแง่ของสีสันความอิ่มตัวและความสว่างของพวกเขาซึ่งเป็นตัวเลขสำหรับคุณลักษณะทั้งสามของสีเหล่านี้

ฮิวคือตำแหน่งสีของวงล้อสีซึ่งแสดงเป็นองศาตั้งแต่ 0 °ถึง 359 °หรือคิดเป็น 360 องศาของวงล้อ 0 °เป็นสีแดง 180 °เป็นสีฟ้าของสีแดงตรงกันข้ามเป็นต้น

ความอิ่มตัวของสีคือความเข้มของสีว่ามันน่าเบื่อหรือสว่างแค่ไหน ความอิ่มตัวของสียิ่งต่ำ นี่แสดงเป็นเปอร์เซ็นต์, 100% เป็นความอิ่มตัวเต็ม, สว่างที่สุดและ 0% ไม่มีความอิ่มตัว, สีเทา

ความสว่างคือความสว่างของสี แตกต่างกันเล็กน้อยเพื่อความอิ่มตัว ยิ่งสีขาวมีค่าความสว่างมากเท่าไหร่สีดำก็ยิ่งมีความสว่างมากขึ้นเท่านั้น ดังนั้นความสว่าง 100% เปลี่ยนสีขาว, 0% ​​ความสว่างเปลี่ยนเป็นสีดำและสี "บริสุทธิ์" จะเป็น 50% ความสว่าง

การเห็นความแตกต่างระหว่าง Saturation และ Lightness ง่ายกว่าการอธิบาย หากคุณต้องการชี้แจงให้ลองดูรูปแบบความสว่างและความอิ่มตัวของสีบนหน้าเครื่องคิดเลขสีโดยเลือกสีที่สดใสเป็นสีเริ่มต้นของคุณ

ดังนั้นเครื่องหมาย HSL จะมีลักษณะเช่นนี้โดยให้ค่า Hue, Saturation และ Lightness ตามลำดับ: t

สีแดง: 0 ° 100% 50% สีชมพูอ่อน: 0 ° 100% 90% ฟ้า: 180 ° 100% 50% นี่คือขั้นตอน:

  1. แปลงสีของคุณเป็น HSL

  2. เปลี่ยนค่าฮิวเป็นค่าที่ตรงกันข้ามของฮิว (เช่นถ้าฮิวของคุณคือ 50 °ค่าที่ตรงกันข้ามจะอยู่ที่ 230 °บนวงล้อ - 180 องศาต่อไป)

  3. ปล่อยให้ค่าความอิ่มตัวและความสว่างเท่าที่ควร

  4. แปลงค่า HSL ใหม่นี้กลับไปเป็นรูปแบบสีดั้งเดิมของคุณ (RGB หรืออะไรก็ตาม)

ไซต์เช่น EasyRGB.com สามารถทำการแปลงทั่วไปสำหรับคุณจาก RGB เป็น HSL หรือในทางกลับกัน

ตัวอย่างการเขียนโปรแกรมทำใน PHP ตามการอ้างอิง

การแปลงจาก RGB เป็น HSL

ค่าดังกล่าวข้างต้นสีน้ำเงิน # 0000FF rgb (0,0,255) สามารถแสดงเป็นเลขฐานสิบหกสีแดง 00 + เลขฐานสิบหกสีเขียว 00 + เลขฐานสิบหกสีฟ้า FF

$redhex  = substr($hexcode,0,2);
$greenhex = substr($hexcode,2,2);
$bluehex = substr($hexcode,4,2);

นอกจากนี้ยังสามารถนำเสนอเป็นสีแดงทศนิยม 0 + สีเขียวทศนิยม 0 + สีน้ำเงินทศนิยม 255

$var_r = (hexdec($redhex)) / 255;
$var_g = (hexdec($greenhex)) / 255;
$var_b = (hexdec($bluehex)) / 255;

ตอนนี้เสียบค่าเหล่านี้ลงในรูทีน rgb2hsl ด้านล่างนี้คือรหัสทั่วไปของ EasyRGB.com รุ่น PHP ของฉันสำหรับการแปลง:

ข้อมูลเข้าคือ $ var_r, $ var_g และ $ var_b จากด้านบนผลลัพธ์เป็น HSL เทียบเท่ากับ $ h, $ s และ $ l - สิ่งเหล่านี้จะแสดงเป็นเศษส่วน 1 เช่นค่าอินพุต

$var_min = min($var_r,$var_g,$var_b);ttt
$var_max = max($var_r,$var_g,$var_b);
$del_max = $var_max - $var_min;

$l = ($var_max + $var_min) / 2;

if ($del_max == 0)
{
        $h = 0;
        $s = 0;
}
else
{
        if ($l < 0.5)
        {
                $s = $del_max / ($var_max + $var_min);
        }
        else
        {
                $s = $del_max / (2 - $var_max - $var_min);
        };

        $del_r = ((($var_max - $var_r) / 6) + ($del_max / 2)) / $del_max;
        $del_g = ((($var_max - $var_g) / 6) + ($del_max / 2)) / $del_max;
        $del_b = ((($var_max - $var_b) / 6) + ($del_max / 2)) / $del_max;

        if ($var_r == $var_max)
        {
                $h = $del_b - $del_g;
        }
        elseif ($var_g == $var_max)
        {
                $h = (1 / 3) + $del_r - $del_b;
        }
        elseif ($var_b == $var_max)
        {
                $h = (2 / 3) + $del_g - $del_r;
        };

        if ($h < 0)
        {
                $h += 1;
        };

        if ($h > 1)
        {
                $h -= 1;
        };
};

ตอนนี้เรามีสีเป็นค่า HSL ในตัวแปร $ h, $ s และ $ l ตัวแปรเอาต์พุตทั้งสามนี้ถูกจัดขึ้นอีกครั้งเป็นเศษส่วน 1 ในระยะนี้แทนที่จะเป็นองศาและเปอร์เซ็นต์ ดังนั้นเช่นสีฟ้า (180 ° 100% 50%) จะออกมาเป็น $ h = 0.5, $ s = 1, และ $ l = 0.5

จากนั้นหาค่าของสีตรงข้ามเช่นค่าที่อยู่ที่ 180 °หรือ 0.5 ห่างออกไป (ฉันแน่ใจว่านักคณิตศาสตร์มีวิธีที่สง่างามกว่าในเรื่องนี้ แต่):

คำนวณเว้ตรงข้าม, $ h2

            $h2 = $h + 0.5;

            if ($h2 > 1)
                    {
                            $h2 -= 1;
                    };

ตอนนี้ค่า HSL ของสีเสริมเป็น $ h2, $ s, $ l ดังนั้นเราพร้อมที่จะแปลงกลับเป็น RGB (อีกครั้งสูตร PHP EasyRGB.com ของฉัน) หมายเหตุรูปแบบอินพุตและเอาต์พุตต่างกันในเวลานี้โปรดดูความคิดเห็นของฉันที่ด้านบนของรหัส:

อินพุตคือค่า HSL ของสีเสริมจัดขึ้นใน $ h2, $ s, $ l เป็นเศษส่วนของ 1 เอาท์พุทคือ RGB ในรูปแบบปกติ 255 255 255 255 จัดขึ้นใน $ r, $ g, $ b เว้ถูกแปลงโดยใช้ฟังก์ชัน hue_2_rgb ในตอนท้ายของรหัสนี้

    if ($s == 0)
    {
            $r = $l * 255;
            $g = $l * 255;
            $b = $l * 255;
    }
    else
    {
            if ($l < 0.5)
            {
                    $var_2 = $l * (1 + $s);
            }
            elset
            {
                    $var_2 = ($l + $s) - ($s * $l);
            };

            $var_1 = 2 * $l - $var_2;
            $r = 255 * hue_2_rgb($var_1,$var_2,$h2 + (1 / 3));
            $g = 255 * hue_2_rgb($var_1,$var_2,$h2);
            $b = 255 * hue_2_rgb($var_1,$var_2,$h2 - (1 / 3));
    };

   // Function to convert hue to RGB, called from above

    function hue_2_rgb($v1,$v2,$vh)
    {
            if ($vh < 0)
            {
                    $vh += 1;
            };

            if ($vh > 1)
            {
                    $vh -= 1;
            };

            if ((6 * $vh) < 1)
            {
                    return ($v1 + ($v2 - $v1) * 6 * $vh);
            };

            if ((2 * $vh) < 1)
            {
                    return ($v2);
            };

            if ((3 * $vh) < 2)
            {
                    return ($v1 + ($v2 - $v1) * ((2 / 3 - $vh) * 6));
            };

            return ($v1);
    };

และหลังจากรูทีนนั้นในที่สุดเราก็มี $ r, $ g และ $ b ในรูปแบบ 255 255 255 (RGB) ซึ่งเราสามารถแปลงเป็นเลขฐานสิบหกของ hex:

    $rhex = sprintf("%02X",round($r));
    $ghex = sprintf("%02X",round($g));
    $bhex = sprintf("%02X",round($b));

    $rgbhex = $rhex.$ghex.$bhex;

$ rgbhex คือคำตอบของเรา - สีประกอบกันเป็นฐานสิบหก

เนื่องจากพื้นหลังสีของคุณเป็นสีน้ำเงินหรือ 0,0,255 HSL จึงเป็น

ฮิว (H): 240 องศา / ความอิ่มตัว (S): 100% / ความสว่าง (L): 4.9%

ตรงข้ามกับ 240 คือ 60 ในวงกลมแล้วแปลงกลับเป็น RGB ให้ค่า # 181800


ขอบคุณ! แต่พูดถึงการเชื่อมโยงเกี่ยวกับการสร้างเป็น "สีเสริม" (สิ่งที่) ของตัวเอง ฉันยังไม่รู้วิธีการใช้เพื่อแก้ไขปัญหาของฉัน: ตรวจสอบให้แน่ใจว่าสีแบบสุ่มแต่ละสีไม่คล้ายกับสีพื้นหลัง สีพื้นหลังเป็นค่าคงที่สีเดียวและมีหลายลูก
MestreLion

ขอบคุณ Krom ที่ทำสิ่งนี้ @MestreLion เนื่องจากพื้นหลังเป็นค่าคงที่คุณสามารถระบุช่วงของลูกของคุณที่ยังคงเติมเต็มพื้นหลัง
Ace Caserya

กำลังอธิบายคำตอบของฉันให้ลึกซึ้ง
Ace Caserya

เสร็จสิ้น ฉันไม่ได้เปลี่ยนแปลงอะไรมากในการอธิบายเว็บไซต์เพราะมันอธิบายได้ดีพอ ให้เครดิตกับพวกที่ EasyRGB.com
Ace Caserya

ขอให้เรายังคงอภิปรายนี้ในการแชท
Ace Caserya

1

ฉันต้องการขยายแนวคิดของ @ ashes999 ในการสร้างโครงร่าง

รหัสของฉันจะเป็นเหมือนงูเหลือมที่ฉันสามารถปิดส่วนบนของหัวของฉัน (ฉันไม่เคยเขียนบรรทัดของหลามในชีวิตของฉัน แต่ฉันเหลือบมองหนังสือเล่มหนึ่งหรือสองครั้ง)

def lerp(a,b,value): # assuming your library was not kind enough to give you this for free
    return a + ((b - a) * value);

def drawRandomBall(bgColour,radius,point):
    var ballColour = Colour(random(0,255),random(0,255),random(0,255);
    var outlineColour = Colour(lerp(bgColour.R,255 - ballColour.R,0.5),lerp(bgColour.G,255 - ballColour.G,0.5),lerp(bgColour.B,255 - ballColour.B,0.5));
    fillCircle(point,radius+1,outlineColour);
    fillCircle(point,radius,ballColour);

มันอาจดูไม่สวยโดยเฉพาะและมันไม่เหมาะกับโค้ดการผลิตจริง ๆ แต่มันควรจะพอเพียงในการแก้ไขด่วน ฉันไม่ได้ทดสอบรหัสเพราะฉันไม่มีโปรแกรม "ลูกบอลที่กระดอนไปมารอบ ๆ หน้าจอ" เพื่อส่งให้ฉันสามารถทำให้เกิดการเสียหายเพื่อทดสอบ


แก้ไข:

เมื่อเห็นรหัสที่ใช้งานจริงสถานการณ์พลิกไปที่หัวดังนั้นฉันจึงเสนอวิธีแก้ปัญหานี้แทน

แทนที่บรรทัด 276-284 ด้วยสิ่งต่อไปนี้:

# Colour generator
def generateColourNonBG(leeway):
    color = (randint(0,255), randint(0,255), randint(0,255))
    while color[0] >= BG_COLOR[0]-leeway and color[0] =< BG_COLOR[0] + leeway and
    color[1] >= BG_COLOR[1]-leeway and color[1] =< BG_COLOR[1] + leeway and
    color[2] >= BG_COLOR[2]-leeway and color[2] =< BG_COLOR[2] + leeway:
        color = (randint(0,255), randint(0,255), randint(0,255))

# Ball generator
def generateBall():
    Ball(generateColourNonBG(5),
                   radius=randint(10, radius),
                   position=[randint(100, screen.get_size()[0]-radius),
                             randint(100, screen.get_size()[0]-radius)],
                   velocity=[randint(50, 50+vel[0]), randint(50, 50+vel[1])],
                   )                       

# Create the balls
balls = pygame.sprite.Group()
for _ in xrange(BALLS):
    balls.add(generateBall())

ในเวอร์ชั่นที่ย่อใหม่นี้วิธีการจากโรงงานพ่นลูกบอลและวิธีการเฉพาะสร้างสี ตัวสร้างสีจะทดสอบสีที่สร้างแบบสุ่มเพื่อดูว่าอยู่ในช่วงที่ใกล้เคียงกับสีพื้นหลังหรือไม่ สีนั้นถือว่าใกล้เคียงกับสี BG มากเกินไปหากช่องสีทั้งสามอยู่ภายในleewayด้านใดด้านหนึ่งของ BG ดังนั้นถ้า leeway เป็น 0 สีที่ตรงกับ BG เท่านั้นที่จะถูกปฏิเสธ ฉันเลือก 5 เป็นค่าเริ่มต้นซึ่งปฏิเสธสี BG และ 5 สีทั้งสองด้าน เนื่องจากสี BG เป็นสีขาวฉันไม่แน่ใจว่ามันจะปฏิเสธสีดำหรือไม่เพราะตัวเลขล้อมรอบ ที่สามารถหลีกเลี่ยงได้ด้วยการใช้ฟังก์ชั่นขั้นต่ำและสูงสุด แต่ฉันก็ทิ้งมันไว้เพื่อความกะทัดรัด


ฉันเปิดรับกลยุทธ์ใด ๆ :) สำหรับโปรแกรมที่จะทำลายฉันสามารถให้คุณว่า: github.com/MestreLion/rainballsบรรทัดที่เกี่ยวข้องจะเป็น 279-284
MestreLion

ฉันใช้pygameเป็นห้องสมุด ไม่มี Lerp เพียงแค่การแปลง RGB-HSV-CYMK พื้นฐาน: pygame.org/docs/ref/color.html
MestreLion

@ MestreLion โอ้เจ้าข้าตอนนี้ฉันต้องติดตั้ง pygame และ python เพื่อทดสอบมัน ฉันยิงตัวเองด้วย XP ตัวนี้ Lerping ง่ายlerpฟังก์ชั่นในคำตอบของฉันคือทั้งหมดที่มีให้มัน (Lerp หมายถึง 'การประมาณเชิงเส้น')
Pharap

@MestreLion เล่น ๆ นิด ๆ หน่อย ๆ กลับกลายเป็นว่าฉันใช้ภาษาไพ ธ อนไม่ชอบการพิมพ์โดยไม่มีวงเล็บ แก้ไขปัญหาที่ แต่ตอนนี้ฉันมีข้อผิดพลาดจาก pygame ไม่สามารถค้นหาไลบรารีที่เหมาะสม ฉันจะเขียนรหัสของฉันใหม่เพื่อให้สอดคล้องกับสิ่งที่คุณมี แต่ฉันไม่สามารถทดสอบได้จนกว่าฉันจะแก้ไข pygame ฉันขอแนะนำให้ผนวกไฟล์นั้นกับคำถามหากคุณยังไม่ได้ทำ (ในกรณีที่ใคร ๆ ก็รู้สึกดีพอที่จะเขียนหลามให้คุณ)
Pharap

คุณprintแตกต่างเพราะคุณใช้ Python 3 และฉันยังอยู่ใน Python 2 และฉันไม่แน่ใจว่าpygameพอร์ตไปยัง Py3 แล้วหรือยัง ด้านล่าง: ไม่ต้องกังวล :) คำถามเกี่ยวกับสีคุณไม่จำเป็นต้องมีลูกบอลจริง ๆ ที่กระเด้งไปรอบ ๆ :)
MestreLion

1

สำหรับรูปแบบ RGB สิ่งนี้ดูเหมือนว่าจะทำงานได้ดีและไม่สำคัญ:

หลากหลาย _score = (abs (r1 - r2) + abs (g1 - g2) + abs (b1 - b2)) / 765.0

สิ่งนี้จะให้คะแนนระหว่าง 0.0 ถึง 1.0 ยิ่งต่ำก็ยิ่งยากที่จะแยกแยะสีสองสี

มันควรจะชัดเจน แต่เพื่อความสมบูรณ์: ค่า r, g, b จะต้องถูกโยนไปยังหมายเลขจุดลอยตัวก่อนและจะถือว่าค่าสูงสุดของพวกเขาคือ 255

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.