簡體   English   中英

在“圖形”中,什么時候需要考慮Gamma?

[英]In Graphics, when do I need to account for Gamma?

因此,我有一些旨在在兩種輸入顏色之間生成線性漸變的代碼:

struct color {
    float r, g, b, a;
}

color produce_gradient(const color & c1, const color & c2, float ratio) {
    color output_color;
    output_color.r = c1.r + (c2.r - c1.r) * ratio;
    output_color.g = c1.g + (c2.g - c1.g) * ratio;
    output_color.b = c1.b + (c2.b - c1.b) * ratio;
    output_color.a = c1.a + (c2.a - c1.a) * ratio;
    return output_color;
}

我也已經在着色器中編寫了(在語義上是相同的)代碼。

問題在於,由於亮度在計算機屏幕和用於表示這些像素的原始數據之間如何轉換的怪癖,使用這種代碼在中間的顏色會產生“暗帶”。

所以我的問題是:

  • 我是否需要校正主機功能,設備功能(兩者)或兩者都不校正?
  • 糾正功能以正確處理伽瑪的最佳方法是什么? 我在下面提供的代碼是否以適當的方式轉換了顏色?

碼:

color produce_gradient(const color & c1, const color & c2, float ratio) {
    color output_color;
    output_color.r = pow(pow(c1.r,2.2) + (pow(c2.r,2.2) - pow(c1.r,2.2)) * ratio, 1/2.2);
    output_color.g = pow(pow(c1.g,2.2) + (pow(c2.g,2.2) - pow(c1.g,2.2)) * ratio, 1/2.2);
    output_color.b = pow(pow(c1.b,2.2) + (pow(c2.b,2.2) - pow(c1.b,2.2)) * ratio, 1/2.2);
    output_color.a = pow(pow(c1.a,2.2) + (pow(c2.a,2.2) - pow(c1.a,2.2)) * ratio, 1/2.2);
    return output_color;
}

編輯:作為參考,這是與此問題相關的帖子,目的是解釋實踐中“錯誤”的外觀: https : //graphicdesign.stackexchange.com/questions/64890/in-gimp-how-我可以使塗抹模糊工具正常工作嗎

我認為您的代碼中存在缺陷。 首先,我要確保0 <= ratio <=1

第二我將使用公式c1.x * (1-ratio) + c2.x *ratio

您目前進行計算的方式會產生負面結果,這可以解釋黑點。

當您不得不擔心伽瑪時,沒有輕拍的答案。

在混合,混合,計算照明等時,通常需要在線性色彩空間中工作。

如果您的輸入不在線性空間中(例如,經過伽瑪校正或在諸如sRGB之類的某些顏色空間中),則通常需要立即將它們轉換為線性。 您尚未告訴我們您的輸入是否為線性RGB。

完成后,無論是簡單的gamma轉換還是其他色彩空間轉換,都希望確保針對輸出設備的色彩空間校正了線性值。 同樣,這里沒有拍拍的答案,因為您必須知道轉換是在堆棧的較低級別隱式完成的,還是您的責任。

就是說,很多代碼都與作弊無關。 他們將以sRGB形式輸入其輸入,並像在線性RGB中一樣應用alpha混合或淡入,然后按原樣輸出結果(可能帶有鉗位)。 有時候,這是一個合理的權衡。

您的問題完全出在感知色彩實現領域。 要照顧到感知的亮度偏差,您可以使用在線找到的許多算法之一, Luma這樣的算法

float luma(color c){
return 0.30 * c.r + 0.59 * c.g + 0.11 * c.b;
}

在這一點上,我想指出的是,標准方法是將所有算法應用於感知顏色空間,然后轉換為rgb顏色空間進行顯示。

colorRGB- (轉換)-> colorPerceptual- (輸入)-> f( colorPerceptual )-(輸出)-> colorPerceptual' -(轉換)-> colorRGB

但是,如果您只想調整亮度(感知色差不會固定),則可以按照以下方式高效地進行調整

//define color of unit lightness. based on Luma algorithm 
color unit_l(1/0.3/3, 1/0.59/3, 1/0.11/3);

color produce_gradient(const color & c1, const color & c2, float ratio) {
    color output_color;
    output_color.r = c1.r + (c2.r - c1.r) * ratio;
    output_color.g = c1.g + (c2.g - c1.g) * ratio;
    output_color.b = c1.b + (c2.b - c1.b) * ratio;
    output_color.a = c1.a + (c2.a - c1.a) * ratio;

    float target_lightness = luma(c1) + (luma(c2) - luma(c1)) * ratio; //linearly interpolate perceptual lightness
    float delta_lightness = target_lightness - luma(output_color); //calculate required lightness change magnitude

    //adjust lightness
    output_color.g += unit_l.r * delta_lightness;
    output_color.b += unit_l.g * delta_lightness;
    output_color.a += unit_l.b * delta_lightness;

    //at this point luma(output_color) approximately equals target_lightness which takes care of the perceptual lightness aberrations

    return output_color;
}

您的第二個代碼示例完全正確,只是alpha通道通常未經過伽馬校正,因此您不應在其上使用pow 為了提高效率,最好對每個通道進行一次伽馬校正,而不要加倍。

一般規則是,無論何時添加或減去值,都必須在兩個方向上進行伽馬。 如果只乘或除,則沒有區別: pow(pow(x, 2.2) * pow(y, 2.2), 1/2.2)在數學上等效於x * y

有時,您可能會發現在未校正的空間中工作可獲得更好的結果。 例如,如果要調整圖像的大小,則應在縮小圖像時進行伽瑪校正,而在放大圖像時則不應進行伽瑪校正。 我忘記了我在哪里讀的書,但我自己進行了驗證-如果您使用的是經過伽瑪校正的像素值與線性像素值,則放大帶來的偽影就不會那么令人討厭。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM