การค้นหาสีที่ "เทียบเท่า" ด้วยความทึบ


92

สมมติว่าฉันมีสีพื้นหลังที่มี "ริบบิ้น" วิ่งทับเป็นสีทึบอื่น ตอนนี้ฉันต้องการให้ริบบิ้นโปร่งใสบางส่วนเพื่อให้รายละเอียดบางส่วนกลมกลืนกัน แต่ยังคงให้ริบบิ้น "สีเดียวกัน" อยู่เหนือพื้นหลัง

มีวิธี (ง่าย ๆ ) หรือไม่สำหรับความทึบ / อัลฟาที่กำหนดให้ <100% ของสีริบบิ้นค่า RGB ใดที่ควรจะต้องเหมือนกับสีของมันโดยมีความทึบ 100% บนพื้นหลัง

นี่คือภาพ พื้นหลังเป็นริบบิ้นrgb(72, 28, 97) rgb(45, 34, 70)ฉันต้องการrgba(r, g, b, a)ริบบิ้นเพื่อให้ดูเหมือนกับสีทึบนี้

ป้อนคำอธิบายภาพที่นี่


1
คุณสามารถดูคำถามที่คล้ายกันได้ที่นี่: stackoverflow.com/questions/6672374/convert-rgb-rgbaแต่ความแตกต่างที่สำคัญคือคำถามนั้นระบุสีพื้นฐานของสีขาวในขณะที่คำถามนี้เป็นสีตามอำเภอใจ
BoltClock

คำตอบ:


129

การผสมสีเป็นเพียงการแก้ไขเชิงเส้นต่อช่องใช่ไหม? ดังนั้นคณิตศาสตร์จึงค่อนข้างง่าย หากคุณมี RGBA1 มากกว่า RGB2 ผลลัพธ์ของภาพที่มีประสิทธิภาพ RGB3 จะเป็นดังนี้:

r3 = r2 + (r1-r2)*a1
g3 = g2 + (g1-g2)*a1
b3 = b2 + (b1-b2)*a1

…โดยที่ช่องอัลฟาอยู่ระหว่าง 0.0 ถึง 1.0

การตรวจสอบความสมบูรณ์: ถ้าอัลฟาเป็น 0 RGB3 จะเหมือนกับ RGB2 หรือไม่ ใช่. ถ้าอัลฟาคือ 1 RGB3 จะเหมือนกับ RGB1 หรือไม่ ใช่.

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

การเลือกสีตาม Alpha

หากคุณรู้จัก RGB3 (สีสุดท้ายที่ต้องการ), RGB2 (สีพื้นหลัง) และ A1 (ความทึบที่คุณต้องการ) และคุณกำลังมองหา RGB1 เราสามารถจัดเรียงสมการใหม่ได้ดังนี้:

r1 = (r3 - r2 + r2*a1)/a1
g1 = (g3 - g2 + g2*a1)/a1
b1 = (b3 - b2 + b2*a1)/a1

มีการผสมสีบางอย่างที่เป็นไปได้ในทางทฤษฎี แต่เป็นไปไม่ได้สำหรับช่วง RGBA มาตรฐาน ตัวอย่างเช่นหากพื้นหลังเป็นสีดำล้วนสีที่รับรู้ที่ต้องการคือสีขาวบริสุทธิ์และอัลฟ่าที่ต้องการคือ 1% คุณจะต้อง:

r1 = g1 = b1 = 255/0.01 = 25500

…สีขาวสว่างสุด 100 ×สว่างกว่าที่มีอยู่

เลือกอัลฟ่าตามสี

หากคุณรู้จัก RGB3 (สีสุดท้ายที่ต้องการ), RGB2 (สีพื้นหลัง) และ RGB1 (สีที่คุณต้องการเปลี่ยนความทึบ) และคุณกำลังมองหา A1 เราสามารถจัดเรียงใหม่ได้ สมการดังนั้น:

a1 = (r3-r2) / (r1-r2)
a1 = (g3-g2) / (g1-g2)
a1 = (b3-b2) / (b1-b2)

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


ไม่ได้r1, g1และb1ยังไม่ทราบ?
Eric

@ เอริกฉันไม่แน่ใจ ฉันได้แก้ไขคำตอบในกรณีที่เป็นระดับอัลฟาที่ทราบและสีที่ไม่ได้
Phrogz

โปรดทราบว่าฉันใช้สามสูตรแรกของคุณใน Photoshop เพื่อค้นหาว่าสีจะอยู่ที่ 0.8 อัลฟาเมื่อสีอ้างอิงอื่น ๆ ของฉันเป็นสีขาว ... ฉันต้องใช้ 1 + (1 - a) หรือ 1.2 เพื่อค้นหา สีที่ถูกต้อง ...
John William Domingo

1
@Phrogz ฉันใช้สมการ 'เลือกสีตามอัลฟา' ของคุณและฉันได้จำนวนลบ (-31) สำหรับช่องสีแดง เมื่อฉันใช้ค่าลบเป็นค่าสีแดงฉันจะได้ผลลัพธ์เหมือนกับว่าฉันใช้ 0 เป็นค่าสีแดง มีวิธีแปลงค่าลบนี้เป็นสิ่งที่ใช้ได้หรือไม่? เบาะแสเกี่ยวกับสิ่งที่เกิดขึ้นที่นี่?
Nocturno

