WPF 通過(guò) WriteableBitmap 實(shí)現(xiàn) TAGC 低光增強(qiáng)效果算法
開(kāi)始之前,必須感謝 只(摯)愛(ài)圖像處理 - Imageshop 大佬的分享。本文將參閱 伊拉克團(tuán)隊(duì)的TAGC(低光增強(qiáng)效果)算法實(shí)現(xiàn)。 - Imageshop - 博客園 進(jìn)行實(shí)現(xiàn)
原論文信息如下:
論文標(biāo)題: Tuning adaptive gamma correction (TAGC) for enhancing images in low light
發(fā)表日期: 2025年07月
作者: Ghufran Alhamzawi, Alfoudi Ali Saeed, Suha Mohammed Hadi等
發(fā)表單位: University of Al-Qadisiyah, University of Information Technology and Communications等
原文鏈接: http://arxiv.org/pdf/2507.19574v1
實(shí)現(xiàn)效果如下圖所示


這個(gè)過(guò)程無(wú)需玄學(xué)算法參與,無(wú)需對(duì)接任何 AI 相關(guān)的算法,僅僅只是非常簡(jiǎn)單的逐個(gè)像素進(jìn)行數(shù)學(xué)計(jì)算。核心實(shí)現(xiàn)代碼如下
/// <summary>
/// Tuning adaptive gamma correction (TAGC) 低光增強(qiáng)效果算法
/// </summary>
public class TuningAdaptiveGammaCorrectionAlgorithm
{
public static unsafe void Enhancement(WriteableBitmap sourceBitmap, WriteableBitmap targetBitmap)
{
if (sourceBitmap.Format != targetBitmap.Format)
{
return;
}
if (sourceBitmap.Format != PixelFormats.Bgra32)
{
return;
}
float inv255 = 1.0f / 255;
sourceBitmap.Lock();
targetBitmap.Lock();
byte* src = (byte*)sourceBitmap.BackBuffer;
byte* dest = (byte*)targetBitmap.BackBuffer;
var height = sourceBitmap.PixelHeight;
var width = sourceBitmap.PixelWidth;
var stride = sourceBitmap.BackBufferStride;
int channel = stride / width;
for (int yIndex = 0; yIndex < height; yIndex++)
{
byte* linePixelSource = src + yIndex * stride;
byte* linePixelDest = dest + yIndex * stride;
for (int xIndex = 0; xIndex < width; xIndex++)
{
float blue = linePixelSource[0] * inv255;
float green = linePixelSource[1] * inv255;
float red = linePixelSource[2] * inv255;
double l = 0.2126f * red + 0.7152 * green + 0.0722 * blue;
float a = (blue + green + red) / 3;
double gamma = 5.0f + (0.5f - l) * (1 - a) - 2 * l;
double y = 2 / gamma;
byte tb = ClampToByte((int)(Math.Pow(blue, y) * 255 + 0.4999999f));
double y1 = 2 / gamma;
byte tg = ClampToByte((int)(Math.Pow(green, y1) * 255 + 0.4999999f));
double y2 = 2 / gamma;
byte tr = ClampToByte((int)(Math.Pow(red, y2) * 255 + 0.4999999f));
byte ta = 0xFF;
linePixelDest[0] = tb;
linePixelDest[1] = tg;
linePixelDest[2] = tr;
linePixelDest[3] = ta;
linePixelSource += channel;
linePixelDest += channel;
}
}
targetBitmap.AddDirtyRect(new Int32Rect(0, 0, targetBitmap.PixelWidth, targetBitmap.PixelHeight));
sourceBitmap.Unlock();
targetBitmap.Unlock();
}
private static byte ClampToByte(int value)
{
return (byte)Math.Clamp(value, 0, byte.MaxValue);
}
}
具體計(jì)算的原理,如 http://www.rzrgm.cn/Imageshop/p/19025343 博客內(nèi)容所述:

