Ask Your Question

Revision history [back]

Actually I think that there is a smarter way of retrieving the points on a given circle using the ellipse2Poly functionality. Then it is basically looping through all points in the resulting point vector and matching them with edge pixel locations that have white values.

Point circle_center (x,y);
Size axes (1,1); // If you want a circle of diameter 2 like shown in your code
vector<Point>& points_on_circle;
ellipse2Poly(circle_center, axes, 0, 0, 360, 1, points_on_circle);

This will result in 360 points that can be matched.

Actually I think that there is a smarter way of retrieving the points on a given circle using the ellipse2Poly functionality. Then it is basically looping through all points in the resulting point vector and matching them with edge pixel locations that have white values.

Point circle_center (x,y);
Size axes (1,1); (10,10); // If you want a circle of Ellipse axis dimensions, divided by 2, here the diameter 2 like shown in your code
will be 20 pixels
vector<Point>& points_on_circle;
ellipse2Poly(circle_center, axes, 0, 0, 360, 1, points_on_circle);

This will result in 360 points that can be matched.

Actually I think that there is a smarter way of retrieving the points on a given circle using the ellipse2Poly functionality. Then it is basically looping through all points in the resulting point vector and matching them with edge pixel locations that have white values.

Point circle_center (x,y);
Size axes (10,10); // Ellipse axis dimensions, divided by 2, here the diameter will be 20 pixels
vector<Point>& points_on_circle;
ellipse2Poly(circle_center, axes, 0, 0, 360, 1, points_on_circle);

This will result in 360 points that can be matched.

ADDITION 1:

Can you try this for matching the points in edges and i_points?

for(int i = 0; i < i_points.size(); i++){
    Point current_point = i_points[i];
    if ( edges.at<uchar>(i_points[i].x, i_points[i].y) == 1 ){
         circle( original, i_point, 1, CV_RGB( 255, 0, 0 ), -1); // filled circle at the position
    }
}

Actually I think that there is a smarter way of retrieving the points on a given circle using the ellipse2Poly functionality. Then it is basically looping through all points in the resulting point vector and matching them with edge pixel locations that have white values.

Point circle_center (x,y);
Size axes (10,10); // Ellipse axis dimensions, divided by 2, here the diameter will be 20 pixels
vector<Point>& points_on_circle;
ellipse2Poly(circle_center, axes, 0, 0, 360, 1, points_on_circle);

This will result in 360 points that can be matched.

ADDITION 1:

Can you try this for matching the points in edges and i_points?

for(int i = 0; i < i_points.size(); i++){
    Point current_point = i_points[i];
    if ( edges.at<uchar>(i_points[i].x, i_points[i].y) == 1 ){
         circle( original, i_point, 1, CV_RGB( 255, 0, 0 ), -1); // filled circle at the position
    }
}

SOLUTION

After some digging, i found a solution for this. Single circle, focussed around the center of the image for now, looks for intersecting points with the points on the circle and visualises them.

An image to prove that this works (ignore the red dots in the original, had to grab your visualisation for tryout):

image description

And the code used for this.

#include <iostream>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

#define I_CIRCLE_RADIUS 100
#define CANNY_THRESHOLD 70

using namespace std;
using namespace cv;

int main()
{
    namedWindow( "Original", CV_WINDOW_AUTOSIZE );
    namedWindow( "Binary", CV_WINDOW_AUTOSIZE );
    moveWindow( "Binary", 570, 100 );
    moveWindow( "Original", 0, 100 );

    // Read image
    Mat original = imread( "c:/data/test.png" );

    // Define circle center
    // put the circle center at the center of image for test purposes
    // Scalar is the way to go CV_RGB is old format, openCV uses Scalar on BGR now
    Point circle_center( original.cols/2, original.rows/2 ); 

    // Calculate all points on that circle
    // Axes are half of the ellipse axes, a circle is a perfect ellipse, with radius = 2x half of the axes :)
    Size axes( I_CIRCLE_RADIUS, I_CIRCLE_RADIUS );
    vector<Point> circle_points;
    ellipse2Poly( circle_center, axes, 0, 0, 360, 1, circle_points );

    //Make a grayscale copy
    Mat gray( original.size(), CV_8UC1 );
    cvtColor( original, gray, CV_BGR2GRAY );

    //Find edges in grayscale image
    Mat edges( original.size(), CV_8UC1 );
    Canny( gray, edges, CANNY_THRESHOLD, CANNY_THRESHOLD * 3, 3 );

    // Only draw extra info right before visualisation
    circle( original, circle_center, I_CIRCLE_RADIUS, Scalar( 255, 0, 0 ), 2);

    // Lets make a edge map on a 3 channel color image for output purposes
    Mat edges_color(edges.rows, edges.cols, CV_8UC3);
    Mat in[] = { edges, edges, edges };
    int from_to[] = { 0,0, 1,1, 2,2 };
    mixChannels( in, 3, &edges_color, 1, from_to, 3 );

    //Iterate pixels in circle
    for(int i = 0; i < circle_points.size(); i++){
        Point current_point = circle_points[i];
        int value_at_that_location_in_edge_map = edges.at<uchar>(circle_points[i].y, circle_points[i].x);
        cout << value_at_that_location_in_edge_map << " ";
        if ( value_at_that_location_in_edge_map == 255 ){
                circle( edges_color, circle_points[i], 2, Scalar( 0, 0, 255 ), -1); // filled circle at the position
        }
    }

    // Always add a waitKey(5) after an imshow so that the onpaint inner method can get executed without problems
    imshow( "Binary", edges_color ); waitKey(5);
    imshow( "Original", original ); waitKey(5);

    // Wait forever on a hit to close application
    waitKey(0);

    return 0;
}

