selection & border (like photoshop)

Just starting out? Need help? Post your questions and find answers here.
User avatar
[blendman]
Enthusiast
Enthusiast
Posts: 297
Joined: Thu Apr 07, 2011 1:14 pm
Location: 3 arks
Contact:

selection & border (like photoshop)

Post by [blendman] »

Hi

I'm looking for a way to :
- display a selection border (dash-line created from a border shape) from an image (with alpha channel), like I select the alpha channel.
Do you know how I can do that (if possible, no api, to be crossplatform ^^) ?
- a way to get a selection easily thanks to the alpha.

Some images to explain :
- I have this funny cat, (as you can see he's not happy, because he would like to be selected ^^) :
Image

- I select the line. We can see the line+the selection border :
Image

- Or, if I hide the layer, we can see only the selection border (the pixels whith alpha>0)
Image

I have thinking about a technic like remplissage() (=fillarea) by Comtois, see the last post (http://forums.purebasic.com/english/vie ... ght=myfill). But it doesn't take all the pixel non transparent, only the pixels in the selection.

If you an idea on how to achieve that, I will be very happy (better than my cat :))



In my exemple, I can draw on a selection (made by the two circles), but I would like to see the border of this selection (like in photoshop/gimp).

Code: Select all

; Alpha selection
; by blendman jully 2015

Global w, h
w = 1024
h = 768

Enumeration ; sprite
  
  #Sp_Layer
  #Sp_LayerTempo
  #Sp_Checker
  #Sp_Selection
    
EndEnumeration
Enumeration ;Image
  
  #Img_Layer
  #Img_LayerTempo
  #Img_AlphaSel
  
EndEnumeration

CreateImage(#Img_Layer,w,h,32,#PB_Image_Transparent)
CreateImage(#Img_LayerTempo,w,h,32,#PB_Image_Transparent)
CreateImage(#Img_AlphaSel,w,h,32,#PB_Image_Transparent)

;{ procedure
Procedure cb(x,y,top,bottom)
  ; by wilbert
  If (x!y) & 8; checkerboard pattern
    ProcedureReturn top
  Else 
    ProcedureReturn bottom
  EndIf
EndProcedure
Procedure Filtre_MaskAlpha(x, y, CouleurSource, CouleurDestination)
   ProcedureReturn (CouleurSource & $00FFFFFF) | (Alpha(CouleurSource)*Alpha(CouleurDestination)/255)<<24
EndProcedure
Procedure CanvasUpdate()
  If StartDrawing(SpriteOutput(#Sp_Layer))
    
    ; Box(0, 0, w, h, RGB(160,160,160))
    DrawingMode(#PB_2DDrawing_AlphaChannel)
    Box(0,0,w,h,RGBA(0,0,0,0))
    
    DrawingMode(#PB_2DDrawing_AlphaBlend)
    DrawAlphaImage(ImageID(#Img_Layer),0,0)
    
    
    DrawAlphaImage(ImageID(#Img_AlphaSel),0,0)   
    ; draw the painting
    DrawingMode(#PB_2DDrawing_CustomFilter)
    CustomFilterCallback(@Filtre_MaskAlpha())       
    DrawAlphaImage(ImageID(#Img_LayerTempo),0,0)
    
    StopDrawing()
  EndIf 
  
  ClearScreen(RGB(160,160,160))
  DisplayTransparentSprite(#Sp_Checker,0,0)
  DisplayTransparentSprite(#Sp_Layer,0,0)
  DisplayTransparentSprite(#Sp_Selection,0,0)
  FlipBuffers()

EndProcedure
;}

InitSprite()

OpenWindow(0, 0, 0, w, h, "Selection and alpha", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
screenwidth = 1024
screenheight = 768

If OpenWindowedScreen(WindowID(0),0,0,w, h)=0
  MessageRequester("Error", "Can't Open Screen!", 0)
  End
EndIf

; the image
If StartDrawing(ImageOutput(#Img_Layer))
   DrawingMode(#PB_2DDrawing_AlphaChannel) 
   Box(0,0,w,h,RGBA(0,0,0,0))
   StopDrawing()
 EndIf
If StartDrawing(ImageOutput(#Img_LayerTempo))
   DrawingMode(#PB_2DDrawing_AlphaChannel) 
   Box(0,0,w,h,RGBA(0,0,0,0))
   StopDrawing()
 EndIf
If StartDrawing(ImageOutput(#Img_AlphaSel))
   DrawingMode(#PB_2DDrawing_AlphaChannel) 
    ; create the mask
   Circle(450,350,100,RGBA(0,0,0,255))
   Circle(305,240,145,RGBA(0,0,0,120))
   StopDrawing()
 EndIf
 
; the sprite (for the preview)
 CreateSprite(#Sp_Layer,w,h,#PB_Sprite_AlphaBlending)
 CreateSprite(#Sp_LayerTempo,w,h,#PB_Sprite_AlphaBlending)
 CreateSprite(#Sp_Selection,w,h,#PB_Sprite_AlphaBlending) 
 CreateSprite(#Sp_Checker,w,h,#PB_Sprite_AlphaBlending) ; the checker
 
If StartDrawing(SpriteOutput(#Sp_Checker))
   DrawingMode(#PB_2DDrawing_AlphaBlend)
   Box(0,0,w,h,RGBA(200,200,200,255))
   DrawingMode(#PB_2DDrawing_CustomFilter)
   CustomFilterCallback(@cb())  
   Box(0,0,w,h,RGBA(160,160,160,255))
  StopDrawing()
EndIf
If StartDrawing(SpriteOutput(#Sp_Selection))
  DrawingMode(#PB_2DDrawing_AlphaChannel)
  Box(0,0,w,h,RGBA(0,0,0,0))
  ;DrawingMode(#PB_2DDrawing_Outlined) ; <------------- here, I would like to find a way to see a selection border 
  ;                                                     based on the alpha of the shape (the two icrcle, in this exemple), 
  ;                                                     which could work With image( it's ok if I use only box(), circle()....
  ;DrawAlphaImage(ImageID(#Img_AlphaSel),0,0)   
  StopDrawing()
EndIf

CanvasUpdate()

Repeat
  
  Repeat
    
    Event = WaitWindowEvent(1)
    
    Select Event 
        
      Case #PB_Event_CloseWindow
        End
        
      Case #WM_LBUTTONDOWN ; left buton down
        paint = 1
        
      Case #PB_Event_LeftClick ; left buton up
        paint = 0
        
    EndSelect
    
  Until  event = 0
  
  If paint = 1
    If StartDrawing(ImageOutput(#Img_LayerTempo))
      DrawingMode(#PB_2DDrawing_AlphaBlend) 
      x = WindowMouseX(0)
      y = WindowMouseY(0)
      Circle(x, y, 50, RGBA(255,120,120,255))
      StopDrawing()
    EndIf
    CanvasUpdate()
    
  EndIf

ForEver
alter Mann
User
User
Posts: 39
Joined: Fri Oct 17, 2014 8:52 pm

Re: selection & border (like photoshop)

Post by alter Mann »

I don't know if you are looking for something like that

Code: Select all

; ++++++++++++++++++++++++++++++++++++++++++
; + calculate the outline of an image area +
; ++++++++++++++++++++++++++++++++++++++++++
; - With the left mouse button the drawing is turned on and off again
; ( The mouse has not kept )
; - The drawing color is red
; - The calculated area is outlined in green
; - The outline function is not optimized
;
; Author : alter Mann
; Date : 12/11/08;================
; Konstanten
#Image1   = 1
#Window   = 2
#ImageGad = 3
#Button1  = 4
#Text2    = 5
#Text1    = 7
#Button2  = 8
#Spin     = 9
#MaxX     = 800
#MaxY     = 600
#MaxAnz   = 1000
#Timer    = 111

#Time     = 20

#BIT0 = 1
#BIT1 = 2
#BIT2 = 4
#BIT3 = 8
;================

;===========
; Strukturen
;===========
Structure STRECKE  ; Umrissstrecke
  wX1.w
  wY1.w
  wX2.w
  wY2.w
  wK.w
EndStructure

Structure PIXEL ; Pixel
  bRed.b
  bGreen.b
  bBlue.b
  bAlpha.b
EndStructure

Structure PIXELIDX ; Pixelindex
  wX.w
  wY.w
EndStructure

Structure PIXELKONTUR ; Umrisskontur
  wAnz.w
  List sPixel.PIXELIDX()
EndStructure

Structure PIXELBEREICH ; alle Umrisskonturen
  wAnz.w
  List sKontur.PIXELKONTUR()
EndStructure

;==============================================================
; Prototyp für Pixeltest - Funktion, ob Pixel zum Gebiet gehört 
Prototype.i fPixelTest(wPosX.w,wPosY.w,wAnzX.w,wAnzY.w,*lBild.PIXEL)
;==============================================================

Global sBereich.PIXELBEREICH

;==========================
; Integer-Absolutwert
;==========================
Procedure.i iAbs (iWert.i)
  If iWert < 0
    ProcedureReturn -iWert
  EndIf
  ProcedureReturn iWert
EndProcedure

; ===================================================
; Linie mit Liniendicke zeichnen mit Hilfe von Circle
; ===================================================
Procedure DrawLine(lX1.l,lY1.l,lX2.l,lY2.l,lR.l,lF.l)
  ; ----------------------------------
  ; Eingabe
  ; lX1,lY1    : Startpunkt
  ; lX2,lY2    : Endpunkt
  ; lR         : halbe Linienstärke
  ; lF         : Farbe
  ; ----------------------------------
  Protected lX.l, lY.l, lH.l, lT.l, lA.l, lD.l
  Circle(lX1,lY1,lR,lF)   ; Kreis um Startpunkt
  If lX1=lX2 And lY1=lY2  
    ProcedureReturn      ; Anfangspunkt = Endpunkt
  EndIf
  If iAbs(lX1-lX2) > iAbs(lY1-lY2) ; X-Differenz > Y-Differenz
    lD = lX2-lX1
    If lX1>lX2
      For lX=lX1-1 To lX2 Step -1 ; für jedes Pixel
        lH = (lX-lX1)*(lY2-lY1)
        lT = (lH % lD) << 1
        If lT<lD                   ; Y-Wert ausrechnen
          lY = lY1 + lH / lD - 1
        Else
          lY = lY1 + lH / lD
        EndIf
        Circle(lX,lY,lR,lF)
      Next lX
    Else
      For lX=lX1+1 To lX2 Step 1
        lH = (lX-lX1)*(lY2-lY1)
        lT = (lH % lD) << 1
        If lT>lD
          lY = lY1 + lH / lD + 1
        Else
          lY = lY1 + lH / lD
        EndIf
        Circle(lX,lY,lR,lF)
      Next lX
    EndIf
  Else                          ; Y-Differenz <= X-Differenz
    lD = lY2-lY1
    If lY1>lY2
      For lY=lY1-1 To lY2 Step -1 ; für jedes Pixel
        lH = (lY-lY1)*(lX2-lX1)
        lT = (lH % lD) << 1
        If lT<lD                   ; X-Wert ausrechnen
          lX = lX1 + lH / lD - 1  
        Else
          lX = lX1 + lH / lD
        EndIf
        Circle(lX,lY,lR,lF)
      Next lY
    Else
      For lY=lY1+1 To lY2 Step 1
        lH = (lY-lY1)*(lX2-lX1)
        lT = (lH % lD) << 1
        If lT>lD
          lX = lX1 + lH / lD + 1
        Else
          lX = lX1 + lH / lD
        EndIf
        Circle(lX,lY,lR,lF)
      Next lY
    EndIf
  EndIf
EndProcedure

;========================================
; Umriss um einen Grafikbereich berechnen
;========================================
Procedure Umriss(wAnzX.w, wAnzY.w, *lBild, *pFunction.fPixelTest)
  ; --------------------------------------------------------------------------------
  ; Eingabe
  ; wAnzX      : Anzahl Pixel in X-Richtung
  ; wAnzY      : Anzahl Pixel in Y-Richtung
  ; *lBild     : Pointer auf Farbwerte des Bildes
  ; *pFunction : Userdefinierte Funktion zur Bestimmung, ob Pixel zum Bereich gehört
  ; --------------------------------------------------------------------------------
  Protected i.w,j.w
  Protected iAnzP.i = 0
  Protected Dim bRand.b(wAnzX,wAnzY) ; Feld für Randkennung
  
  For i=0 To wAnzY-1 Step 1
    For j=0 To wAnzX-1 Step 1
      If *pFunction(j,i,wAnzX,wAnzY,*lBild) = #True  ; Pixel gehört zum Bereich
        bRand(j,i) = (#BIT0|#BIT1|#BIT2|#BIT3)       ; alle Randkennungen setzen
        iAnzP + 1
        If j>0 And (bRand(j-1,i) & #BIT1) = #BIT1    ; je nach Nachbar entsprechende Randkennungen streichen
          bRand(j  ,i) & ~#BIT3
          bRand(j-1,i) & ~#BIT1
        EndIf
        If i>0 And (bRand(j,i-1) & #BIT2) = #BIT2
          bRand(j,i  ) & ~#BIT0
          bRand(j,i-1) & ~#BIT2
        EndIf
      EndIf
    Next j
  Next i
  
  Protected iMaxS = 1000
  Protected Dim sStr.STRECKE(iMaxS)
  Protected iAnzS.i = 0
  ; je nach Kennung Strecken eintagen  
  For i=0 To wAnzY-1 Step 1
    For j=0 To wAnzX-1 Step 1
      If (bRand(j,i) & #BIT0) = #BIT0
        If iAnzS+1 > iMaxS
          iMaxS + 1000
          ReDim sStr.STRECKE(iMaxS)
        EndIf
        sStr(iAnzS)\wX1 = j
        sStr(iAnzS)\wY1 = i
        sStr(iAnzS)\wX2 = j+1
        sStr(iAnzS)\wY2 = i
        sStr(iAnzS)\wK  = 0
        iAnzS + 1
      EndIf
      If (bRand(j,i) & #BIT1) = #BIT1
        If iAnzS+1 > iMaxS
          iMaxS + 1000
          ReDim sStr.STRECKE(iMaxS)
        EndIf
        sStr(iAnzS)\wX1 = j+1
        sStr(iAnzS)\wY1 = i
        sStr(iAnzS)\wX2 = j+1
        sStr(iAnzS)\wY2 = i+1      
        sStr(iAnzS)\wK  = 0
        iAnzS + 1
      EndIf
      If (bRand(j,i) & #BIT2) = #BIT2
        If iAnzS+1 > iMaxS
          iMaxS + 1000
          ReDim sStr.STRECKE(iMaxS)
        EndIf
        sStr(iAnzS)\wX1 = j+1
        sStr(iAnzS)\wY1 = i+1
        sStr(iAnzS)\wX2 = j
        sStr(iAnzS)\wY2 = i+1        
        sStr(iAnzS)\wK  = 0
        iAnzS + 1
      EndIf
      If (bRand(j,i) & #BIT3) = #BIT3
        If iAnzS+1 > iMaxS
          iMaxS + 1000
          ReDim sStr.STRECKE(iMaxS)
        EndIf
        sStr(iAnzS)\wX1 = j
        sStr(iAnzS)\wY1 = i+1
        sStr(iAnzS)\wX2 = j
        sStr(iAnzS)\wY2 = i        
        sStr(iAnzS)\wK  = 0
        iAnzS + 1
      EndIf
    Next j
  Next i
  ; Feld sortieren
  SortStructuredArray(sStr(),#PB_Sort_Ascending,OffsetOf(STRECKE\wX1),#PB_Word,0,iAnzS-1)
  
  Protected Dim sStr1.STRECKE(iAnzS)
  Protected k.i,iS.i=-1,iE.i, iAnz.i=1, iFind.i=0, iIdx.i=0
  Protected wX0.w = sStr(0)\wX2
  Protected wDx1.w=sStr(0)\wX2-sStr(0)\wX1,wDy1.w=sStr(0)\wY2-sStr(0)\wY1
  Protected wDx2.w,wDy2.w,wDx3.w,wDy3.w,wW2.w,wW3.w
  
  ; erste Strecke ist Startstrecke
  For k=0 To iAnzS Step 1
    If sStr(k)\wX1 = wX0 And iS = -1
      iS = k
    ElseIf sStr(k)\wX1 > wX0
      iE = k
      Break
    EndIf
  Next k
  sStr(0)\wK = 1
  sStr1(0) = sStr(0)
  ; Strecken sortieren
  While iFind < iAnzS
    If sStr1(iAnz-1)\wX2 > wX0
      iS = iE
      While iE<iAnzS And sStr(iE)\wX1 = sStr1(iAnz-1)\wX2
        iE + 1
      Wend
      wX0 = sStr1(iAnz-1)\wX2
    ElseIf sStr1(iAnz-1)\wX2 < wX0
      iE = iS
      iS - 1
      While iS>=0 And sStr(iS)\wX1 = sStr1(iAnz-1)\wX2
        iS - 1
      Wend
      iS + 1
      wX0 = sStr1(iAnz-1)\wX2
    EndIf
    iIdx = -1
    wW2  =  4
    For k=iS To iE-1
      If sStr(k)\wK = 1
        Continue
      EndIf
      If sStr(k)\wX1 = sStr1(iAnz-1)\wX2 And sStr(k)\wY1 = sStr1(iAnz-1)\wY2
        wDx3 = sStr(k)\wX2 - sStr(k)\wX1
        wDy3 = sStr(k)\wY2 - sStr(k)\wY1
        wW3  = wDx1 * wDy3 - wDy1 * wDx3
        If wW3 < wW2
          iIdx = k
          wW2  = wW3
          wDx2 = wDx3
          wDy2 = wDy3
        EndIf
      EndIf
    Next k
    If iIdx = -1 And sStr1(0)\wX1 = sStr1(iAnz-1)\wX2 And sStr1(0)\wY1 = sStr1(iAnz-1)\wY2 ; geschlossene Kontur übernehmen
      sBereich\wAnz + 1
      AddElement(sBereich\sKontur())
      For k=0 To iAnz-1 Step 1
        wDx1 = sStr1(k)\wX2 - sStr1(k)\wX1
        wDy1 = sStr1(k)\wY2 - sStr1(k)\wY1
        If     wDx1 =  1 And wDy1 =  0
          wDx2 = sStr1(k)\wX1
          wDy2 = sStr1(k)\wY1
        ElseIf wDx1 =  0 And wDy1 =  1
          wDx2 = sStr1(k)\wX1-1
          wDy2 = sStr1(k)\wY1
        ElseIf wDx1 = -1 And wDy1 =  0
          wDx2 = sStr1(k)\wX2
          wDy2 = sStr1(k)\wY1-1
        ElseIf wDx1 =  0 And wDy1 = -1
          wDx2 = sStr1(k)\wX2
          wDy2 = sStr1(k)\wY2
        Else
        EndIf
        If sBereich\sKontur()\wAnz > 0 And sBereich\sKontur()\sPixel()\wX = wDx2 And sBereich\sKontur()\sPixel()\wY = wDy2
          Continue
        EndIf
        sBereich\sKontur()\wAnz + 1
        AddElement(sBereich\sKontur()\sPixel())
        sBereich\sKontur()\sPixel()\wX = wDx2
        sBereich\sKontur()\sPixel()\wY = wDy2        
      Next k
      iAnz = 0 ; neue Startstrecke suchen
      For k=0 To iAnzS-1 Step 1
        If sStr(k)\wK = 0
          sStr1(iAnz) = sStr(k)
          sStr(k)\wK = 1
          wX0 = sStr1(0)\wX2
          iAnz + 1
          iFind + 1
          iS = -1
          For j=0 To iAnzS-1 Step 1
            If sStr(j)\wX1 = wX0 And iS = -1
              iS = j
              iE = iAnzS
            ElseIf sStr(j)\wX1 > wX0
              iE = j
              Break
            EndIf
          Next j
          Break
        EndIf
      Next k
      If iAnz = 0
        Break
      EndIf
      wDx1 = sStr1(0)\wX2 - sStr1(0)\wX1
      wDy1 = sStr1(0)\wY2 - sStr1(0)\wY1
    ElseIf iIdx >-1
      sStr1(iAnz) = sStr(iIdx)
      sStr(iIdx)\wK = 1
      iAnz + 1
      iFind + 1
      wDx1 = wDx2
      wDy1 = wDy2
    Else
      Break ; Fehler
    EndIf
  Wend
  k = 0
EndProcedure

;=======================
; Bild in Speicher laden
;=======================
Procedure.i GetPixelFromImage (iImage.i, *sPixel.PIXEL)
  ; ---------------------
  ; Eingabe
  ; iImage     : Imagegadgetnummer
  ; *sPixel    : Speicher für Bild
  ; -------------
  If StartDrawing(ImageOutput(iImage))
    Protected *bBuffer = DrawingBuffer()
    Protected iPitch.i = DrawingBufferPitch()
    Protected iPixelFormat.i = DrawingBufferPixelFormat()
    Protected iWidth.i = ImageWidth(iImage)
    Protected iHeight.i = ImageHeight(iImage)
    Protected iByte.i,iRev.i
    Protected *bBuffer2, bL.b
    Protected i.i,j.i
    Protected sPixel.PIXEL, *sPixel1.PIXEL = *sPixel
    
    If iPixelFormat & #PB_PixelFormat_24Bits_RGB
      iByte = 3
      iRev  = 1
    ElseIf iPixelFormat & #PB_PixelFormat_24Bits_BGR
      iByte = 3
      iRev  = -1
    ElseIf iPixelFormat & #PB_PixelFormat_32Bits_RGB
      iByte = 4
      iRev  = 1
    ElseIf iPixelFormat & #PB_PixelFormat_32Bits_BGR
      iByte = 4
      iRev  = -1
    Else
      StopDrawing()
      ProcedureReturn 1
    EndIf
    iPitch / iByte
    
    If iPitch < iWidth
      StopDrawing()
      ProcedureReturn 2
    EndIf
    If iByte < SizeOf(PIXEL)                                ; Imagefarbe an PIXEL-Struktur anpassen
      sPixel\bAlpha = 255
      If iPixelFormat & #PB_PixelFormat_ReversedY
        For i=0 To iHeight-1
          For j=0 To iWidth-1
            CopyMemory (*bBuffer,@sPixel,iByte)
            *bBuffer + iByte
            CopyMemory(@sPixel,*sPixel,SizeOf(PIXEL))
            *sPixel + SizeOf(PIXEL)
          Next j
          *bBuffer + iByte*(iPitch-iWidth)
        Next i
      Else      
        For i=iHeight-1 To 0 Step -1
          *bBuffer2 = *bBuffer + iPitch * i * iByte
          For j=0 To iWidth-1
            CopyMemory (*bBuffer2,@sPixel,iByte)
            *bBuffer2 + iByte
            CopyMemory(@sPixel,*sPixel,SizeOf(PIXEL))
            *sPixel + SizeOf(PIXEL)
          Next j
        Next i
      EndIf
    ElseIf iAbs(i) = SizeOf(PIXEL)                           ; selbe Größe
      If iPixelFormat & #PB_PixelFormat_ReversedY
        If iPitch = iWidth
          CopyMemory (*bBuffer,*sPixel,iWidth*iHeight*SizeOf(PIXEL))
        ElseIf iPitch > iWidth
          For i=0 To iHeight-1
            CopyMemory (*bBuffer,*sPixel,iWidth*SizeOf(PIXEL))
            *bBuffer + iPitch*SizeOf(PIXEL)
            *sPixel + iWidth*SizeOf(PIXEL)
          Next i
        EndIf
      Else      
        *bBuffer2 = *bBuffer + iPitch * (iHeight-1) * SizeOf(PIXEL)
        For i=iHeight-1 To 0 Step -1
          CopyMemory (*bBuffer2,*sPixel,iWidth*SizeOf(PIXEL))
          *bBuffer2 - iPitch*SizeOf(PIXEL)
          *sPixel + iWidth*SizeOf(PIXEL)
        Next i
      EndIf
    Else
      ProcedureReturn 2
    EndIf
    StopDrawing()
    SetGadgetState(#ImageGad,ImageID(iImage))
    If iRev = -1                               ; Blau und Rot tauschen
      j = iHeight*iWidth - 1 
      For i=0 To j Step 1
        Swap *sPixel1\bBlue,*sPixel1\bRed
        *sPixel1 + SizeOf(PIXEL)
      Next i
    EndIf
  Else
    ProcedureReturn 3
  EndIf
  ProcedureReturn 0
EndProcedure

;============================
; Benutzerdefinierte Funktion
; hier : rote Pixel
;============================
Procedure.i TestePixel (wX.w, wY.w, wAX.w, wAY.w, *sPix.PIXEL)
  ; ---------------------------------------
  ; Eingabe
  ; wX,wY       : Pixelindex
  ; wAX         : Anzahl Pixel in X im Bild
  ; wAY         : Anzahl Pixel in Y im Bild
  ; *lPix       : Bildspeicher
  ; ---------------------------------------
  Protected lX.l = wX, lY.l = wY, lAX.l = wAX
  *sPix + (lX + lY*lAX) * SizeOf(PIXEL)
  If (*sPix\bGreen & $FF) = 0 And (*sPix\bRed & $FF) = 255 And (*sPix\bBlue & $FF) = 0
    ProcedureReturn 1
  EndIf
  ProcedureReturn 0
EndProcedure

InitializeStructure(@sBereich,PIXELBEREICH) 

Define iEvent.i
Define iAktion.i = 0
Define iDraw.i = #False
Define iTimer.i = -1
Define lX.l,lY.l,lX1.l,lY1.l
Define lR.l = 5
Define lF.l = RGBA(255,0,0,255)
Define *sPixel.PIXEL
Define i.w,j.w

If CreateImage(#Image1,#MaxX,#MaxY,24) = 0
  MessageRequester("attention!","can't create image")
  End
EndIf

sBereich\wAnz = 0

If OpenWindow(#Window,0,0,#MaxX+10,#MaxY+55,"contur outline",#PB_Window_ScreenCentered|#PB_Window_SystemMenu)
  ImageGadget (#ImageGad,  5,10, #MaxX,#MaxY,ImageID(#Image1))
  ButtonGadget(#Button1,5,#MaxY+20,50,25, "new")
  TextGadget(#Text1,650,#MaxY+25,100,30,"drawing : off")
  ButtonGadget(#Button2,180,#MaxY+20,100,25, "calculate outline")
  SpinGadget(#Spin,350,#MaxY+15,50,20,1,10,#PB_Spin_Numeric)
  SetGadgetState(#Spin,lR)
  TextGadget(#Text2,350,#MaxY+37,100,15,"half line thickness")
  
  StartDrawing(ImageOutput(#Image1)) ; Hintergrund zeichnen
  DrawingMode(#PB_2DDrawing_AllChannels)
  Box(0,0,#MaxX,#MaxY,RGB(50,50,50))
  StopDrawing()
  SetGadgetState(#ImageGad,ImageID(#Image1))

  Repeat
    iEvent = WaitWindowEvent()
     
    Select iEvent

      Case #PB_Event_Gadget
        
        Select EventGadget()
          
          Case #ImageGad
            If EventType() = #PB_EventType_LeftClick  ; Zeichnen ein-/ausschalten
              iAktion = 1-iAktion
              If iAktion = 1
                AddWindowTimer(#Window,#Timer,#Time)
                iTimer = #Timer
                SetGadgetColor(#Text1,#PB_Gadget_FrontColor,RGB(255,0,0))
                SetGadgetText(#Text1,"drawing : on")
              Else
                If iDraw = #False
                  lX = WindowMouseX(#Window)
                  lY = WindowMouseY(#Window)
                EndIf
                lX1 = WindowMouseX(#Window)
                lY1 = WindowMouseY(#Window)
                If lX1 > -1 And lY1 > -1
                  StartDrawing(ImageOutput(#Image1))
                  DrawLine(lX,lY,lX1,lY1,lR,lF)
                  StopDrawing()
                  SetGadgetState(#ImageGad,ImageID(#Image1))
                EndIf
                RemoveWindowTimer(#Window,#Timer)
                iTimer = -1
                SetGadgetColor(#Text1,#PB_Gadget_FrontColor,RGB(0,0,0))
                SetGadgetText(#Text1,"drawing : off")
                iDraw = #False
              EndIf
            EndIf
          
          Case #Button1     ; Hintergrund neu zeichnen
            If iTimer = #Timer
              RemoveWindowTimer(#Window,#Timer)
              iTimer = -1
              SetGadgetText(#Text1,"drawing : off")
            EndIf              
            StartDrawing(ImageOutput(#Image1))
            Box(0,0,#MaxX,#MaxY,RGB(50,50,50))
            StopDrawing()
            SetGadgetState(#ImageGad,ImageID(#Image1))               
            iDraw = #False
            
          Case #Button2    ; Umriss berechnen und Zeichnen
            
            Define *fSuchePixel.fPixelTest = @TestePixel()
            
            lX1 = ImageWidth(#Image1)
            lY1 = ImageHeight(#Image1)
            *sPixel = AllocateMemory(lX1*lY1*SizeOf(PIXEL))
            GetPixelFromImage (#Image1, *sPixel)
            
            Umriss(lX1, lY1, *sPixel, *fSuchePixel)
            If sBereich\wAnz>0
              ;Debug sBereich\wAnz
              StartDrawing(ImageOutput(#Image1))
              ResetList(sBereich\sKontur())
              While NextElement(sBereich\sKontur())
                If sBereich\sKontur()\wAnz
                  ResetList(sBereich\sKontur()\sPixel())
                  NextElement(sBereich\sKontur()\sPixel())                  
                  lX1 = sBereich\sKontur()\sPixel()\wX
                  lY1 = ImageHeight(#Image1)-sBereich\sKontur()\sPixel()\wY-1
                  ;Debug lX1
                  ;Debug lY1
                  While NextElement(sBereich\sKontur()\sPixel())
                    LineXY(lX1,lY1,sBereich\sKontur()\sPixel()\wX,ImageHeight(#Image1)-sBereich\sKontur()\sPixel()\wY-1,RGB(0,255,0))
                    lX1 = sBereich\sKontur()\sPixel()\wX
                    lY1 = ImageHeight(#Image1)-sBereich\sKontur()\sPixel()\wY-1
                  Wend
                  ;Debug lX1
                  ;Debug lY1
                  ClearList(sBereich\sKontur()\sPixel())
                EndIf
              Wend
              StopDrawing()
              ClearList(sBereich\sKontur())
              sBereich\wAnz = 0
              SetGadgetState(#ImageGad,ImageID(#Image1))               
            EndIf
            FreeMemory(*sPixel)

        EndSelect
      Case #PB_Event_Timer           ; Timer zum Zeichnen
        If EventTimer() = #Timer
          If iDraw = #False
            lX = WindowMouseX(#Window)
            lY = WindowMouseY(#Window)
          EndIf
          iDraw = #True
          lX1 = WindowMouseX(#Window)
          lY1 = WindowMouseY(#Window)
          If lX1 > -1 And lY1 > -1
            lR = GetGadgetState(#Spin)
            StartDrawing(ImageOutput(#Image1))
            DrawLine(lX,lY,lX1,lY1,lR,lF)
            StopDrawing()
            lX = lX1
            lY = lY1
            SetGadgetState(#ImageGad,ImageID(#Image1))
          EndIf
        EndIf
    EndSelect
  Until iEvent = #PB_Event_CloseWindow
EndIf
CloseWindow(#Window)
It's from the german forum with german comments. I posted it some years ago.
Sonki
New User
New User
Posts: 2
Joined: Thu Jul 30, 2015 12:32 am

Re: selection & border (like photoshop)

Post by Sonki »

Hi Blendman,
I work in Photoshop and I know what you are looking for. This is what with I come with. In this example click Load Image and then show selection. It should work like in Photoshop and it will select areas which are brighter then 50%. It would be like you ctrl + click on RGB channel in PS, but you could make it to select alpha channel like in your example. First it wil make grayscale image, then thresholded image (higher then 127 will be white otherwise black). After that will be generate selection mask in list. Hope it is will work for you.

Code: Select all

UseJPEGImageDecoder() 

Global Window_0
Global Canvas_0, Button_Load, Button_Selection

Structure SelectPoint
  x.l
  y.l
EndStructure

Structure Selection
  ImageIn.l
  ImageInCopy.l
  xMax.l
  yMax.l
  SelectDraw.l
  List Selection.SelectPoint()
EndStructure


Procedure OpenWindow_0(x = 0, y = 0, width = 1160, height = 800)
  Window_0 = OpenWindow(#PB_Any, x, y, width, height, "",  #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_ScreenCentered)
  Canvas_0 = CanvasGadget(#PB_Any, 10, 10, 1140, 720)
  Button_Load = ButtonGadget(#PB_Any, 900, 740, 110, 40, "Load image")
  Button_Selection = ButtonGadget(#PB_Any, 1040, 740, 110, 40, "Show selection")
EndProcedure

Procedure GenerateGrayscale(*Selection.Selection)
  Protected Color.l, x.l, y.l, Gray.l
  StartDrawing(ImageOutput(*Selection\ImageInCopy))
  For y = 0 To *Selection\yMax
    For x = 0 To *Selection\xMax
      Color = Point(x, y)
      Gray = (Red(Color) + Green(Color) + Blue(Color)) / 3
      Plot(x, y, RGB(Gray, Gray, Gray))
    Next x
  Next y
  StopDrawing()
  ProcedureReturn ImageInCopy
EndProcedure

Procedure GenerateThreshold(*Selection.Selection)
  Protected x.l, y.l, Color
  StartDrawing(ImageOutput(*Selection\ImageInCopy))
  For y = 0 To *Selection\yMax
    For x = 0 To *Selection\xMax
      Color = Point(x, y)
      If Red(Color) > 127
        Plot(x, y, $FFFFFF)
      Else
        Plot(x, y, $0)
      EndIf
    Next x
  Next y
  StopDrawing()
EndProcedure

Procedure GenerateSelectionMask(*Selection.Selection)
  Protected x.l, y.l, PointF.l
  
  StartDrawing(ImageOutput(*Selection\ImageInCopy))
  For y = 0 To *Selection\yMax
    For x = 0 To *Selection\xMax
      PointF = 0
      Color = Point(x, y)
      If Color = $FFFFFF
        PointF = 0
          If x = 0
            PointF = 1
          ElseIf Point(x-1, y) = $0
            PointF = 1
          EndIf
          
          If x = *Selection\xMax
            PointF = 1
          ElseIf Point(x+1, y) = $0
            PointF = 1
          EndIf
          
          If y = 0
            PointF = 1
          ElseIf Point(x, y-1) = $0
            PointF = 1
          EndIf
          
          If y = *Selection\yMax
            PointF = 1
          ElseIf Point(x, y+1) = $0
            PointF = 1
          EndIf
          
          If PointF = 1
            AddElement(*Selection\Selection())
            *Selection\Selection()\x = x
            *Selection\Selection()\y = y
          EndIf
      EndIf
    Next x
  Next y
  StopDrawing()
EndProcedure

Procedure DrawSelectionThread(*Selection.Selection)
  Protected x.l, y.l, xmax.l, ymax.l, offset.l, a.l, b.l, color.l
  Dim PatternArray.a(7, 7)
  ;*pointer = @PatternArray()
  StartDrawing(CanvasOutput(Canvas_0))
  xmax = OutputWidth() - 1
  ymax = OutputHeight() - 1
  StopDrawing()

  Repeat
    CopyMemory(?Pattern2 + offset * 8, @PatternArray(), 64)
    StartDrawing(CanvasOutput(Canvas_0))
    DrawImage(ImageID(*Selection\ImageIn), 0, 0)
      ForEach *Selection\Selection()
        x = *Selection\Selection()\x
        y = *Selection\Selection()\y
        
        If x >= 0 And y >= 0 And x <= xmax And y <=ymax
          a = x % 8
          b = y % 8
          color = PatternArray(b, a)
          If color = 255
            color = $FFFFFF
          Else
            color = $0
          EndIf
          Plot(x, y, color)
        EndIf
      Next
    StopDrawing()
    offset - 1
    If offset = -1 : offset = 7 : EndIf
    Delay(200)
  Until *Selection\SelectDraw = 0
  FreeArray(PatternArray())
EndProcedure

Procedure DrawSelection(*Selection.Selection)
  CreateThread(@DrawSelectionThread(), *Selection)
EndProcedure


Procedure MakeSelection(*Selection.Selection)
  Protected ImageW.l, ImageH.l, Thread1.l
  ImageW = ImageWidth(*Selection\ImageIn)
  ImageH = ImageHeight(*Selection\ImageIn)

  *Selection\ImageInCopy = CopyImage(*Selection\ImageIn, #PB_Any)
  *Selection\xMax = ImageW - 1
  *Selection\yMax = ImageH - 1
  ;*Selection\SelectDraw = 1
  NewList *Selection\Selection()
  
  Thread1 = CreateThread(@GenerateGrayscale(), *Selection)
  WaitThread(Thread1)
  Thread1 = CreateThread(@GenerateThreshold(), *Selection)
  WaitThread(Thread1)
  Thread1 = CreateThread(@GenerateSelectionMask(), *Selection)
  WaitThread(Thread1)
  ;Thread1 = CreateThread(@DrawSelection(), *Selection)
  ;WaitThread(Thread1)
EndProcedure

Procedure FreeSelection(*Selection.Selection)
  If *Selection
    If IsImage(*Selection\ImageIn) : FreeImage(*Selection\ImageIn) : *Selection\ImageIn = 0 : EndIf
    If IsImage(*Selection\ImageInCopy) : FreeImage(*Selection\ImageInCopy) : EndIf
    FreeList(*Selection\Selection())
  EndIf
EndProcedure


Pattern$ = "Jpeg (*.jpg)|*.jpg|Bitmap (*.bmp)|*.bmp"
*Selection.Selection = AllocateMemory(SizeOf(Selection))

OpenWindow_0()

Repeat
  event = WaitWindowEvent()
  Select event
    Case #PB_Event_Gadget
      Select EventGadget()
        Case Button_Load
          ImageName$ = OpenFileRequester("Load image", "D:\", Pattern$, 0)
          LoadedImage = LoadImage(#PB_Any, ImageName$)
          If LoadedImage > 0
            *Selection\SelectDraw = 0
            FreeSelection(*Selection)
            *Selection\ImageIn = LoadedImage
            SetGadgetData(Button_Selection, 0)
            SetGadgetText(Button_Selection, "Show selection")
          EndIf
          
          StartDrawing(CanvasOutput(Canvas_0)) : Box(0, 0, 1140, 720, $FFFFFF) : DrawImage(ImageID(*Selection\ImageIn), 0, 0) : StopDrawing()
          MakeSelection(*Selection)
        Case Button_Selection
          If *Selection\ImageIn > 0
            If GetGadgetData(Button_Selection) = 0 
              SetGadgetData(Button_Selection, 1)
              SetGadgetText(Button_Selection, "Hide Selection")
              *Selection\SelectDraw = 1
              DrawSelection(*Selection)
            Else
              *Selection\SelectDraw = 0
              StartDrawing(CanvasOutput(Canvas_0)) : DrawImage(ImageID(*Selection\ImageIn), 0, 0) : StopDrawing()
              SetGadgetData(Button_Selection, 0)
              SetGadgetText(Button_Selection, "Show selection")
            EndIf
          EndIf
      EndSelect
    EndSelect
Until event = #PB_Event_CloseWindow


;{ DataSection
DataSection
  
  Pattern2: 
Data.a  0, 0, 0, 0, 255, 255, 255, 255,
        0, 0, 0, 255, 255, 255, 255, 0,
        0, 0, 255, 255, 255, 255, 0, 0,
        0, 255, 255, 255, 255, 0, 0, 0,
        255, 255, 255, 255, 0, 0, 0, 0,
        255, 255, 255, 0, 0, 0, 0, 255,
        255, 255, 0, 0, 0, 0, 255, 255,
        255, 0, 0, 0, 0, 255, 255, 255,
        0, 0, 0, 0, 255, 255, 255, 255,
        0, 0, 0, 255, 255, 255, 255, 0,
        0, 0, 255, 255, 255, 255, 0, 0,
        0, 255, 255, 255, 255, 0, 0, 0,
        255, 255, 255, 255, 0, 0, 0, 0,
        255, 255, 255, 0, 0, 0, 0, 255,
        255, 255, 0, 0, 0, 0, 255, 255,
        255, 0, 0, 0, 0, 255, 255, 255,
        0, 0, 0, 0, 255, 255, 255, 255
EndDataSection
;}

acreis
Enthusiast
Enthusiast
Posts: 234
Joined: Fri Jun 01, 2012 12:20 am

Re: selection & border (like photoshop)

Post by acreis »

Hi Sonki,

That's fantastic! Thank you so much!

ACReis
Sonki
New User
New User
Posts: 2
Joined: Thu Jul 30, 2015 12:32 am

Re: selection & border (like photoshop)

Post by Sonki »

You are welcome acreis :D
Post Reply