Xtreme Visual Basic Talk

Xtreme Visual Basic Talk (http://www.xtremevbtalk.com/)
-   .NET Interface and Graphics (http://www.xtremevbtalk.com/-net-interface-and-graphics/)
-   -   Speed up Edge detection (http://www.xtremevbtalk.com/-net-interface-and-graphics/327312-speed-edge-detection.html)

Goggy 10-06-2014 03:26 AM

Speed up Edge detection
 
Hello,

I was playing around...
Turns out my code isn't all that fast.
For small images its more or less ok... .2 sec, but when the images become bigger lets say around 4000x4000 it takes around 40 seconds...

so the simple question beeing... does any one see or know of a methode to speed things up a little?


Code:

Imports System.Drawing
Imports EdgeDetection

Public Class EdgeDetection
       
        Private m_Original As Bitmap 
        Private m_Threshold As Double
       
        Private m_Detected As Bitmap
        Private m_Rectangle As Rectangle
        Private m_Data As Imaging.BitmapData
        Private m_Ptr As IntPtr
        Private m_ByteCount As Integer
    Private m_RGBValues() As Byte                  ' The RGB Values
    Private m_PixelMatrix(8) As Color          ' Array of pixels.
    Private m_Pixels() As Color


    Private Offset As Integer
    Private Index As Integer = 0
    Private Black() As Byte = {0, 0, 0}
    Private White() As Byte = {255, 255, 255}

    Public Sub New()
        Me.new(Nothing)
    End Sub
    Public Sub New(Img As Bitmap, Optional Threshold As Double = 0.001)
        Me.m_Original = Img
        Me.m_Threshold = Threshold
    End Sub

    Public Property Image As Bitmap
        Get
            Return Me.m_Original
        End Get
        Set(value As Bitmap)
            Me.m_Original = value

        End Set
    End Property
    Public ReadOnly Property Detected As Bitmap
        Get
            Detect()
            Return Me.m_Detected
        End Get
    End Property

    Private Sub Detect()
        Dim Start As Integer = System.Environment.TickCount

        m_Rectangle = New Rectangle(0, 0, Me.m_Original.Width, Me.m_Original.Height)
        m_Detected = m_Original.Clone(m_Rectangle, m_Original.PixelFormat)
        m_Data = m_Detected.LockBits(m_Rectangle, Imaging.ImageLockMode.ReadWrite, m_Detected.PixelFormat)
        ' Get the address of the first line.
        m_ByteCount = m_Data.Stride * m_Detected.Height
        '= not RGB But BGR
        ReDim m_RGBValues(m_ByteCount) '  - 1)
        ReDim m_Pixels(Convert.ToInt32(m_ByteCount / 3))
        ' Copy the RGB values into the array.
        System.Runtime.InteropServices.Marshal.Copy(m_Data.Scan0, m_RGBValues, 0, m_ByteCount)
        ' Todo: First transform to pixel array and then do the check. This way the 9 pixels aren't transformt every single time.
        Index = 0
        For I As Integer = 0 To m_ByteCount - 1 Step 3
            m_Pixels(Index) = Color.FromArgb(m_RGBValues(I + 2), m_RGBValues(I + 1), m_RGBValues(I))
            Index += 1
        Next
        ' Y
        ' |X----►
        ' |
        ' ▼
        Try
            For I As Integer = 1 To Me.m_Original.Height - 2
                For J As Integer = 1 To Me.m_Original.Width - 1
                    ' 0 0 0
                    ' 0 X 0
                    ' 0 0 0
                    Index = 0
                    For K As Integer = I - 1 To I + 1
                        For L As Integer = J - 1 To J + 1
                            m_PixelMatrix(Index) = m_Pixels((K * Me.m_Original.Width) + L)
                            Index += 1
                        Next
                    Next
                    Offset = (I * m_Data.Stride) + (J * 3)
                    If Brightest(m_PixelMatrix) - m_PixelMatrix(4).GetBrightness >= m_Threshold Then
                        System.Buffer.BlockCopy(Black, 0, m_RGBValues, Offset, 3)
                    Else
                        System.Buffer.BlockCopy(White, 0, m_RGBValues, Offset, 3)
                    End If
                Next
            Next
        Catch ex As Exception
            Debug.Print(ex.ToString)
        End Try
        ' Copy the RGB values back to the bitmap
        System.Runtime.InteropServices.Marshal.Copy(m_RGBValues, 0, m_Data.Scan0, m_ByteCount)
        ' Unlock the bits.
        m_Detected.UnlockBits(m_Data)

        Debug.Print(((System.Environment.TickCount - Start) / 1000).ToString)
    End Sub

    Private Function Brightest(Pixels As Color()) As Double
        Brightest = Pixels(0).GetBrightness
        For i As Integer = 1 To 8
            If Pixels(i).GetBrightness > Brightest Then
                Brightest = Pixels(i).GetBrightness
            End If
        Next
    End Function
End Class


dotnetwrassler 10-13-2014 05:09 PM

Parallel Processing?
 
1 Attachment(s)
Perhaps if you created a new class to spawn separate threads to process the image in parallel?

Goggy 10-16-2014 03:34 AM

Thank you for the hint, i will take a loop at your example and try to understand it. :-)

Oswald 04-24-2015 11:07 AM

- dont use expressions in for..next lines, calculate the value beforehand and put it into a var (otherwise these will be calculated on each run)
- dont use variants they are slow as hell, declare all variables
- this line calculates brightness twice. put brigtness into a var:

If Pixels(i).GetBrightness > Brightest Then
Brightest = Pixels(i).GetBrightness

- color.fromargb probably much slower, than you could do yourself, just AND's and bitshifts in the end!
- its a pointless convert anyway argb->rgb, you can extract the color just as good from argb.
- why blockcopy into rgbvalues, when its a perfectly usable array?

-Me.m_Original.Width this in the very inner loop should also be replaced to a local var. you force .net to dig trough objects a gazillion time to get that width value.

Goggy 06-26-2015 08:07 AM

Tweaked the code a little...
 
It now run's alot faster.

Code:

Imports System.Drawing
Imports EdgeDetection

Public Class EdgeDetection
       
        Private m_Original As Bitmap 
        Private m_Threshold As Double
       
        Private m_Detected As Bitmap
        Private m_Rectangle As Rectangle
        Private m_Data As Imaging.BitmapData
        Private m_Ptr As IntPtr
        Private m_ByteCount As Integer
    Private m_RGBValues() As Byte                  ' The RGB Values
    Private m_RGBOutput() As Byte                  ' The RGB Values
   
    Private Black() As Byte = {0, 0, 0}
    Private White() As Byte = {255, 255, 255}

    Public Sub New()
        Me.new(Nothing)
    End Sub
    Public Sub New(Img As Bitmap, Optional Threshold As Double = 0.1)
        Me.m_Original = Img
        Me.m_Threshold = Threshold
    End Sub

    Public Property Image As Bitmap
        Get
            Return Me.m_Original
        End Get
        Set(value As Bitmap)
            Me.m_Original = value

        End Set
    End Property
    Public ReadOnly Property Detected As Bitmap
        Get
            Detect()
            Return Me.m_Detected
        End Get
    End Property

    Private Sub Detect()
        Dim OriginalWidth As Integer = Me.m_Original.Width
        Dim PixelMatrix(26) As Byte
        Dim Start As Integer = System.Environment.TickCount
        Dim Offset As Integer = 0
        Dim StepSize As Integer = 3

        m_Rectangle = New Rectangle(0, 0, Me.m_Original.Width, Me.m_Original.Height)
        m_Detected = m_Original.Clone(m_Rectangle, m_Original.PixelFormat)

        m_Data = m_Detected.LockBits(m_Rectangle, Imaging.ImageLockMode.ReadWrite, m_Detected.PixelFormat)
        ' Get the address of the first line.
        m_ByteCount = m_Data.Stride * m_Detected.Height
        '= not RGB But BGR
        ReDim m_RGBValues(m_ByteCount)
        ReDim m_RGBOutput(m_ByteCount)
        ' Copy the RGB values into the array.
        System.Runtime.InteropServices.Marshal.Copy(m_Data.Scan0, m_RGBValues, 0, m_ByteCount)
        System.Runtime.InteropServices.Marshal.Copy(m_Data.Scan0, m_RGBOutput, 0, m_ByteCount)
        Select Case m_Detected.PixelFormat
            Case Imaging.PixelFormat.Format16bppArgb1555, Imaging.PixelFormat.Format16bppGrayScale, Imaging.PixelFormat.Format16bppRgb555
            Case Imaging.PixelFormat.Format32bppArgb, Imaging.PixelFormat.Format32bppPArgb, Imaging.PixelFormat.Format32bppRgb
                Offset = 1
                StepSize = 4
        End Select
        '
        For Row As Integer = 1 To m_Detected.Height - 2
            For Column As Integer = Offset To m_Data.Stride - 9 Step StepSize
                System.Buffer.BlockCopy(m_RGBValues, ((Row - 1) * m_Data.Stride) + Column, PixelMatrix, 0, 9)
                System.Buffer.BlockCopy(m_RGBValues, (Row * m_Data.Stride) + Column, PixelMatrix, 9, 9)
                System.Buffer.BlockCopy(m_RGBValues, ((Row + 1) * m_Data.Stride) + Column, PixelMatrix, 18, 9)
                If IsBrighterThenTreshold(PixelMatrix) Then
                    System.Buffer.BlockCopy(Black, 0, m_RGBOutput, (Row * m_Data.Stride) + Column + 3, 3)
                Else
                    System.Buffer.BlockCopy(White, 0, m_RGBOutput, (Row * m_Data.Stride) + Column + 3, 3)
                End If
            Next
        Next
        ' Copy the RGB values back to the bitmap
        System.Runtime.InteropServices.Marshal.Copy(m_RGBOutput, 0, m_Data.Scan0, m_ByteCount)
        ' Unlock the bits.
        m_Detected.UnlockBits(m_Data)

        Debug.Print(((System.Environment.TickCount - Start) / 1000).ToString)
    End Sub
   
    Private Function GetBrightness(R As Double, G As Double, B As Double) As Double
        ' Return (R + R + B + G + G + G) / 6
        Return (0.2126 * R + 0.7152 * G + 0.0722 * B)
        ' Return(.299 * R^2 + .587 * G^2 + .114 * B^2)
        ' Return (R * R * 0.241 + G * G * 0.691 + B * B * 0.068) ^ 0.5
    End Function

    Private Function IsBrighterThenTreshold(RGB() As Byte) As Boolean
        Dim Current As Double
        Dim Brightest As Double = GetBrightness(RGB(0), RGB(2), RGB(1))
        For I As Integer = 3 To 26 Step 3
            Current = GetBrightness(RGB(I), RGB(I + 2), RGB(I + 1))
            If Current > Brightest Then
                Brightest = Current
            End If
        Next
        Return (Brightest - GetBrightness(RGB(12), RGB(14), RGB(13)) >= m_Threshold)
    End Function
End Class



All times are GMT -6. The time now is 05:31 AM.

Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Search Engine Optimisation provided by DragonByte SEO v2.0.15 (Lite) - vBulletin Mods & Addons Copyright © 2017 DragonByte Technologies Ltd.
All site content is protected by the Digital Millenium Act of 1998. Copyright©2001-2011 MAS Media Inc. and Extreme Visual Basic Forum. All rights reserved.
You may not copy or reproduce any portion of this site without written consent.