如何自动确定具有最高对比度的RGBA图像的背景颜色?
背景
我有一堆RGBA图像。想象一下我想显示的图标,徽标或类似图像。这些图像可以具有任何颜色。另请注意,这些图像是RGBA,因此它们具有透明度的第四个Alpha通道。
并发症
最初,我在白色背景上展示了图像。但是,有时整个图像或其中的一部分是白色的,因此这些区域对用户看上去很空。
问题是图像不是全白或全黑。可能有多种颜色和颜色梯度。而且,由于RGBA图像的工作方式,像素并不总是全部颜色和不透明的。即使图像仅在中心显示纯黑图标,也可能在黑色图标的边缘有过渡区域,其像素具有某些透明度或更灰色的颜色。
问题
假定,对于每个图像,我可以在黑色,灰色或白色背景之间进行选择。 如何算法可以确定三种背景颜色选项中的哪个最适合任何单独的RGBA图像?
“最佳”是指图像的任何区域都不能虚假地出现空白,并且图像和背景之间的对比度最高。
示例
在下面的玩具示例中,我想显示的图标周围有一个白色圆圈。因此,我不能将白色用作背景颜色。我需要选择灰色或黑色。黑色是最好的,因为它最大化对比度。
在第二个玩具示例中,情况变得更加复杂,因为不同颜色的多个区域直接接触图像的透明区域。黑色背景似乎具有最高的对比度,但不再是微不足道的。
想法
- 不透明区域的内部没有关系。背景颜色不会影响可见度。
- 完全透明区域的内部没有关系。没有什么可以看不见的。
- 我可能需要在不透明和透明之间的这些过渡区域中找到这些像素。然后确定这些颜色。
这似乎效率低下。由于大多数图标,徽标等都是为了明亮或黑暗的背景而设计的,因此也许足以在不透明和透明之间的过渡区域进行一些像素进行采样?
我觉得我正在重新发明轮子,并且有人以前已经找到了解决这个问题的解决方案。
stackoverflow上的现有问题
- 我发现了有关背景颜色确定最佳字体颜色的现有问题。但是我的问题是不同的。我看到的问题仅处理仅在两种简单的RGB颜色之间最大化对比度。
附加示例3
请注意该徽标周围如何具有细小的白线。这意味着最佳背景颜色可能应该是黑色的。
可以与之播放的示例
这里有十几个左右的RGBA图像可以播放。我不拥有版权 - 这仅是为了说明问题。 ”
我添加了所有示例图像,从左到右如下:
- 在棋盘上,在棋盘上显示
- 上的
- 在白色背景上的黑色
- 背景
- 透明区域,而仅提取了alpha通道
Background
I have a bunch of RGBA images. Imagine icons, logos or similar images that I would like to display. These images can be of any color. Please also note that the images are RGBA, so they have the fourth alpha channel for transparency.
Complication
Initially, I showed the images all on a white background. However, sometimes the whole image or parts of it were white, so these areas looked empty to the user.
The problem is that images are not all-white or all-black. There may be multiple colors and color gradients. And, due to the way RGBA images work, pixels are not always all one color and all opaque. Even if an image just showed a pure black icon in the center, there may be transition areas at the edges of the black icon with pixels of some transparency or more greyish colors.
Question
Assume, for each image I can choose between a black, grey, or white background.
How can I algorithmically determine which of the three background color options is the best for any individual RGBA image?
By "best" I mean that no areas of the image should falsely appear empty and the highest contrast between image and background is achieved.
Example
In the toy example below, the icon I want to show has a white circle around it. So I cannot use white as a background color. I need to choose grey or black. Black would be best since it maximises contrast.
In the second toy example things are slightly more complicated since multiple areas of different color directly touch the transparent areas of the image. The black background appears to have the highest contrast but it is no longer trivial.
Ideas
- The inner parts of opaque areas do not matter. The background color would not affect the visibility.
- The inner parts of the fully transparent areas do not matter. There is nothing that could be made invisible.
- I would probably need to find those pixels in these transition areas between opaque and transparent. And then determine the color of these.
This appears awfully inefficient. Since most icons, logos, etc. have been designed for either a bright or a dark background, maybe it is sufficient to sample just a few pixels in the transition area between opaque and transparent?
I feel I am reinventing the wheel and someone must have found a solution to this problem before.
Existing questions on Stackoverflow
- I found existing questions on determining the best font color given a background color. However my problem is different. The problems I saw were only dealing with maximising the contrast between only two simple RGB colors.
Additional example 3
Note how this logo has a fine white line around it. This implies the optimal background color should probably be black.
Examples to play around with
Here are a dozen or so RGBA images to play around with. I don't own the copyright -- this is just for the illustration of the problem.
Google Drive link
Edited in by Mark Setchell
I have added all sample images, going left-to-right as follows:
- over a chessboard to show transparent areas
- over black background
- over grey background
- over white background
- with just the alpha channel extracted
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这个想法是计算图像的最“主要”颜色,然后选择与图像中最强的颜色相反的相应背景颜色。因为我们只能选择白色,灰色或黑色;我们可以假设最大化对比度的最佳颜色等于与最主要的颜色相反的颜色。这是一种使用
sklearn.cluster.kmean.kmean.kmeans()
the我们可以选择的三个可能的
rgb
颜色代码是:我们可以通过找到优势颜色的平均值来计算最佳颜色,并将其分类在颜色区域之间。由于颜色通道的范围从
[0-255]
,我们可以简单地将其分为三个象限:以下是一些示例:
使用
n_clusters = 5
,以下是最主要的 每种颜色的颜色和百分比分布可视化(在深色背景上,您可以看到白色)
结果
第二张图像
n_clusters = 5
,以下是最主要的颜色和每种颜色的百分比分布(在黑暗的背景下,您可以看到白色
的示例徽标
具有主导的白色示例,因此最好的背景应该是黑色。可能会有一种更有趣的方法来计算最佳颜色,但我会把它留给您。
徽标的结果不是主要是白色
=“ https://i.sstatic.net/xk13d.png” alt =“在此处输入图像说明”>
代码
The idea is to calculate the most "dominant" color of an image then choose the corresponding background color most opposite to the strongest color present in the image. Since we can only choose white, gray, or black; we can assume the best color to maximize contrast is equal to the color that is polar opposite to the most dominant color. Here's an approach using K-Means Clustering to determine the dominant colors of an image with
sklearn.cluster.KMeans()
The three possible
RGB
color codes we can choose are:We can calculate the best color by finding the average of the dominant color and categorize it between color zones. Since a color channel ranges from
[0 - 255]
, we can simply split it into three quadrants:Here are some examples:
With
n_clusters=5
, here are the most dominant colors and percentage distributionVisualization of each color (on a dark background so you can see the white)
Results
The second image
With
n_clusters=5
, here are the most dominant colors and percentage distributionVisualization of each color (on a dark background so you can see the white)
Results
Both of your example logos have dominant white colors therefore the best background should be black. There could be a more interesting way of calculating the best color but I'll leave that up to you.
Results with logos that are not dominantly white
Code
这更像是“进行中的工作” ,而不是一个完整的答案 - 但没有要求Afaik完成SO答案,任何其他人都欢迎您采用这个想法并发展或发展适应它。
因此,虽然我还没有提出完整的解决方案,但我试图解决您问题的部分,上面说“不透明区域的内部无关紧要” 以及内部部分透明区域。我的想法是,如果您可以识别出和不重要的零件,那么您将更接近解决方案...
我只是在这里的终端中使用 Imagemagick ,但是您可以做到如果该方法证明有用,则与Python相同。因此,如果我拍摄您的第一张图像,我可以以下提取alpha频道:
如果我现在在边缘周围添加一个1像素宽的黑色边框,我可以在红色从0,0开始,红色意志“流” 沿新边界的边缘周围,并从各个方面渗入图像,但没有达到透明的内部岛屿。边界的原因是如果黑色接触图像的边缘,这允许一个微小的1像素通道以使洪水在障碍物周围流动:
红色像素是您认为自己感兴趣的……,接下来需要发生的事情是进一步思考的主题。我想我们可以使剩余的黑色零件白色:
,然后将其推回图像作为新的,修改的alpha通道。
这是其他几个样本接受相同处理的样本,因此您可以看到它的发展方向。
This is more of a "work-in-progress", than a complete answer - but there is no requirement AFAIK for SO answers to be complete, and anyone else is welcome to take the idea and develop or adapt it.
So, whilst I have not yet come up with a full solution, I am attempting to address the part of your question that says "the inner parts of the opaque areas do not matter" and likewise the inner parts of the transparent areas. My idea is that if you can identify the parts that do and don't matter, you will be closer to a solution...
I am just using ImageMagick in the Terminal here, but you can do exactly the same things with Python if the approach proves useful. So, if I take your first image, I can extract the alpha channel like this:
If I now add a 1-pixel wide black border all around the edges, I can do a flood-fill in red starting at 0,0 and the red will "flow" all around the edges along the new border and seep into the image from all sides but without ever reaching the inner islands of transparency. The reason for the border is in case the black touches the edge of the image, this allows a tiny 1-pixel channel for the flood to flow around the obstruction:
So, what I am saying is that the red pixels are the ones you think you are interested in... and what needs to happen next is the subject of further thought. I guess we could make the remaining black parts white:
and push that back into the image as a new, modified alpha channel.
Here are a couple of other samples subjected to the same treatment so you can see where it is headed..