Feel free to accept as correct answer if this completely solves your problem. The main problem was indeed the row/col mixup I made before.

Actually I think that there is a smarter way of retrieving the points on a given circle using the ellipse2Poly functionality. Then it is basically looping through all points in the resulting point vector and matching them with edge pixel locations that have white values.

Point circle_center (x,y);
Size axes (10,10); // Ellipse axis dimensions, divided by 2, here the diameter will be 20 pixels
vector<Point>& points_on_circle;
ellipse2Poly(circle_center, axes, 0, 0, 360, 1, points_on_circle);

This will result in 360 points that can be matched.

ADDITION 1:

Can you try this for matching the points in edges and i_points?

for(int i = 0; i < i_points.size(); i++){
    Point current_point = i_points[i];
    if ( edges.at<uchar>(i_points[i].x, i_points[i].y) == 1 ){
         circle( original, i_point, 1, CV_RGB( 255, 0, 0 ), -1); // filled circle at the position
    }
}

SOLUTION

After some digging, i found a solution for this. Single circle, focussed around the center of the image for now, looks for intersecting points with the points on the circle and visualises them.

An image to prove that this works (ignore the red dots in the original, had to grab your visualisation for tryout):

image description

And the code used for this.

#include <iostream>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

#define I_CIRCLE_RADIUS 100
#define CANNY_THRESHOLD 70

using namespace std;
using namespace cv;

int main()
{
    namedWindow( "Original", CV_WINDOW_AUTOSIZE );
    namedWindow( "Binary", CV_WINDOW_AUTOSIZE );
    moveWindow( "Binary", 570, 100 );
    moveWindow( "Original", 0, 100 );

    // Read image
    Mat original = imread( "c:/data/test.png" );

    // Define circle center
    // put the circle center at the center of image for test purposes
    // Scalar is the way to go CV_RGB is old format, openCV uses Scalar on BGR now
    Point circle_center( original.cols/2, original.rows/2 ); 

    // Calculate all points on that circle
    // Axes are half of the ellipse axes, a circle is a perfect ellipse, with radius = 2x half of the axes :)
    Size axes( I_CIRCLE_RADIUS, I_CIRCLE_RADIUS );
    vector<Point> circle_points;
    ellipse2Poly( circle_center, axes, 0, 0, 360, 1, circle_points );

    //Make a grayscale copy
    Mat gray( original.size(), CV_8UC1 );
    cvtColor( original, gray, CV_BGR2GRAY );

    //Find edges in grayscale image
    Mat edges( original.size(), CV_8UC1 );
    Canny( gray, edges, CANNY_THRESHOLD, CANNY_THRESHOLD * 3, 3 );

    // Only draw extra info right before visualisation
    circle( original, circle_center, I_CIRCLE_RADIUS, Scalar( 255, 0, 0 ), 2);

    // Lets make a edge map on a 3 channel color image for output purposes
    Mat edges_color(edges.rows, edges.cols, CV_8UC3);
    Mat in[] = { edges, edges, edges };
    int from_to[] = { 0,0, 1,1, 2,2 };
    mixChannels( in, 3, &edges_color, 1, from_to, 3 );

    //Iterate pixels in circle
    for(int i = 0; i < circle_points.size(); i++){
        Point current_point = circle_points[i];
        int value_at_that_location_in_edge_map = edges.at<uchar>(circle_points[i].y, circle_points[i].x);
        cout << value_at_that_location_in_edge_map << " ";
        if ( value_at_that_location_in_edge_map == 255 ){
                circle( edges_color, circle_points[i], 2, Scalar( 0, 0, 255 ), -1); // filled circle at the position
        }
    }

    // Always add a waitKey(5) after an imshow so that the onpaint inner method can get executed without problems
    imshow( "Binary", edges_color ); waitKey(5);
    imshow( "Original", original ); waitKey(5);

    // Wait forever on a hit to close application
    waitKey(0);

    return 0;
}

Feel free to accept as correct answer if this completely solves your problem. The main problem was indeed the row/col mixup I made before.

ADDITION 2 SOLUTION

What you could do to counter the problem of the missing intersections (due to them falling between your circle sampling points) is the following.

// Create a copy of the original image and litteraly paint the circle on top of it in blue
// Use a clone to perform an actual deep copy of all the data!
Mat backup_image = original.clone();
// Now draw the original blue circle on top of it
// Be sure in this case to only draw a 1 pixel line! This is important!
circle( backup_image, circle_center, I_CIRCLE_RADIUS, Scalar( 255, 0, 0 ), 1);
// Now loop over the edge map and check if for each white edge pixel, the corresponding pixel is blue in the backup image
for(int i=0; i<edges.rows; i++){
   for(int j=0; j<edges.cols; j++){
      // Check if the edge pixel is white AND that pixel in original image is blue
      bool white = false, blue = false;
      if( edges.at<uchar>(i,j) == 255 ){ white = true; }
      if( backup_image.at<uchar>(i,j) == Scalar(255, 0, 0) ){ blue = true; }
      // Now if both apply, draw your marker
      if( white && blue ){
           circle( edges_color, Point(i,j), 2, Scalar( 0, 0, 255 ), -1);
      }
   }
}