简体   繁体   English

如何重新着色图像? (见图片)

[英]How do I recolor an image? (see images)

How do I achieve this kind of color replacement programmatically?如何以编程方式实现这种颜色替换?用蓝色代替黑色


So this is the function I have used to replace a pixel:所以这是我用来替换像素的函数:

Color.FromArgb(
    oldColorInThisPixel.R + (byte)((1 - oldColorInThisPixel.R / 255.0) * colorToReplaceWith.R),
    oldColorInThisPixel.G + (byte)((1 - oldColorInThisPixel.G / 255.0) * colorToReplaceWith.G),
    oldColorInThisPixel.B + (byte)((1 - oldColorInThisPixel.B / 255.0) * colorToReplaceWith.B)
    )

Thank you, CodeInChaos!谢谢你,CodeInChaos!

The formula for calculating the new pixel is:计算新像素的公式为:

newColor.R = OldColor;
newColor.G = OldColor;
newColor.B = 255;

Generalizing to arbitrary colors:泛化到任意颜色:

I assume you want to map white to white and black to that color.我假设您想将白色映射到白色并将黑色映射到该颜色。 So the formula is newColor = TargetColor + (White - TargetColor) * Input所以公式是newColor = TargetColor + (White - TargetColor) * Input

newColor.R = OldColor + (1 - oldColor / 255.0) * TargetColor.R;
newColor.G = OldColor + (1 - oldColor / 255.0) * TargetColor.G;
newColor.B = OldColor + (1 - oldColor / 255.0) * TargetColor.B;

And then just iterate over the pixels of the image(byte array) and write them to a new RGB array.然后只需遍历图像(字节数组)的像素并将它们写入新的 RGB 数组。 There are many threads on how to copy an image into a byte array and manipulate it.有许多关于如何将图像复制到字节数组并对其进行操作的线程。

Easiest would be to use ColorMatrix for processing images, you will even be able to process on fly preview of desired effect - this is how many color filters are made in graphic editing applications.最简单的方法是使用ColorMatrix处理图像,您甚至可以即时处理所需效果的预览 - 这是图形编辑应用程序中制作的滤色器数量。 Here and here you can find introductions to color effects using Colormatrix in C#.您可以在此处此处找到在 C# 中使用 Colormatrix 的颜色效果介绍。 By using ColorMatrix you can make colorizing filter like you want, as well as sepia, black/white, invert, range, luminosity, contrast, brightness, levels (by multi-pass) etc.通过使用 ColorMatrix,您可以制作您想要的着色滤镜,以及棕褐色、黑/白、反转、范围、亮度、对比度、亮度、级别(通过多通道)等。

EDIT: Here is example (update - fixed color matrix to shift darker values into blue instead of previous zeroing other than blue parts - and - added 0.5f to blue because on picture above black is changed into 50% blue):编辑:这是示例(更新 - 固定颜色矩阵以将较暗的值转换为蓝色而不是蓝色部分以外的先前归零 - 并且 - 将 0.5f 添加到蓝色,因为上面的图片黑色变为 50% 蓝色):

var cm = new ColorMatrix(new float[][]
{
  new float[] {1, 0, 0, 0, 0},
  new float[] {0, 1, 1, 0, 0},
  new float[] {0, 0, 1, 0, 0},
  new float[] {0, 0, 0, 1, 0},
  new float[] {0, 0, 0.5f, 0, 1}
});

var img = Image.FromFile("C:\\img.png");
var ia = new ImageAttributes();
ia.SetColorMatrix(cm);

var bmp = new Bitmap(img.Width, img.Height);
var gfx = Graphics.FromImage(bmp);
var rect = new Rectangle(0, 0, img.Width, img.Height);

gfx.DrawImage(img, rect, 0, 0, img.Width, img.Height, GraphicsUnit.Pixel, ia);

bmp.Save("C:\\processed.png", ImageFormat.Png);

You'll want to use a ColorMatrix here.您将要在此处使用 ColorMatrix。 The source image is grayscale, all its R, G and B values are equal.源图像是灰度的,它的所有 R、G 和 B 值都相等。 Then it is just a matter of replacing black with RGB = (0, 0, 255) for dark blue, white with RGB = (255, 255, 255) to get white.然后只需将黑色替换为 RGB = (0, 0, 255) 即可获得深蓝色,将白色替换为 RGB = (255, 255, 255) 即可获得白色。 The matrix thus can look like this:因此,矩阵可以如下所示:

1 0 0 0 0       // not changing red
0 1 0 0 0       // not changing green
0 0 0 0 0       // B = 0
0 0 0 1 0       // not changing alpha
0 0 1 0 1       // B = 255

This sample form reproduces the right side image:此示例表单再现了右侧图像:

