Update: As suggested. I added my current code that detects all boundaries of each shape (not desired) with another problem that these boundary lines can be a few pixels wide and form inside and outside countour to be recognized
Let say I click on a point inside wanted3 shape/contour (see second image).
I would use C#.net OpenCV 2 and/or 3
One Note. The lines denoting shapes can be one or more pixel wide. I would like the recognized points to lay exactly in the middle of that line, so when I do another recognition of surrounding shape I will get an exact point for that shared line recognized in 2 contours
I want the closest contour recognized, that encompasses the pressed point with a mouse left click within it.
There can however be a larger encompassing contour (not shown here; think of it as a county encompassing cities/places), and I just want the closest one recognized.
Whan I press inside wanted2 shape I want South-East border to have exactly the same discoverer contour points as wanted3 no matter how thick the bordering line is (so some calculation of where the middle point is necessaryl
Thanks
Rad
Sub ProcessImageAndUpdateGUI(sender As Object, arg As EventArgs)
Try
If (rdoImageFile.Checked = True) Then 'if the image file radio button is chosen . . .
Try
imgOriginal = New Image(Of Bgr, Byte)(txtFile.Text) 'get original image from file name in text box
Catch ex As Exception
Return
End Try
ElseIf (rdoWebcam.Checked = True) Then 'else if the webcam radio button is chosen . . .
Try
imgOriginal = capWebcam.QueryFrame() 'get next frame from webcam
Catch ex As Exception
Return
End Try
Else
'should never get here
End If
If (imgOriginal Is Nothing) Then 'if imgOriginal is null
Return 'bail
End If
'perform image smoothing
imgSmoothed = imgOriginal.PyrDown().PyrUp() 'Gaussian pyramid decomposition
imgSmoothed._SmoothGaussian(3) 'Gaussian smooth, argument is size of filter window
If (ckFilterOnColor.Checked = True) Then 'if filter on color check box is checked, then filter on color
imgGrayColorFiltered = imgSmoothed.InRange(New Bgr(dblMinBlue, dblMinGreen, dblMinRed), New Bgr(dblMaxBlue, dblMaxGreen, dblMaxRed))
imgGrayColorFiltered = imgGrayColorFiltered.PyrDown().PyrUp() 'repeat smoothing process after InRange function call,
imgGrayColorFiltered._SmoothGaussian(3) 'seems to work out better this way
ElseIf (ckFilterOnColor.Checked = False) Then 'if filter on color is not checked,
imgGrayColorFiltered = imgSmoothed.Convert(Of Gray, Byte)() 'then convert to gray without filtering
End If
'Dim grayCannyThreshold As Gray = New Gray(160) 'first Canny threshold, used for both circle detection, and line / triangle / rectangle detection
'Dim grayCannyThreshold As Gray = New Gray(200) 'first Canny threshold, used for both circle detection, and line / triangle / rectangle detection
Dim grayCannyThreshold As Gray = New Gray(240) 'first Canny threshold, used for both circle detection, and line / triangle / rectangle detection
Dim grayCircleAccumThreshold As Gray = New Gray(100) 'second Canny threshold for circle detection, higher number = more selective
Dim grayThreshLinking As Gray = New Gray(80) 'second Canny threshold for line / triangle / rectangle detection
'imgCanny = imgGrayColorFiltered.Canny(grayCannyThreshold, grayThreshLinking) 'Canny image used for line, triangle, rectangle, and polygon detection
imgCanny = imgGrayColorFiltered.ThresholdBinary(grayCannyThreshold, New Gray(255))
imgCircles = imgOriginal.CopyBlank() 'create blank image, use for circles later
imgLines = imgOriginal.CopyBlank() 'create blank image, use for lines later
imgTrisRectsPolys = imgOriginal.CopyBlank() 'create blank image, use for triangles and rectangles later
'HoughCircles arguments
Dim dblAccumRes As Double = 2.0 'resulution of the accumulator used to detect centers of circles
Dim dblMinDistBetweenCircles As Double = imgGrayColorFiltered.Height / 4 'min distance between centers of detected circles
Dim intMinRadius As Integer = 10 'min radius of circles to search for
Dim intMaxRadius As Integer = 400 'max radius of circles to search for
'find circles
Dim circles As CircleF() = imgGrayColorFiltered.HoughCircles(grayCannyThreshold, grayCircleAccumThreshold, dblAccumRes, dblMinDistBetweenCircles, intMinRadius, intMaxRadius)(0)
For Each circle As CircleF In circles
imgCircles.Draw(circle, New Bgr(Color.Red), 2) 'draw circles on circles image
If (ckDrawCirclesOnOriginalImage.Checked = True) Then 'if check box is checked
imgOriginal.Draw(circle, New Bgr(Color.Red), 2) 'then also draw circles on original image
End If
Next
'HoughLinesBinary arguments
Dim dblRhoRes As Double = 1.0 'distance resolution in pixels
Dim dblThetaRes As Double = 4.0 * (Math.PI / 180.0) 'angle resolution in radians (multiply by PI / 180 converts to radians)
Dim intThreshold As Integer = 20 'a line is returned by the function if the corresponding accumulator value is greater than threshold
Dim dblMinLineWidth As Double = 30.0 'minimum width of a line
Dim dblMinGapBetweenLines As Double = 10.0 'minimum gap between lines
'find lines
Dim lines() As LineSegment2D = imgCanny.HoughLinesBinary(dblRhoRes, dblThetaRes, intThreshold, dblMinLineWidth, dblMinGapBetweenLines)(0)
For Each line As LineSegment2D In lines
imgLines.Draw(line, New Bgr(Color.DarkGreen), 2) 'draw lines on lines image
If (ckDrawLinesOnOriginalImage.Checked = True) Then 'if check box is checked
imgOriginal.Draw(line, New Bgr(Color.DarkGreen), 2) 'then also draw lines on original image
End If
Next
Dim lstTriangles As List(Of Triangle2DF) = New List(Of Triangle2DF)() 'declare list of triangles
Dim lstRectangles As List(Of MCvBox2D) = New List(Of MCvBox2D)() 'declare list of "rectangles"
Dim lstPolygons As List(Of Contour(Of Point)) = New List(Of Contour(Of Point)) 'declare list of polygons
Dim i1 = 0 Mod 2 '0
Dim i2 = 1 Mod 2 '1
Dim i3 = 2 Mod 2 '0
Dim i4 = 3 Mod 2 '1
Dim i5 = 4 Mod 2 '0
'Dim contours As Contour(Of Point) = imgCanny.FindContours() 'find a sequence (similar to a linked list) of contours using the simple approximation method
Dim i = 0
Using storage As New MemStorage
Dim contours1 As Contour(Of Point) = imgCanny.FindContours(Emgu.CV.CvEnum.CHAIN_APPROX_METHOD.CV_CHAIN_APPROX_SIMPLE, Emgu.CV.CvEnum.RETR_TYPE.CV_RETR_TREE, storage)
Dim contours As Contour(Of Point) = imgCanny.FindContours()
While contours IsNot Nothing ' And CvInvoke.cvCheckContourConvexity(contours) = 0
Dim currentContour As Contour(Of Point) = contours.ApproxPoly(contours.Perimeter * 0.0015, storage) ' 0.0015 za Kragujevac1.jpg - 76 points
If currentContour.BoundingRectangle.Width > 20 Then
'CvInvoke.cvDrawContours(color, contours, New MCvScalar(255), New MCvScalar(255), -1, 2, Emgu.CV.CvEnum.LINE_TYPE.EIGHT_CONNECTED, New Point(0, 0))
'color.Draw(currentContour.BoundingRectangle, New Bgr(0, 255, 0), 1)
End If
'http://stackoverflow.com/questions/33715981/emgucv-findcontours-how-to-get-the-points-themselves
For Each point As Point In currentContour.ToArray()
'https://github.com/AnthonyNystrom/Pikling/blob/f58082b0be767994ea09e64613b83eea3e9b1497/Server/Emu-CV/Emgu.CV.SourceAndExample-1.5.0.1/src/Emgu.CV/Seq.cs
'if i Mod 2 = 1 then
imgCanny.Draw(New Rectangle(point.X, point.Y, 4, 4), New Gray(100), 0)
'end if
Next
i += 1
contours = contours.HNext
End While
End Using