1、图像对数增强
计算公式为:
NewPixel=255/log(255)*log(OldPixel)
考虑到log(0)为负无穷大,对于图像来说这毫无意义,因此修改上述公式为:
NewPixel=255/log(256)*log(OldPixel+1);
我们看下上述的公式的原理。根据增强前后的象素值的函数关系式,可得到输入和输出的关系曲线,如下图:
可见,输出始终大于输入,整个画面的亮度增大。
在photoshop中的曲线界面中调整曲线如上图后的效果于本例一样。
由于根据上述算式直接编制程序如下:
' ******************************************************************************************
'
' 函数名 : LogCalc
' 功能 : 对图像进行对数增强(整体变亮)
' 参数 : Bmp ------ Bitmap 待处理位图
' TimeElapse ------ Integer 处理所需的时间
' 返回值 : Boolean
' 作者 : laviewpbt
' 时间 : 2005-5-20 10:05
' 修改者 :
' 修改时间 :
'
' ******************************************************************************************
Public Shared Function LogCalc(ByVal Bmp As Bitmap, ByRef TimeElapse As Integer) As Boolean
TimeElapse = Environment.TickCount
Dim i, j, Stride, Temp As Integer, k As Single, BmpData() As Byte
ReadBitmap(Bmp, BmpData)
k = 255 / Log(256)
ReadBitmap(Bmp, BmpData)
Stride = (((Bmp.Width * 24) + 31) / 32) * 4
For i = 0 To Bmp.Height - 1
For j = 0 To Bmp.Width - 1
Temp = i * Stride + j * 3
BmpData(Temp) = k * Log(BmpData(Temp) + 1)
BmpData(Temp + 1) = k * Log(BmpData(Temp + 1) + 1)
BmpData(Temp + 2) = k * Log(BmpData(Temp + 2) + 1)
Next
Next
WriteBitmap(Bmp, BmpData)
TimeElapse = Environment.TickCount - TimeElapse
Return True
End Function
上述过程对于1024*768的图片大约需要150ms的时间。仔细分析会发现这个过程大部分的运算开销在log函数的计算中,而log函数中的参数BmpData(Temp) + 1的范围是[1,256],因此如果事先计算出这255个值的对数保存在一数组中,则利用查表法可以极大的提高速度。以下是修改后的代码:
Public Shared Function LogCalc(ByVal Bmp As Bitmap, ByRef TimeElapse As Integer) As Boolean
TimeElapse = Environment.TickCount
Dim i, j, Stride, Temp As Integer, k As Single, BmpData() As Byte
Dim TempLogValue(256) As Single
For i = 1 To 256
TempLogValue(i) = Log(i)
Next
ReadBitmap(Bmp, BmpData)
k = 255 / Log(256)
Stride = (((Bmp.Width * 24) + 31) / 32) * 4
For i = 0 To Bmp.Height - 1
For j = 0 To Bmp.Width - 1
Temp = i * Stride + j * 3
BmpData(Temp) = k * TempLogValue(BmpData(Temp) + 1)
BmpData(Temp + 1) = k * TempLogValue(BmpData(Temp + 1) + 1)
BmpData(Temp + 2) = k * TempLogValue(BmpData(Temp + 2) + 1)
Next
Next
WriteBitmap(Bmp, BmpData)
TimeElapse = Environment.TickCount - TimeElapse
Return True
End Function
对数增强效果图(整体变亮)
上述过程只需40ms左右。
(2006-6-1更改) 更改如下形式则更快:
Public Shared Function LogCalc(ByVal Bmp As Bitmap, ByRef TimeElapse As Integer) As Boolean
TimeElapse = Environment.TickCount
Dim i, j, Stride, Temp As Integer
Dim k As Single, TempLogValue(256) As Single
Dim BmpData() As Byte
k = 255 / Log(256)
For i = 0 To 255
TempLogValue(i) = k * Log(i + 1)
Next
ReadBitmap(Bmp, BmpData)
Stride = (((Bmp.Width * 24) + 31) / 32) * 4
For i = 0 To Bmp.Height - 1
For j = 0 To Bmp.Width - 1
Temp = i * Stride + j * 3
BmpData(Temp) = TempLogValue(BmpData(Temp))
BmpData(Temp + 1) = TempLogValue(BmpData(Temp + 1))
BmpData(Temp + 2) = TempLogValue(BmpData(Temp + 2))
Next
Next
WriteBitmap(Bmp, BmpData)
TimeElapse = Environment.TickCount - TimeElapse
Return True
End Function
2、图像的指数增强
指数运算的的计算公式为:
NewPixel=1/255*OldPixel*OldPixel
该关系的输入输出曲线如下图所示:
输出始终小于输入,即图像整体变暗。同样,在循环中也要避免大量重复OldPixel*OldPixel计算,因为OldPixel属于[0,255],优化后的代码如下:
' ******************************************************************************************
'
' 函数名 : ExpCalc
' 功能 : 对图像进行指数增强(整体变暗)
' 参数 : Bmp ------ Bitmap 待处理位图
' TimeElapse ------ Integer 处理所需的时间
' 返回值 : Boolean
' 作者 : laviewpbt
' 时间 : 2005-5-20 10:10
' 修改者 :
' 修改时间 :
'
' ******************************************************************************************
Public Shared Function ExpCalc(ByVal bmp As Bitmap, ByRef TimeElapse As Integer) As Boolean
TimeElapse = Environment.TickCount
Dim i, j, Stride, Temp As Integer, k As Single
Dim BmpData() As Byte
ReadBitmap(bmp, BmpData)
Dim TempPowerValue(255) As Single
For i = 0 To 255
TempPowerValue(i) = i ^ 2
Next
k = 1 / 255
Stride = (((bmp.Width * 24) + 31) / 32) * 4
For i = 0 To bmp.Height - 1
For j = 0 To bmp.Width - 1
Temp = i * Stride + j * 3
BmpData(Temp) = k * TempPowerValue(BmpData(Temp))
BmpData(Temp + 1) = k * TempPowerValue(BmpData(Temp + 1))
BmpData(Temp + 2) = k * TempPowerValue(BmpData(Temp + 2))
Next
Next
WriteBitmap(bmp, BmpData)
TimeElapse = Environment.TickCount - TimeElapse
Return True
End Function
计算时间大约为40ms.
(2006-6-1更改) 更改如下形式则更快:
Public Shared Function ExpCalc(ByVal bmp As Bitmap, ByRef TimeElapse As Integer) As Boolean
TimeElapse = Environment.TickCount
Dim i, j, Stride, Temp As Integer
Dim TempPowerValue(255) As Integer
Dim k As Single
Dim BmpData() As Byte
ReadBitmap(bmp, BmpData)
k = 1 / 255
For i = 0 To 255
TempPowerValue(i) = k * i ^ 2
Next
Stride = (((bmp.Width * 24) + 31) / 32) * 4
For i = 0 To bmp.Height - 1
For j = 0 To bmp.Width - 1
Temp = i * Stride + j * 3
BmpData(Temp) = TempPowerValue(BmpData(Temp))
BmpData(Temp + 1) = TempPowerValue(BmpData(Temp + 1))
BmpData(Temp + 2) = TempPowerValue(BmpData(Temp + 2))
Next
Next
WriteBitmap(bmp, BmpData)
TimeElapse = Environment.TickCount - TimeElapse
Return True
End Function
指数增强效果(整体便暗)
上述过程用时40ms左右。
3、直方图均衡化
直方图均衡化处理的中心思想是把原始图像的灰度直方图从比较集中的某个灰度区间变成在全部灰度范围内的均匀分布。这里选用常用的增强函数:累计分布函数(cumulative distribution function,CDF)。
' ******************************************************************************************
'
' 函数名 : EqualizeCalc
' 功能 : 直方图均衡化
' 参数 : Bmp ------ Bitmap 待处理位图
' TimeElapse ------ Integer 处理所需的时间
' 返回值 : Boolean
' 作者 : laviewpbt
' 时间 : 2005-5-20 12:37
' 修改者 :
' 修改时间 :
'
' ******************************************************************************************
PublicSharedFunction EqualizeCalc(ByVal Bmp As Bitmap, ByRef TimeElapse AsInteger) AsBoolean
TimeElapse = Environment.TickCount
Dim i, j, Stride, Temp AsInteger
Dim BmpData() AsByte
ReadBitmap(Bmp, BmpData)
Stride = (((Bmp.Width * 24) + 31) / 32) * 4
Dim MidValue(2) AsInteger, NumOfPixel AsInteger
Dim Map(255, 2) AsByte
Dim Histgram(255, 2) AsInteger
NumOfPixel = Bmp.Width * Bmp.Height
'******************** 得到图像的灰度分布情况 *****************
For i = 0 To Bmp.Height - 1
For j = 0 To Bmp.Width - 1
Temp = i * Stride + j * 3
Histgram(BmpData(Temp), 0) += 1
Histgram(BmpData(Temp + 1), 1) += 1
Histgram(BmpData(Temp + 2), 2) += 1
Next
Next
'*********************** 计算灰度映射表 *********************
For i = 0 To 255
MidValue(0) = 0 : MidValue(1) = 0 : MidValue(2) = 0
For j = 0 To i
MidValue(0) += Histgram(j, 0)
MidValue(1) += Histgram(j, 1)
MidValue(2) += Histgram(j, 2)
Next
Map(i, 0) = MidValue(0) * 255 / NumOfPixel
Map(i, 1) = MidValue(1) * 255 / NumOfPixel
Map(i, 2) = MidValue(2) * 255 / NumOfPixel
Next
'************************** 更新图像数据 ***********************
For i = 0 To Bmp.Height - 1
For j = 0 To Bmp.Width - 1
Temp = i * Stride + j * 3
BmpData(Temp) = Map(BmpData(Temp), 0)
BmpData(Temp + 1) = Map(BmpData(Temp + 1), 1)
BmpData(Temp + 2) = Map(BmpData(Temp + 2), 2)
Next
Next
WriteBitmap(Bmp, BmpData)
TimeElapse = Environment.TickCount - TimeElapse
ReturnTrue
EndFunction
均衡化效果(用时70ms)
由上图可见,视觉效果并没有得到改善,反而差了,呵呵,这就要看你原始图片的质量了,因为我的图片质量本身是非常好的。还有一点,如果你对一副图片均衡化后在均衡则图像不会有任何变化了,这从其实现原理上可以很清楚的看到。
要注意的是,均衡化处理后的图象只能是近似均匀分布。均衡化图象的动态范围扩大了,但其本质是扩大了量化间隔,而量化级别反而减少了,因此,原来灰度不同的象素经处理后可能变的相同,形成了一片的相同灰度的区域,各区域之间有明显的边界,从而出现了伪轮廓。如果原始图像对比度本来就很高,如果再均衡化则灰度调和,对比度降低。