有效地调整C#中图像的对比度

有没有一种有效的方法来调整C#中图像的对比度?

我看过这篇文章主张进行逐像素操作。 不快

我已经在地方使用了颜色矩阵并且发现它们很快。 有没有办法调整对比度? (注意: 这家伙弄错了。)

我也在使用EmguCV。 我注意到OpenCV(Emgu包装) 似乎有一个对比function – 有没有办法通过Emgu访问它? 目前我在Emgu所能做的就是将直方图标准化,这确实会改变对比度,但不会对我有任何程度的控制。

有人有任何想法吗?

如果该示例中的代码适合您,则可以使用Bitmap.LockBits大幅加速(按数量级), Bitmap.LockBits返回一个BitmapData对象,该对象允许通过指针访问Bitmap的像素数据。 Web和StackOverflow上有大量示例,展示了如何使用LockBits。

Bitmap.SetPixel()Bitmap.GetPixel()是人类已知的最慢的方法,它们都使用Color类,这是人类已知的最慢的类。 它们应该被命名为Bitmap.GetPixelAndByGodYoullBeSorryYouDid()Bitmap.SetPixelWhileGettingCoffee作为警告,以警惕开发人员。

更新:如果您要修改该示例中的代码,请注意此块:

 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(); 

可以替换为:

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

更新2:这是AdjustContrast方法的LockBits版本(还有一些其他的速度改进):

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

注意:此代码需要using System.Drawing.Imaging; 在你的类'using语句中,它要求项目allow unsafe code检查allow unsafe code选项(在项目的Build Properties选项卡上)。

GetPixel和SetPixel对于逐像素操作来说如此缓慢的原因之一是方法调用本身的开销开始成为一个重要因素。 通常,我的代码示例将被视为重构的候选者,因为您可以编写自己的使用现有BitmapData对象的SetPixel和GetPixel方法,但相对于方法开销,函数内部的数学处理时间将非常短。每次通话。 这就是我在原始方法中删除了Clamp调用的原因。

另一种加快速度的方法是简单地使其成为“破坏性”function,并修改传递的Bitmap参数,而不是制作副本并返回修改后的副本。

@MusiGenesis,

只是想注意我将这种方法用于我一直在写的图像编辑器。 它运行良好,但有时此方法会触发此行上的AccessViolationException:

 byte B = row[columnOffset]; 

我意识到这是因为没有BitDepth的标准化,所以如果一个图像是32位颜色我得到了这个错误。 所以我更改了这一行:

 BitmapData data = NewBitmap.LockBits(new Rectangle(0, 0, NewBitmap.Width, NewBitmap.Height), ImageLockMode.ReadWrite, NewBitmap.PixelFormat); 

至:

 BitmapData data = NewBitmap.LockBits(new Rectangle(0, 0, NewBitmap.Width, NewBitmap.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppRgb); 

希望这有帮助,因为它似乎已经根除了我的问题。

谢谢你的post。

吊臂

我有点晚了,但是使用颜色矩阵实现,因为这些将针对这样的变换进行优化,并且比自己操作像素要容易得多: http : //www.geekpedia.com/tutorial202_Using-the-ColorMatrix-in-Csharp html的