Ask Your Question
0

Detect markers position in 2D images

asked Apr 22 '15

xDarkLink gravatar image

Hi there, I am trying to detect the position of multiple markers in a single 2D image.

For example in the following image:

image description

I need to detect the position of the four markers.

I already manage to do this tutorial in java http://docs.opencv.org/doc/tutorials/...

But it only finds out one match, how do I change it to found more matches?

Is it possible to put it inside a loop and keep finding matches till a minValue is not reached?

Thank you so much in advance, I am new to OpenCV =/

Preview: (hide)

3 answers

Sort by » oldest newest most voted
2

answered Apr 22 '15

theodore gravatar image

updated Apr 23 '15

Another approach would be to use the SimpleBlobDetector() class, and playing with the parameters extract (have a look here for a nice explanation of the parameters) the desired result, plus that it can be implemented with much less code and personally I find it a bit neater as an approach. Have a look in the example bellow:

#include <iostream>
#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;

int main()
{
    Mat src = imread("markers.png");

    // resizing for practical reasons
    Mat rsz;
    Size size(800, 900);
    resize(src, rsz, size);

    imshow("rsz", rsz);

    vector<KeyPoint> keypoints;
    // Change parameters
    SimpleBlobDetector::Params params;

    // Specify how close you want to be to a square, if you check  
    // the link you can make this work for other shapes as well
    params.filterByCircularity = true;
    params.maxCircularity = .85;
    params.minCircularity = .785;

    Ptr<FeatureDetector> blobsDetector = SimpleBlobDetector::create(params);
    blobsDetector->detect(rsz, keypoints);

    Mat drawImage = rsz.clone();
    for (size_t i = 0; i < keypoints.size(); ++i)
        circle(drawImage, keypoints[i].pt, 16, Scalar(0, 0, 255), 2);
//    imwrite("result.png", drawImage);
    imshow("result", drawImage);

    waitKey(0);
    return 0;
}

image description

Preview: (hide)

Comments

of course unfortunately this approach will not work with custom markers like in the case that @Eduardo shows in his example

theodore gravatar imagetheodore (Apr 22 '15)edit

I need the points of each square in the image to do some further calculations, so in your example the points are in keypoints[i].pt right ? The KeyPoint is a class with an X and Y coord ? Thank you so much for your help, I have the code in java and since I am new to OpenCV is kinda hard to translate it, but I will give it a try, here is my code in java at the moment: http://pastebin.com/qsS9sqz3

Thank you anyways for your help ;)

xDarkLink gravatar imagexDarkLink (Apr 23 '15)edit
1

@xDarkLink yes the center point of each square/box corresponds to keypoints[i].pt. If you want to obtain the x and y values just call keypoints[i].pt.x and keypoints[i].pt.y respectively.

theodore gravatar imagetheodore (Apr 23 '15)edit

The class SimpleBlobDetector doesn't exist in java library of OpenCV am I right ? =s

xDarkLink gravatar imagexDarkLink (Apr 24 '15)edit

@xDarkLink unfortunately I do not know to answer this. I have not work with the java wrapper at all.

theodore gravatar imagetheodore (Apr 24 '15)edit
1

answered Apr 22 '15

You could find the maximum, set the area around this position to zero and iterate.

Preview: (hide)

Comments

Can you explain better please? I didn't understood

xDarkLink gravatar imagexDarkLink (Apr 27 '15)edit
1

answered Apr 22 '15

Eduardo gravatar image

As already answered by FooBar, yes you can do it.

Just an example code here.

The image to find the templates:

Query image

The template image.

#include <iostream>

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


//See: http://docs.opencv.org/doc/tutorials/imgproc/histograms/template_matching/template_matching.html
//See: http://answers.opencv.org/question/60382/detect-markers-position-in-2d-images/
int main() {
  cv::Mat img, templateImg, result;
  cv::VideoCapture capture("http://answers.opencv.org/upfiles/14297307634571599.png");
  if(capture.isOpened()) {
    capture >> img;
  } else {
    return -1;
  }

  capture = cv::VideoCapture("http://answers.opencv.org/upfiles/14297308125543022.png");
  if(capture.isOpened()) {
    capture >> templateImg;
  } else {
    return -1;
  }

  /// Reduce the size of the image to display it on my screen
  cv::resize(img, img, cv::Size(), 0.5, 0.5);
  /// Reduce the size of the template image
  /// (first to fit the size used to create the image test, second to fit the size of the reduced image)
  cv::resize(templateImg, templateImg, cv::Size(), 0.25, 0.25);

  cv::Mat img_display;
  img.copyTo(img_display);

  // Create the result matrix
  int result_cols =  img.cols - templateImg.cols + 1;
  int result_rows = img.rows - templateImg.rows + 1;

  result.create(result_rows, result_cols, CV_32FC1);

  /// Do the Matching and Normalize
  cv::matchTemplate(img, templateImg, result, CV_TM_CCORR_NORMED);
  cv::normalize(result, result, 0, 1, cv::NORM_MINMAX, -1, cv::Mat());

  /// Localizing the best match with minMaxLoc
  double minVal; double maxVal; cv::Point minLoc; cv::Point maxLoc;
  cv::Point matchLoc;

  for(;;) {
    cv::minMaxLoc(result, &minVal, &maxVal, &minLoc, &maxLoc, cv::Mat());
    matchLoc = maxLoc;
    std::cout << "Max correlation=" << maxVal << std::endl;
    if(maxVal < 0.8) {
      break;
    }

    /// Show me what you got
    cv::rectangle(img_display, matchLoc, cv::Point(matchLoc.x + templateImg.cols , matchLoc.y + templateImg.rows),
        cv::Scalar::all(0), 2, 8, 0);
    cv::rectangle(result, cv::Point(matchLoc.x - templateImg.cols/2 , matchLoc.y - templateImg.rows/2),
        cv::Point(matchLoc.x + templateImg.cols/2 , matchLoc.y + templateImg.rows/2 ), cv::Scalar::all(0), 2, 8, 0);

    cv::imshow("result", result);
    cv::waitKey(0);

    /// Fill the detected location with a rectangle of zero
    cv::rectangle(result, cv::Point( matchLoc.x - templateImg.cols/2 , matchLoc.y - templateImg.rows/2),
        cv::Point(matchLoc.x + templateImg.cols/2 , matchLoc.y + templateImg.rows/2 ), cv::Scalar::all(0), -1);
  } while (maxVal > 0.9);


  cv::imshow("result", result);
  cv::imshow("img_display", img_display);
  cv::waitKey(0);

  return 0;
}
Preview: (hide)

Comments

The matchLoc.x and matchLoc.y is the coordinates of each square right? Thank you . I am trying to translate into java and its kinda hard. Here is my code at the moment, only detects one marker:

http://pastebin.com/qsS9sqz3

xDarkLink gravatar imagexDarkLink (Apr 23 '15)edit

I tryed converting what you have to java, this was the result:

http://pastebin.com/sFWBvjzs

but the loop doesn't end, do you know what is the problem? Thank you very much in advance!

xDarkLink gravatar imagexDarkLink (Apr 24 '15)edit

Are you sure that the for loop is not an infinite loop? I am trying to convert it to java code and is not working, here it is my sample in java resulting in a infinite loop: http://pastebin.com/sdzU0iAh

xDarkLink gravatar imagexDarkLink (Apr 27 '15)edit

Question Tools

1 follower

Stats

Asked: Apr 22 '15

Seen: 5,588 times

Last updated: Jan 05 '18