Как мне перекрасить изображение?(см. изображения) - PullRequest
13 голосов
/ 15 января 2011

Как мне добиться такой замены цвета программно? replacing black with blue


Итак, эту функцию я использовал для замены пикселя:

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!

Ответы [ 7 ]

10 голосов
/ 15 января 2011

Формула для расчета нового пикселя:

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. Существует множество потоков о том, как скопировать изображение в байтовый массив и манипулировать им.

9 голосов
/ 15 января 2011

Проще всего было бы использовать ColorMatrix для обработки изображений, вы даже сможете обрабатывать предварительный просмотр желаемого эффекта - это то, сколько цветовых фильтров сделано в приложениях графического редактирования. Здесь и здесь Вы можете найти введение в цветовые эффекты, используя Colormatrix в C #.Используя 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);
4 голосов
/ 15 января 2011

Вы хотите использовать 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();
    }
}
3 голосов
/ 15 января 2011

Многое зависит от того, какой у вас формат изображения и каким будет ваш окончательный формат.

Также зависит от того, какой инструмент вы хотите использовать.Вы можете использовать:

  • 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);
}
2 голосов
/ 15 января 2011

Эта статья проекта кода охватывает это и многое другое: 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 );
1 голос
/ 15 января 2011

Это также зависит от того, что вы хотите: хотите ли вы сохранить оригинал и настроить его только так, как показано?Эффект или пиксельный шейдер в WPF могут помочь, и будут очень быстрыми.

0 голосов
/ 07 октября 2016

Если какие-то разработчики Android в конечном итоге смотрят на это, это то, что я придумал для серой шкалы и тонировки изображения с помощью формулы CodesInChaos и классов графики для Android ColorMatrix и ColorMatrixColorFilter.

Спасибоза помощь!

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