การแปลง RGB เป็นระดับสีเทา / ความเข้ม


130

เมื่อแปลงจาก RGB เป็นโทนสีเทามีการกล่าวว่าควรใช้น้ำหนักเฉพาะสำหรับช่อง R, G และ B น้ำหนักเหล่านี้คือ 0.2989, 0.5870, 0.1140

ว่ากันว่าเหตุผลนี้คือการรับรู้ / ความรู้สึกของมนุษย์ที่แตกต่างกันต่อสีทั้งสามนี้ บางครั้งก็มีการกล่าวว่านี่คือค่าที่ใช้ในการคำนวณสัญญาณ NTSC

อย่างไรก็ตามฉันไม่พบข้อมูลอ้างอิงที่ดีสำหรับเรื่องนี้บนเว็บ ที่มาของค่าเหล่านี้คืออะไร?

ดูเพิ่มเติมคำถามก่อนหน้านี้: ที่นี่และที่นี่


26
ใช่แล้ว. ฉันเขียนโปรแกรมเกี่ยวกับค่า RGB ตลอดเวลา การใช้ค่า "โลกแห่งความจริง" ในการคำนวณเหล่านี้มีความสำคัญมากหากคุณต้องการให้แอปของคุณคุ้มค่า
Neil N

1
โปรแกรมเมอร์หลายคนอาจไม่สนใจและคำนวณภาพระดับสีเทาที่ "ผิด" แต่ฉันเข้าใจ
ypnos

6
ฉันยอมรับว่ามันเกี่ยวข้องกับการเข้ารหัส - เป็นปัญหาที่น่าสนใจและเกี่ยวข้องอย่างท้าทายหากคุณกำลังเข้ารหัสกราฟิก +1 เพราะฉันอยากรู้คำตอบด้วยตัวเอง
Cruachan

6
RGB เป็นโปรแกรมที่เกี่ยวข้อง เป็นการเขียนโปรแกรมที่เกี่ยวข้องกับการแยกวิเคราะห์สตริงวันที่ เป็นการแปลงข้อความ "true" เป็นค่าบูลีน
Neil N

คำตอบ:


87

ตัวเลขเฉพาะในคำถามมาจาก CCIR 601 (ดูลิงก์ Wikipedia ด้านล่าง)

หากคุณแปลง RGB -> โทนสีเทาด้วยตัวเลขที่แตกต่างกันเล็กน้อย / วิธีการต่างๆคุณจะไม่เห็นความแตกต่างมากนักบนหน้าจอคอมพิวเตอร์ปกติภายใต้สภาพแสงปกติ - ลองใช้

ลิงค์เพิ่มเติมเกี่ยวกับสีโดยทั่วไปมีดังนี้:

วิกิพีเดียLuma

เว็บไซต์ที่โดดเด่นของBruce Lindbloom

บทที่ 4 เรื่องสีในหนังสือโดย Colin Ware, "Information Visualization", isbn 1-55860-819-2; ลิงก์แบบยาวนี้ไปยัง Ware ในbooks.google.com อาจใช้งานได้หรือไม่ก็ได้

cambridgeincolor : บทแนะนำที่ยอดเยี่ยมและมีการเขียนอย่างดีเกี่ยวกับวิธีการได้มาตีความและประมวลผลภาพถ่ายดิจิทัลโดยใช้วิธีการที่เน้นภาพที่เน้นแนวคิดมากกว่าขั้นตอน "

หากคุณพบ RGB แบบ "linear" กับ "nonlinear" นี่เป็นส่วนหนึ่งของบันทึกเก่า ๆ สำหรับตัวเอง ทำซ้ำในทางปฏิบัติคุณจะไม่เห็นความแตกต่างมากนัก


RGB -> ^ แกมม่า -> Y -> L *

ในวิทยาการสีค่า RGB ที่พบบ่อยเช่นใน html rgb (10%, 20%, 30%) จะถูกเรียกว่า "ไม่เชิงเส้น" หรือ แกมมาแก้ไข ค่า "Linear" ถูกกำหนดเป็น

Rlin = R^gamma,  Glin = G^gamma,  Blin = B^gamma

โดยที่ gamma คือ 2.2 สำหรับพีซีหลายเครื่อง RGB ปกติบางครั้งจะเขียนเป็น R 'G' B '(R' = Rlin ^ (1 / gamma)) (คลิกลิ้นที่บริสุทธิ์) แต่ที่นี่ฉันจะปล่อย '

