本文介绍了C#如何将获取的GetPixel / SetPixel颜色处理转换为Lockbits?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

编辑:我非常感谢回复。我在这里需要的不仅仅是示例代码,用于我在嵌套循环中使用几行代码所做的事情,因为这在GetPixel / SetPixel中是正常的,但也是我无法使用Lockbits工作的。谢谢

我正在尝试将我的图像处理过滤器从GetPixel / SetPixel转换为Lockbits,以缩短处理时间。 我已经在Stack Overflow,MSDN和其他网站上看过Lockbits教程,但我做错了。我从一个非常简单的过滤器开始,它简单地减少了绿色以创建一个红色和紫色的效果。这是我的代码:

I'm trying to convert my image processing filters from GetPixel / SetPixel to Lockbits, to improve processing time. I have seen Lockbits tutorials here on Stack Overflow, MSDN, and other sites as well, but I'm doing something wrong. I'm starting with an exceedingly simple filter, which simply reduces green to create a red and purple effect. Here's my code:

   private void redsAndPurplesToolStripMenuItem_Click(object sender, EventArgs e)
    {
        // Get bitmap from picturebox
        Bitmap bmpMain = (Bitmap)pictureBoxMain.Image.Clone();

        // search through each pixel via x, y coordinates, examine and make changes. Dont let values exceed 255 or fall under 0.
        for (int y = 0; y < bmpMain.Height; y++)
            for (int x = 0; x < bmpMain.Width; x++)
            {
                bmpMain.GetPixel(x, y);
                Color c = bmpMain.GetPixel(x, y);
                int myRed = c.R, myGreen = c.G, myBlue = c.B;
                myGreen -= 128;
                if (myGreen < 0) myGreen = 0;
                bmpMain.SetPixel(x, y, Color.FromArgb(255, myRed, myGreen, myBlue));
            }

        // assign the new bitmap to the picturebox
        pictureBoxMain.Image = (Bitmap)bmpMain;

        // Save a copy to the HD for undo / redo.
        string myString = Environment.GetEnvironmentVariable("temp", EnvironmentVariableTarget.Machine);
        pictureBoxMain.Image.Save(myString + "\\ColorAppRedo.png", System.Drawing.Imaging.ImageFormat.Png);
    }

因此GetPixel / SetPixel代码工作正常,但速度很慢。所以我尝试了这个:

So that GetPixel / SetPixel code works fine, but it's slow. So I tried this:

    private void redsAndPurplesToolStripMenuItem_Click(object sender, EventArgs e)
    {
        // Get bitmap from picturebox
        Bitmap bmpMain = (Bitmap)pictureBoxMain.Image.Clone();

        Rectangle rect = new Rectangle(Point.Empty, bmpMain.Size);
        BitmapData bmpData = bmpMain.LockBits(rect, ImageLockMode.ReadOnly, bmpMain.PixelFormat);

        // search through each pixel via x, y coordinates, examine and make changes. Dont let values exceed 255 or fall under 0.
        for (int y = 0; y < bmpMain.Height; y++)
            for (int x = 0; x < bmpMain.Width; x++)
            {
                bmpMain.GetPixel(x, y);
                Color c = new Color();
                int myRed = c.R, myGreen = c.G, myBlue = c.B;
                myGreen -= 128;
                if (myGreen < 0) myGreen = 0;
                bmpMain.SetPixel(x, y, Color.FromArgb(255, myRed, myGreen, myBlue));

            }

        bmpMain.UnlockBits(bmpData);

        // assign the new bitmap to the picturebox
        pictureBoxMain.Image = (Bitmap)bmpMain;

        // Save a copy to the HD for undo / redo.
        string myString = Environment.GetEnvironmentVariable("temp", EnvironmentVariableTarget.Machine);
        pictureBoxMain.Image.Save(myString + "\\ColorAppRedo.png", System.Drawing.Imaging.ImageFormat.Png);
    }

抛出错误发生了'System.InvalidOperationException'类型的未处理异常在System.Drawing.dll中附加信息:位图区域已经锁定当它到达嵌套循环的第一行时。

Which throws the error "An unhandled exception of type 'System.InvalidOperationException' occurred in System.Drawing.dll Additional information: Bitmap region is already locked" when it reaches the first line of the nested loop.

我意识到这必须是一个初学者的错误,如果有人能够演示正确方式将这个非常简单的过滤器转换为Lockbits。非常感谢

I realize this has to be a beginner's error, I'd appreciate if someone could demonstrate the correct way to convert this very simple filter to Lockbits. Thank you very much

推荐答案

scan0返回的数组格式为BGRA BGRA BGRA BGRA ...依此类推,
其中B =蓝色,G =绿色,R =红色,A = Alpha。

The array returned by scan0 is in this format BGRA BGRA BGRA BGRA ... and so on,where B = Blue, G = Green, R = Red, A = Alpha.

一个非常小的位图示例,宽4像素,高3像素。 / p>

Example of a very small bitmap 4 pixels wide and 3 pixels height.

BGRA BGRA BGRA BGRA
BGRA BGRA BGRA BGRA
BGRA BGRA BGRA BGRA

stride = width*bytesPerPixel = 4*4 = 16 bytes
height = 3
maxLenght = stride*height= 16*3 = 48 bytes

要到达图像中的某个像素(x,y),请使用此公式

To reach a certain pixel in the image (x, y) use this formula

int certainPixel = bytesPerPixel*x + stride * y;
B = scan0[certainPixel + 0];
G = scan0[certainPixel + 1];
R = scan0[certainPixel + 2];
A = scan0[certainPixel + 3];







    public unsafe void Test(Bitmap bmp)
    {
        int width = bmp.Width;
        int height = bmp.Height;
        //TODO determine bytes per pixel
        int bytesPerPixel = 4; // we assume that image is Format32bppArgb
        int maxPointerLenght = width * height * bytesPerPixel;
        int stride = width * bytesPerPixel;
        byte R, G, B, A;

        BitmapData bData = bmp.LockBits(
            new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height),
            ImageLockMode.ReadWrite, bmp.PixelFormat);


        byte* scan0 = (byte*)bData.Scan0.ToPointer();

        for (int i = 0; i < maxPointerLenght; i += 4)
        {
            B = scan0[i + 0];
            G = scan0[i + 1];
            R = scan0[i + 2];
            A = scan0[i + 3];

            // do anything with the colors
            // Set the green component to 0
            G = 0;
            // do something with red
            R = R < 54 ? (byte)(R + 127) : R;
            R = R > 255 ? 255 : R;
        }


        bmp.UnlockBits(bData);
    }

您可以自己测试。在绘画或任何其他程序中创建一个非常小的位图(几个像素宽/高),并在方法的开头放置一个断点。

You can test is yourself. Create a very small bitmap ( few pixels wide/height) in paint or any other program and put a breakpoint at the begining of the method.

这篇关于C#如何将获取的GetPixel / SetPixel颜色处理转换为Lockbits?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

06-10 18:34