Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Border detect
#3
Fast version, use _Mem not Point, optimized directly

Code: (Select All)

' -------------------------------------------
'    Border detect 0.2  (MEM version)
' -------------------------------------------

Screen _NewImage(800, 600, 256)
Randomize Timer

Dim Bcount As Integer
Dim OptimStep As Integer
OptimStep = 20 ' step optimized border is 20 pixels

Do
    Locate 1
    ' draw random image (1 color, is enough as mask)
    For f = 1 To 5000
        If Rnd * 10 > 4 Then p = -1 Else p = 1
        x = 400 + Rnd * p * 300
        y = 300 + Rnd * p * 200
        r = (10 + f / 500) * Rnd
        CircleFill x, y, r, 40
    Next

    ' prepare output arrays
    ReDim Bx(0) As Integer, By(0) As Integer
    ReDim count As Long

    ' use _Dest as source image, because image is drawn directly to screen in previous step
    DetectBorder _Dest, 40, Bx(), By(), count

    _Dest 0
    Print "Generate random picture in 1 color and detect the border (white). ESC for end."
    Print "Border points (count):"; count

    ' draw detected border points (small squares)
    If count > 0 Then
        For d = 0 To count
            Line (Bx(d), By(d))-(Bx(d) + 1, By(d) + 1), , BF
        Next
    End If

    If Bcount > 0 Then
        For d = 1 To Bcount
            Line (Bx(d), By(d))-(Bx(d - 1), By(d - 1)), 2
        Next
        Line (Bx(Bcount), By(Bcount))-(Bx(0), By(0)), 25
    End If

    _Display
    ' Sleep
    _Limit 2000
    Cls
Loop Until _KeyDown(27)

Function GetPix~%% (mem As _MEM, x As Long, y As Long, w As Long)
    ' vrací 0..255 (unsigned byte)
    GetPix = _MemGet(mem, mem.OFFSET + y * w + x, _Unsigned _Byte)
End Function

' ---------------------------------------------
' IsBoundary using _MEM (returns -1 if boundary, 0 otherwise)
' ---------------------------------------------
Function IsBoundary (px As Long, py As Long, targetColor As Integer, mem As _MEM, W As Long, H As Long, dx() As Integer, dy() As Integer)
    ' outside = boundary
    If px < 0 Or px >= W Or py < 0 Or py >= H Then
        IsBoundary = -1
        Exit Function
    End If

    If GetPix(mem, px, py, W) <> targetColor Then
        IsBoundary = 0
        Exit Function
    End If

    ' at least one neighbor must differ -> boundary
    For k = 0 To 7
        nx = px + dx(k)
        ny = py + dy(k)

        If nx < 0 Or nx >= W Or ny < 0 Or ny >= H Then
            IsBoundary = -1
            Exit Function
        Else
            If GetPix(mem, nx, ny, W) <> targetColor Then
                IsBoundary = -1
                Exit Function
            End If
        End If
    Next

    IsBoundary = 0
End Function

