改变位图的色调同时保持整体亮度

5

我正在尝试编写一个函数,可以在保持图像整体亮度的同时让我对位图进行红移或蓝移。基本上,完全红移的位图亮度与原始图像相同,但会被彻底染成红色(即所有像素的G和B值相等)。蓝色调同理(但R和G相等)。光谱移动的程度需要从0到1变化。

提前感谢您的帮助。


1
将颜色空间更改为HSV,然后移动色调是否可以实现您想要的效果? - sourcenouveau
HSV 算法可能有些作用,但并不完全适用。 - MusiGenesis
1
听起来你想要的是一张特定颜色的“灰度”图像,对吗? - sourcenouveau
@emddudley:是的,那正是我想要的,你的评论启发了我下面的解决方案。谢谢。 - MusiGenesis
2个回答

4

这是我想要的效果(抱歉,图像质量不佳):

alt text http://www.freeimagehosting.net/uploads/d15ff241ca.jpg

中间的图像是原始图像,侧面的图像分别是完全红移、部分红移、部分蓝移和完全蓝移。

下面是产生此效果的函数:

public void RedBlueShift(Bitmap bmp, double factor)
{
    byte R = 0;
    byte G = 0;
    byte B = 0;
    byte Rmax = 0;
    byte Gmax = 0;
    byte Bmax = 0;
    double avg = 0;
    double normal = 0;
    if (factor > 1)
    {
        factor = 1;
    }
    else if (factor < -1)
    {
        factor = -1;
    }
    for (int x = 0; x < bmp.Width; x++)
    {
        for (int y = 0; y < bmp.Height; y++)
        {
            Color color = bmp.GetPixel(x, y);
            R = color.R;
            G = color.G;
            B = color.B;
            avg = (double)(R + G + B) / 3;
            normal = avg / 255.0; // to preserve overall intensity
            if (factor < 0) // red-tinted:
            {
                if (normal < .5)
                {
                    Rmax = (byte)((normal / .5) * 255);
                    Gmax = 0;
                    Bmax = 0;
                }
                else
                {
                    Rmax = 255;
                    Gmax = (byte)(((normal - .5) * 2) * 255);
                    Bmax = Gmax;
                }
                R = (byte)((double)R - ((double)(R - Rmax) * -factor));
                G = (byte)((double)G - ((double)(G - Gmax) * -factor));
                B = (byte)((double)B - ((double)(B - Bmax) * -factor));
            }
            else if (factor > 0) // blue-tinted:
            {
                if (normal < .5)
                {
                    Rmax = 0;
                    Gmax = 0;
                    Bmax = (byte)((normal / .5) * 255);
                }
                else
                {
                    Rmax = (byte)(((normal - .5) * 2) * 255);
                    Gmax = Rmax;
                    Bmax = 255;
                }
                R = (byte)((double)R - ((double)(R - Rmax) * factor));
                G = (byte)((double)G - ((double)(G - Gmax) * factor));
                B = (byte)((double)B - ((double)(B - Bmax) * factor));
            }
            color = Color.FromArgb(R, G, B);
            bmp.SetPixel(x, y, color);
        }
    }
}

我可以想象这段代码非常慢,因为它使用每个像素的操作。我会像Hans Passant建议的那样研究ColorMatrix类。 - Will Kru
@Will Kru:是的,我发布的代码由于使用了 GetPixelSetPixel 会非常慢。但是,ColorMatrix 对我来说不适用,因为我的“位图”实际上不是 .NET 位图 - 它们是二维 int 数组。我的包含函数使用 .NET 位图和 GetPixel/SetPixel,因此它对他人更有用。 - MusiGenesis

3
你可以使用ColorMatrix类来实现这个功能。在这个项目中有一个很好的教程可供参考。

我还没有看到使用ColorMatrix实现颜色偏移和亮度保持(即色调)的任何示例。我已经努力寻找了,你提供的链接也不是。你有任何示例吗? - Todd Main

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