使用不透明度查找“等效”颜色

时间:2012-09-01 14:24:50

标签: css css3 colors

假设我的背景颜色带有另一种纯色的“色带”。现在,我希望色带部分透明,让一些细节融合,但仍然保持色带在背景上的“相同颜色”。

对于给定的不透明度/ alpha<有没有办法(轻松)确定100%的色带颜色,它的RGB值必须与背景上100%不透明度的颜色相同吗?

这是一张照片。背景为rgb(72, 28, 97),功能区rgb(45, 34, 70)。我想要一个rgba(r, g, b, a)的色带,使它看起来与这个纯色相同。

enter image description here

7 个答案:

答案 0 :(得分:109)

颜色混合只是每个通道的线性插值,对吗?所以数学很简单。如果你有RGBA1而不是RGB2,有效的视觉结果RGB3将是:

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

... alpha通道的范围是0.0到1.0。

完整性检查:如果alpha为0,则RGB3与RGB2相同吗?是。如果alpha为1,则RGB3与RGB1相同吗?是。

如果仅锁定背景颜色和最终颜色,则可以满足要求的大量RGBA颜色(无限,在浮点空间中)。所以你必须选择你想要的条形颜色或不透明度,并找出另一个的值。

根据Alpha

选择颜色

如果您知道RGB3(最终所需的颜色),RGB2(背景颜色)和A1(您想要多少不透明度),并且您只是在寻找RGB1,那么我们可以重新排列方程式:< / p>

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

理论上可以使用一些颜色组合,但鉴于标准RGBA范围,这是不可能的。例如,如果背景是纯黑色,所需的感知颜色是纯白色,所需的alpha是1%,那么您需要:

r1 = g1 = b1 = 255/0.01 = 25500

...超亮白色100倍比任何可用的亮白色。

根据颜色挑选Alpha

如果你知道RGB3(最终所需的颜色),RGB2(背景颜色)和RGB1(你想要改变不透明度的颜色),你只需要找A1,那我们就可以了 - 因此安排方程式:

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

如果这些值给出不同的值,那么就无法使其完全匹配,但您可以平均alpha值以尽可能接近。例如,世界上没有任何不透明度会让你把绿色变成红色以获得蓝色。

答案 1 :(得分:12)

我使用Phrogz的答案做了一个LESS mixin。你输入:

  1. 颜色应该是什么样的
  2. 有一定的alpha
  3. 在给定的背景上(默认为白色)
  4. 以下是代码:

    .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所述),这意味着只支持轻微的透明度。看看你如何使用它。

答案 2 :(得分:7)

感谢 Phrogz ephemer 的精彩答案,这是一个SASS功能,自动计算最佳等效RGBA颜色。

您使用所需的颜色和现有背景调用它,它将计算最佳(意味着最透明)等效RGBA颜色,该颜色在每个RGB分量的±1/256范围内提供所需结果(由于舍入误差):

@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,直到达到所需的精度。

答案 3 :(得分:5)

来自@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的任何值,这会找到所需的r1g1b1的相应值。例如,选择1的alpha表示您需要RGB1 = RGB3,但是选择0的alpha不会给出解决方案(显然)。

答案 4 :(得分:1)

到目前为止,我发现的最实用的解决方案是:仅使用颜色选择器工具测量所得的颜色,然后将测得的颜色用于覆盖。这种方法可以提供完美的色彩匹配。

我尝试使用不同的mixins,但是由于舍入错误,我仍然可以用肉眼看到差异

答案 5 :(得分:0)

扩展@Tobia的答案,并允许指定不透明度,更像是透明化:

from scipy import stats
import time

# Start timer
start_time = time.time()

# Select only 'Variation of interest' and 'mean_age' columns
r1 = tdf [['1_944296_G/A', 'mean_age']]

# Use scipy lingress function to perform linear regression
slope, intercept, r_value, p_value, std_err = stats.linregress(tdf['mean_age'], \
    tdf['1_69270_A/G'])

print('The p-value between the 2 variables is measured as ' + str(p_value) + '\n')
print('Least squares linear model coefficients, intercept = ' + str(intercept) + \
  '. Slope = ' + str(slope)+'\n')

# Create regression line
regressLine = intercept + tdf['mean_age']*slope

# Regression using Theil-Sen with 95% confidence intervals 
res = stats.theilslopes(tdf['1_69270_A/G'], tdf['mean_age'], 0.95)

print('Thiel-Sen linear model coefficients, intercept = ' + str(res[1]) + '. Slope = ' + \
  str(res[0]) +'\n')

# Scatter plot the temperature
plt.clf()
plt.scatter(tdf['mean_age'], tdf['1_69270_A/G'], s = 3, label = 'Allele frequency')

# Add least squares regression line
plt.plot(tdf['mean_age'], regressLine, label = 'Least squares regression line'); 

# Add Theil-Sen regression line
plt.plot(tdf['mean_age'], res[1] + res[0] * tdf['mean_age'], 'r-', label = 'Theil-Sen regression line')

# Add Theil-Sen confidence intervals
plt.plot(tdf['mean_age'], res[1] + res[2] * tdf['mean_age'], 'r--', label = 'Theil-Sen 95% confidence interval')
plt.plot(tdf['mean_age'], res[1] + res[3] * tdf['mean_age'], 'r--')

# Add legend, axis limits and save to png
plt.legend(loc = 'upper left')
#plt.ylim(7,14); plt.xlim(1755, 2016)
plt.xlabel('Year'); plt.ylabel('Temperature (C)')
plt.savefig('pythonRegress.png')

# End timer
end_time = time.time()
print('Elapsed time = ' + str(end_time - start_time) + ' seconds')

答案 6 :(得分:0)

我编写了一个实用程序,可以从 JSS 中使用它来帮助我使颜色透明。它使用来自 material-ui 的实用方法,可以在 here 中找到。
这是我的实用程序类的代码(在 Typescript 中)。请注意,在保持颜色与目标颜色相同的情况下,无法使某些颜色透明。
请原谅我缺少 codepen 或可运行的代码。我希望有人发现这个并从中得到一些利用!

import {
  decomposeColor,
  recomposeColor,
  ColorObject,
} from '@material-ui/core/styles/colorManipulator';

/**
 * Take a non transparent color and create a transparent color that looks identical visually.
 * Using formula from this SO post https://stackoverflow.com/questions/12228548/finding-equivalent-color-with-opacity
 * Assuming a white background
 * @param origColor The color you want to match.
 * @param value Transparency value between 0 and 1. Cannot be too low because it is mathematically not possible (usually <0.2 but depends on the color)
 */
export const makeTransparent = (origColor: string, value: number): string => {
  const origColorObj: ColorObject = decomposeColor(origColor);

  if (value >= 1 || value <= 0)
    throw new Error('makeTransparent: invalid value provided');

  if (origColorObj.values[3] != null && origColorObj.values[3] !== 1)
    throw new Error('makeTransparent: origColor cannot be transparent');

  const newColorObj: ColorObject = {
    type: 'rgba',
    values: [0, 0, 0, value],
  };

  for (let i = 0; i < 3; i++) {
    const rgbNum: number = (255 * value + origColorObj.values[i] - 255) / value;

    if (rgbNum < 0 || rgbNum > 255)
      throw new Error('makeTransparent: Transparency value too low');

    newColorObj.values[i] = rgbNum;
  }

  return recomposeColor(newColorObj);
};