BitmapBytesRGB24 class to apply an embossing filter to an image very quickly

Started by dhilipkumar, Oct 02, 2008, 10:16 PM

Previous topic - Next topic

dhilipkumar

This example shows how to use the BitmapBytesRGB24 class to apply an embossing filter to an image very quickly in Visual Basic 2005.


This version adds the following GetPixel and SetPixel methods to the class. These methods calculate a pixel's location in the array and then gets or sets the pixel's red, green, and blue byte values.

' Return a pixel's byte values.
Public Sub GetPixel(ByVal x As Integer, ByVal y As Integer, _
    ByRef r As Byte, ByRef g As Byte, ByRef b As Byte)
    Dim offset As Integer = y * RowSizeBytes + x * _
        PixelSizeBytes
    b = ImageBytes(offset)
    g = ImageBytes(offset + 1)
    r = ImageBytes(offset + 2)
End Sub

' Set a pixel's byte values.
Public Sub SetPixel(ByVal x As Integer, ByVal y As Integer, _
    ByVal r As Byte, ByVal g As Byte, ByVal b As Byte)
    Dim offset As Integer = y * RowSizeBytes + x * _
        PixelSizeBytes
    ImageBytes(offset) = b
    ImageBytes(offset + 1) = g
    ImageBytes(offset + 2) = r
End Sub



When it starts, the program uses the following code to initialize its embossing filter.


Private m_Filter(,) As Integer
Private m_Weight As Integer

' Initialize the filter.
Private Sub Form1_Load(ByVal sender As System.Object, ByVal _
    e As System.EventArgs) Handles MyBase.Load
    m_Filter = New Integer(,) { _
        {-1, 0, 0}, _
        {0, 0, 0}, _
        {0, 0, 1}}
    m_Weight = 1
End Sub


dhilipkumar

To apply the filter, the program considers each pixel in the image (except those on the very edges of the image). It looks at the 3x3 square of pixels surrounding the target pixel and multiplies their red, green, and blue component values by the corresponding filter value. It adds the results and divides by the filter's weight.


For an embossing filter, the program then adds 127 to make pixels with a neutral value become gray.

' Apply the filter to the image.
Private Sub ApplyFilter()
    Me.Cursor = Cursors.WaitCursor
    picNew.Image = Nothing
    Me.Refresh()
    Dim start_time As Date = Now

    Dim bm1 As Bitmap = picOld.Image
    Dim bm2 As New Bitmap(bm1.Width, bm1.Height)

    ' Make BitmapBytesRGB24 objects for the bitmaps.
    Dim bm1_bytes As New BitmapBytesRGB24(bm1)
    Dim bm2_bytes As New BitmapBytesRGB24(bm2)

    ' Lock the bitmaps' bytes.
    bm1_bytes.LockBitmap()
    bm2_bytes.LockBitmap()

    Dim wid As Integer = bm1.Width
    Dim hgt As Integer = bm1.Height
    Dim new_r As Byte = 0
    Dim new_g As Byte = 0
    Dim new_b As Byte = 0
    For x As Integer = 1 To wid - 2
        For y As Integer = 1 To hgt - 2
            Dim r As Integer = 0
            Dim g As Integer = 0
            Dim b As Integer = 0
            For dx As Integer = 0 To 2
                For dy As Integer = 0 To 2
                    bm1_bytes.GetPixel(x + dx - 1, y + dy - _
                        1, new_r, new_g, new_b)
                    r += new_r * m_Filter(dx, dy)
                    g += new_g * m_Filter(dx, dy)
                    b += new_b * m_Filter(dx, dy)
                Next dy
            Next dx

            r = CInt(127 + r / m_Weight)
            g = CInt(127 + g / m_Weight)
            b = CInt(127 + b / m_Weight)
            If r < 0 Then r = 0
            If g < 0 Then g = 0
            If b < 0 Then b = 0
            If r > 255 Then r = 255
            If g > 255 Then g = 255
            If b > 255 Then b = 255
            bm2_bytes.SetPixel(x, y, r, g, b)
        Next y
    Next x

    ' Unlock the bitmaps.
    bm1_bytes.UnlockBitmap()
    bm2_bytes.UnlockBitmap()

    Dim stop_time As Date = Now
    Dim elapsed_time As TimeSpan = stop_time - start_time
    Debug.WriteLine(elapsed_time.TotalSeconds.ToString("0.00") _
        & " seconds")
    picNew.Image = bm2
    picNew.Refresh()
    Me.Cursor = Cursors.Default
End Sub



Note that the embossing filter only has two non-zero values and that its weight is 1. You can improve performance slightly by performing the multiplications directly rather than by looping through the filter array. That makes the code a bit less general, however, so it would be harder to modify to apply other filters. For example, try changing the values in the filter array and then setting the weight to the sum of the values in the array to see what happens.

nandagopal