Edge detection with bevel effect

Share your advanced PureBasic knowledge/code with the community.
User avatar
Keya
Addict
Addict
Posts: 1890
Joined: Thu Jun 04, 2015 7:10 am

Edge detection with bevel effect

Post by Keya »

a very simple 1-pixel inner bevel (so, quite limited! but im only using it for small text where it adds a nice subtle effect) ... the basic idea is to scan each row of pixels and simply monitor for transitions to and from transparent/opaque pixels using the alpha channel. Probably about as simple as edge detection gets i guess!? Then because we know which transition we're making we can brighten or darken accordingly. Because of corner overlap where double-brightening/darkening occurs the result is usually 4 new shades. Before & After:
Image Image

Code: Select all

Procedure Bound(value,min,max)
  If value < min: value = min: EndIf
  If value > max: value = max: EndIf
  ProcedureReturn value
EndProcedure


Procedure AdjustPixelBrightness(*pixel.Long, adjust)
  Protected r=Bound(Red(*pixel\l)+adjust,0,255)
  Protected g=Bound(Green(*pixel\l)+adjust,0,255)
  Protected b=Bound(Blue(*pixel\l)+adjust,0,255)
  *pixel\l = RGBA(r,g,b,$FF)
EndProcedure


Procedure EdgeDetectBevel(hImg, brighter, darker)
  rowbytes = DrawingBufferPitch() 
  *pixel.Long = DrawingBuffer()
  For row = 1 To ImageHeight(hImg)
    bevstate = 0
    For rowpixel = 0 To rowbytes-1 Step 4        
      If (*pixel\l & $FF000000) = 0     ;Transparent pixel (alpha 0)
        If bevstate = 1
          *pixel - 4
          AdjustPixelBrightness(*pixel, brighter)
          *pixel + 4
          bevstate = 0
        EndIf
      Else                              ;Opaque pixel (alpha >0)
        If bevstate = 0
          AdjustPixelBrightness(*pixel, darker): bevstate = 1
        Else
          If rowpixel > 0
            If Alpha(PeekL(*pixel + rowbytes)) = 0: AdjustPixelBrightness(*pixel, darker): EndIf
          EndIf
          If rowpixel < rowbytes-1
            If Alpha(PeekL(*pixel - rowbytes)) = 0: AdjustPixelBrightness(*pixel, brighter): EndIf
          EndIf          
        EndIf
      EndIf    
      *pixel + 4
    Next rowpixel
  Next row      
  StopDrawing()
EndProcedure


;--TEST--
UsePNGImageDecoder()
OpenWindow(0, 0, 0, 100, 100, "Edge-detection with bevel", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
hImg = CatchImage(#PB_Any, ?H32png)    ;hImg = LoadImage(#PB_Any, "C:\temp\H32.png")
If IsImage(hImg) = 0: MessageRequester("Error","LoadImage fail"): End: EndIf  
If StartDrawing(ImageOutput(hImg)) = 0: MessageRequester("Error","StartDrawing fail"): End: EndIf
If ImageDepth(hImg) <> 32: MessageRequester("Error","32bit RGBA required"): End: EndIf

EdgeDetectBevel(hImg, 80, -50)   ;Image, Brighten, Darken
ImageGadget(0, 40, 30, 200, 200, ImageID(hImg))
FreeImage(hImg)
Repeat
  If WaitWindowEvent() = #PB_Event_CloseWindow: End: EndIf
ForEver


DataSection
  H32png:  ;32bit PNG of blue "H" on transparent background as seen in screenshot
  Data.a $89,$50,$4E,$47,$D,$A,$1A,$A,$0,$0,$0,$D,$49,$48,$44,$52,$0,$0,$0,$19,$0,$0,$0,$17,$8,$6,$0,$0,$0,$FE,$E3,$E4
  Data.a $13,$0,$0,$0,$19,$74,$45,$58,$74,$53,$6F,$66,$74,$77,$61,$72,$65,$0,$41,$64,$6F,$62,$65,$20,$49,$6D,$61,$67,$65,$52,$65,$61
  Data.a $64,$79,$71,$C9,$65,$3C,$0,$0,$0,$62,$49,$44,$41,$54,$78,$DA,$62,$FC,$FF,$FF,$3F,$3,$AD,$1,$13,$3,$1D,$0,$B,$32,$87,$51
  Data.a $E4,$18,$DC,$5B,$FF,$DF,$58,$31,$92,$6A,$18,$2E,$FD,$8C,$B0,$E0,$42,$56,$80,$AC,$F,$AA,$81,$24,$B,$D0,$2D,$A2,$7F,$70,$61,$71
  Data.a $C9,$D0,$89,$F8,$E1,$63,$9,$B,$A9,$29,$66,$34,$4E,$46,$40,$C4,$93,$52,$7E,$E1,$4B,$24,$A3,$71,$32,$D2,$2D,$41,$4F,$49,$A4,$D6
  Data.a $8C,$F8,$F4,$33,$E,$9B,$86,$4,$40,$80,$1,$0,$F5,$35,$29,$C2,$2E,$48,$3E,$FB,$0,$0,$0,$0,$49,$45,$4E,$44,$AE,$42,$60,$82
EndDataSection