Results 1 to 8 of 8

Thread: Making a grayscale version with RC6 that preserve the alpha channel

  1. #1

    Thread Starter
    Fanatic Member
    Join Date
    Jul 2017
    Posts
    761

    Question Making a grayscale version with RC6 that preserve the alpha channel

    Hello!

    I am unable to fix the following problem on my own so far despite like 10 hours of trying it:

    There is a very good example of an edge detection algorithm by Olaf Schmidt here:

    I was searching for a grayscale function, and I wanted to use the one shown in this project.
    The grayscale function in this project discards the alpha channel while I must preserve it in my project.

    I tried change to the function to preserve the alpha channel, but I am experiencing an overflow problem.
    I am not sure if the math formula is actually correct and it's only a VB6 problem, or if my approach is generally faulty.

    I have not been able to fix the overflow problem in the following attempt.
    Can somebody help me resolve it?

    Thank you!

    Code:
    Public Function Grayscale(SrcSrf As cCairoSurface) As cCairoSurface
    Dim x As Long, y As Long, xL As Long, Src() As Byte, Dst() As Byte, DstL() As Long
      
      Static SqrLut(0 To 255, 0 To 255) As Long, LogLut(2 To 130052) As Byte, LLut&(0 To 255)
      If LogLut(130052) = 0 Then 'init the lookup-tables (for squared deltas, logarithmic scaling and 32Bit-GreyValues)
        For y = 0 To 255: For x = 0 To 255: SqrLut(x, y) = (x - y) ^ 2 + 1: Next x, y
        For x = 2 To 130052: LogLut(x) = Log(x) * 23 - 16: Next 'in a normal Roberts, we would use Sqr() instead of Log()
        For x = 0 To 255: LLut(x) = (x + 256 * x + 65536 * x) Or &HFF000000: Next
      End If
    
      SrcSrf.BindToArray Src
      Set Grayscale = Cairo.CreateSurface(SrcSrf.Width, SrcSrf.Height)
          Grayscale.BindToArray Dst
          Grayscale.BindToArrayLong DstL
    
            For y = 1 To UBound(Src, 2)
                xL = 1
                For x = 4 To UBound(Src, 1) Step 4
                    'Calculate the gray value
                    Dim grayValue As Long
                    grayValue = LogLut(SqrLut(Src(x, y), Src(x - 4, y - 1)) + _
                    SqrLut(Src(x - 4, y), Src(x, y - 1)))
                    
                    'Put the gray values into the rgb channels
                    DstL(xL, y) = (grayValue + 256 * grayValue + 65536 * grayValue) ' grayscale for R, G, B
                    
                    ' Preserve the alpha value of the source array
                    DstL(xL, y) = CDbl(DstL(xL, y)) Or CDbl((Src(x + 3, y))) * CDbl(&H1000000)   ' Alpha value of original source
                    
                    xL = xL + 1
                Next x
            Next y
    
     
      SrcSrf.ReleaseArray Src
      Grayscale.ReleaseArray Dst
      Grayscale.ReleaseArrayLong DstL
    
    End Function

  2. #2
    PowerPoster VanGoghGaming's Avatar
    Join Date
    Jan 2020
    Location
    Eve Online - Mining, Missions & Market Trading!
    Posts
    2,619

    Talking Re: Making a grayscale version with RC6 that preserve the alpha channel

    Wherever you multiply by an integer constant (less than 32768}, add an ampersand after it for implicit conversion to Long. That should take care of your overflow problem.

  3. #3
    PowerPoster
    Join Date
    Jun 2013
    Posts
    7,454

    Re: Making a grayscale version with RC6 that preserve the alpha channel

    The explicit "greyscale-looping" was only for demonstration-purposes (on "non-alpha-Bitmaps").

    There is an easier way to accomplish grey-output of Icon- or Image-Resources via CC-Operators:
    Code:
    Private Sub Form_Load()
      Cairo.ImageList.AddIconFromResourceFile "ico", "shell32", 167
      
      Dim CC As cCairoContext
      Set CC = Cairo.CreateSurface(800, 600).CreateContext
          CC.Paint 1, Cairo.CreateCheckerPattern
          
          CC.RenderSurfaceContent "ico", 10, 10 'first we render the resource with the default-operator (CAIRO_OPERATOR_OVER)
          
          CC.Operator = Cairo_OPERATOR_HSL_LUMINOSITY 'for grey-output one can the switch to the HSL-Luminance-Operator
            CC.RenderSurfaceContent "ico", 100, 10
          CC.Operator = CAIRO_OPERATOR_OVER 'reset the CC to the default-render-operator
          
      Set Picture = CC.Surface.Picture
    End Sub
    Olaf

  4. #4
    Fanatic Member
    Join Date
    Sep 2010
    Location
    Italy
    Posts
    731

    Re: Making a grayscale version with RC6 that preserve the alpha channel

    If you wish to customize the grayscale formula (or for other color transformations) I would do something like this
    Code:
    Public Function Grayscale(SrcSrf As cCairoSurface) As cCairoSurface
        Dim Y As Long, Src() As Byte, Dst() As Byte
        Dim Gray      As Double
        Dim R#, G#, B#
        Dim X0&, X1&, X2&, X3&
        
        SrcSrf.BindToArray Src
        Set Grayscale = Cairo.CreateSurface(SrcSrf.Width, SrcSrf.Height)
        Grayscale.BindToArray Dst
    
        For Y = 0 To UBound(Src, 2)
            For X0 = 0 To UBound(Src, 1) Step 4
                X1 = X0 + 1&
                X2 = X0 + 2&
                X3 = X0 + 3&
    
                R = Src(X2, Y)
                G = Src(X1, Y)
                B = Src(X0, Y)
    
                '// GRAYSCALE formula Customization: //
                'Gray = (R + G + B) * 0.3333333                'Simple Mean
                'Gray = (0.3 * R + 0.59 * G + 0.11 * B)        'A common formula in image processors
                'https://en.wikipedia.org/wiki/Grayscale#Luma_coding_in_video_systems
                 Gray = (0.299 * R + 0.587 * G + 0.114 * B)    '(BT.601)  slightly different [Common/Favorite]
                'Gray = (0.2126 * R + 0.7152 * G + 0.0722 * B) '(BT.709)
                'Gray = (0.2627 * R + 0.6780 * G + 0.0593 * B) '(BT.2100)
    
                Dst(X2, Y) = Gray 'R
                Dst(X1, Y) = Gray 'G
                Dst(X0, Y) = Gray 'B
                Dst(X3, Y) = Src(X3, Y)     'Alpha (Preserved)
    
            Next X0
        Next Y
    
        SrcSrf.ReleaseArray Src
        Grayscale.ReleaseArray Dst
    
    End Function

  5. #5

    Thread Starter
    Fanatic Member
    Join Date
    Jul 2017
    Posts
    761

    Re: Making a grayscale version with RC6 that preserve the alpha channel

    Thank you for your showing me how to do it!!

  6. #6

    Thread Starter
    Fanatic Member
    Join Date
    Jul 2017
    Posts
    761

    Re: Making a grayscale version with RC6 that preserve the alpha channel

    Olaf, thank you. What is happening if the offset is not applied? I tried to render the same image at the same position, and I was not greyscaled but colored instead.
    I drew the same image with 1 pixel offset, it was still colored.
    Only after I applied an offset of 3 pixels, it started becoming grayscale.
    Is that because the function requires some pixels around it to work?
    You knew about it and expected me to stumble over it, right? :-)

    Name:  HSL offsets.jpg
