如何反转颜色?

47

我知道这不会直接反转一种颜色,而只是“反对”它。 我想知道是否有人知道一种简单的方法(几行代码)可以从任何给定的颜色中反转一个颜色?

目前我有这个(这并不完全符合反转的定义,因为如果我传递一个灰色/灰色的颜色,它将返回非常相似的东西,例如127, 127, 127):

const int RGBMAX = 255;

Color InvertMeAColour(Color ColourToInvert)
{
    return Color.FromArgb(RGBMAX - ColourToInvert.R, 
      RGBMAX - ColourToInvert.G, RGBMAX - ColourToInvert.B);
}

8
实际上,这确实是通常定义颜色反转的方式...那么你想要找的是什么? - Martin B
2
也许您需要生成一个背景颜色,使得给定的颜色能够被清晰地阅读? - bohdan_trotsenko
5
那么,灰色的反义词应该是什么呢? ;) - jalf
2
沉闷无趣的灰色的反义词是漂亮明亮的红色,或者也可以是漂亮的绿色。 - Matthew Scharley
11
@ThePower: 127,127,127 的色彩反转是 128,128,128。尽管这可能让你感到失望... - korona
显示剩余4条评论
8个回答

53

这要看你所说的“反转”颜色是指什么。

你的代码提供了一个“负面”的颜色。

如果你想把红色变成青色,绿色变成紫色,蓝色变成黄色(等等),那么你需要将RGB颜色转换为HSV模式(你可以在这里找到相应的转换方法)。

然后只需反转色调值(将Hue改为360-Hue),并重新转换为RGB模式。

编辑:正如Alex Semeniuk所提到的,将Hue改为(Hue + 180) % 360是一个更好的解决方案(它不会颠倒色调,而是在色彩圆上找到相反的颜色)。


3
感谢您正确回答我的问题并提供正确的解决方案(而不是提供我所发布代码的替代方案)。我对此表示赞赏(+1)。 - Lloyd Powell
3
当Hue=180时会发生什么?颜色会保持不变吗? - bfontaine
1
正如Steve Gilham所说:“不动点定理意味着从(实值)颜色到颜色的任何连续函数都会保持一个值不变;如果函数相当平滑,则围绕该点的区域也不会移动太多。”因此,色调为180的颜色将不会被更改。 - ThibThib
5
不正确。如果您希望通过仅更改“色调”来“反转”HSV颜色,则应使用(色调+180)%360,而不是360-色调。这样做可以避免在色调为180时出现“问题”(并不保证您会获得正确的反转颜色)。 - Alex Semeniuk
1
计算机屏幕上的颜色反转无需解释,这是几十年来的常见事情,并且在第一个WIMPS被发明时就被使用。我不确定为什么需要解释这个,或者Thib为什么会感到困惑。很明显OP所谈论的是什么颜色空间和媒介。 你的答案太泛泛了,OP正在寻找一个代码示例。@Remy下面的解决方案要好得多。 - John Stock
显示剩余4条评论

34

您可以使用:

MyColor=Color.FromArgb(MyColor.ToArgb()^0xffffff);

这将反转MyColor。


10
那么,这会对灰色产生什么影响? 127、127、127? - Lloyd Powell
6
它会使灰色更加浅一些:128,128,128。 - Jerther
2
我认为这是许多情况下非常好的答案。例如,红色将被转换为青色。这是Remy代码的vbnet等效代码:MyColor = Color.FromArgb(MyColor.ToArgb() Xor &Hffffff) - Alex

11

试试这个:

uint InvertColor(uint rgbaColor)
{
    return 0xFFFFFF00u ^ rgbaColor; // Assumes alpha is in the rightmost byte, change as needed
}

