有效地调整图像在C#中的对比 [英] Adjust the contrast of an image in C# efficiently

查看:154
本文介绍了有效地调整图像在C#中的对比的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有在C#调整图像的对比度的一种有效的方法

Is there an efficient way of adjusting the contrast of an image in C#?

我见过本文主张做每个像素的操作。还不快。

I've seen this article which advocates doing a per-pixel operation. Not quick.

我使用的色彩矩阵的地方已经去找他们要快。有没有办法利用它们来调节对比度? (注:这家伙得到它错了。 )

I'm using colour matrices in places already and find them to be quick. Is there a way to adjust contrast using them? (Note: This guy gets it wrong.)

我还使用EmguCV。我注意到的OpenCV(其中Emgu包装)似乎有一个对比功能 - 是有通过Emgu访问该的方法吗?此刻,我只能在Emgu做的是标准化的直方图,它不改变对比度,而与控制我的一部分任何程度。

I'm also using EmguCV. I notice that OpenCV (which Emgu wraps) seems to have a contrast function - is there any way of accessing this through Emgu? At the moment all I can do in Emgu is normalise the histogram, which does change the contrast, but not with any degree of control on my part.

任何人有什么想法?

推荐答案

如果该样本中的code为你工作,你可以大量(数量级),通过使用加速它 Bitmap.LockBits ,它返回一个的BitmapData 对象,允许通过指针访问位图的像素数据。有在网络上,并在计算器上显示如何使用LockBits众多的样品。

If the code in that sample works for you, you can speed it up massively (by orders of magnitude) by using Bitmap.LockBits, which returns a BitmapData object that allows access to the Bitmap's pixel data via pointers. There are numerous samples on the web and on StackOverflow that show how to use LockBits.

Bitmap.SetPixel() Bitmap.GetPixel()是人类已知的最慢的方法,他们既利用颜色类,这是人类已知的最慢的类。它们应该被命名为 Bitmap.GetPixelAndByGodYoullBeSorryYouDid() Bitmap.SetPixelWhileGettingCoffee 以警示粗心的开发者。

Bitmap.SetPixel() and Bitmap.GetPixel() are the slowest methods known to mankind, and they both utilize the Color class, which is the slowest class known to mankind. They should have been named Bitmap.GetPixelAndByGodYoullBeSorryYouDid() and Bitmap.SetPixelWhileGettingCoffee as a warning to unwary developers.

更新::如果你要修改code的样品中,请注意此块:

Update: If you're going to modify the code in that sample, note that this chunk:

System.Drawing.Bitmap TempBitmap = Image;
System.Drawing.Bitmap NewBitmap = new System.Drawing.Bitmap(TempBitmap.Width,
    TempBitmap.Height);
System.Drawing.Graphics NewGraphics = 
    System.Drawing.Graphics.FromImage(NewBitmap);
NewGraphics.DrawImage(TempBitmap, new System.Drawing.Rectangle(0, 0, 
    TempBitmap.Width, TempBitmap.Height), 
    new System.Drawing.Rectangle(0, 0, TempBitmap.Width, TempBitmap.Height),
    System.Drawing.GraphicsUnit.Pixel);
NewGraphics.Dispose();

可以用这个来代替:

can be replaced with this:

Bitmap NewBitmap = (Bitmap)Image.Clone();

更新2:这里是LockBits版本AdjustContrast方法(有一些其他的速度提升):

Update 2: Here is the LockBits version of the AdjustContrast method (with a few other speed improvements):

public static Bitmap AdjustContrast(Bitmap Image, float Value)
{
    Value = (100.0f + Value) / 100.0f;
    Value *= Value;
    Bitmap NewBitmap = (Bitmap)Image.Clone();
    BitmapData data = NewBitmap.LockBits(
        new Rectangle(0, 0, NewBitmap.Width, NewBitmap.Height), 
        ImageLockMode.ReadWrite,
        NewBitmap.PixelFormat);
    int Height = NewBitmap.Height;
    int Width = NewBitmap.Width;

    unsafe
    {
        for (int y = 0; y < Height; ++y)
        {
            byte* row = (byte*)data.Scan0 + (y * data.Stride);
            int columnOffset = 0;
            for (int x = 0; x < Width; ++x)
            {
                byte B = row[columnOffset];
                byte G = row[columnOffset + 1];
                byte R = row[columnOffset + 2];

                float Red = R / 255.0f;
                float Green = G / 255.0f;
                float Blue = B / 255.0f;
                Red = (((Red - 0.5f) * Value) + 0.5f) * 255.0f;
                Green = (((Green - 0.5f) * Value) + 0.5f) * 255.0f;
                Blue = (((Blue - 0.5f) * Value) + 0.5f) * 255.0f;

                int iR = (int)Red;
                iR = iR > 255 ? 255 : iR;
                iR = iR < 0 ? 0 : iR;
                int iG = (int)Green;
                iG = iG > 255 ? 255 : iG;
                iG = iG < 0 ? 0 : iG;
                int iB = (int)Blue;
                iB = iB > 255 ? 255 : iB;
                iB = iB < 0 ? 0 : iB;

                row[columnOffset] = (byte)iB;
                row[columnOffset + 1] = (byte)iG;
                row[columnOffset + 2] = (byte)iR;

                columnOffset += 4;
            }
        }
    }

    NewBitmap.UnlockBits(data);

    return NewBitmap;
}

注:此code要求使用System.Drawing.Imaging; 在你的类'using语句,并要求该项目的允许不安全code 选项进行检查(生成属性选项卡上的项目)。

NOTE: this code requires using System.Drawing.Imaging; in your class' using statements, and it requires that the project's allow unsafe code option be checked (on the Build Properties tab for the project).

的原因之一GetPixel和的setPixel的是逐个像素操作,以便慢在于,该方法的开销调用自身开始成为一个重要因素。通常情况下,我的code这里的样品将被视为重构的候选,因为你可以编写使用现有的BitmapData对象自己的setPixel和GetPixel方法,但处理时间函数中的数学相对非常小会每次调用的方法开销。这就是为什么我删除了原来的方法在电话也是如此。

One of the reasons GetPixel and SetPixel are so slow for pixel-by-pixel operations is that the overhead of the method call itself starts to become a huge factor. Normally, my code sample here would be considered a candidate for refactoring, since you could write your own SetPixel and GetPixel methods that use an existing BitmapData object, but the processing time for the math inside the functions would be very small relative to the method overhead of each call. This is why I removed the Clamp calls in the original method as well.

另外一个方式来加快这是简单地使之成为破坏性的功能,并修改通过位图参数,而不是制作一份拷贝并返回修改后的副本。

One other way to speed this up would be to simply make it a "destructive" function, and modify the passed Bitmap parameter instead of making a copy and returning the modified copy.

这篇关于有效地调整图像在C#中的对比的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