Calculate Sum Opacity from Layers

Calculate sum opacity from layers

Here is StackOverflow question addressing this issue HERE

In your case first div block 70% background light (since opacity is 0.7). Another div which sits on top of that block more 70% background light of remaining visible light.

Thus,

Total Opacity = First Opacity + (100 - First Opacity) * Second Opacity
= 0.7 + (1 - 0.7) * 0.7
= 0.7 + (0.3) * 0.7
= 0.7 + 0.21
= 0.91

Thus you should use opacity 0.91 OR 91% for your third div.

CSS overlapping elements & opacity issue

Try and think of it like percentage sales. It's a bit different, but the analogy gives sense of what's happening. When a $10 item is 80% off, then you take off an additional 20%, it's' not 100% off (80% + 20%). You calculate final price like this:

$10 * (1 - 0.8)  = $2 * (1 - 0.2) = $1.60.

50% opacity means, 50% of the light is blocked. So when you stack two 50% opacity elements, that means 50% of the light is blocked and 50% more light is blocked by the additional layer. Since only 50% light is coming through the first layer, only 50% of that additional light is blocked. So the calculation would be:

50% + (50% * 50%) = 75% opacity.

DEMO

.num2 {
opacity: 0.75;
}

Transparency to Opacity conversion

The formula is

opacity = 1 - (transparency/100)

You can easily verify it works:

  • Transparency=0 leads to opacity=1
  • Transparency=100 leads to opacity=0
  • Transparency=50 leads to opacity=0.5

How does SVG opacity stack?

The answer is 0.6667.

The rule is that transparency combines by multiplication. So if you have two overlapping objects with transparencies of 60% and 33.33%, then the transparency of the overlapping region will be (0.6 × 0.3333) = 0.2.

An object's alpha value is equal to 1 minus its transparency, so the combination of α=0.4 and α=0.6667 is equal to 1 - (1-0.4) × (1-0.6667) = 1 - 0.6 × 0.3333 = 1 - 0.2 = 0.8.

By way of illustration, here's an SVG image containing two overlapping circles with alpha values of 0.4 and 0.6667 next to a solid circle filled with 80% black (#333):

<svg width="340" height="200" viewBox="0 0 340 200">  <circle cx="100" cy="80" r="60" fill="#000" opacity="0.4" />  <circle cx="100" cy="120" r="60" fill="#000" opacity="0.6667" />  <circle cx="180" cy="100" r="60" fill="#333" opacity="1" />  <text x="0" y="30">α=0.4</text>  <text x="0" y="180">α=0.6667</text>  <text x="250" y="110">80% black</text></svg>

Control alpha blending / opacity of n overlapping areas

Adding to @MKBakker's answer, one could use a function to predict the resulting alpha from any number of layers and alpha values:

alpha_out <- function(alpha, num = 1) {
result = alpha
if(num == 1) return(result)
for(i in 2:num) { result = result + alpha * (1-result) }
return (result)
}

alpha_out(0.33, 1)
#[1] 0.33
alpha_out(0.33, 2)
#[1] 0.5511
alpha_out(0.33, 3)
#[1] 0.699237

This makes it easier to see that alpha asymptotically approaches 1 with more layers.

alpha_out(0.33, 40)
#[1] 0.9999999

If one presumes that 0.99 is "close enough," you need to use 0.8 to get there with three layers

alpha_out(0.8, 3)
#[1] 0.992

EDIT: Added chart of results

We can see what results we'd get from a range of alphas and layers:

library(tidyverse)
alpha_table <-
tibble(
alpha = rep(0.01*1:99, 10),
layers = rep(1:10, each = 99)
)

alpha_table <- alpha_table %>%
rowwise() %>%
mutate(result = alpha_out(alpha, layers))

ggplot(alpha_table, aes(alpha, result, color = as_factor(layers),
group = layers)) +
geom_line()

Sample Image

And we can also see how much alpha we need to pass a threshold of combined opacity, given each number of layers. For instance, here's how much alpha you need to reach 0.99 total opacity for a given number of layers. For 5 layers, you need alpha = 0.61, for instance.

