Mean Removal
This algorithm is like Sharpen filter. Unlike the Sharpen filter, which only worked in the horizontal and vertical directions, this one spreads it's influence diagonally as well, with the following result on the same source image.
Private Class ConvolutionMatrix
Public Sub New()
Pixel = 1
Factor = 1
End Sub
Public Sub Apply(Val As Integer)
TopLeft = Val
TopMid = Val
TopRight = Val
MidLeft = Val
MidRight = Val
BottomLeft = Val
BottomMid = Val
BottomRight = Val
Pixel = Val
End Sub
Public Property TopLeft() As Integer
Get
Return m_TopLeft
End Get
Set(value As Integer)
m_TopLeft = value
End Set
End Property
Private m_TopLeft As Integer
Public Property TopMid() As Integer
Get
Return m_TopMid
End Get
Set(value As Integer)
m_TopMid = value
End Set
End Property
Private m_TopMid As Integer
Public Property TopRight() As Integer
Get
Return m_TopRight
End Get
Set(value As Integer)
m_TopRight = value
End Set
End Property
Private m_TopRight As Integer
Public Property MidLeft() As Integer
Get
Return m_MidLeft
End Get
Set(value As Integer)
m_MidLeft = value
End Set
End Property
Private m_MidLeft As Integer
Public Property MidRight() As Integer
Get
Return m_MidRight
End Get
Set(value As Integer)
m_MidRight = value
End Set
End Property
Private m_MidRight As Integer
Public Property BottomLeft() As Integer
Get
Return m_BottomLeft
End Get
Set(value As Integer)
m_BottomLeft = value
End Set
End Property
Private m_BottomLeft As Integer
Public Property BottomMid() As Integer
Get
Return m_BottomMid
End Get
Set(value As Integer)
m_BottomMid = value
End Set
End Property
Private m_BottomMid As Integer
Public Property BottomRight() As Integer
Get
Return m_BottomRight
End Get
Set(value As Integer)
m_BottomRight = value
End Set
End Property
Private m_BottomRight As Integer
Public Property Pixel() As Integer
Get
Return m_Pixel
End Get
Set(value As Integer)
m_Pixel = value
End Set
End Property
Private m_Pixel As Integer
Public Property Factor() As Integer
Get
Return m_Factor
End Get
Set(value As Integer)
m_Factor = value
End Set
End Property
Private m_Factor As Integer
Public Property Offset() As Integer
Get
Return m_Offset
End Get
Set(value As Integer)
m_Offset = value
End Set
End Property
Private m_Offset As Integer
End Class
Private Class Convolution
Public Sub Convolution3x3(ByRef bmp As Bitmap)
Dim Factor As Integer = Matrix.Factor
If Factor = 0 Then
Return
End If
Dim TopLeft As Integer = Matrix.TopLeft
Dim TopMid As Integer = Matrix.TopMid
Dim TopRight As Integer = Matrix.TopRight
Dim MidLeft As Integer = Matrix.MidLeft
Dim MidRight As Integer = Matrix.MidRight
Dim BottomLeft As Integer = Matrix.BottomLeft
Dim BottomMid As Integer = Matrix.BottomMid
Dim BottomRight As Integer = Matrix.BottomRight
Dim Pixel As Integer = Matrix.Pixel
Dim Offset As Integer = Matrix.Offset
Dim TempBmp As Bitmap = bmp.Clone()
Dim bmpData As BitmapData = bmp.LockBits(New Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb)
Dim TempBmpData As BitmapData = TempBmp.LockBits(New Rectangle(0, 0, TempBmp.Width, TempBmp.Height), ImageLockMode.[ReadOnly], PixelFormat.Format24bppRgb)
Dim ptr As IntPtr = bmpData.Scan0
Dim TempPtr As IntPtr = TempBmpData.Scan0
Dim Pix As Integer = 0
Dim Stride As Integer = bmpData.Stride
Dim DoubleStride As Integer = Stride * 2
Dim Width As Integer = bmp.Width - 2
Dim Height As Integer = bmp.Height - 2
Dim stopAddress As Integer = CInt(ptr) + bmpData.Stride * bmpData.Height
For y As Integer = 0 To Height - 1
For x As Integer = 0 To Width - 1
Pix = (((((Marshal.ReadByte(TempPtr + 2) * TopLeft) + (Marshal.ReadByte(TempPtr + 5) * TopMid) + (Marshal.ReadByte(TempPtr + 8) * TopRight)) + _
((Marshal.ReadByte(TempPtr + 2 + Stride) * MidLeft) + (Marshal.ReadByte(TempPtr + 5 + Stride) * Pixel) + (Marshal.ReadByte(TempPtr + 8 + Stride) * MidRight)) + _
((Marshal.ReadByte(TempPtr + 2 + DoubleStride) * BottomLeft) + (Marshal.ReadByte(TempPtr + 5 + DoubleStride) * BottomMid) + (Marshal.ReadByte(TempPtr + 8 + DoubleStride) * BottomRight))) \ Factor) + Offset)
If Pix < 0 Then
Pix = 0
ElseIf Pix > 255 Then
Pix = 255
End If
Marshal.WriteByte(ptr + 5 + Stride, CByte(Pix))
Pix = (((((Marshal.ReadByte(TempPtr + 1) * TopLeft) + (Marshal.ReadByte(TempPtr + 4) * TopMid) + (Marshal.ReadByte(TempPtr + 7) * TopRight)) + _
((Marshal.ReadByte(TempPtr + 1 + Stride) * MidLeft) + (Marshal.ReadByte(TempPtr + 4 + Stride) * Pixel) + (Marshal.ReadByte(TempPtr + 7 + Stride) * MidRight)) + _
((Marshal.ReadByte(TempPtr + 1 + DoubleStride) * BottomLeft) + (Marshal.ReadByte(TempPtr + 4 + DoubleStride) * BottomMid) + (Marshal.ReadByte(TempPtr + 7 + DoubleStride) * BottomRight))) \ Factor) + Offset)
If Pix < 0 Then
Pix = 0
ElseIf Pix > 255 Then
Pix = 255
End If
Marshal.WriteByte(ptr + 4 + Stride, CByte(Pix))
Pix = (((((Marshal.ReadByte(TempPtr) * TopLeft) + (Marshal.ReadByte(TempPtr + 3) * TopMid) + (Marshal.ReadByte(TempPtr + 6) * TopRight)) + _
((Marshal.ReadByte(TempPtr + Stride) * MidLeft) + (Marshal.ReadByte(TempPtr + 3 + Stride) * Pixel) + (Marshal.ReadByte(TempPtr + 6 + Stride) * MidRight)) + _
((Marshal.ReadByte(TempPtr + DoubleStride) * BottomLeft) + (Marshal.ReadByte(TempPtr + 3 + DoubleStride) * BottomMid) + (Marshal.ReadByte(TempPtr + 6 + DoubleStride) * BottomRight))) \ Factor) + Offset)
If Pix < 0 Then
Pix = 0
ElseIf Pix > 255 Then
Pix = 255
End If
Marshal.WriteByte(ptr + 3 + Stride, CByte(Pix))
ptr += 3
TempPtr += 3
Next
Next
bmp.UnlockBits(bmpData)
TempBmp.UnlockBits(TempBmpData)
End Sub
Public Property Matrix() As ConvolutionMatrix
Get
Return m_Matrix
End Get
Set(value As ConvolutionMatrix)
m_Matrix = value
End Set
End Property
Private m_Matrix As ConvolutionMatrix
End Class
Public Shared Sub ApplyMeanRemoval(ByRef bmp As Bitmap, weight As Integer)
Dim m As New ConvolutionMatrix()
m.Apply(-1)
m.Pixel = weight
m.Factor = weight - 8
Dim C As New Convolution()
C.Matrix = m
C.Convolution3x3(bmp)
End Sub
Example
DIm b As Bitmap = CType(Image.FromFile("rose.jpg"), Bitmap)
ApplyMeanRemoval(b, 9)