How do I recolor an image? (see images)

后端 未结 7 617
没有蜡笔的小新
没有蜡笔的小新 2020-12-29 08:53

How do I achieve this kind of color replacement programmatically? \"replacing


So this i

相关标签:
7条回答
  • 2020-12-29 08:56

    You'll want to use a ColorMatrix here. The source image is grayscale, all its R, G and B values are equal. 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. 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();
        }
    }
    
    0 讨论(0)
  • 2020-12-29 08:58

    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.

    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

    imageView.setColorFilter(getColorFilter(imageView.getContext()));
    
    0 讨论(0)
  • 2020-12-29 09:09

    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.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. There are many threads on how to copy an image into a byte array and manipulate it.

    0 讨论(0)
  • 2020-12-29 09:10

    This code project article covers this and more: 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:

      // 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 );
    
    0 讨论(0)
  • 2020-12-29 09:18

    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

    GDI is quite fast but can be quite cumbersome. You need to change the palette. GDI+ is exposed in .NET and can be slower but easier. OpenCV is great but adds dependency.


    (UPDATE)

    This code changes the image to blue-scales instead of grey-scales - image format is 32 bit 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);
    }
    
    0 讨论(0)
  • 2020-12-29 09:19

    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. Here and here you can find introductions to color effects using Colormatrix in C#. 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.

    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):

    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);
    
    0 讨论(0)
提交回复
热议问题