【问题标题】:How do I recolor an image? (see images)如何重新着色图像? (见图片)
【发布时间】:2011-06-09 15:26:34
【问题描述】:

如何以编程方式实现这种颜色替换?


所以这是我用来替换像素的函数:

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

谢谢你,CodeInChaos!

【问题讨论】:

  • 为什么我失去了赞成票,或者得到了反对票?大声笑...
  • 没有反对意见。我假设在您编辑问题时有人能够删除他们的赞成票。无论哪种方式,除非有人发表评论并提出具体的建议或批评,否则这不是值得担心的事情。 :-)

标签: c# image image-processing colors


【解决方案1】:

新像素的计算公式为:

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

推广到任意颜色:

我假设您想将白色映射到白色,将黑色映射到该颜色。所以公式是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;

然后只需遍历图像的像素(字节数组)并将它们写入新的 RGB 数组。关于如何将图像复制到字节数组并对其进行操作,有很多线程。

【讨论】:

  • 这个答案对我来说是最好的,但蓝色可以是任何颜色。
  • @Vercas 添加了任意颜色的公式。
  • @CodeInChaos 我现在正在测试公式。另外,您忘记将 .R、.G 和 .B 添加到“oldColor”变量中。
  • 这可能是最简单的解决方案,但是即使您使用Bitmap.LockBits,遍历位图并修改每个像素也可能非常慢。这取决于您需要处理多少张图片以及执行此操作的频率。
  • 我没有将它们添加到 oldColor 中,因为我认为旧颜色只是一个字节,因为左侧图像只是灰度。而我的代码只是伪代码。您不应该使用ColorGetPixel,因为这非常很慢。您需要使用基于 Bitmap.LockBits 的东西,并可能复制到字节数组。
【解决方案2】:

如果任何 Android 开发人员最终看到这个,这就是我想出的灰度和使用 CodesInChaos 的公式和 android 图形类 ColorMatrixColorMatrixColorFilter 着色图像。

感谢您的帮助!

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);
}

ColorFilter 然后可以应用于 ImageView

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

【讨论】:

    【解决方案3】:

    很大程度上取决于您的图像格式和最终格式。

    还取决于您想使用什么工具。 您可以使用:

    • GDI
    • GD+
    • OpenCV 等图像处理库

    GDI 速度很快,但也很麻烦。您需要更改调色板。 GDI+ 在 .NET 中公开,速度较慢但更容易。 OpenCV 很棒,但增加了依赖性。


    (更新)

    此代码将图像更改为蓝色而不是灰度 - 图像格式为 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);
    }
    

    【讨论】:

    • 是的,我的朋友,但 ImageFormat 很重要。是8bit灰度吗? 24位Windows位图? 32位有阿尔法?如果你告诉我你想用哪一个,我可以给你代码示例。
    • 好吧,我打开一个没有透明度的PNG图像,所以我猜它是24位的。
    • 正如我评论接受的答案时,蓝色只是一个例子。它可以是任何颜色,我的图像可以有更多的白色,例如,它也可以有一些红色。
    • 请记住,您的字节按 BGRA(而不是 ARGB)排序,您可以想出各种组合。我的代码只是将红色和绿色通道设置为零并最大化 alpha 通道。
    【解决方案4】:

    最简单的方法是使用 ColorMatrix 处理图像,您甚至可以处理所需效果的动态预览 - 这就是图形编辑应用程序中制作的彩色滤镜的数量。 Herehere 你可以找到在 C# 中使用 Colormatrix 的颜色效果介绍。通过使用 ColorMatrix,您可以根据需要制作颜色滤镜,以及棕褐色、黑白、反转、范围、亮度、对比度、亮度、级别(通过多通道)等。

    编辑:这是示例(更新 - 固定颜色矩阵以将较暗的值转换为蓝色,而不是之前的除蓝色部分之外的归零 - 并且 - 将 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);
    

    【讨论】:

    • 我可能会使用颜色矩阵,但我不知道那是什么或如何将它用于我的目的。
    • 上面的示例与上面的示例图像转换完全相同。
    • 您可以尝试使用值,在最后一行 3 个值添加 RGB 值(-1 到 1 的值表示 -255 到 255 的值),对角线上是原始 RGB 值的乘积(如果您乘法/加法太多,像素值将是 0 或 255),在对角线附近我设置了 1 以将值转换为蓝色。实验一下,值得。
    【解决方案5】:

    您需要在此处使用 ColorMatrix。源图像是灰度的,它的所有 R、G 和 B 值都相等。然后只需将黑色替换为 RGB = (0, 0, 255) 以获得深蓝色,将白色替换为 RGB = (255, 255, 255) 即可获得白色。因此矩阵可以如下所示:

    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
    

    此示例表单复制了右侧图像:

    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();
        }
    }
    

    【讨论】:

    • 那个蓝色只是一个例子。要重新着色的图像可以有任何颜色,而不仅仅是灰度,要替换/添加的颜色可以是任何颜色,这意味着 R、G 和 B 可以是任何颜色。我根本不懂这个颜色矩阵。
    • 好吧,那么这只是一个示例,说明如何使用 ColorMatrix 替换颜色。您必须提出自己的系数来进行自己的替换。使用本教程了解其工作原理:active.tutsplus.com/tutorials/effects/…
    【解决方案6】:

    这也取决于你想要什么:你想保留原件并只调整它的显示方式吗? WPF 中的效果或像素着色器可能会起到作用,而且速度非常快。

    【讨论】:

    • 不行,我需要调整原件。
    【解决方案7】:

    这篇代码项目文章涵盖了这个以及更多内容:http://www.codeproject.com/KB/GDI-plus/Image_Processing_Lab.aspx

    它使用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 );
    

    【讨论】:

    • 那么,这会将范围内的任何颜色更改为我的颜色吗?
    • 我相信该库利用色调范围来轻松替换使用相机拍摄的图像的颜色。想想绿屏,图像中的绿色并不均匀,而是在一个取决于阴影等的范围内。
    猜你喜欢
    • 1970-01-01
    • 2015-07-02
    • 1970-01-01
    • 1970-01-01
    • 2020-09-18
    • 1970-01-01
    • 2021-08-29
    • 2017-01-03
    相关资源
    最近更新 更多