ความสว่างบนจอแสดงผล CRT เป็นสัดส่วนกับ RGBlin = RGB ^ gamma ดังนั้น 50% สีเทาบน CRT จึงค่อนข้างมืด: .5 ^ 2.2 = 22% ของความสว่างสูงสุด (จอ LCD มีความซับซ้อนมากขึ้นนอกจากนี้กราฟิกการ์ดบางรุ่นยังชดเชยแกมมาด้วย)

หากต้องการวัดความสว่างที่เรียกL*จาก RGB ให้แบ่ง RGB ด้วย 255 ก่อนแล้วคำนวณ

Y = .2126 * R^gamma + .7152 * G^gamma + .0722 * B^gamma

นี่คือYพื้นที่สี XYZ มันเป็นการวัด "ความส่องสว่าง" ของสี (สูตรจริงไม่ใช่แกมมา x ^ แต่ปิดให้ใช้ x ^ gamma ในการส่งครั้งแรก)

สุดท้าย

L* = 116 * Y ^ 1/3 - 16

"... ปรารถนาที่จะรับรู้ความเท่าเทียมกัน [และ] อย่างใกล้ชิดกับการรับรู้ของมนุษย์เกี่ยวกับความสว่าง" - พื้นที่สีของ Wikipedia Lab


8
Y = 0.2126 * R + 0.7152 * G + 0.0722 * B - Wikipedia ( en.wikipedia.org/wiki/Grayscale )
iamantony

14

ฉันพบว่าสิ่งพิมพ์นี้อ้างถึงในคำตอบของคำถามที่คล้ายกันก่อนหน้านี้ เป็นประโยชน์มาก:

http://cadik.posvete.cz/color_to_gray_evaluation/

มันแสดงวิธีการต่างๆ 'มากมาย' ในการสร้างภาพระดับสีเทาพร้อมผลลัพธ์ที่แตกต่างกัน!


9

นี่คือรหัสบางส่วนใน c เพื่อแปลง rgb เป็นสีเทา น้ำหนักจริงที่ใช้สำหรับการแปลง rgb เป็นสีเทาคือ 0.3R + 0.6G + 0.11B น้ำหนักเหล่านี้ไม่สำคัญอย่างยิ่งดังนั้นคุณสามารถเล่นกับมันได้ ฉันทำให้พวกเขา 0.25R + 0.5G + 0.25B ทำให้ภาพมืดลงเล็กน้อย

หมายเหตุ: โค้ดต่อไปนี้ถือว่าเป็นรูปแบบพิกเซล xRGB 32 บิต

unsigned int *pntrBWImage=(unsigned int*)..data pointer..;  //assumes 4*width*height bytes with 32 bits i.e. 4 bytes per pixel
unsigned int fourBytes;
        unsigned char r,g,b;
        for (int index=0;index<width*height;index++)
        {
            fourBytes=pntrBWImage[index];//caches 4 bytes at a time
            r=(fourBytes>>16);
            g=(fourBytes>>8);
            b=fourBytes;

            I_Out[index] = (r >>2)+ (g>>1) + (b>>2); //This runs in 0.00065s on my pc and produces slightly darker results
            //I_Out[index]=((unsigned int)(r+g+b))/3;     //This runs in 0.0011s on my pc and produces a pure average
        }

2
0.3 0.6 0.11 อย่าเพิ่มใน 1 Wikipedia ดูเหมือนจะแนะนำ 0.30 0.59 0.11
damix911

จริง แต่ผลลัพธ์เดียวของพวกเขาที่ไม่เพิ่มเป็น 1 จะเป็นการเปลี่ยนแปลงความเข้มเล็กน้อยมาก วิธีที่เสนอ 0.25,0.5,0.25 จะเพิ่มเป็น 1 แต่มันจะไม่สำคัญถ้ามันไม่ได้ เป็นการเพิ่มประสิทธิภาพดังนั้นการละทิ้งความแม่นยำเล็กน้อยจึงเป็นการแลกเปลี่ยนที่สมเหตุสมผล
twerdster