Views: 157
Size:  10.0 KB

    Edit: Ok, I found out that it works by difference...
    Attached Files Attached Files
    Last edited by tmighty2; Sep 18th, 2024 at 03:01 PM.

  7. #7

    Thread Starter
    Fanatic Member
    Join Date
    Jul 2017
    Posts
    761

    Re: Making a grayscale version with RC6 that preserve the alpha channel

    Can you show me how to achieve the same result without the offset?

  8. #8
    PowerPoster
    Join Date
    Jun 2013
    Posts
    7,454

    Re: Making a grayscale version with RC6 that preserve the alpha channel

    Quote Originally Posted by tmighty2 View Post
    Can you show me how to achieve the same result without the offset?
    If you try to render on "uncleared, non-solid background" and want to render over it,
    "masking-out" the target-area with vbWhite beforehand, should help:

    Code:
    Private Sub Form_Load()
      Cairo.ImageList.AddIconFromResourceFile "ico", "shell32", 167
      
      Dim CC As cCairoContext
      Set CC = Cairo.CreateSurface(800, 600).CreateContext
            CC.Paint 1, Cairo.CreateCheckerPattern
          
            CC.RenderSurfaceContent "ico", 10, 10
          
            RenderDisabledIco CC, Cairo.ImageList("ico"), 30, 30
    
      Set Picture = CC.Surface.Picture
    End Sub
    
    Private Sub RenderDisabledIco(CC As cCairoContext, Srf As cCairoSurface, x, y)
          CC.SetSourceColor vbWhite
          CC.MaskSurface Srf, x, y
          CC.Operator = Cairo_OPERATOR_HSL_LUMINOSITY
            CC.RenderSurfaceContent Srf, x, y
          CC.Operator = CAIRO_OPERATOR_OVER
    End Sub
    Olaf

Tags for this Thread

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