<p>Sounds like you could be using the sum of all pixels disregarding the transparency for each pixel, and that the image has black pixels where it is transparent which leads to the issue. Instead add the pixels with their alpha value as weight, and divide the result with the total weight. Premultiplied alpha you should handle also as suggested above.</p>

CC BY-SA 4.0
2018-08-22T08:49:33.790Z
Hi Beyond, FWIW, Jim Blinn's article "Compositing, Part I: Theory" (https://graphics.stanford.edu/courses/cs248-02/blinn_theory.pdf) has a discussion on how to do filtering/averaging for colours with alpha. This states the correct way is to use premultiplied alpha  (AKA associative alpha).
Simon F
CC BY-SA 4.0
2018-08-22T10:52:11.710Z
Sure, the trick is that not all files are saved that way. So in order to do it correctly you need to know which type of file you're dealing with :)
beyond
CC BY-SA 4.0
2018-08-22T12:59:57.850Z
Sorry, looks like I misread your post! Wasn't entirely awake at the time.
Simon F
CC BY-SA 4.0
2018-08-22T08:05:29.910Z
2018-08-22T08:05:29.910Z
beyond
<p>Averaging RGB should be correct assuming you do it in linear RGB. If your images are in sRGB, you can remove the gamma correction by doing something like the following for each of the R, G, and B components:</p>

<pre><code>float sRGBToLinear(UInt8 component)
{
    float tempComponent = (float)component / 255.0;
    if (tempComponent &lt;= 0.04045)
    {
        tempComponent = tempComponent / 12.92;
    }
    else
    {
        tempComponent = pow((tempComponent + 0.055) / (1.055), 2.4);
    }
    return tempComponent;
}
</code></pre>

<p>You can then average together all of the red values in the image, all of the green values in the image, and all of the blue values in the image after they've been run through the above conversion. You can then do the opposite conversion to get back to sRGB:</p>

<pre><code>UInt8 linearRGBTosRGB(float component)
{
    float tempComponent =  0.0;
    if (component &lt;= 0.00318308)
    {
        tempComponent = 12.92 * component;
    }
    else
    {
        tempComponent = 1.055 * pow(component, 1.0 / 2.4) - 0.055;
    }
    return (UInt8)(tempComponent * 255.0);
}
</code></pre>

