将图片插值为特定颜色

时间:2014-11-18 17:52:48

标签: c# colors interpolation

我希望将图像插值为一种颜色,以便过渡看起来与此相似:

1 2 3 4 5 6

我认为这很容易,但似乎比我想象的要困难一些。我尝试过的事情:

  1. 起始像素和随机颜色之间的平滑和线性插值。
  2. 选择随机色调和饱和度并插入该颜色。
  3. 我不确定这种效果是如何实现的。以下是像素如何改变5个随机非黑色像素的颜色:

    ╔══════════════════╦═════╦═════╦═════╦════════╦═══════╦═══════╦═════════╗
    ║ Sample.Iteration ║  R  ║  G  ║  B  ║   H    ║   S   ║   V   ║   X,Y   ║
    ╠══════════════════╬═════╬═════╬═════╬════════╬═══════╬═══════╬═════════╣
    ║ 1.1              ║ 104 ║ 168 ║ 144 ║ 157.50 ║ 38.10 ║ 65.88 ║ 121,81  ║
    ║ 1.2              ║  96 ║ 152 ║ 144 ║ 171.43 ║ 36.84 ║ 59.61 ║ 121,81  ║
    ║ 1.3              ║  80 ║ 120 ║ 152 ║ 206.67 ║ 47.37 ║ 59.61 ║ 121,81  ║
    ║ 1.4              ║  72 ║ 104 ║ 152 ║ 216.00 ║ 52.63 ║ 59.61 ║ 121,81  ║
    ║ 1.5              ║  56 ║  72 ║ 160 ║ 230.77 ║ 65.00 ║ 62.75 ║ 121,81  ║
    ║ 1.6              ║  40 ║  40 ║ 168 ║ 240.00 ║ 76.19 ║ 65.88 ║ 121,81  ║
    ║                  ║     ║     ║     ║        ║       ║       ║         ║
    ║ 2.1              ║  72 ║ 144 ║ 128 ║ 166.67 ║ 50.00 ║ 56.47 ║ 125,119 ║
    ║ 2.2              ║  64 ║ 128 ║ 128 ║ 180.00 ║ 50.00 ║ 50.20 ║ 125,119 ║
    ║ 2.3              ║  56 ║  96 ║ 128 ║ 206.67 ║ 56.25 ║ 50.20 ║ 125,119 ║
    ║ 2.4              ║  48 ║  88 ║ 128 ║ 210.00 ║ 62.50 ║ 50.20 ║ 125,119 ║
    ║ 2.5              ║  40 ║  56 ║ 136 ║ 230.00 ║ 70.59 ║ 53.33 ║ 125,119 ║
    ║ 2.6              ║  32 ║  32 ║ 136 ║ 240.00 ║ 76.47 ║ 53.33 ║ 125,119 ║
    ║                  ║     ║     ║     ║        ║       ║       ║         ║
    ║ 3.1              ║ 152 ║ 208 ║ 168 ║ 137.14 ║ 26.92 ║ 81.57 ║ 80,82   ║
    ║ 3.2              ║ 136 ║ 184 ║ 168 ║ 160.00 ║ 26.09 ║ 72.16 ║ 80,82   ║
    ║ 3.3              ║ 112 ║ 144 ║ 184 ║ 213.33 ║ 39.13 ║ 72.16 ║ 80,82   ║
    ║ 3.4              ║  96 ║ 128 ║ 192 ║ 220.00 ║ 50.00 ║ 75.29 ║ 80,82   ║
    ║ 3.5              ║  72 ║  88 ║ 200 ║ 232.50 ║ 64.00 ║ 78.43 ║ 80,82   ║
    ║ 3.6              ║  48 ║  48 ║ 216 ║ 240.00 ║ 77.78 ║ 84.71 ║ 80,82   ║
    ║                  ║     ║     ║     ║        ║       ║       ║         ║
    ║ 4.1              ║  40 ║  72 ║ 104 ║ 210.00 ║ 61.54 ║ 40.78 ║ 158,75  ║
    ║ 4.2              ║  32 ║  64 ║  96 ║ 210.00 ║ 66.67 ║ 37.65 ║ 158,75  ║
    ║ 4.3              ║  32 ║  48 ║  88 ║ 222.86 ║ 63.64 ║ 34.51 ║ 158,75  ║
    ║ 4.4              ║  24 ║  40 ║  88 ║ 225.00 ║ 72.73 ║ 34.51 ║ 158,75  ║
    ║ 4.5              ║  24 ║  32 ║  80 ║ 231.43 ║ 70.00 ║ 31.37 ║ 158,75  ║
    ║ 4.6              ║  16 ║  16 ║  72 ║ 240.00 ║ 77.78 ║ 28.24 ║ 158,75  ║
    ║                  ║     ║     ║     ║        ║       ║       ║         ║
    ║ 5.1              ║ 144 ║ 192 ║ 232 ║ 207.27 ║ 37.93 ║ 90.98 ║ 127,99  ║
    ║ 5.2              ║ 128 ║ 168 ║ 224 ║ 215.00 ║ 42.86 ║ 87.84 ║ 127,99  ║
    ║ 5.3              ║ 104 ║ 136 ║ 224 ║ 224.00 ║ 53.57 ║ 87.84 ║ 127,99  ║
    ║ 5.4              ║  96 ║ 120 ║ 216 ║ 228.00 ║ 55.56 ║ 84.71 ║ 127,99  ║
    ║ 5.5              ║  72 ║  88 ║ 216 ║ 233.33 ║ 66.67 ║ 84.71 ║ 127,99  ║
    ║ 5.6              ║  48 ║  48 ║ 208 ║ 240.00 ║ 76.92 ║ 81.57 ║ 127,99  ║
    ╚══════════════════╩═════╩═════╩═════╩════════╩═══════╩═══════╩═════════╝
    

    值得注意的是,每种RGB颜色似乎是8的倍数,减量或增量也是8的倍数。我无法想象它在这里做了什么样的插值。

    我需要做的一件事就是能够选择一种随机颜色(比如橙色,粉红色,蓝色),并能够实现与随机颜色相似的插值。

