Results 1 to 8 of 8

Thread: [RESOLVED] Problem sharpening semi-transparent image

  1. #1

    Thread Starter
    eXtreme Programmer .paul.'s Avatar
    Join Date
    May 2007
    Location
    Chelmsford UK
    Posts
    25,481

    Resolved [RESOLVED] Problem sharpening semi-transparent image

    I found this code for sharpening images online. I haven't done much testing with it yet, but i do know it's ruining the transparent parts of my bitmaps.
    Can anyone give a solution, that retains the transparent pixels?

    Code:
    Imports System.Runtime.InteropServices
    Imports System.Drawing.Imaging
    
    Public 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(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(CInt(TempPtr) + 2) * TopLeft) + (Marshal.ReadByte(CInt(TempPtr) + 5) * TopMid) + (Marshal.ReadByte(CInt(TempPtr) + 8) * TopRight)) + _
                       ((Marshal.ReadByte(CInt(TempPtr) + 2 + Stride) * MidLeft) + (Marshal.ReadByte(CInt(TempPtr) + 5 + Stride) * Pixel) + (Marshal.ReadByte(CInt(TempPtr) + 8 + Stride) * MidRight)) + _
                       ((Marshal.ReadByte(CInt(TempPtr) + 2 + DoubleStride) * BottomLeft) + (Marshal.ReadByte(CInt(TempPtr) + 5 + DoubleStride) * BottomMid) + (Marshal.ReadByte(CInt(TempPtr) + 8 + DoubleStride) * BottomRight))) \ Factor) + Offset)
    
                    If Pix < 0 Then
                        Pix = 0
                    ElseIf Pix > 255 Then
                        Pix = 255
                    End If
    
                    Marshal.WriteByte(CInt(ptr) + 5 + Stride, CByte(Pix))
    
                    Pix = (((((Marshal.ReadByte(CInt(TempPtr) + 1) * TopLeft) + (Marshal.ReadByte(CInt(TempPtr) + 4) * TopMid) + (Marshal.ReadByte(CInt(TempPtr) + 7) * TopRight)) + _
                       ((Marshal.ReadByte(CInt(TempPtr) + 1 + Stride) * MidLeft) + (Marshal.ReadByte(CInt(TempPtr) + 4 + Stride) * Pixel) + (Marshal.ReadByte(CInt(TempPtr) + 7 + Stride) * MidRight)) + _
                       ((Marshal.ReadByte(CInt(TempPtr) + 1 + DoubleStride) * BottomLeft) + (Marshal.ReadByte(CInt(TempPtr) + 4 + DoubleStride) * BottomMid) + (Marshal.ReadByte(CInt(TempPtr) + 7 + DoubleStride) * BottomRight))) \ Factor) + Offset)
    
                    If Pix < 0 Then
                        Pix = 0
                    ElseIf Pix > 255 Then
                        Pix = 255
                    End If
    
                    Marshal.WriteByte(CInt(ptr) + 4 + Stride, CByte(Pix))
    
                    Pix = (((((Marshal.ReadByte(CInt(TempPtr)) * TopLeft) + (Marshal.ReadByte(CInt(TempPtr) + 3) * TopMid) + (Marshal.ReadByte(CInt(TempPtr) + 6) * TopRight)) + _
                       ((Marshal.ReadByte(CInt(TempPtr) + Stride) * MidLeft) + (Marshal.ReadByte(CInt(TempPtr) + 3 + Stride) * Pixel) + (Marshal.ReadByte(CInt(TempPtr) + 6 + Stride) * MidRight)) + _
                       ((Marshal.ReadByte(CInt(TempPtr) + DoubleStride) * BottomLeft) + (Marshal.ReadByte(CInt(TempPtr) + 3 + DoubleStride) * BottomMid) + (Marshal.ReadByte(CInt(TempPtr) + 6 + DoubleStride) * BottomRight))) \ Factor) + Offset)
    
                    If Pix < 0 Then
                        Pix = 0
                    ElseIf Pix > 255 Then
                        Pix = 255
                    End If
    
                    Marshal.WriteByte(CInt(ptr) + 3 + Stride, CByte(Pix))
    
                    ptr = CInt(ptr) + 3
                    TempPtr = CInt(TempPtr) + 3
                Next
            Next
    
            bmp.UnlockBits(bmpData)
            TempBmp.UnlockBits(TempBmpData)
        End Sub
    
        Public Property Matrix() As ConvolutionMatrix
            Get
                Return m_Matrix
            End Get
            Set(ByVal value As ConvolutionMatrix)
                m_Matrix = value
            End Set
        End Property
        Private m_Matrix As ConvolutionMatrix
    End Class
    Code:
    Public Class ConvolutionMatrix
        Public Sub New()
            Pixel = 1
            Factor = 1
        End Sub
    
        Public Sub Apply(ByVal 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(ByVal 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(ByVal 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(ByVal 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(ByVal 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(ByVal 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(ByVal 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(ByVal 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(ByVal 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(ByVal 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(ByVal 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(ByVal value As Integer)
                m_Offset = value
            End Set
        End Property
        Private m_Offset As Integer
    End Class
    Code:
    Public Shared Sub ApplySharpen(ByRef bmp As Bitmap, ByVal weight As Integer)
        Dim m As New ConvolutionMatrix()
        m.Apply(0)
        m.Pixel = weight
        m.TopMid = -2
        m.MidLeft = -2
        m.MidRight = -2
        m.BottomMid = -2
        m.Factor = weight - 8
    
        Dim C As New Convolution()
        C.Matrix = m
        C.Convolution3x3(bmp)
    End Sub

  2. #2
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    6,582

    Re: Problem sharpening semi-transparent image

    I don't know, but I suppose you could try checking the Alpha value of the destination pixel you are working on, and if it is not 255, then skip all the processing so you don't modify that pixel, i.e. you won't take values from the surrounding pixels and modify the transparent/translucent pixel.

    I think, looking at the code, I would have to watch it work to understand where the alpha value to be check would be in the loop.
    A quick look at the code seems to suggest the loop is looking at a number of pixels around a reference pixel and then writing the result to a pixel above and to the right of the reference pixel being pointed at in the loop, so it would be the alpha value of the pixel the line above and to the right (thinking that the pixels are stored from the bottom up) that is being modified.
    "Anyone can do any amount of work, provided it isn't the work he is supposed to be doing at that moment" Robert Benchley, 1930

  3. #3

    Thread Starter
    eXtreme Programmer .paul.'s Avatar
    Join Date
    May 2007
    Location
    Chelmsford UK
    Posts
    25,481

    Re: Problem sharpening semi-transparent image

    That was my initial thoughts about it too, but I also can’t see where to test the Alpha value of the destination pixel, or even how to test the alpha value of the destination pixel…

  4. #4

    Thread Starter
    eXtreme Programmer .paul.'s Avatar
    Join Date
    May 2007
    Location
    Chelmsford UK
    Posts
    25,481

    Re: Problem sharpening semi-transparent image

    @passel… I can put together a quick test app, if you wouldn’t mind taking a look and want to see it running?

  5. #5

    Thread Starter
    eXtreme Programmer .paul.'s Avatar
    Join Date
    May 2007
    Location
    Chelmsford UK
    Posts
    25,481

    Re: Problem sharpening semi-transparent image

    Here's the test project. I've tidied the code significantly, making it error free was a task and a half

    Sharpen_Image_Test.zip

    The relevant code...

    Code:
    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 = DirectCast(bmp.Clone(), Bitmap)
    
        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 Integer = bmpData.Scan0.ToInt32
        Dim TempPtr As Integer = TempBmpData.Scan0.ToInt32
    
        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 = ptr + bmpData.Stride * bmpData.Height
    
        For y As Integer = 0 To Height - 1
            For x As Integer = 0 To Width - 1
                Pix = (((Marshal.ReadByte(New IntPtr((TempPtr + 2))) * TopLeft + _
                          Marshal.ReadByte(New IntPtr((TempPtr + 5))) * TopMid + _
                          Marshal.ReadByte(New IntPtr((TempPtr + 8))) * TopRight + _
                          Marshal.ReadByte(New IntPtr((TempPtr + 2 + Stride))) * MidLeft + _
                          Marshal.ReadByte(New IntPtr((TempPtr + 5 + Stride))) * Pixel + _
                          Marshal.ReadByte(New IntPtr((TempPtr + 8 + Stride))) * MidRight + _
                          Marshal.ReadByte(New IntPtr((TempPtr + 2 + DoubleStride))) * BottomLeft + _
                          Marshal.ReadByte(New IntPtr((TempPtr + 5 + DoubleStride))) * BottomMid + _
                          Marshal.ReadByte(New IntPtr((TempPtr + 8 + DoubleStride))) * BottomRight) \ _
                          Factor) + Offset)
    
                If Pix < 0 Then
                    Pix = 0
                ElseIf Pix > 255 Then
                    Pix = 255
                End If
    
                'Dim b As Byte = Marshal.ReadByte(New IntPtr(ptr + 5 + Stride))
                'If b Then ' how to detect if dest pixel is transparent???
                Marshal.WriteByte(New IntPtr(ptr + 5 + Stride), CByte(Pix))
    
                Pix = (((Marshal.ReadByte(New IntPtr((TempPtr + 1))) * TopLeft + _
                          Marshal.ReadByte(New IntPtr((TempPtr + 4))) * TopMid + _
                          Marshal.ReadByte(New IntPtr((TempPtr + 7))) * TopRight + _
                          Marshal.ReadByte(New IntPtr((TempPtr + 1 + Stride))) * MidLeft + _
                          Marshal.ReadByte(New IntPtr((TempPtr + 1 + Stride))) * Pixel + _
                          Marshal.ReadByte(New IntPtr((TempPtr + 4 + Stride))) * MidRight + _
                          Marshal.ReadByte(New IntPtr((TempPtr + 1 + DoubleStride))) * BottomLeft + _
                          Marshal.ReadByte(New IntPtr((TempPtr + 4 + DoubleStride))) * BottomMid + _
                          Marshal.ReadByte(New IntPtr((TempPtr + 7 + DoubleStride))) * BottomRight) \ _
                          Factor) + Offset)
    
                If Pix < 0 Then
                    Pix = 0
                ElseIf Pix > 255 Then
                    Pix = 255
                End If
    
                'b = Marshal.ReadByte(New IntPtr(ptr + 4 + Stride))
                'If b Then ' how to detect if dest pixel is transparent???
                Marshal.WriteByte(New IntPtr(ptr + 4 + Stride), CByte(Pix))
    
                Pix = (((Marshal.ReadByte(New IntPtr((TempPtr))) * TopLeft + _
                          Marshal.ReadByte(New IntPtr((TempPtr + 3))) * TopMid + _
                          Marshal.ReadByte(New IntPtr((TempPtr + 6))) * TopRight + _
                          Marshal.ReadByte(New IntPtr((TempPtr + Stride))) * MidLeft + _
                          Marshal.ReadByte(New IntPtr((TempPtr + 3 + Stride))) * Pixel + _
                          Marshal.ReadByte(New IntPtr((TempPtr + 6 + Stride))) * MidRight + _
                          Marshal.ReadByte(New IntPtr((TempPtr + DoubleStride))) * BottomLeft + _
                          Marshal.ReadByte(New IntPtr((TempPtr + 3 + DoubleStride))) * BottomMid + _
                          Marshal.ReadByte(New IntPtr((TempPtr + 6 + DoubleStride))) * BottomRight) \ _
                          Factor) + Offset)
    
                If Pix < 0 Then
                    Pix = 0
                ElseIf Pix > 255 Then
                    Pix = 255
                End If
    
                'b = Marshal.ReadByte(New IntPtr(ptr + 3 + Stride))
                'If b Then ' how to detect if dest pixel is transparent???
                Marshal.WriteByte(New IntPtr(ptr + 3 + Stride), CByte(Pix))
    
                ptr += 3
                TempPtr += 3
            Next
        Next
    
        bmp.UnlockBits(bmpData)
        TempBmp.UnlockBits(TempBmpData)
    End Sub

  6. #6
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    6,582

    Re: Problem sharpening semi-transparent image

    Looking at that code, I would expect the Alpha is being stripped off, and all the transparent pixels would end up being black.
    It appears you're converting the pixels to 24bpp which ignores the Alpha, when putting the pixels into a byte array.

    That also explains why the destination offsets of 3,4,5 didn't make sense to me. I would have expected 4,5,6 or 5,6,7 depending on which of the four bytes was the alpha byte.
    i.e. the first pixel would be at offsets 0,1,2,3 and the second at 4,5,6,7 and third at 8,... if there were 32-bits per pixel.
    But with 24-bpp the first pixel would be at offset 0,1,2 and the second at 3,4,5 and 3,4,5 offsets is what is in your code for the WriteBytes.

    So, the sharpening code is expecting 24-bit rgb, not 32-bit argb.
    "Anyone can do any amount of work, provided it isn't the work he is supposed to be doing at that moment" Robert Benchley, 1930

  7. #7

    Thread Starter
    eXtreme Programmer .paul.'s Avatar
    Join Date
    May 2007
    Location
    Chelmsford UK
    Posts
    25,481

    Re: Problem sharpening semi-transparent image

    I'm a little confused by the code. I've seen similar before, loads of times, but i've never attempted to use it. Would it be very difficult to modify that to use 32bpp ?

  8. #8

    Thread Starter
    eXtreme Programmer .paul.'s Avatar
    Join Date
    May 2007
    Location
    Chelmsford UK
    Posts
    25,481

    Re: Problem sharpening semi-transparent image

    Actually, I think i'll abandon this image sharpening. It was for an icon editing app, and there weren't any encouraging results before the transparency problem, so no big loss...

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width