<p>(My apologies if I've messed up the syntax. I'm a C/C++ programmer and don't know the intricacies of Java.)</p>

<p>Note that alpha makes things slightly more complicated. If you're using premultiplied alpha, you can simply apply the above calculations for the average. If you're using straight alpha, you'll want to multiply each of the R, G, and B components by the alpha before doing the averaging.</p>

CC BY-SA 4.0
2018-08-22T06:06:09.933Z
Also, you probably want to weight by alpha during the averaging, so that the (invisible) color in transparent areas doesn't contaminate the average.
Nathan Reed
CC BY-SA 4.0
2018-08-22T08:53:09.563Z
@NathanReed Not just "*probably*", Jim Blinn says to be correct you should use [premultiplied alpha in filtering calcs](https://graphics.stanford.edu/courses/cs248-02/blinn_theory.pdf)  .  :-)
Simon F
CC BY-SA 4.0
2018-08-22T09:39:44.553Z
Does this mean that ideally, I convert back to sRGB after *all* processing steps have been done (not only the downscaling)? Is alpha gamma corrected too? My images are not premultiplied: pixels with zero alpha may have any RGB color. How do I take in the alpha when averaging?
piegames
CC BY-SA 4.0
2018-08-22T16:00:51.183Z
@NathanReed Interesting. I would have thought there would be cases where you want to and cases where you don't. But I will certainly defer to Mr. Blinn.
user1118321
CC BY-SA 4.0
2018-08-22T16:01:15.483Z
@piegames - Yes, you probably want to convent back to sRGB after you've done all the averaging. Otherwise the color you're left with is in a different color space than the ones you started with. Alpha does not get gamma corrected. As  mentioned in the comment above, you probably want to make sure that your values are premultiplied, so you can skip the un-pre-multiply step I mentioned.  I'll update the  post to remove that.
user1118321
CC BY-SA 4.0
2018-08-22T02:20:40.710Z
2018-08-22T16:02:19.990Z
2018-08-22T16:02:19.990Z
user1118321
<p>I want to calculate the average color+opacity of an image. First I thought about just averaging all ARGB values component-wise, but this got really dark on images with a lot of transparency. I also don't think mixing RGB colors is a good idea in general since they are nonlinear due to Gamma or something. I also had a look at HSV/HSB but this seems a pretty stupid idea.</p>

<p><strong>So, what is a reasonably physically correct way to average the color of an ARGB image?</strong> I prefer solutions in Java and using 8 bit per color channel. The solution should also take care that the image may have an arbitrary amount of transparent or semi-transparent pixels.</p>

CC BY-SA 4.0
2018-08-26T14:49:50.143Z
What do you mean by component?
information
CC BY-SA 4.0
2018-08-27T12:03:43.400Z
@x-rw https://en.wikipedia.org/wiki/RGB_color_model#Additive_colors
piegames
<image-processing><color>
Calculate the average color of an image
piegames
# Calculate the average color of an image

(Asked by: username_0 on 2018-08-21)

I want to calculate the average color+opacity of an image. First I thought about just averaging all ARGB values component-wise, but this got really dark on images with a lot of transparency. I also don't think mixing RGB colors is a good idea in general since they are nonlinear due to Gamma or something. I also had a look at HSV/HSB but this seems a pretty stupid idea.

**So, what is a reasonably physically correct way to average the color of an ARGB image?** I prefer solutions in Java and using 8 bit per color channel. The solution should also take care that the image may have an arbitrary amount of transparent or semi-transparent pixels.

**Tags:** image-processing, color

> **Comments:**
> **username_1**: What do you mean by component?  
> **username_0**: @x-rw https://en.wikipedia.org/wiki/RGB_color_model#Additive_colors  

---

## 2 answers

### Answer by username_4 on 2018-08-22. Score: 5 | Accepted answer

Averaging RGB should be correct assuming you do it in linear RGB. If your images are in sRGB, you can remove the gamma correction by doing something like the following for each of the R, G, and B components:

```
float sRGBToLinear(UInt8 component)
{
    float tempComponent = (float)component / 255.0;
    if (tempComponent <= 0.04045)
    {
        tempComponent = tempComponent / 12.92;
    }
    else
    {
        tempComponent = pow((tempComponent + 0.055) / (1.055), 2.4);
    }
    return tempComponent;
}

```

You can then average together all of the red values in the image, all of the green values in the image, and all of the blue values in the image after they've been run through the above conversion. You can then do the opposite conversion to get back to sRGB:

```
UInt8 linearRGBTosRGB(float component)
{
    float tempComponent =  0.0;
    if (component <= 0.00318308)
    {
        tempComponent = 12.92 * component;
    }
    else
    {
        tempComponent = 1.055 * pow(component, 1.0 / 2.4) - 0.055;
    }
    return (UInt8)(tempComponent * 255.0);
}

```

(My apologies if I've messed up the syntax. I'm a C/C++ programmer and don't know the intricacies of Java.)

Note that alpha makes things slightly more complicated. If you're using premultiplied alpha, you can simply apply the above calculations for the average. If you're using straight alpha, you'll want to multiply each of the R, G, and B components by the alpha before doing the averaging.

> **Comments:**
> **username_5**: Also, you probably want to weight by alpha during the averaging, so that the (invisible) color in transparent areas doesn't contaminate the average.  
> **username_3**: @username_5 Not just "*probably*", Jim Blinn says to be correct you should use [premultiplied alpha in filtering calcs](https://graphics.stanford.edu/courses/cs248-02/blinn_theory.pdf)  .  :-)  
> **username_0**: Does this mean that ideally, I convert back to sRGB after *all* processing steps have been done (not only the downscaling)? Is alpha gamma corrected too? My images are not premultiplied: pixels with zero alpha may have any RGB color. How do I take in the alpha when averaging?  
> **username_4**: @username_5 Interesting. I would have thought there would be cases where you want to and cases where you don't. But I will certainly defer to Mr. Blinn.  
> **username_4**: @username_0 - Yes, you probably want to convent back to sRGB after you've done all the averaging. Otherwise the color you're left with is in a different color space than the ones you started with. Alpha does not get gamma corrected. As  mentioned in the comment above, you probably want to make sure that your values are premultiplied, so you can skip the un-pre-multiply step I mentioned.  I'll update the  post to remove that.  

---

### Answer by username_2 on 2018-08-22. Score: 1

Sounds like you could be using the sum of all pixels disregarding the transparency for each pixel, and that the image has black pixels where it is transparent which leads to the issue. Instead add the pixels with their alpha value as weight, and divide the result with the total weight. Premultiplied alpha you should handle also as suggested above.

> **Comments:**
> **username_3**: Hi username_2, FWIW, Jim Blinn's article "Compositing, Part I: Theory" (https://graphics.stanford.edu/courses/cs248-02/blinn_theory.pdf) has a discussion on how to do filtering/averaging for colours with alpha. This states the correct way is to use premultiplied alpha  (AKA associative alpha).  
> **username_2**: Sure, the trick is that not all files are saved that way. So in order to do it correctly you need to know which type of file you're dealing with :)  
> **username_3**: Sorry, looks like I misread your post! Wasn't entirely awake at the time.  

---

