Ask Your Question
0

Detect markers position in 2D images

asked 2015-04-22 11:52:30 -0600

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

edit retag flag offensive close merge delete

3 answers

Sort by ยป oldest newest most voted
2

answered 2015-04-22 17:11:09 -0600

theodore gravatar image

updated 2015-04-22 18:00:07 -0600

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

edit flag offensive delete link more

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 ( 2015-04-22 17:17:52 -0600 )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 ( 2015-04-23 11:00:14 -0600 )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 ( 2015-04-23 12:23:17 -0600 )edit

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

xDarkLink gravatar imagexDarkLink ( 2015-04-24 10:00:16 -0600 )edit

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

theodore gravatar imagetheodore ( 2015-04-24 13:43:42 -0600 )edit
1

answered 2015-04-22 14:34:03 -0600

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;
}
edit flag offensive delete link more

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 ( 2015-04-23 11:02:34 -0600 )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 ( 2015-04-24 10:26:40 -0600 )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 ( 2015-04-27 06:48:38 -0600 )edit
1

answered 2015-04-22 14:10:05 -0600

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

edit flag offensive delete link more

Comments

Can you explain better please? I didn't understood

xDarkLink gravatar imagexDarkLink ( 2015-04-27 06:49:08 -0600 )edit

Question Tools

1 follower

Stats

Asked: 2015-04-22 11:52:30 -0600

Seen: 5,440 times

Last updated: Jan 05 '18