无需外部 dll 即可制作图像负片的有效方法

发布于 2024-07-13 09:22:18 字数 64 浏览 6 评论 0原文

这就是在 C# Windows 窗体中从图像制作底片而无需任何 dll 并以有效、快速的方式制作底片的解决方案吗?

That is the solution to make a negative from a image in C# Windows Forms without any dlls and in a effective, fast way?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

挽清梦 2024-07-20 09:22:18

执行此操作的最佳方法是直接使用位图数据访问像素。

只是添加一些计时细节:

在 8 兆像素图像上执行 Negate(在 2.4 Ghz Core 2 Duo 上):

  • SetPixel(约 22 秒)- 慢 220 倍的
  • 7 倍
  • 颜色矩阵,下面的 Matajon 方法(约 750 毫秒)-慢 访问位图数据(~100 毫秒) - 最快

因此,如果您不能有不安全的代码,那么 Color Matrix 比 SetPixel 好得多。

    public static void Negate(Bitmap image)
    {
        const int RED_PIXEL = 2;
        const int GREEN_PIXEL = 1;
        const int BLUE_PIXEL = 0;


        BitmapData bmData = currentImage.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadWrite, image.PixelFormat);

        try
        {
            int stride = bmData.Stride;
            int bytesPerPixel = (currentImage.PixelFormat == PixelFormat.Format24bppRgb ? 3 : 4);

            unsafe
            {
                byte* pixel = (byte*)(void*)bmData.Scan0;
                int yMax = image.Height;
                int xMax = image.Width;

                for (int y = 0; y < yMax; y++)
                {
                    int yPos = y * stride;
                    for (int x = areaSize.X; x < xMax; x++)
                    {
                        int pos = yPos + (x * bytesPerPixel);

                        pixel[pos + RED_PIXEL] = (byte)(255 - pixel[pos + RED_PIXEL]);
                        pixel[pos + GREEN_PIXEL] = (byte)(255 - pixel[pos + GREEN_PIXEL]);
                        pixel[pos + BLUE_PIXEL] = (byte)(255 - pixel[pos + BLUE_PIXEL]);                                                    
                    }

                }
            }
        }
        finally
        {
            image.UnlockBits(bmData);
        }

    }

如果您有兴趣,这里是颜色矩阵的代码:

    public static void Negate(Bitmap image)
    {

            Bitmap clone = (Bitmap) image.Clone();

            using (Graphics g = Graphics.FromImage(image))
            {

                // negation ColorMatrix
                ColorMatrix colorMatrix = new ColorMatrix(
                    new float[][]
                        {
                            new float[] {-1, 0, 0, 0, 0},
                            new float[] {0, -1, 0, 0, 0},
                            new float[] {0, 0, -1, 0, 0},
                            new float[] {0, 0, 0, 1, 0},
                            new float[] {0, 0, 0, 0, 1}
                        });

                ImageAttributes attributes = new ImageAttributes();

                attributes.SetColorMatrix(colorMatrix);

                g.DrawImage(clone, new Rectangle(0, 0, clone.Width, clone.Height),
                            0, 0, clone.Width, clone.Height, GraphicsUnit.Pixel, attributes);
           }
    }

The best way to do this is directly accessing the pixels with bitmap data.

Just to add some timing details:

Performing Negate on an 8 Megapixel Image (on a 2.4 Ghz Core 2 Duo):

  • SetPixel (~22 seconds) - 220 Times slower
  • Color Matrix, Matajon's method below (~750 milliseconds) - 7 times slower
  • Directly accesing the bitmap data (~100 milliseconds) - Fastest

So, if you can't have unsafe code, then Color Matrix is much better than SetPixel.

    public static void Negate(Bitmap image)
    {
        const int RED_PIXEL = 2;
        const int GREEN_PIXEL = 1;
        const int BLUE_PIXEL = 0;


        BitmapData bmData = currentImage.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadWrite, image.PixelFormat);

        try
        {
            int stride = bmData.Stride;
            int bytesPerPixel = (currentImage.PixelFormat == PixelFormat.Format24bppRgb ? 3 : 4);

            unsafe
            {
                byte* pixel = (byte*)(void*)bmData.Scan0;
                int yMax = image.Height;
                int xMax = image.Width;

                for (int y = 0; y < yMax; y++)
                {
                    int yPos = y * stride;
                    for (int x = areaSize.X; x < xMax; x++)
                    {
                        int pos = yPos + (x * bytesPerPixel);

                        pixel[pos + RED_PIXEL] = (byte)(255 - pixel[pos + RED_PIXEL]);
                        pixel[pos + GREEN_PIXEL] = (byte)(255 - pixel[pos + GREEN_PIXEL]);
                        pixel[pos + BLUE_PIXEL] = (byte)(255 - pixel[pos + BLUE_PIXEL]);                                                    
                    }

                }
            }
        }
        finally
        {
            image.UnlockBits(bmData);
        }

    }

If you are interested, here is the code for Color Matrix:

    public static void Negate(Bitmap image)
    {

            Bitmap clone = (Bitmap) image.Clone();

            using (Graphics g = Graphics.FromImage(image))
            {

                // negation ColorMatrix
                ColorMatrix colorMatrix = new ColorMatrix(
                    new float[][]
                        {
                            new float[] {-1, 0, 0, 0, 0},
                            new float[] {0, -1, 0, 0, 0},
                            new float[] {0, 0, -1, 0, 0},
                            new float[] {0, 0, 0, 1, 0},
                            new float[] {0, 0, 0, 0, 1}
                        });

                ImageAttributes attributes = new ImageAttributes();

                attributes.SetColorMatrix(colorMatrix);

                g.DrawImage(clone, new Rectangle(0, 0, clone.Width, clone.Height),
                            0, 0, clone.Width, clone.Height, GraphicsUnit.Pixel, attributes);
           }
    }
呢古 2024-07-20 09:22:18

逐一遍历所有像素(Bitmap.GetPixel() 或其他)并从 0xff 中减去 RGB 值以创建负颜色像素。 将此像素保存到新图像或使用 (Bitmap.SetPixel()) 保存到同一图像的相同位置。

    // Retrieve the image.
    var image1 = new Bitmap(@"C:\Documents and Settings\All Users\" 
        + @"Documents\My Music\music.bmp", true);

    int x, y;

    // Loop through the images pixels to reset color.
    for(x=0; x<image1.Width; x++)
    {
        for(y=0; y<image1.Height; y++)
        {
            Color pixelColor = image1.GetPixel(x, y);
            Color newColor = Color.FromArgb(0xff - pixelColor.R
            , 0xff - pixelColor.G, 0xff - pixelColor.B);
            image1.SetPixel(x, y, newColor);
        }
    }

Go through all the pixels one by one (Bitmap.GetPixel() or something) and subtract the RGB values from 0xff to create a pixel of negative color. Save this pixel to a new image or onto the same image using (Bitmap.SetPixel()) at the same position.

    // Retrieve the image.
    var image1 = new Bitmap(@"C:\Documents and Settings\All Users\" 
        + @"Documents\My Music\music.bmp", true);

    int x, y;

    // Loop through the images pixels to reset color.
    for(x=0; x<image1.Width; x++)
    {
        for(y=0; y<image1.Height; y++)
        {
            Color pixelColor = image1.GetPixel(x, y);
            Color newColor = Color.FromArgb(0xff - pixelColor.R
            , 0xff - pixelColor.G, 0xff - pixelColor.B);
            image1.SetPixel(x, y, newColor);
        }
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文