alpha_table %>%
group_by(layers) %>%
filter(result >= 0.99) %>%
slice(1)
## A tibble: 10 x 3
## Groups: layers [10]
# alpha layers result
# <dbl> <int> <dbl>
# 1 0.99 1 0.99
# 2 0.9 2 0.99
# 3 0.79 3 0.991
# 4 0.69 4 0.991
# 5 0.61 5 0.991
# 6 0.54 6 0.991
# 7 0.49 7 0.991
# 8 0.44 8 0.990
# 9 0.41 9 0.991
#10 0.37 10 0.990

All this to say that I don't think there is a simple implementation to get what you're looking for. If you want 100% dark in the overlapped area, you might try these approaches:

  • image manipulation after the fact (perhaps doable using imagemagick) to apply a brightness curve to make the dark areas 100% black and make the others scale to the darkness levels you expect.

  • convert the graph to an sf object and analyze the shapes to somehow count how many shapes are overlapping at any given point. You could then manually map those to the darkness levels you want.

How to perform weighted sum of colors in python?

The issue isn't the color model, it's assumptions about the model and medium.

A simple linear model for mixing may not be accurate, but it may suffice, depending on the code's purpose.

In the case of printing ink, a large part of the perceived color is the surface you're printing on, which isn't part of a color model (though it may be part of a color profile).

Pigments are also subtractive, rather than additive; this can be considered an attribute of the color model. Note RGB is additive, which is one reason it isn't a good model for inks. CMYK is the most-used color model in printing, but even then it's not a direct representation of printed colors. Instead, CMYK colors should be mapped to a profile that's particular to the printer, inks and paper used.

With your current implementation (and assumption of a subtractive linear color model), you would need to subtract the weighted sum from white.

white = np.array((1,) * 3)
# subtractive:
printed_color = white - mixed_colors

You could also pre-process the palette and transform it into an additive space:

palette = [white - color for color in palette]
# or
palette = white - np.array(palette)

In the case of rendering on screen, what you have as "weight" is the channel opacity. In image formats that have separate layers for each channel, mixing as you require is easily accomplished simply by setting each layer's opacity. For other formats, you can separate the channels and then apply an opacity to each.

How to make two transparent layer with c#?

If you need a control support transparency, you should override painting of the control and draw the control in this order:

  • Draw all controls in the same container which are under your control (based on z-index) on a bitmap.
  • Then draw that bitmap on graphics of your control.
  • At last draw content of your control.
  • Also the BackColor of your control should be Color.Transparent.

Here is the result of creating TransparentLabel and TransparentPictureBox controls. In the below image, there is label, image, label, image and then label in order and as you can see picture boxes and labels has been rendered having transparent background and respecting the z-index:

Sample Image

Transparent Label

class TransparentLabel : Label
{
public TransparentLabel()
{
this.BackColor = Color.Transparent;
}
protected override void OnPaint(PaintEventArgs e)
{
if (Parent != null && this.BackColor == Color.Transparent)
{
using (var bmp = new Bitmap(Parent.Width, Parent.Height))
{
Parent.Controls.Cast<Control>()
.Where(c => Parent.Controls.GetChildIndex(c) > Parent.Controls.GetChildIndex(this))
.Where(c => c.Bounds.IntersectsWith(this.Bounds))
.OrderByDescending(c => Parent.Controls.GetChildIndex(c))
.ToList()
.ForEach(c => c.DrawToBitmap(bmp, c.Bounds));

e.Graphics.DrawImage(bmp, -Left, -Top);

}
}
base.OnPaint(e);
}
}

Transparent PictureBox

class TransparentPictureBox : PictureBox
{
public TransparentPictureBox()
{
this.BackColor = Color.Transparent;
}
protected override void OnPaint(PaintEventArgs e)
{
if (Parent != null && this.BackColor==Color.Transparent)
{
using (var bmp = new Bitmap(Parent.Width, Parent.Height))
{
Parent.Controls.Cast<Control>()
.Where(c => Parent.Controls.GetChildIndex(c) > Parent.Controls.GetChildIndex(this))
.Where(c => c.Bounds.IntersectsWith(this.Bounds))
.OrderByDescending(c => Parent.Controls.GetChildIndex(c))
.ToList()
.ForEach(c => c.DrawToBitmap(bmp, c.Bounds));

e.Graphics.DrawImage(bmp, -Left, -Top);

}
}
base.OnPaint(e);
}
}


Related Topics



Leave a reply



Submit