' ---------------------------------
' Moore-neighborhood border tracer (reads from _MEM)
' ---------------------------------
Sub DetectBorder (src As Long, targetColor As Integer, bx() As Integer, by() As Integer, bcnt As Long)

    Dim dx(7) As Integer, dy(7) As Integer
    dx(0) = 1: dy(0) = 0 ' East
    dx(1) = 1: dy(1) = 1 ' SE
    dx(2) = 0: dy(2) = 1 ' South
    dx(3) = -1: dy(3) = 1 ' SW
    dx(4) = -1: dy(4) = 0 ' West
    dx(5) = -1: dy(5) = -1 ' NW
    dx(6) = 0: dy(6) = -1 ' North
    dx(7) = 1: dy(7) = -1 ' NE

    W = _Width(src)
    H = _Height(src)

    ' create memory image for fast pixel reads
    Dim imgMem As _MEM
    imgMem = _MemImage(src)

    ' 1) find first boundary pixel
    found = 0
    For yy = 0 To H - 1
        For xx = 0 To W - 1
            If GetPix(imgMem, xx, yy, W) = targetColor Then
                If IsBoundary(xx, yy, targetColor, imgMem, W, H, dx(), dy()) Then
                    sx = xx: sy = yy
                    found = -1
                    Exit For
                End If
            End If
        Next
        If found Then Exit For
    Next

    If found = 0 Then
        bcnt = -1
        Exit Sub
    End If

    ' 2) preallocate storage and prevent overflow
    maxPts = W * H
    ReDim bx(maxPts - 1) As Integer
    ReDim by(maxPts - 1) As Integer

    ' 3) initialize tracker
    x = sx: y = sy
    prevX = sx - 1: prevY = sy
    startPrevX = prevX: startPrevY = prevY

    idx = 0

    Do
        If idx >= maxPts Then Exit Do

        bx(idx) = x
        by(idx) = y
        idx = idx + 1

        ' find direction to previous pixel
        dirPrev = -1
        For d = 0 To 7
            If x + dx(d) = prevX And y + dy(d) = prevY Then
                dirPrev = d
                Exit For
            End If
        Next
        If dirPrev = -1 Then dirPrev = 4

        ' search next boundary neighbor (clockwise from dirPrev+1)
        foundNext = 0
        For k = 1 To 8
            i = (dirPrev + k) Mod 8
            nx = x + dx(i)
            ny = y + dy(i)

            If nx >= 0 And nx < W And ny >= 0 And ny < H Then
                If IsBoundary(nx, ny, targetColor, imgMem, W, H, dx(), dy()) Then
                    prevX = x: prevY = y
                    x = nx: y = ny
                    foundNext = -1
                    Exit For
                End If
            End If
        Next

        If foundNext = 0 Then Exit Do

    Loop Until (x = sx And y = sy)

    If idx = 0 Then
        bcnt = -1
    Else
        bcnt = idx - 1
        ' shrink arrays to actual size
        ReDim _Preserve bx(bcnt) As Integer
        ReDim _Preserve by(bcnt) As Integer
    End If

End Sub


' ---------------------------------------------
' Fast filled circle  - SMcNeill gold standard
' (left as-is because it draws into screen)
' ---------------------------------------------
Sub CircleFill (CX As Long, CY As Long, R As Long, C As Long)
    Dim Radius As Long, RadiusError As Long
    Dim X As Long, Y As Long

    Radius = Abs(R)
    RadiusError = -Radius
    X = Radius
    Y = 0

    If Radius = 0 Then PSet (CX, CY), C: Exit Sub

    Line (CX - X, CY)-(CX + X, CY), C, BF

    While X > Y
        RadiusError = RadiusError + Y * 2 + 1
        If RadiusError >= 0 Then
            If X <> Y + 1 Then
                Line (CX - Y, CY - X)-(CX + Y, CY - X), C, BF
                Line (CX - Y, CY + X)-(CX + Y, CY + X), C, BF
            End If
            X = X - 1
            RadiusError = RadiusError - X * 2
        End If
        Y = Y + 1
        Line (CX - X, CY - Y)-(CX + X, CY - Y), C, BF
        Line (CX - X, CY + Y)-(CX + X, CY + Y), C, BF
    Wend
End Sub


Reply


Messages In This Thread
Border detect - by Petr - 11-13-2025, 03:45 PM
RE: Border detect - by Petr - 11-13-2025, 07:46 PM
RE: Border detect - by Petr - 11-13-2025, 09:17 PM
RE: Border detect - by Dav - 11-13-2025, 10:06 PM
RE: Border detect - by Petr - 11-13-2025, 10:24 PM
RE: Border detect - by Petr - 11-14-2025, 08:02 PM
RE: Border detect - by bplus - 11-14-2025, 08:55 PM
RE: Border detect - by NakedApe - 11-14-2025, 11:05 PM

Possibly Related Threads…
Thread Author Replies Views Last Post
  Detect point in triangle (2D) Petr 2 874 11-20-2024, 07:31 PM
Last Post: Petr

Forum Jump:


Users browsing this thread: 1 Guest(s)