将颜色和阴影图像合并在一起

时间:2016-09-12 17:26:25

标签: c# image image-processing

我正在尝试"混合"两个透明图像在一起:一个用于颜色,第二个用于阴影。这是我的两张图片:

enter image description here enter image description here

以下是我要找的结果:

enter image description here

忽略最后一个徽标。我试图使用此代码https://softwarebydefault.com/2013/03/10/bitmap-blending/ 但它产生了这个结果: enter image description here

如果我使用正确的方法,有人能指出吗?可能是我应该使用其他算法来实现所需的结果?

2 个答案:

答案 0 :(得分:3)

重新发送old LockBits代码,这就是结果

enter image description here

这个功能:

public Bitmap Multiply(Bitmap bmp1, Bitmap bmp2)
{
    Size s1 = bmp1.Size;
    Size s2 = bmp2.Size;
    if (s1 != s2) return null;

    PixelFormat fmt1 = bmp1.PixelFormat;
    PixelFormat fmt2 = bmp2.PixelFormat;

    PixelFormat fmt = new PixelFormat();
    fmt = PixelFormat.Format32bppArgb;
    Bitmap bmp3 = new Bitmap(s1.Width, s1.Height, fmt);

    Rectangle rect = new Rectangle(0, 0, s1.Width, s1.Height);

    BitmapData bmp1Data = bmp1.LockBits(rect, ImageLockMode.ReadOnly, fmt1);
    BitmapData bmp2Data = bmp2.LockBits(rect, ImageLockMode.ReadOnly, fmt2);
    BitmapData bmp3Data = bmp3.LockBits(rect, ImageLockMode.ReadWrite, fmt);

    byte bpp1 = 4;
    byte bpp2 = 4;
    byte bpp3 = 4;

    if (fmt1 == PixelFormat.Format24bppRgb) bpp1 = 3;
    else if (fmt1 == PixelFormat.Format32bppArgb) bpp1 = 4; else return null;
    if (fmt2 == PixelFormat.Format24bppRgb) bpp2 = 3;
    else if (fmt2 == PixelFormat.Format32bppArgb) bpp2 = 4; else return null;

    int size1 = bmp1Data.Stride * bmp1Data.Height;
    int size2 = bmp2Data.Stride * bmp2Data.Height;
    int size3 = bmp3Data.Stride * bmp3Data.Height;
    byte[] data1 = new byte[size1];
    byte[] data2 = new byte[size2];
    byte[] data3 = new byte[size3];
    System.Runtime.InteropServices.Marshal.Copy(bmp1Data.Scan0, data1, 0, size1);
    System.Runtime.InteropServices.Marshal.Copy(bmp2Data.Scan0, data2, 0, size2);
    System.Runtime.InteropServices.Marshal.Copy(bmp3Data.Scan0, data3, 0, size3);

    for (int y = 0; y < s1.Height; y++)
    {
        for (int x = 0; x < s1.Width; x++)
        {
            int index1 = y * bmp1Data.Stride + x * bpp1;
            int index2 = y * bmp2Data.Stride + x * bpp2;
            int index3 = y * bmp3Data.Stride + x * bpp3;
            Color c1, c2;

            if (bpp1 == 4)
                c1 = Color.FromArgb(data1[index1 + 3], data1[index1 + 2], data1[index1 + 1], data1[index1 + 0]);
            else c1 = Color.FromArgb(255, data1[index1 + 2], data1[index1 + 1], data1[index1 + 0]);
            if (bpp2 == 4)
                c2 = Color.FromArgb(data2[index2 + 3], data2[index2 + 2], data2[index2 + 1], data2[index2 + 0]);
            else c2 = Color.FromArgb(255, data2[index2 + 2], data2[index2 + 1], data2[index2 + 0]);

            data3[index3 + 0] = (byte)( c1.B * c2.B / 256);
            data3[index3 + 1] = (byte)( c1.G * c2.G / 256);
            data3[index3 + 2] = (byte)( c1.R * c2.R / 256);
            data3[index3 + 3] = c1.A;
        }
    }

    System.Runtime.InteropServices.Marshal.Copy(data3, 0, bmp3Data.Scan0, data3.Length);
    bmp1.UnlockBits(bmp1Data);
    bmp2.UnlockBits(bmp2Data);
    bmp3.UnlockBits(bmp3Data);
    return bmp3;
}

请注意,alpha通道是从第1个位图复制的。

而不是'Multiply''ColorBurn'也是一个不错的选择。对于各种混合模式,Here是非常好的数学写法。

更新:使用Anna的算法

    data3[index3 + 0] = (byte)(c2.B + (c1.B * (255 - c2.B) / 256f));
    data3[index3 + 1] = (byte)(c2.G + (c1.G * (255 - c2.G) / 256f));
    data3[index3 + 2] = (byte)(c2.R + (c1.R * (255 - c2.R) / 256f));

导致这种较轻的图像:

enter image description here

为了保持红色的颜色到处仍然使结果更轻,我会使用Color Matrix进行一点伽马校正。

答案 1 :(得分:2)

很抱歉忽略那个博客,我实际上读了一下但是有了我自己的算法,你也可以忽略我xD。

每个像素都很简单:

  1. 在主图片(红色)中找到RGBA值,我们称之为ColorM
  2. 在阴影图片中,找到RGBA值,让我们称之为ColorS
  3. 对于R,G,B和A值中的每一个,计算((255 - ColorM) * ColorS) / 255,让我们调用最终的RGBA值ColorOver
  4. 计算ColorM + ColorOver,它将给出最终图像。
  5. 如果你想要测试它,似乎有点儿麻烦。