如何在 C# 中以像素级操作图像

问题描述 投票:0回答:5

如何在 C# 中以像素级别操作图像?

我需要能够分别读取/修改每个位图像素 RGB 值。

代码示例将不胜感激。

c# image-processing image-manipulation
5个回答
51
投票

如果你想要速度,那么 LockBits在这里查看 Bob Powell 的精彩演练。如果你只想编辑一些,那么 GetPixel/SetPixel 应该做你想做的。


16
投票

示例代码例程(我将其用于简单的合并和比较功能。它需要两张图像并生成第三张灰度图像,显示两张图像之间的差异作为灰度色调级别。它越暗,差异越大。) :

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

Marc 的帖子 注释 LockBits 并使用它直接修改内存中的图像。如果性能是一个问题,我建议查看它而不是我发布的内容。谢谢马克!


5
投票

System.Drawing.Bitmap 有一个 GetPixel(int x, int y) 公共方法,它返回一个 System.Drawing.Color 结构。该结构具有字节成员 R、G、B 和 A,您可以直接修改它们,然后再次在您的位图上调用 SetPixel(Color)。
不幸的是,这将相对较慢,但这是在 C# 中执行此操作的最简单方法。如果您经常处理单个像素并且发现性能不足,并且您需要更快的东西,您可以使用 LockBits ......但是它要复杂得多,因为您需要了解该颜色深度和类型的位结构,并使用位图的步幅等等......所以如果你觉得有必要,一定要找到一个好的教程!网上有几个,谷歌搜索“C# LockBits”会给你半打值得一读的东西。


3
投票

如果性能至关重要,LockBits 的另一种替代方法是托管 DirectX。

有关更多信息,请参阅之前的 Stack Overflow 问题 Rendering graphics in C#

与 Lockbits 一样,您需要使用不安全关键字/编译器开关,但您可以获得高性能像素级访问权限。

与使用普通的 Bitmap 类和 PictureBox 控件相比,您还可以通过 DirectX 后备缓冲获得更高性能的屏幕渲染。


0
投票
下面列出的代码包含一个基本示例,说明如何在 Microsoft Visual Studio 2022 上使用 C# 编程语言创建像素图像编辑器。

namespace 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() ; } } }
    
© www.soinside.com 2019 - 2024. All rights reserved.