บางทีการคำนวณของฉันปิดอยู่ แต่สูตรนี้ให้ผลลัพธ์ที่ไม่คาดคิดเมื่อ RGB3 = # 163920, RGB2 = #FFFFFF และ A1 = 0.92; RGB1 ที่คำนวณได้ = rgb (2, 40, 13) แต่ rgba (2, 40, 13, 0.92) = # 15381F ไม่ใช่ # 163920
ถึง

12

ฉันทำมิกซ์อินน้อยโดยใช้คำตอบของ Phrogz คุณป้อนข้อมูล:

  1. สีควรเป็นอย่างไร
  2. กับอัลฟ่าบางตัว
  3. บนพื้นหลังที่กำหนด (ค่าเริ่มต้นเป็นสีขาว)

นี่คือรหัส:

.bg_alpha_calc (@desired_colour, @desired_alpha, @background_colour: white) {
    @r3: red(@desired_colour);
    @g3: green(@desired_colour);
    @b3: blue(@desired_colour);

    @r2: red(@background_colour);
    @g2: green(@background_colour);
    @b2: blue(@background_colour);

    // r1 = (r3 - r2 + r2 * a1) / a1
    @r1: ( @r3 - @r2 + (@r2 * @desired_alpha) ) / @desired_alpha;
    @g1: ( @g3 - @g2 + (@g2 * @desired_alpha) ) / @desired_alpha;
    @b1: ( @b3 - @b2 + (@b2 * @desired_alpha) ) / @desired_alpha;

    background-color: @desired_colour;
    background-color: rgba(@r1, @g1, @b1, @desired_alpha);

}

การใช้งานดังนี้:

@mycolour: #abc;
@another_colour: blue;
.box_overlay {
  // example:
  .bg_alpha_calc (@mycolour, 0.97, @another_colour);
  // or (for white bg) just:
  .bg_alpha_calc (@mycolour, 0.97);
}

เห็นได้ชัดว่าใช้ไม่ได้กับชุดค่าผสมที่เป็นไปไม่ได้ (ตามที่กล่าวโดย Phrogz) นั่นหมายความว่ารองรับความโปร่งใสในระดับเล็กน้อยเท่านั้น ดูว่าคุณจะไปกับมัน