1 个答案:

答案 0 :(得分:3)

这是一种产生相当简单结果的方法。正如我在评论中所写的那样,也许应该研究更复杂的方法,但是对于这个例子,这似乎就是这样做的。

我添加了6个PictureBox来模仿你的截图。第一个加载您的第一张图片。

最后一个被赋予makeMonoChrome函数的结果,该函数使用ColorMatrix;这是通常的灰度代码的变体,它将目标颜色乘以矩阵。这里重要的是魔术数字,它包含3个通道的加权亮度。

您可能想要使用目标颜色;我认为(255,64,64,255)看起来更接近......

其他图像是通过mix2Bitmaps方法生成的第一个和最后一个图像之间的直接插值创建的,该方法采用两个位图,第二个应该在结果中具有百分比。 (可以通过分别检查percent == 0percent == 100并返回其中一个源位图的克隆来扩展此方法。)

这是我的结果:

enter image description here

private void Form1_Load(object sender, EventArgs e)
{
    Color targetColor = Color.FromArgb(255, 48, 48, 216);
    pictureBox6.Image = MakeMonoChrome ((Bitmap)pictureBox1.Image, targetColor);

    pictureBox2.Image = 
                mix2Bitmaps((Bitmap)pictureBox1.Image, (Bitmap)pictureBox6.Image, 20);
    pictureBox3.Image = 
                mix2Bitmaps((Bitmap)pictureBox1.Image, (Bitmap)pictureBox6.Image, 40);
    pictureBox4.Image = 
                mix2Bitmaps((Bitmap)pictureBox1.Image, (Bitmap)pictureBox6.Image, 60);
    pictureBox5.Image = 
                mix2Bitmaps((Bitmap)pictureBox1.Image, (Bitmap)pictureBox6.Image, 80);
}


Bitmap mix2Bitmaps(Bitmap bmp0, Bitmap bmp1, int percent)
{
    Bitmap bmp2 = new Bitmap(bmp0.Width, bmp0.Height, PixelFormat.Format32bppArgb);

    int Bpp = 4;  // assuming an effective pixelformat of 32bpp

    var bmpData0 = bmp0.LockBits( new Rectangle(0, 0, bmp0.Width, bmp0.Height),
                                  ImageLockMode.ReadOnly, bmp0.PixelFormat);
    var bmpData1 = bmp1.LockBits( new Rectangle(0, 0, bmp1.Width, bmp1.Height),
                                  ImageLockMode.ReadOnly, bmp1.PixelFormat);
    var bmpData2 = bmp2.LockBits( new Rectangle(0, 0, bmp2.Width, bmp2.Height),
                                  ImageLockMode.ReadWrite, bmp2.PixelFormat);


    int len = bmpData0.Height * bmpData0.Stride;
    byte[] data0 = new byte[len];
    byte[] data1 = new byte[len];
    byte[] data2 = new byte[len];
    Marshal.Copy(bmpData0.Scan0, data0, 0, len);
    Marshal.Copy(bmpData1.Scan0, data1, 0, len);
    Marshal.Copy(bmpData2.Scan0, data2, 0, len);

    float pctD = (100f - percent) / 100f;
    float pct  =  percent / 100f;

    for (int i = 0; i < len; i += Bpp)
    {
        data2[i + 0] = (byte)(data0[i + 0] * pctD + data1[i + 0] * pct);
        data2[i + 1] = (byte)(data0[i + 1] * pctD + data1[i + 1] * pct);
        data2[i + 2] = (byte)(data0[i + 2] * pctD + data1[i + 2] * pct);
        if (Bpp == 4) data2[i + 3] = 255;   
    }

    Marshal.Copy(data2, 0, bmpData2.Scan0, len);
    bmp0.UnlockBits(bmpData0);
    bmp1.UnlockBits(bmpData1);
    bmp2.UnlockBits(bmpData2);
    return bmp2;
}

public static Bitmap MakeMonoChrome(Bitmap bmp0, Color tCol)
{
    Bitmap bmp1 = new Bitmap(bmp0.Width, bmp0.Height);
    using (Graphics g = Graphics.FromImage(bmp1) )
    {
      float tr = tCol.R / 255f;
      float tg = tCol.G / 255f;
      float tb = tCol.B / 255f;

      ColorMatrix colorMatrix = new ColorMatrix(  new float[][] 
        {
            new float[] {.3f * tr, .3f * tg, .3f * tb, 0, 0},
            new float[] {.59f * tr, .59f * tg, .59f * tb, 0, 0},
            new float[] {.11f * tr, .11f * tg, .11f * tb, 0, 0},
            new float[] {0, 0, 0, 1, 0},
            new float[] {0, 0, 0, 0, 1}
        });

      ImageAttributes attributes = new ImageAttributes();
      attributes.SetColorMatrix(colorMatrix);

      g.DrawImage(bmp0, new Rectangle(0, 0, bmp0.Width, bmp0.Height),
          0, 0, bmp0.Width, bmp0.Height, GraphicsUnit.Pixel, attributes);

    }
    return bmp1;
}