它在C#中的实现方式是相同的。语法完全一样。0xFFFFFFFF ^ 颜色 - Nick Berardi
几乎一模一样。 :) 我只是做了一些小改动,将它转换成了C#。 - Noldorin
1
@Eyal,不是一样的。这里使用的是异或操作而不是减号。 - bohdan_trotsenko
谢谢,它保持了alpha不变!(在Java jmonkeyengine ColorRGBA中:) - Aquarius Power

9
如果您想更改每个颜色,尝试使用旋转函数(移位或添加)而不是翻转函数(反转)。换句话说,考虑将0到255的范围应用于每种单一颜色(红色、绿色和蓝色),并将其包装在一起,连接在末端,就像值的圆圈一样。然后通过添加一些值并执行mod 256来将每个颜色在圆形中移动。例如,如果您的红色起始值为255,并添加1,则会得到0。如果您将所有三种颜色移位128,则会得到完全不同的值,甚至对于灰色也是如此。灰色127、127、127变为白色255、255、255。灰色128、128、128变成黑色0、0、0。类似于1930年代Man Ray无意中发现的Solarization,有一种摄影效果。
您还可以对每种颜色(红色、绿色、蓝色)进行不同程度的旋转操作,以使图像混乱。
您还可以对色调进行旋转操作,通过色调圆上的某个量将每个原始颜色的色调改变,从而改变所有颜色而不改变亮度,使阴影看起来仍然像阴影,例如让人看起来像辛普森或斯莫夫。
移位128的代码可能如下所示:
public static Color Invert(this Color c) => Color.FromArgb(c.R.Invert(), c.G.Invert(), c.B.Invert());

public static byte Invert(this byte b) {
    unchecked {
        return (byte)(b + 128);
    }
}

6

分别反转每个组件的位:

Color InvertMeAColour(Color ColourToInvert)
{
   return Color.FromArgb((byte)~ColourToInvert.R, (byte)~ColourToInvert.G, (byte)~ColourToInvert.B);
}

编辑: ~ 操作符不会自动适用于字节,需要进行强制转换。


这会抛出一个异常(ArgumentException "“-129”的值对于“red”无效") - Lloyd Powell
现在它已经被编辑过了,虽然它仍然像我的函数一样处理负数,而不是反转。无论如何,还是谢谢你的回答 :-) - Lloyd Powell

5
你已经拥有一个RGB反转。还有其他方法来分类颜色,因此也有其他定义颜色的反转方式。
但是看起来你可能想要一种对比色,而简单的反转不会适用于包括RGB(127、127、127)在内的所有颜色。
你需要做的是:1)将其转换为HSV(参见ThibThibs的回答),并反转色调,同时2)检查色调是否接近中央,如果是,则到达完全明亮或完全黑暗。

2
不动点定理意味着从(实值)颜色到颜色的任何连续函数都会保持一个值不变;如果该函数是相当平滑的,则围绕该点的补丁也不会移动太多。 - Steve Gilham

1
我用最简单和懒惰的方法来处理不仅是三个12x,而且是混合值的工作,方法如下:
Color invertedColor= Color.FromArgb(fromColor.ToArgb() ^ 0xffffff);

if (invertedColor.R > 110 && invertedColor.R < 150 &&
    invertedColor.G > 110 && invertedColor.G < 150 &&
    invertedColor.B > 110 && invertedColor.B < 150)
{
    int avg = (invertedColor.R + invertedColor.G + invertedColor.B) / 3;
    avg = avg > 128 ? 200 : 60;
    invertedColor= Color.FromArgb(avg, avg, avg);
}

现在,invertedColor有一个不同的颜色,即使我们有一个128、128、128或接近它的颜色值。

0
我已经为VB.NET创建了这个简单的函数:
Public Shared Function Invert(ByVal Culoare As Color) As Color
    Return Color.FromArgb(Culoare.ToArgb() Xor &HFFFFFF)
End Function

还有这个是针对C#的:

public static Color Invert(Color Culoare)
{
    return Color.FromArgb(Culoare.ToArgb() ^ 0xFFFFFF);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接