1

I'm trying to make a hysteresis thresholding in visual basic for canny edge detection. As I'm new into this topic and new to vb (I mainly use php), many of the references I read,point out that I need to do this. Since the image is already on black and white, I only get 1 color for the intensities. I already did the gaussian blur, grayscale, sobel mask, and non maxima supression in only seconds. but on hysteresis, the time to execute the function is taking too long. I don't know where I did wrong. The image is on 640 x 480 if that helps. I try to change the resolution to smaller one, it's indeed faster but I want to keep the resolution to 640 x 480. I already change the code, and this is my final approach

  Dim bmp_thres As New Bitmap(pic_nonmaxima)


    Dim visited_maps As New List(Of String)

    Dim threshold_H As Integer = 100
    Dim threshold_L As Integer = 50
    Dim Ycount As Integer
    For Ycount = 1 To bmp_thres.Height - 2
        Dim Xcount As Integer
        For Xcount = 1 To bmp_thres.Width - 2


            'check current pointer 
            Dim currPointer As String = Xcount & "," & Ycount
            'find if coordinate visited already
            Dim find_array As String
            If visited_maps IsNot Nothing Then
                find_array = visited_maps.Contains(currPointer)
            Else
                find_array = "False"
            End If

            If find_array Then
                'if existed, do nothing
            Else
                'if not, do something
                Dim currThreshold As Integer
                Dim currColor As Color
                currColor = bmp_thres.GetPixel(Xcount, Ycount)
                currThreshold = currColor.R


                'add coordinate into visited maps
                Dim visited As String = Xcount & "" & Ycount
                visited_maps.Add(visited)

                If currThreshold > threshold_H Then
                    bmp_thres.SetPixel(Xcount, Ycount, Color.FromArgb(255, 255, 255))
                Else
                    bmp_thres.SetPixel(Xcount, Ycount, Color.FromArgb(0, 0, 0))
                    'check connectedness

                    Dim coord_N As String = Xcount & "," & Ycount + 1
                    Dim coord_E As String = Xcount + 1 & "," & Ycount
                    Dim coord_S As String = Xcount & "," & Ycount - 1
                    Dim coord_W As String = Xcount - 1 & "," & Ycount

                    Dim coord_NE As String = Xcount + 1 & "," & Ycount + 1
                    Dim coord_SE As String = Xcount + 1 & "," & Ycount - 1
                    Dim coord_SW As String = Xcount - 1 & "," & Ycount - 1
                    Dim coord_NW As String = Xcount - 1 & "," & Ycount + 1

                    Dim myCoord As New List(Of String)

                    myCoord.Add(coord_N)
                    myCoord.Add(coord_E)
                    myCoord.Add(coord_S)
                    myCoord.Add(coord_W)

                    myCoord.Add(coord_NE)
                    myCoord.Add(coord_SE)
                    myCoord.Add(coord_SW)
                    myCoord.Add(coord_NW)


                    For Each coord In myCoord
                        If Not visited_maps.Contains(coord) Then
                            'Split by ,
                            Dim split_Coord() As String = Split(coord, ",")
                            'check thres on coord
                            Dim coordColor As Color = bmp_thres.GetPixel(split_Coord(0), split_Coord(1))
                            Dim coordThres As Integer = coordColor.R

                            If coordThres > threshold_H Then
                                bmp_thres.SetPixel(split_Coord(0), split_Coord(1), Color.FromArgb(255, 255, 255))
                            Else
                                bmp_thres.SetPixel(split_Coord(0), split_Coord(1), Color.FromArgb(0, 0, 0))
                            End If

                        End If

                        visited_maps.Add(coord)
                    Next 'end if foreach

                End If ' end if checking current threshold
            End If 'end if find coord in visited maps

        Next 'end for xcount
    Next 'end for ycount

    Return bmp_thres

Or if you spot some wrong codes I did, please point out to me.

If I get it right, when we do hysteresis thresholding, we first check the coordinate if it's visited already, if it's visited we check the next coordinate. if it's not, we add the coordinate into the visited maps and if the current coordinate is larger than the threshold high, we change the pixel value into white else black. then we check the connectedness, if they pass the threshold low, we change the pixel value into white else black. then we add all the connectedness into visited maps. repeat.

What can I do to reduce the time ? or please point out my mistake. any help will be appreciated. sorry for the english if you didnt understand. this will help my final year project T_T

annonim
  • 15
  • 5

1 Answers1

0

I think this could be on topic at Code Review as it is working (albeit slowly). But just in case it isn't, I'm leaving this here as a partial answer.

You have a slight bug in your coordinate search. Regardless of whether it is already in visited_maps or not you still add it in, which will be a lot of extra results in the list.

If Not visited_maps.Contains(coord) Then
    ' YOUR CODE
End If

visited_maps.Add(coord)

This line: visited_maps.Add(coord) needs to be inside the If so you don't have repeat values expanding your list further than it needs to. A 640 * 480 px image will create over 300 000 entries into your list, and with this coordinate bug it will have even more.


List is probably also not the most appropriate type, something like a HashSet is better because you don't need to access by index. Have a look at What is the difference between HashSet and List?


When you call Color.FromArgb(255, 255, 255) you are creating a new Color object every time. That's going to be at least 300 000 objects again, when you could declare one instance for black and another for white at the top and then use those as needed.


I'm not sure what the performance difference of using the Point structure over a comma-separated string would be, but it would save a lot of splitting/concatenation and be much nicer to read.

Dim currPointer As String = Xcount & "," & Ycount

Dim coord_N As String = Xcount & "," & Ycount + 1

Would become

Dim currPointer As Point = New Point(Xcount, Ycount)

Dim coord_N as Point = New Point(currPointer.X, currPointer.Y + 1)


There are still more things wrong but they are fairly minor so I'll leave them off for now

A Friend
  • 2,750
  • 2
  • 14
  • 23
  • thanks, I moved the visited_maps inside the if block and create the instance for black and white. while at it, I spotted some typos and fix them too. Is point structure the same as adding commas in string and split it ? like calling it split_coord(0) or split_coord(1) ? will look into the hashset after this. the time is reduced thanks to your help, but I think it's too long because the other only took secs, while this takes almost 4 mins. is it normal ? – annonim May 31 '17 at 14:37
  • `split_coord(0)` would become `coord.X`, and 1 -> Y – A Friend May 31 '17 at 14:39
  • thanks, I figure it out. and the hashset and point structure are working flawlessly. now it's taking only 38 secs to do all of it. from gaussian to hysteresis . you saved me from headache :) – annonim May 31 '17 at 15:00