public partial class Form1 : Form {
    public Form1() {
        InitializeComponent();
    }
    private Image mImage;
    protected override void OnPaint(PaintEventArgs e) {
        if (mImage != null) e.Graphics.DrawImage(mImage, Point.Empty);
        base.OnPaint(e);
    }
    private void button1_Click(object sender, EventArgs e) {
        using (var srce = Image.FromFile(@"c:\temp\grayscale.png")) {
            if (mImage != null) mImage.Dispose();
            mImage = new Bitmap(srce.Width, srce.Height);
            float[][] coeff = {
                            new float[] { 1, 0, 0, 0, 0 },
                            new float[] { 0, 1, 0, 0, 0 },
                            new float[] { 0, 0, 0, 0, 0 },
                            new float[] { 0, 0, 0, 1, 0 },
                            new float[] { 0, 0, 1, 0, 1 }};
            ColorMatrix cm = new ColorMatrix(coeff);
            var ia = new ImageAttributes();
            ia.SetColorMatrix(new ColorMatrix(coeff));
            using (var gr = Graphics.FromImage(mImage)) {
                gr.DrawImage(srce, new Rectangle(0, 0, mImage.Width, mImage.Height),
                    0, 0, mImage.Width, mImage.Height, GraphicsUnit.Pixel, ia);
            }
        }
        this.Invalidate();
    }
}

Depends a lot on what your image format is and what your final format is going to be.很大程度上取决于您的图像格式是什么以及您的最终格式是什么。

Also depends on what tool you wanna use.也取决于你想使用什么工具。 You may use:您可以使用:

  • GDI全球发展指数
  • GD+广东+
  • Image Processing library such as OpenCV图像处理库,如 OpenCV

GDI is quite fast but can be quite cumbersome. GDI 速度非常快,但可能非常麻烦。 You need to change the palette.您需要更改调色板。 GDI+ is exposed in .NET and can be slower but easier. GDI+ 在 .NET 中公开,可能更慢但更容易。 OpenCV is great but adds dependency. OpenCV 很棒,但增加了依赖性。


(UPDATE) (更新)

This code changes the image to blue-scales instead of grey-scales - image format is 32 bit ARGB:此代码将图像更改为蓝色而不是灰度 - 图像格式为 32 位 ARGB:

private static unsafe void ChangeColors(string imageFileName)
{
    const int noOfChannels = 4;
    Bitmap img = (Bitmap) Image.FromFile(imageFileName);
    BitmapData data = img.LockBits(new Rectangle(0,0,img.Width, img.Height), ImageLockMode.ReadWrite, img.PixelFormat);
    byte* ptr = (byte*) data.Scan0;
    for (int j = 0; j < data.Height; j++)
    {
        byte* scanPtr = ptr + (j * data.Stride);
        for (int i = 0; i < data.Stride; i++, scanPtr++)
        {
            if (i % noOfChannels == 3)
            { 
                *scanPtr = 255;
                continue;
            }
            if (i % noOfChannels != 0)
            {
                *scanPtr = 0;
            }
        }
    }

    img.UnlockBits(data);
    img.Save(Path.Combine( Path.GetDirectoryName(imageFileName), "result.png"), ImageFormat.Png);
}

This code project article covers this and more: http://www.codeproject.com/KB/GDI-plus/Image_Processing_Lab.aspx此代码项目文章涵盖了这一点以及更多内容: http : //www.codeproject.com/KB/GDI-plus/Image_Processing_Lab.aspx

It uses the AForge.NET library to do a Hue filter on an image for a similar effect:它使用AForge.NET库对图像进行色相过滤以获得类似的效果:

  // create filter

  AForge.Imaging.Filters.HSLFiltering filter =
      new AForge.Imaging.Filters.HSLFiltering( );
  filter.Hue = new IntRange( 340, 20 );
  filter.UpdateHue = false;
  filter.UpdateLuminance = false;
  // apply the filter

  System.Drawing.Bitmap newImage = filter.Apply( image );

It also depends on what you want: do you want to keep the original and only adjust the way it is shown?这也取决于您想要什么:您想保留原始内容并仅调整其显示方式吗? An effect or pixelshader in WPF might do the trick and be very fast. WPF 中的效果或像素着色器可能会起作用并且速度非常快。

If any Android devs end up looking at this, this is what I came up with to gray scale and tint an image using CodesInChaos's formula and the android graphics classes ColorMatrix and ColorMatrixColorFilter .如果任何 Android 开发人员最终看到这个,这就是我想出的使用 CodesInChaos 的公式和 android 图形类ColorMatrixColorMatrixColorFilter对图像进行灰度和着色的方法。

Thanks for the help!感谢您的帮助!

public static ColorFilter getColorFilter(Context context) {
    final int tint = ContextCompat.getColor(context, R.color.tint);

    final float R = Color.red(tint);
    final float G = Color.green(tint);
    final float B = Color.blue(tint);

    final float Rs = R / 255;
    final float Gs = G / 255;
    final float Bs = B / 255;

    // resultColor = oldColor + (1 - oldColor/255) * tintColor
    final float[] colorTransform = {
            1, -Rs, 0, 0, R,
            1, -Gs, 0, 0, G,
            1, -Bs, 0, 0, B,
            0, 0, 0, 0.9f, 0};

    final ColorMatrix grayMatrix = new ColorMatrix();
    grayMatrix.setSaturation(0f);
    grayMatrix.postConcat(new ColorMatrix(colorTransform));
    return new ColorMatrixColorFilter(grayMatrix);
}

The ColorFilter can then be applied to an ImageView然后可以将ColorFilter应用于 ImageView

imageView.setColorFilter(getColorFilter(imageView.getContext()));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM