如何在C#中以像素级别操作图像?
我需要能够单独读取/修改每个位图像素的RGB值。
如果有代码示例将不胜感激。
如何在C#中以像素级别操作图像?
我需要能够单独读取/修改每个位图像素的RGB值。
如果有代码示例将不胜感激。
以下是一段样例代码(我用它来实现简单的合并和比较功能)。它需要两张图片,并生成第三张灰度图像,显示两个原始图片之间的差异程度。颜色越深,差异越大:
public static Bitmap Diff(Bitmap src1, Bitmap src2, int x1, int y1, int x2, int y2, int width, int height)
{
Bitmap diffBM = new Bitmap(width, height, PixelFormat.Format24bppRgb);
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
//Get Both Colours at the pixel point
Color col1 = src1.GetPixel(x1 + x, y1 + y);
Color col2 = src2.GetPixel(x2 + x, y2 + y);
// Get the difference RGB
int r = 0, g = 0, b = 0;
r = Math.Abs(col1.R - col2.R);
g = Math.Abs(col1.G - col2.G);
b = Math.Abs(col1.B - col2.B);
// Invert the difference average
int dif = 255 - ((r+g+b) / 3);
// Create new grayscale RGB colour
Color newcol = Color.FromArgb(dif, dif, dif);
diffBM.SetPixel(x, y, newcol);
}
}
return diffBM;
}
马克的帖子指出了 LockBits 并建议直接在内存中修改图像。如果性能是一个关注点,我建议查看那个帖子。谢谢马克!
GetPixel
和SetPixel
非常慢。 Bitmap.LockBits
与Marshal.Copy
结合使用可以实现相同的功能,但是以块状数据而不是逐像素获取数据,这使得速度更快。 - Nyergudsnamespace GreekPicturePixelEditor
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private int X1 = 0; // picture box 1 mouse click X position
private int Y1 = 0; // picture box 1 mouse click y position
private bool mousePress = false; // is left mouse pressed in picture box 2
private Bitmap statueBitmap;
private SolidBrush brush;
private Pen pen;
private Rectangle rec;
private Color color;
private const int pSize = 20; // pixel size
// Step 1. Create first picture box 1 at least 512x512 pixel
// Create second picture box 2 at least 32x32 pixel
// Create a 512x512 bitmap image using MS Paint
// Load and display statue bitmap on picture box 1
private void Form1_Load(object sender, EventArgs e)
{
statueBitmap = new Bitmap(@"C:\VS2022\Pic\Greek512x512.bmp");
pictureBox1.Image = statueBitmap;
}
// Step 2. Save X1,Y1 mouse coordinate when user click on picture box 1
private void pictureBox1_MouseClick(object sender, MouseEventArgs e)
{
X1 = e.X; // Save X1, Y1 mouse coordinate when user click on picture box 1
Y1 = e.Y;
pictureBox2.Refresh(); // force re-draw picture box 2
}
// Step 3. Create a 32x32 pixel grid on picture box 2. When user click on
// picture box 1, a pixel grid is created based on the X1,
// Y1 coordinate of picture box 2. In other words, 32x32 bitmap image
// is cloned starting at X1,Y1 position in picture box 1 to picture box 2.
private void pictureBox2_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
for( int px = 0; px < 31; px++ )
{
for( int py = 0; py < 31; py++ )
{
color = ((Bitmap)pictureBox1.Image).GetPixel( X1 + px, Y1 + py );
brush = new SolidBrush( color );
pen = new Pen( Form1.DefaultBackColor );
rec = new Rectangle( px * pSize, py * pSize, pSize, pSize );
g.FillRectangle( brush, rec );
g.DrawRectangle( pen, rec );
}
}
}
// Step 4. Handle mouse events when drawing picture box 2 with a mouse
private void pictureBox2_MouseUp(object sender, MouseEventArgs e)
{
mousePress = false;
}
// Step 4. Handle mouse events when drawing picture box 2 with a mouse
private void pictureBox2_MouseDown(object sender, MouseEventArgs e)
{
if( e.Button == MouseButtons.Left )
{
mousePress = true;
int X2 = e.X / 20; // Normalized the mouse position X and Y of picture box 2
int Y2 = e.Y / 20;
((Bitmap)pictureBox1.Image).SetPixel( X1 + X2, Y1 + Y2, System.Drawing.Color.Red );
pictureBox1.Refresh();
pictureBox2.Refresh();
}
}
// Step 4. Handle mouse events when drawing picture box 2 with a mouse
private void pictureBox2_MouseMove(object sender, MouseEventArgs e)
{
if( mousePress )
{
int X2 = e.X / 20; // Normalized the mouse position X and Y of picture box 2
int Y2 = e.Y / 20;
((Bitmap)pictureBox1.Image).SetPixel( X1 + X2, Y1 + Y2, System.Drawing.Color.Red );
pictureBox1.Refresh();
pictureBox2.Refresh();
}
}
// Step 5. Deallocate memory to the system
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
statueBitmap.Dispose();
brush.Dispose();
pen.Dispose() ;
}
}
}