11# Color Averaging
22
3- Color averaging is the process of calculating an average color from a set of other colors by taking the mean of each
4- color channel.
3+ Color averaging is the process taking multiple colors and calculating an average color from them, essentially mixing
4+ all the colors together. This involves looking at each color channel of all colors under consideration and averaging
5+ and averaging each channel independently. Additionally, by default, transparency is taken into account by using
6+ premultiplication which weights the colors such that more opaque colors have a greater significance in the mixing vs
7+ more translucent colors.
8+
9+ ![ Average RGB] ( images/avg-rgb.png )
10+
511
612Averaging under ColorAide can take as many colors as desired and will return a color that represents the average. This
7- is not to be confused with interpolation which employs a different technique, but in certain situations, it can sort of
8- function like mixing multiple colors.
13+ is not to be confused with interpolation which employs a different technique. One thing that sets it apart from
14+ interpolation is that when performing the operation, the order of the colors does not matter and will yield the same
15+ results even the colors are shuffled.
16+
17+ Averaging can be used as a way to mix multiple colors into one color or simply determine what the overall average color
18+ is from a set of colors. Results are subject to the geometry of the color space in which the average is performed.
919
1020## Rectangular Space Averaging
1121
12- ColorAide, by default, averages in rectangular color spaces, the default being Linear sRGB. If desired, other color
13- spaces can be used, such as perceptually uniform spaces like Oklab .
22+ ColorAide, by default, averages in the rectangular Linear sRGB color spaces . If desired, other color spaces can be used.
23+ Results will vary due to the geometry of the color space being used .
1424
1525``` py play
1626Color.average([' red' , ' blue' ])
1727Color.average([' red' , ' blue' ], space = ' srgb' )
1828Color.average([' red' , ' blue' ], space = ' oklab' )
1929```
2030
21- Averaging is not restricted to any certain amount of colors.
31+ Averaging can be applied to any amount of colors.
2232
2333``` py play
2434Color.average([' red' , ' yellow' , ' orange' , ' green' ])
2535```
2636
2737## Cylindrical Space Averaging
2838
29- ColorAide can average colors in rectangular spaces and cylindrical spaces. When applying averaging in a cylindrical
30- space, hues will be averaged taking the circular mean.
31-
32- Colors that appear to be achromatic will have their hue treated as undefined, even if the hue is defined.
33-
34- Cylindrical averaging may provide very different results that averaging in rectangular spaces.
39+ ColorAide can also average colors in cylindrical spaces. When applying averaging in a cylindrical space, hues will be
40+ averaged taking the circular mean. Due the difference in approach, colors can be quite different.
3541
3642``` py play
3743Color.average([' purple' , ' green' , ' blue' ])
3844Color.average([' purple' , ' green' , ' blue' ], space = ' hsl' )
3945```
4046
41- It should be noted that when averaging colors with hues which are evenly distributed around the color wheel, the result
47+ Colors that are deemed achromatic will have their hue treated as undefined, even if the hue is defined. This is to
48+ ensure that the average color makes sense and isn't tainted by a non-functional hue.
49+
50+ ``` py play
51+ Color.average([' white' , ' blue' ], space = ' hsl' )
52+ ```
53+
54+ It should be noted that when averaging colors with hues which are evenly distributed around color space, the result
4255will produce an achromatic hue. When achromatic hues are produced during circular mean, the color will discard
4356chroma/saturation information, producing an achromatic color.
4457
4558``` py play
4659Color.average([' red' , ' green' , ' blue' ], space = ' hsl' )
4760```
4861
62+ ## Weighted Averaging
63+
64+ To allow for greater control and nuance of mixing multiple colors, ColorAide allows weights to be defined to adjust how
65+ much a specific color is mixed relative to other colors.
66+
67+ As an example, let's assume we wanted to mix ` #!color orange ` and ` #!color red ` but brighten it up with ` #!color white ` .
68+ More specifically, let's say we want 4 times the amount of white for every 1 part of the other colors. We can simply
69+ specify weights intuitively as ` #!py [1, 1, 4] ` .
70+
71+
72+ ``` py play
73+ Color.average([' orange' , ' red' , ' white' ])
74+ Color.average([' orange' , ' red' , ' white' ], [1 , 1 , 4 ])
75+ ```
76+
77+ ![ Weighted Average] ( images/avg-weighted.png )
78+
79+ Regardless of how big or small the numbers are, they are scaled relative to the largest value, so internally,
80+ ` #!py [1, 1, 4] ` and ` #!py [0.25, 0.25, 1] ` are essentially the same.
81+
82+ ``` py play
83+ Color.average([' orange' , ' red' , ' white' ], [1 , 1 , 4 ])
84+ Color.average([' orange' , ' red' , ' white' ], [0.25 , 0.25 , 1 ])
85+ ```
86+
87+ If more weights are provided that there are colors, the only the weights sufficient to satisfy the number of colors
88+ is consumed.
89+
90+ ``` py play
91+ Color.average([' orange' , ' red' , ' white' ], [1 , 1 , 4 , 2 , 1 ])
92+ ```
93+
94+ If more colors are provided than weights, colors without defined weights are assumed to be full weight.
95+
96+ ``` py play
97+ Color.average([' orange' , ' red' , ' white' ], [0 , 1 ])
98+ ```
99+
100+ /// note
101+ It should be noted that negative weights are not allowed and will be clipped to zero, which treats the colors as if it
102+ is not included at all.
103+ ///
104+
49105## Averaging with Transparency
50106
51107ColorAide, by default, will account for transparency when averaging colors. Colors which are more transparent will have
@@ -59,11 +115,11 @@ for i in range(12):
59115 )
60116```
61117
62- There are cases where this approach of averaging may not be desired. It may be that color averaging is desired without
63- considering transparency. If so, ` premultiplied ` can be disabled by setting it to ` #!py False ` . While the average of
64- transparency is calculated, it can be discarded from the final result if desired.
118+ There are cases where this approach of averaging may not be desired and results are desired without considering
119+ transparency. If so, ` premultiplied ` can be disabled by setting it to ` #!py False ` . While the average of transparency is
120+ still calculated, it can be discarded from the final result if desired.
65121
66- It should be noted that when a color is fully transparent, its color components will be ignored, regardless of the
122+ It should also be noted that when a color is fully transparent, its color components will be ignored, regardless of the
67123` premultiplied ` parameter, as fully transparent colors provide no meaningful color information.
68124
69125``` py play
@@ -76,8 +132,10 @@ for i in range(12):
76132
77133## Averaging with Undefined Values
78134
79- When averaging with undefined values, ColorAide will not consider the undefined values in the average. This is mainly
80- provided for averaging cylindrical colors, particularly achromatic colors.
135+ When averaging with undefined values, ColorAide will not consider the undefined values in the average. In short, it
136+ will be treated as if there was no value contributing to the average. This is mainly provided for sane averaging of
137+ achromatic colors in cylindrical/polar color spaces. With that said, any channel that has manually specified a channel
138+ as undefined will be treated in this manner.
81139
82140``` py play
83141Color.average([' white' , ' color(srgb 0 0 1)' ], space = ' hsl' )
@@ -90,17 +148,17 @@ distort the average in a non-meaningful way.
90148Color.average([' hsl(30 0 100)' , ' hsl(240 100 50 / 1)' ], space = ' hsl' )
91149```
92150
93- While undefined logic is intended to handle achromatic hues, this logic will be applied to any channel. It should be
94- noted that no attempt to carry forward the undefined values through conversion is made at this time. Conversions will
95- remove any undefined status unless the channel is an achromatic hues.
151+ As stated earlier, undefined logic is applied to any channel with undefined values . It should be noted that no attempt
152+ to carry forward the undefined values through conversion is made at this time. If conversion is required, the
153+ conversions will remove any undefined status unless the channel is an achromatic hues.
96154
97155``` py play
98156for i in range (12 ):
99157 Color.average([' darkgreen' , f ' color(srgb 0 none 0 / { i / 11 } ) ' , ' color(srgb 0 0 1)' ])
100158```
101159
102160When ` premultiplied ` is enabled, premultiplication will not be applied to a color if its ` alpha ` is undefined as it is
103- unknown how to weight the color, instead the color is treated with full weight.
161+ unknown how to weight the color. Instead, a color with undefined transparency will be treated with full weight.
104162
105163``` py play
106164Color.average([' darkgreen' , f ' color(srgb 0 0.50196 0 / none) ' , ' color(srgb 0 0 1)' ])
0 commit comments