1

I have an input image that looks like this:

input image

Notice that there are 6 boxes with black borders. I need to detect the location (upper-left hand corder) of each box. Normally I would use something like template matching but the contents (the colored area inside the black border) of each box is distinct.

Is there a version of template matching that can configured to ignore the inner area of each box? Is the an algorithm better suited to this situation?

Also note, that I have to deal with several different resolutions... thus the actual size of the boxes will be different from image to image. That said, the ratio (length to width) will always be the same.

Real-world example/input image per request:

input image

RobertJoseph
  • 7,968
  • 12
  • 68
  • 113
  • 1
    Can't you simply compute the bounding box of connected components? – Miki Dec 28 '15 at 15:07
  • @Miki I am new to object recognition. Would you be able to point me in the right direction regarding your suggested algorithm? – RobertJoseph Dec 28 '15 at 15:23
  • Do you program in C++? – Miki Dec 28 '15 at 15:24
  • @Miki I can if need be although Ruby is my preferred language. – RobertJoseph Dec 28 '15 at 15:26
  • Ruby? Then why the OpenCV tag? If it's ok for you I can show you how to do it in OpenCV C++... – Miki Dec 28 '15 at 15:28
  • I found a Ruby wrapper (gem) for OpenCV (but it looks like it is a bit out of date). I can write my own Ruby wrappers if necessary but I'm fine with writing in C++ too. Any help/guidance would be greatly appreciated! – RobertJoseph Dec 28 '15 at 15:30
  • 1
    Ok, I'll post an answer as a starting point, we can then improve it to meet your requirements – Miki Dec 28 '15 at 15:31
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/99138/discussion-between-robertjoseph-and-miki). – RobertJoseph Dec 28 '15 at 15:34
  • I updated the code and the images in my answer. Now it's _almost_ ok also for your real image... I'll wait for you to post it before updating my answer with code also for that image. – Miki Dec 28 '15 at 15:59
  • Typo in the code, please check new version. I can't test now, but now should be ok – Miki Dec 29 '15 at 00:40

1 Answers1

6

You can do this finding the bounding box of connected components.

To find connected components you can convert to grayscale, and keep all pixels with value 0, i.e. the black border of the rectangles.

enter image description here

Then you can find the contours of each connected component, and compute its bounding box. Here the red bounding boxes found:

enter image description here

Code:

#include <opencv2/opencv.hpp>
#include <vector>
using namespace cv;
using namespace std;

int main()
{
    // Load the image, as BGR
    Mat3b img = imread("path_to_image");

    // Convert to gray scale
    Mat1b gray;
    cvtColor(img, gray, COLOR_BGR2GRAY);

    // Get binary mask
    Mat1b binary = (gray == 0);

    // Find contours of connected components
    vector<vector<Point>> contours;
    findContours(binary.clone(), contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);

    // For each contour
    for (int i = 0; i < contours.size(); ++i)
    {
        // Get the bounding box
        Rect box = boundingRect(contours[i]);

        // Draw the box on the original image in red
        rectangle(img, box, Scalar(0, 0, 255), 5);
    }

    // Show result
    imshow("Result", img);
    waitKey();

    return 0;
}

From the image posted in chat, this code produces:

enter image description here

In general, this code will correctly detect the cards, as well as noise. You just need to remove noise according to some criteria. Among others: size or aspect ratio of boxes, colors inside boxes, some texture information.

Miki
  • 40,887
  • 13
  • 123
  • 202