使用 Tuning adaptive gamma correction (TAGC) 確實(shí)能夠幫我將很多拍攝暗光照片進(jìn)行低光增強(qiáng)。但對(duì)于一些屏幕截圖的效果或其他非拍攝的圖片的處理效果不佳
整個(gè)算法代碼看起來(lái)也比較清新,代碼量也少,能夠?qū)崿F(xiàn)如此好的效果,也是需要給大佬們點(diǎn)贊。如果大家對(duì)此算法效果感興趣,歡迎按照本文末尾的方法拉取我的代碼跑跑看效果,或直接從 Imageshop 大佬那下載他已經(jīng)構(gòu)建好的程序
細(xì)心的伙伴也許看到了,在本文的 Enhancement 方法里面需要判斷圖片的格式,但并非所有的圖片都能遵循此格式。好在 WPF 里面可以非常方便地通過(guò) FormatConvertedBitmap 進(jìn)行轉(zhuǎn)換,此轉(zhuǎn)換過(guò)程都是利用 WIC 多媒體進(jìn)行轉(zhuǎn)換,性能非常高,損耗非常低。核心代碼如下
var formatConvertedBitmap = new FormatConvertedBitmap();
formatConvertedBitmap.BeginInit();
formatConvertedBitmap.Source = source;
formatConvertedBitmap.DestinationFormat = PixelFormats.Bgra32;
formatConvertedBitmap.EndInit();
使用的時(shí)候直接將 FormatConvertedBitmap 當(dāng)成 BitmapSource 傳遞就可以了。完全的從傳入的圖片文件路徑,經(jīng)過(guò) TAGC 算法,將輸出的 WriteableBitmap 給到 DestImage 控件的 Source 的代碼如下
private void Enhancement(string filePath)
{
if (string.IsNullOrEmpty(filePath) || !File.Exists(filePath))
{
return;
}
filePath = Path.GetFullPath(filePath);
var source = new BitmapImage(new Uri(filePath));
SourceImage.Source = source;
var formatConvertedBitmap = new FormatConvertedBitmap();
formatConvertedBitmap.BeginInit();
formatConvertedBitmap.Source = source;
formatConvertedBitmap.DestinationFormat = PixelFormats.Bgra32;
formatConvertedBitmap.EndInit();
var sourceBitmap = new WriteableBitmap(formatConvertedBitmap);
var targetBitmap = new WriteableBitmap(sourceBitmap.PixelWidth, sourceBitmap.PixelHeight, sourceBitmap.DpiX,
sourceBitmap.DpiY, sourceBitmap.Format, sourceBitmap.Palette);
TuningAdaptiveGammaCorrectionAlgorithm.Enhancement(sourceBitmap, targetBitmap);
var pngBitmapEncoder = new PngBitmapEncoder();
pngBitmapEncoder.Frames.Add(BitmapFrame.Create(targetBitmap));
using var stream = File.Create("1.png");
pngBitmapEncoder.Save(stream);
DestImage.Source = targetBitmap;
}
以上的 DestImage 就是 Image 控件,界面代碼定義如下
<Grid RowDefinitions="Auto,*">
<Grid>
<StackPanel Orientation="Horizontal">
<Button x:Name="OpenImageFileButton" Margin="10,10,10,0" Content="打開(kāi)圖片文件" Click="OpenImageFileButton_OnClick"/>
</StackPanel>
</Grid>
<Grid Grid.Row="1" ColumnDefinitions="*,*">
<Image x:Name="SourceImage" Stretch="Fill" Margin="10,10,10,10"/>
<Image x:Name="DestImage" Grid.Column="1" Stretch="Fill" Margin="10,10,10,10"/>
</Grid>
</Grid>
按鈕點(diǎn)擊打開(kāi)文件,其方法實(shí)現(xiàn)如下
private void OpenImageFileButton_OnClick(object sender, RoutedEventArgs e)
{
var openFileDialog = new OpenFileDialog()
{
Filter = "Image Files|*.jpg;*.jpeg;*.png;*.bmp;",
Multiselect = false,
};
openFileDialog.ShowDialog(this);
var file = openFileDialog.FileName;
Enhancement(file);
}
本文代碼放在 github 和 gitee 上,可以使用如下命令行拉取代碼。我整個(gè)代碼倉(cāng)庫(kù)比較龐大,使用以下命令行可以進(jìn)行部分拉取,拉取速度比較快
先創(chuàng)建一個(gè)空文件夾,接著使用命令行 cd 命令進(jìn)入此空文件夾,在命令行里面輸入以下代碼,即可獲取到本文的代碼
git init
git remote add origin https://gitee.com/lindexi/lindexi_gd.git
git pull origin 13152fb73b02bc3ec1acaca8c34ee44761fdff2c
以上使用的是國(guó)內(nèi)的 gitee 的源,如果 gitee 不能訪問(wèn),請(qǐng)?zhí)鎿Q為 github 的源。請(qǐng)?jiān)诿钚欣^續(xù)輸入以下代碼,將 gitee 源換成 github 源進(jìn)行拉取代碼。如果依然拉取不到代碼,可以發(fā)郵件向我要代碼
git remote remove origin
git remote add origin https://github.com/lindexi/lindexi_gd.git
git pull origin 13152fb73b02bc3ec1acaca8c34ee44761fdff2c
獲取代碼之后,進(jìn)入 WPFDemo/JoyojabujeaCocherallli 文件夾,即可獲取到源代碼
更多技術(shù)博客,請(qǐng)參閱 博客導(dǎo)航
博客園博客只做備份,博客發(fā)布就不再更新,如果想看最新博客,請(qǐng)?jiān)L問(wèn) https://blog.lindexi.com/
如圖片看不見(jiàn),請(qǐng)?jiān)跒g覽器開(kāi)啟不安全http內(nèi)容兼容

本作品采用知識(shí)共享署名-非商業(yè)性使用-相同方式共享 4.0 國(guó)際許可協(xié)議進(jìn)行許可。歡迎轉(zhuǎn)載、使用、重新發(fā)布,但務(wù)必保留文章署名[林德熙](http://www.rzrgm.cn/lindexi)(包含鏈接:http://www.rzrgm.cn/lindexi ),不得用于商業(yè)目的,基于本文修改后的作品務(wù)必以相同的許可發(fā)布。如有任何疑問(wèn),請(qǐng)與我[聯(lián)系](mailto:lindexi_gd@163.com)。

浙公網(wǎng)安備 33010602011771號(hào)