Ask Your Question

Clicking on a point in an image finds the closest contour points

asked 2016-04-21 00:24:07 -0600

Rad gravatar image

updated 2020-10-28 02:40:10 -0600

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 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

image description

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.

image description

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)
        If (rdoImageFile.Checked = True) Then                                                                       'if the image file radio button is chosen . . .
                imgOriginal = New Image(Of Bgr, Byte)(txtFile.Text)                                     'get original image from file name in text box
            Catch ex As Exception
            End Try
        ElseIf (rdoWebcam.Checked = True) Then                                                                  'else if the webcam radio button is chosen . . .
                imgOriginal = capWebcam.QueryFrame()                                                                    'get next frame from webcam
            Catch ex As Exception
            End Try
            '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 ...
edit retag flag offensive close merge delete


  1. Since OpenCV has no official C# support, it is unlikely that someone here will help you with such language
  2. What's the question here? Have you even tried anything? You seem like expecting an out-of-the-box solution for a very particular problem. We're not here to code full programs for you. Read, code, try, and come back when you find concrete problems/errors/are stuck in a very particular step.
LorenaGdL gravatar imageLorenaGdL ( 2016-04-21 05:44:11 -0600 )edit

@LorenaGdL I tried something (still learning). I will post some code soon. I could find all the inside and outside contour points of all boundary lines. I don't want all of contours, only one the closest. Another problem is that I would like to reduce the thickness to only 1 pixel so both inside and outside boundaries should meet. If somebody helps me he/she can be paid for this.

Rad gravatar imageRad ( 2016-04-22 12:52:33 -0600 )edit

@LorenaGdL I added my current code. The language used is not important. I need some concrete steps.Tx.

Rad gravatar imageRad ( 2016-04-22 13:02:24 -0600 )edit

Have you solved your problem? Please accept the answer if you solved the problem!

Balaji R gravatar imageBalaji R ( 2016-04-27 11:26:59 -0600 )edit

I don't have c++ environment to check, but based on the logic and provide picture it is sufficient. I didn't see if you discovered contour points used to draw the contour and what parameter regulates the number of them. Let me know if I missed it. Tx.

Rad gravatar imageRad ( 2016-04-28 01:55:22 -0600 )edit

1 answer

Sort by ยป oldest newest most voted

answered 2016-04-23 03:15:31 -0600

Here is a very simple approach by comparing the contour and Point in the image. You can adapt this code in what ever language you want! Hope this helps you!

#include <iostream>
#include "opencv2/photo.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/ximgproc/edge_filter.hpp"

#include "opencv2/core.hpp"
#include <iostream>
#include <stdlib.h>

using namespace std;
using namespace cv;

Mat mInput;

static void onMouse( int event, int x, int y, int, void* )
    if( event != EVENT_LBUTTONDOWN )

    Point g_ptMousePoint = Point(x,y);
    Mat mGray,mThres,mThresPad,mResult;
    mResult= mInput.clone();

    RNG rng(12345);
    //Convert to Gray Scale

    //Threshold only darker part
    //imshow("mThres Wo Border",mThres);

    //Do you need to detect contours at borders? Then add a border
    bool detectOpenAreas=true;
        Rect rectImage(0,0,mInput.size().width,mInput.size().height);

    vector<vector<Point> > contours;
    vector<Vec4i> hierarchy;

    /// Find contours
    findContours( mThres.clone(), contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0) );

    for( size_t i = 0; i< contours.size(); i++ )
        //Filter out the Text contours
            Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) );                   
            drawContours( mResult, contours, (int)i, color, 1, 8, hierarchy, 0, Point() );                                      

    Mat mCMask(mInput.size(),CV_8UC1,Scalar(0)),mPtMask(mInput.size(),CV_8UC1,Scalar(0)),mResultMask(mInput.size(),CV_8UC1,Scalar(0));
    for( size_t i = 0; i< contours.size(); i++ )

        //Filter out the Text contours by Area & Make sure it does not have any child!
        //you add few more filter to this loop like distance from contour mass centre etc...
        if(contourArea(contours[i])> 100 && hierarchy[i][3] != -1 )
            //Check if Point line on the contour by creating a Mask

            drawContours( mCMask, contours, (int)i, Scalar(255), -1, 8, hierarchy, 0, Point() );                                        

            //Check for Non Zero Pixels if > 1 match found
                drawContours( mResult, contours, (int)i, Scalar(0,255,0), -1, 8, hierarchy, 0, Point() );

int main( int, char** )
    mInput= imread("input.jpg",1);


    setMouseCallback( "Result", onMouse, 0 );
    cout<<"Please Pick a point!";
        int c = waitKey(0);
        if( c == 27 )
            cout << "App Exit ...\n";
    return 0;

image description
image description image description

edit flag offensive delete link more


Great @Balaji R. I will check this solution and let you know if I can replicate this in

Rad gravatar imageRad ( 2016-04-24 14:55:38 -0600 )edit

Question Tools

1 follower


Asked: 2016-04-21 00:24:07 -0600

Seen: 3,959 times

Last updated: Apr 23 '16