Despeckle code too slow

C

Celarian

I've written a function, Despeckle, to remove noise from Bitmaps. The
English description of the algorithm I've implemented might read as follows:

For each pixel in the image, create an array which contains the color of
that pixel and every adjacent pixel. Sort that array, and set the color of
the corresponding pixel in the target bitmap to the median value of the
array.

My code fails in these respects:

1. it does not despeckle the edges of an image, only from (1,1) to (width-1,
height-1)

2. it cannot work with indexed images; i have made the unfortunate
assumption that all images passed in will be 24 bpp.

3. it is slow as molasses in january

I realise that I could accelerate the speed of this function by rewriting it
in C# and using unsafe code, but that is not an option for this project. It
must be written in VB. I have already overcome the slowness of
GetPixel/SetPixel by using Marshaling. How else can I improve this code?

Code follows.

--------------------------------------------------------------------------

Structure RGBPixel
Public R As Byte
Public G As Byte
Public B As Byte
End Structure

Public Function RGB2Int(ByVal r As Byte, ByVal g As Byte, ByVal b As Byte)
As Integer
Return ((r * 256) + g) * 256 + b
End Function

Public Function Int2RGB(ByVal c As Integer) As RGBPixel
Dim nulpad As String = "000000"
Dim inp As String = Hex$(c)

inp = nulpad.Substring(0, 6 - Len(inp)) + inp

Dim p As RGBPixel
p.B = Convert.ToByte(Convert.ToInt32(inp.Substring(0, 2), 16))
p.G = Convert.ToByte(Convert.ToInt32(inp.Substring(2, 2), 16))
p.R = Convert.ToByte(Convert.ToInt32(inp.Substring(4, 2), 16))

Return p
End Function

Public Function Despeckle(ByVal bmp As Bitmap) As Bitmap
' eliminate noise from the source image and return the results

Dim bmpSource As Bitmap = bmp.Clone()

Dim bmpTarget As Bitmap = New Bitmap(bmpSource.Width, bmpSource.Height,
bmpSource.PixelFormat)
bmpTarget.SetResolution(bmpSource.HorizontalResolution,
bmpSource.VerticalResolution)

Dim bmpSourceData As BitmapData = _
bmpSource.LockBits(New Rectangle(0, 0, bmpSource.Width,
bmpSource.Height), _
ImageLockMode.ReadOnly, bmpSource.PixelFormat)

Dim bmpTargetData As BitmapData = _
bmpTarget.LockBits(New Rectangle(0, 0, bmpTarget.Width,
bmpTarget.Height), _
ImageLockMode.WriteOnly, bmpTarget.PixelFormat)

Dim advance As Integer ' iAdvance will equal the number of bits per
pixel / 8

' assume 24bpp for the time being (unfortunate; this code won't work to
despeckle
' bitonal TIFFs as-is
If (bmpSource.PixelFormat = PixelFormat.Format24bppRgb) Then
advance = 3
Else
Throw New ApplicationException("PixelFormat was not Format24bppRgb.")
End If

' allocate space to hold bits in source and target images
Dim sourceArray(bmpSource.Height * bmpSourceData.Stride) As Byte
Dim targetArray(bmpTarget.Height * bmpTargetData.Stride) As Byte

' extract source bits to managed space
Marshal.Copy(bmpSourceData.Scan0, sourceArray, 0, sourceArray.Length)

' map the pixels from source to target
System.Diagnostics.Trace.WriteLine("Beginning despeckle")

Dim dtStart As DateTime = DateTime.Now

Dim x, y As Integer 'pixel locations

Dim r, g, b As Byte 'RGB values of the current pixel
'Dim pixColor As Color 'used to convert between RGB values and integers

Dim p As RGBPixel

Dim prevOffset, currOffset, nextOffset As Integer

'we're using these ranges to stay entirely within the meat of the
image --
'not ready to try dealing with edges yet

For y = 1 To bmpSource.Height - 2

' calculate the offsets of the lines
prevOffset = (y - 1) * bmpSourceData.Stride
currOffset = y * bmpSourceData.Stride
nextOffset = (y + 1) * bmpSourceData.Stride

For x = 1 To bmpSource.Width - 2
Dim al As New ArrayList(10)

' gdi+ still lies to us -- the format is BGR, not RGB

'previous row
r = sourceArray(prevOffset + ((x - 1) * advance) + 2)
g = sourceArray(prevOffset + ((x - 1) * advance) + 1)
b = sourceArray(prevOffset + ((x - 1) * advance))
al.Add(RGB2Int(r, g, b))

r = sourceArray(prevOffset + (x * advance) + 2)
g = sourceArray(prevOffset + (x * advance) + 1)
b = sourceArray(prevOffset + (x * advance))
al.Add(RGB2Int(r, g, b))

r = sourceArray(prevOffset + ((x + 1) * advance) + 2)
g = sourceArray(prevOffset + ((x + 1) * advance) + 1)
b = sourceArray(prevOffset + ((x + 1) * advance))
al.Add(RGB2Int(r, g, b))

'current row
r = sourceArray(currOffset + ((x - 1) * advance) + 2)
g = sourceArray(currOffset + ((x - 1) * advance) + 1)
b = sourceArray(currOffset + ((x - 1) * advance))
al.Add(RGB2Int(r, g, b))

r = sourceArray(currOffset + (x * advance) + 2)
g = sourceArray(currOffset + (x * advance) + 1)
b = sourceArray(currOffset + (x * advance))
al.Add(RGB2Int(r, g, b))

r = sourceArray(currOffset + ((x + 1) * advance) + 2)
g = sourceArray(currOffset + ((x + 1) * advance) + 1)
b = sourceArray(currOffset + ((x + 1) * advance))
al.Add(RGB2Int(r, g, b))

'next row
r = sourceArray(nextOffset + ((x - 1) * advance) + 2)
g = sourceArray(nextOffset + ((x - 1) * advance) + 1)
b = sourceArray(nextOffset + ((x - 1) * advance))
al.Add(RGB2Int(r, g, b))

r = sourceArray(nextOffset + (x * advance) + 2)
g = sourceArray(nextOffset + (x * advance) + 1)
b = sourceArray(nextOffset + (x * advance))
al.Add(RGB2Int(r, g, b))

r = sourceArray(nextOffset + ((x + 1) * advance) + 2)
g = sourceArray(nextOffset + ((x + 1) * advance) + 1)
b = sourceArray(nextOffset + ((x + 1) * advance))
al.Add(RGB2Int(r, g, b))

'write out the target pixel
al.Sort()
p = Int2RGB(al(4))

targetArray(currOffset + (x * advance) + 2) = p.R
targetArray(currOffset + (x * advance) + 1) = p.G
targetArray(currOffset + (x * advance) + 0) = p.B

Next

Next

' copy the target bits from managed space
Marshal.Copy(targetArray, 0, bmpTargetData.Scan0, targetArray.Length)

' unlock the bits
bmpTarget.UnlockBits(bmpTargetData)
bmpSource.UnlockBits(bmpSourceData)

Return bmpTarget

End Function
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top