使用 C# 从 pictureBox 中的图像添加或减去颜色
Adding or subtracting color from an image in a pictureBox using C#
我想学习如何在 Visual Studio 中编写一些非常基本的图像编辑代码。我正在使用 openFileDialog 将图片加载到 pictureBox 中。我在 Internet 上发现了一些旨在逐个像素地转换颜色的循环,但由于各种原因(每个代码示例不同)none 工作。 正确 添加(或减去)红色值以更改 pictureBox 中图像色调的方法是什么?我正在使用 C#。
谢谢
编辑:这里有一个至少是起点的例子:
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");
这让我可以逐个像素地获取图像,并将颜色更改为紫色。当然,那不是我想做的。我想要做的是获取每个像素的原始 RGB 值,并增加或减少这些值。换句话说,执行一些非常基本的色彩校正。
如何获取每个像素的当前RGB,并设置新像素的RGB?
我也看到这个帖子作为例子。问题是,我不知道如何使用 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;
我意识到我应该在第一时间发布代码示例。谢谢
这是使用 Getpixel
和 SetPixel
的示例。
为了(快得多)更快的过滤结果查看 Lockbits and also into using a 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;
}
更新:
上面的代码是一个非常简单的介绍。简单但也很慢,而且不太灵活。
这是一个非常快速且更加灵活的版本:
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;
}
上面的代码调用了一个delegate
:
public delegate Color ModifyHue(Color c, int ch);
并且delegate
设置为调用一个简单的过滤函数:
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;
}
这是另一个将 Color
更改为灰色
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);
}
请注意,我们要通过 delegate
调用的所有方法都需要具有相同的 signature
。因此 ToGreyscale
也将 integer
作为第二个参数,即使它不使用它..
另请注意,您可以像之前的简单示例一样限制 LockBits
循环的开始和结束值,以获取第二个屏幕截图。
我想学习如何在 Visual Studio 中编写一些非常基本的图像编辑代码。我正在使用 openFileDialog 将图片加载到 pictureBox 中。我在 Internet 上发现了一些旨在逐个像素地转换颜色的循环,但由于各种原因(每个代码示例不同)none 工作。 正确 添加(或减去)红色值以更改 pictureBox 中图像色调的方法是什么?我正在使用 C#。
谢谢
编辑:这里有一个至少是起点的例子:
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");
这让我可以逐个像素地获取图像,并将颜色更改为紫色。当然,那不是我想做的。我想要做的是获取每个像素的原始 RGB 值,并增加或减少这些值。换句话说,执行一些非常基本的色彩校正。
如何获取每个像素的当前RGB,并设置新像素的RGB?
我也看到这个帖子作为例子。问题是,我不知道如何使用 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;
我意识到我应该在第一时间发布代码示例。谢谢
这是使用 Getpixel
和 SetPixel
的示例。
为了(快得多)更快的过滤结果查看 Lockbits and also into using a 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;
}
更新:
上面的代码是一个非常简单的介绍。简单但也很慢,而且不太灵活。
这是一个非常快速且更加灵活的版本:
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;
}
上面的代码调用了一个delegate
:
public delegate Color ModifyHue(Color c, int ch);
并且delegate
设置为调用一个简单的过滤函数:
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;
}
这是另一个将 Color
更改为灰色
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);
}
请注意,我们要通过 delegate
调用的所有方法都需要具有相同的 signature
。因此 ToGreyscale
也将 integer
作为第二个参数,即使它不使用它..
另请注意,您可以像之前的简单示例一样限制 LockBits
循环的开始和结束值,以获取第二个屏幕截图。