2
@twerdster ทั้งสองชุดของสัมประสิทธิ์ไม่ถูกต้อง .3, .6, .11 เป็นมาตรฐาน NTSC แบบเก่าไม่ใช่ sRGB / Rec709 (ซึ่งเป็นสิ่งที่เว็บและคอมพิวเตอร์ส่วนใหญ่ใช้) และ 0.25,0.5,0.25 ของคุณไม่ใช่การแลกเปลี่ยนที่สมเหตุสมผล - B เป็นเพียง 7% ของความส่องสว่างคุณผิด 347% ค่าสัมประสิทธิ์สำหรับ sRGB / r709 (หลังการทำให้เป็นเส้นตรง): Rlin * 0.2126 + Glin * 0.7152 + Blin * 0.0722 = Yน้ำหนักสเปกตรัมเหล่านี้ได้มาจากการรับรู้ทางสเปกตรัมของมนุษย์ คุณไม่สามารถติดขัดตัวเลขใดก็ได้ที่คุณต้องการเพื่อความสะดวกและหวังว่าจะแม่นยำ คุณต้องทำให้ sRGB เป็นเส้นตรงแล้วใช้สัมประสิทธิ์ที่ถูกต้อง
Myndex

0.11111111 * ((G + (G<<1) + R) <<1) + B)ถ้าคุณอยู่ในสถานการณ์ที่แบ่งแพงเกินไปประมาณที่ใช้คูณเดียวที่มีการเปลี่ยนแปลงและเพิ่มเป็น: นี้จะเทียบเท่ากับหรือ(2*R+6*G+B) / 9) 0.222 R + 0.666 G + 0.111 Bก่อนนำไปผลิตให้เปรียบเทียบกับสูตรที่แม่นยำสำหรับกรณีทดสอบต่างๆ
ToolmakerSteve


6

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


3

ที่มาของค่าเหล่านี้คืออะไร?

"การที่มา" ของสัมประสิทธิ์ที่โพสต์เป็นข้อกำหนด NTSC ซึ่งสามารถเห็นได้ในRec601และลักษณะของโทรทัศน์

"แหล่งที่มาที่ดีที่สุด" คือการทดลอง CIE เมื่อประมาณปีพ. ศ. 2474 เกี่ยวกับการรับรู้สีของมนุษย์ การตอบสนองทางสเปกตรัมของการมองเห็นของมนุษย์ไม่สม่ำเสมอ การทดลองนำไปสู่การให้น้ำหนักของค่า tristimulus ตามการรับรู้ กรวย L, M และ S 1 ของเรามีความไวต่อความยาวคลื่นแสงที่เราระบุว่าเป็น "แดง" "เขียว" และ "น้ำเงิน" (ตามลำดับ) ซึ่งเป็นที่มาของสีหลักของ tristimulus 2

น้ำหนักเชิงเส้น3สเปกตรัมสำหรับ sRGB (และ Rec709) คือ:

R lin * 0.2126 + G lin * 0.7152 + B lin * 0.0722 = Y

สิ่งเหล่านี้มีไว้เฉพาะสำหรับ sRGB และ Rec709 colorspaces ซึ่งมีไว้เพื่อแสดงหน้าจอคอมพิวเตอร์ (sRGB) หรือจอภาพ HDTV (Rec709) และมีรายละเอียดอยู่ในเอกสาร ITU สำหรับRec709และBT.2380-2 (10/2018)

FOOTNOTES (1) โคนเป็นเซลล์ตรวจจับสีของเรตินาของดวงตา
(2) อย่างไรก็ตามความยาวคลื่น tristimulus ที่เลือกไม่ได้อยู่ที่ "จุดสูงสุด" ของกรวยแต่ละประเภท - แทนที่จะเลือกค่า tristimulus เพื่อกระตุ้นให้เกิดกรวยชนิดใดชนิดหนึ่งมากกว่าค่าอื่นอย่างมากนั่นคือการแยกสิ่งเร้า
(3) คุณต้องกำหนดค่า sRGB ให้เป็นเส้นตรงก่อนที่จะใช้สัมประสิทธิ์ ฉันพูดถึงเรื่องนี้ในคำตอบอื่นที่นี่


-2

ค่าเหล่านี้แตกต่างกันไปในแต่ละบุคคลโดยเฉพาะอย่างยิ่งสำหรับผู้ที่ตาบอดสี


-4

ทั้งหมดนี้จำเป็นจริงๆการรับรู้ของมนุษย์และ CRT เทียบกับ LCD จะแตกต่างกันไป แต่ความเข้มของ RGB ไม่เป็นเช่นนั้นทำไมไม่L = (R + G + B)/3ตั้งค่า RGB ใหม่เป็น L, L, L?


3
เพียงแค่การเฉลี่ยไพรมารี R, G, B ทั้งสามก็ถือว่าพวกเขาเท่าเทียมกันซึ่งไม่ใช่กรณีของระบบการมองเห็นของมนุษย์
Bill Feth
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.