Sumar o restar color de una imagen en un cuadro de imagen usando C#
image-processing picturebox (1)
Me gustaría aprender a codificar algunas ediciones de imágenes muy básicas en Visual Studio. Estoy usando openFileDialog para cargar una imagen en un cuadro de imagen. He encontrado algunos bucles en Internet que están diseñados para convertir el color píxel por píxel, pero por varias razones (que difieren con cada muestra de código) ninguno funciona. ¿Cuál es la forma correcta de sumar (o restar), por ejemplo, el valor rojo, para cambiar el tinte de una imagen en una PictureBox? Estoy usando C #.
Gracias
EDITAR: Aquí hay un ejemplo de algo que es al menos un punto de partida:
Bitmap bmp = (Bitmap)Bitmap.FromFile(pictureBox1.ImageLocation);
for (int x = 0; x < bmp.Width; x++)
{
for (int y = 0; y < bmp.Height; y++)
{
bmp.GetPixel(x, y);
bmp.SetPixel(x, y, Color.FromArgb(128, 0, 128));
}
}
pictureBox1.Image = bmp;
MessageBox.Show("Done");
Esto me permite obtener la imagen píxel por píxel y cambiar el color, en este caso, a púrpura. Por supuesto, eso no es lo que quiero hacer. Lo que quiero hacer es obtener el valor RGB original de cada píxel y aumentar o disminuir los valores. En otras palabras, realice una corrección de color muy básica.
¿Cómo obtengo el RGB actual de cada píxel y establezco el RGB del nuevo píxel?
También he visto esto publicado como un ejemplo. El problema es que no veo cómo usar ModifyHue:
var bmp = new Bitmap(pictureBox1.ImageLocation);
for (int x = 0; x < bmp.Width; x++)
{
for (int y = 0; y < bmp.Height; y++)
{
Color oldColor = bmp.GetPixel(x, y);
Color newColor = ModifyHue(oldColor);
bmp.SetPixel(x, y, newColor);
}
}
pictureBox1.Image = bmp;
Me doy cuenta de que debería haber publicado muestras de código la primera vez. Gracias
Este es un ejemplo del uso de
Getpixel
y
SetPixel
.
Para obtener resultados de filtro (mucho, mucho más rápidos), busque Lockbits y también use un ColorMatrix
private void button2_Click(object sender, EventArgs e)
{
// we pull the bitmap from the image
Bitmap bmp = (Bitmap) pictureBox1.Image;
// we change some picels
for (int y = 100; y < bmp.Height; y++)
for (int x = 100; x < bmp.Width; x++)
{
Color c = bmp.GetPixel(x, y);
bmp.SetPixel(x, y, Color.FromArgb(255, 255, c.G, c.B));
}
// we need to re-assign the changed bitmap
pictureBox1.Image = (Bitmap) bmp;
}
Actualizar:
El código anterior es una introducción muy simple. Es simple pero también muy lento y no es muy flexible.
Aquí hay una versión que es muy rápida y mucho más flexible:
private void button3_Click(object sender, EventArgs e)
{
// pick one of our filter methods
ModifyHue hueChanger = new ModifyHue(MaxChannel);
// we pull the bitmap from the image
Bitmap bmp = (Bitmap)pictureBox1.Image;
Size s = bmp.Size;
PixelFormat fmt = bmp.PixelFormat;
// we need the bit depth and we assume either 32bppArgb or 24bppRgb !
byte bpp = (byte)(fmt == PixelFormat.Format32bppArgb ? 4 : 3);
// lock the bits and prepare the loop
Rectangle rect = new Rectangle(Point.Empty, s);
BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.ReadOnly, fmt);
int size1 = bmpData.Stride * bmpData.Height;
byte[] data = new byte[size1];
System.Runtime.InteropServices.Marshal.Copy(bmpData.Scan0, data, 0, size1);
// loops
for (int y = 0; y < s.Height; y++)
{
for (int x = 0; x < s.Width; x++)
{
// calculate the index
int index = y * bmpData.Stride + x * bpp;
// get the color
Color c = Color.FromArgb( bpp == 4 ?data[index + 3]: 255 ,
data[index + 2], data[index + 1], data[index]);
// process it
c = hueChanger(c, 2);
// set the channels from the new color
data[index + 0] = c.B;
data[index + 1] = c.G;
data[index + 2] = c.R;
if (bpp == 4) data[index + 3] = c.A;
}
}
System.Runtime.InteropServices.Marshal.Copy(data, 0, bmpData.Scan0, data.Length);
bmp.UnlockBits(bmpData);
// we need to re-assign the changed bitmap
pictureBox1.Image = (Bitmap)bmp;
}
El código anterior llama a un
delegate
:
public delegate Color ModifyHue(Color c, int ch);
Y el
delegate
está configurado para llamar a una función de filtro simple:
public Color MaxChannel(Color c, int channel)
{
if (channel == 1) return Color.FromArgb(255, 255, c.G, c.B);
if (channel == 2) return Color.FromArgb(255, c.R, 255, c.B);
if (channel == 3) return Color.FromArgb(255, c.R, c.G, 255);
else return c;
}
Y aquí hay otro que cambia un
Color
a gris
public Color ToGreyscale(Color c, int dummy)
{
byte val = (byte) ( (c.R * 0.299f + c.G * 0.587f + c.B *0.114f) ) ;
return Color.FromArgb(255, val, val,val);
}
Tenga en cuenta que todos los métodos que queremos llamar a través de un
delegate
deben tener la misma
signature
.
Por
ToGreyscale
tanto,
ToGreyscale
también toma un
integer
como segundo parámetro, aunque no lo use.
También tenga en cuenta que puede limitar los
LockBits
inicio y finalización del bucle
LockBits
al igual que en el ejemplo simple anterior para obtener la segunda captura de pantalla.