1
@mixin bg_alpha_calc ($ desire_colour, $ desire_alpha, $ background_colour: white) {$ r3: red ($ desire_colour) $ g3: สีเขียว ($ desire_colour); $ b3: สีฟ้า ($ desire_colour); $ r2: สีแดง ($ background_colour); $ g2: สีเขียว ($ background_colour); $ b2: สีน้ำเงิน ($ background_colour); // r1 = (r3 - r2 + r2 * a1) / a1 $ r1: ($ r3 - $ r2 + ($ r2 * $ ที่ต้องการ_alpha)) / $ ที่ต้องการ _alpha; $ g1: ($ g3 - $ g2 + ($ g2 * $ ที่ต้องการ _alpha)) / $ ที่ต้องการ _alpha; $ b1: ($ b3 - $ b2 + ($ b2 * $ ที่ต้องการ _alpha)) / $ ที่ต้องการ _alpha; พื้นหลังสี: $ ที่ต้องการ _colour; สีพื้นหลัง: rgba ($ r1, $ g1, $ b1, $ desire_alpha); }
metaColin

2
ฉันนำมาใช้และสร้างมิกซ์อินเวอร์ชัน SCSS ค้นหาการสาธิตและรหัสที่นี่: codepen.io/Grienauer/pen/Grogdx
Grienauer

@Grienauer ฉันทำแบบเดียวกันเป๊ะไม่รู้ว่าคุณแชร์แล้ว ข้อแตกต่างเพียงอย่างเดียวของฉันคือฉันตั้งค่าสีพื้นหลังเป็นสีขาว
tehlivi

7

ขอขอบคุณที่Phrogz 's และephemer ' s คำตอบที่ดีที่นี่เป็นฟังก์ชั่นที่ SASS โดยอัตโนมัติคำนวณสี RGBA เทียบเท่าที่ดีที่สุด

คุณเรียกมันด้วยสีที่ต้องการและพื้นหลังที่มีอยู่และมันจะคำนวณสี RGBA ที่เทียบเท่า (หมายถึงโปร่งใสที่สุด) ที่ดีที่สุดซึ่งให้ผลลัพธ์ที่ต้องการภายใน± 1/256 ของส่วนประกอบ RGB แต่ละตัว (เนื่องจากข้อผิดพลาดในการปัดเศษ):

@function alphaize($desired-color, $background-color) {

    $r1: red($background-color);
    $g1: green($background-color);
    $b1: blue($background-color);

    $r2: red($desired-color);
    $g2: green($desired-color);
    $b2: blue($desired-color);

    $alpha: 0;
    $r: -1;
    $g: -1;
    $b: -1;

    @while $alpha < 1 and ($r < 0 or $g < 0 or $b < 0
                           or $r > 255 or $g > 255 or $b > 255) {
        $alpha: $alpha + 1/256;
        $inv: 1 / $alpha;
        $r: $r2 * $inv + $r1 * (1 - $inv);
        $g: $g2 * $inv + $g1 * (1 - $inv);
        $b: $b2 * $inv + $b1 * (1 - $inv);
    }

    @return rgba($r, $g, $b, $alpha);
}

ฉันเพิ่งทดสอบกับชุดค่าผสมต่างๆ (ธีม Bootswatch ทั้งหมด) และมันก็ใช้งานได้ดีทั้งสำหรับผลลัพธ์ที่มืดบนแสงและแสงจากมืด

PS: หากคุณต้องการความแม่นยำที่ดีกว่า± 1/256 ในสีที่ได้คุณจะต้องรู้ว่าเบราว์เซอร์อัลกอริทึมการปัดเศษประเภทใดที่ใช้เมื่อผสมสี rgba (ฉันไม่รู้ว่าเป็นมาตรฐานหรือไม่) และเพิ่มความเหมาะสม ตามเงื่อนไขที่มีอยู่@whileเพื่อให้เพิ่มขึ้นเรื่อย ๆ$alphaจนกว่าจะได้ความแม่นยำที่ต้องการ


2
FYI ฟังก์ชั่นนี้มีอยู่ใน Stylus เป็นtransparentify(): stylus-lang.com/docs/bifs.html#transparentifytop-bottom-alpha ... ซึ่งฉันค้นพบหลังจากย้ายสิ่งนี้ด้วยตนเองไปยัง Stylus ...
weotch

6

จากคำตอบของ @Phrogz:

r3 = r2 + (r1-r2)*a1
g3 = g2 + (g1-g2)*a1
b3 = b2 + (b1-b2)*a1

ดังนั้น:

r3 - r2 = (r1-r2)*a1
g3 - g2 = (g1-g2)*a1
b3 - b2 = (b1-b2)*a1

ดังนั้น:

r1 = (r3 - r2) / a1 + r2
g1 = (g3 - g2) / a1 + g2
b1 = (b3 - b2) / a1 + b2

หมายเหตุคุณสามารถเลือกค่าใด ๆa1และจะพบว่าค่าที่สอดคล้องกันของr1, g1และb1จำเป็น ตัวอย่างเช่นการเลือกอัลฟ่าเป็น 1 เป็นการบอกว่าคุณต้องการ RGB1 = RGB3 แต่การเลือกอัลฟาเป็น 0 ไม่มีทางแก้ปัญหาใด ๆ


1

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

ฉันได้ลองใช้มิกซ์อินที่แตกต่างกัน แต่เนื่องจากข้อผิดพลาดในการปัดเศษฉันยังคงสามารถมองเห็นความแตกต่างได้ด้วยตาเปล่า


1
OP อาจต้องการวิธีในการตัดสินใจแบบไดนามิก แต่ไม่ได้ระบุไว้เป็นพิเศษและคำตอบของคุณให้แฮ็คที่ดีสำหรับการเลือกสีคงที่ / อัลฟา
Erik Knowles

0

หากต้องการขยายคำตอบของ @ Tobia และอนุญาตให้ระบุความทึบมากขึ้นเช่น transparentify:

@function rgbaMorph($desired-color, $background-color: rgb(255,255,255), $desired-alpha: 0) {

    $r1: red($desired-color);
    $g1: green($desired-color);
    $b1: blue($desired-color);

    $r2: red($background-color);
    $g2: green($background-color);
    $b2: blue($background-color);

    $r: -1;
    $g: -1;
    $b: -1;

    @if ($desired-alpha != 0) {
        $r: ( $r1 - $r2 + ($r2 * $desired-alpha) ) / $desired-alpha;
        $g: ( $g1 - $g2 + ($g2 * $desired-alpha) ) / $desired-alpha;
        $b: ( $b1 - $b2 + ($b2 * $desired-alpha) ) / $desired-alpha;
    }

    @if (($desired-alpha == 0) or ($r < 0 or $g < 0 or $b < 0
                           or $r > 255 or $g > 255 or $b > 255)) {
        //if alpha not attainable, this will find lowest alpha that is

        $alpha: $desired-alpha;
        @while $alpha < 1 and ($r < 0 or $g < 0 or $b < 0
                           or $r > 255 or $g > 255 or $b > 255) {
            $alpha: $alpha + 1/256;
            $inv: 1 / $alpha;
            $r: $r1 * $inv + $r2 * (1 - $inv);
            $g: $g1 * $inv + $g2 * (1 - $inv);
            $b: $b1 * $inv + $b2 * (1 - $inv);
        }
        @debug "Color not attainable at opacity using alpha: " $alpha " instead of: " $desired-alpha;

        $desired-alpha: $alpha;
    }

    @return rgba($r, $g, $b, $desired-alpha);
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.