Ask Your Question
2

recognise colours in 3x3 grid

asked 2015-09-16 03:30:46 -0600

nadley gravatar image

updated 2020-11-06 19:34:09 -0600

Hi all,

I'm just starting, so this is a very high level question...

Is it possible to use OpenCV for recognising basic colours in a 3x3 grid? Imagine a rubik's cube, you take a picture of one of the sides and this picture is then either

  • compared to a set of pictures showing all possible combinations and one of them is matched
  • analyzed and the colours are directly identified, i.e. upper left corner is yellow, middle is red...

Do you think something like this is possible in OpenCV and if yes, can you give me first hints what to start with?

Thanks a lot!

edit retag flag offensive close merge delete

3 answers

Sort by ยป oldest newest most voted
8

answered 2015-09-16 13:56:42 -0600

updated 2016-11-29 01:40:33 -0600

there is some solutions on the net about "Solving Rubik's Cube" or "Locating Rubik's Cube" using OpenCV like this. Maybe you can find better code sample.But i want to share a simple code to show with just a simple OpenCV code you will get some result like

image descriptionimage descriptionimage descriptionimage description

the code is modified version of squares.cpp

#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"

using namespace cv;
using namespace std;

// helper function:
// finds a cosine of angle between vectors
// from pt0->pt1 and from pt0->pt2
static double angle( Point pt1, Point pt2, Point pt0 )
{
    double dx1 = pt1.x - pt0.x;
    double dy1 = pt1.y - pt0.y;
    double dx2 = pt2.x - pt0.x;
    double dy2 = pt2.y - pt0.y;
    return (dx1*dx2 + dy1*dy2)/sqrt((dx1*dx1 + dy1*dy1)*(dx2*dx2 + dy2*dy2) + 1e-10);
}

static void drawSquares( Mat& image, const vector<vector<Point> >& squares )
{
    for( size_t i = 0; i < squares.size(); i++ )
    {
        const Point* p = &squares[i][0];
        int n = (int)squares[i].size();
        int shift = 1;

        Rect r=boundingRect( Mat(squares[i]));
        r.x = r.x + r.width / 4;
        r.y = r.y + r.height / 4;
        r.width = r.width / 2;
        r.height = r.height / 2;

        Mat roi = image(r);
        Scalar color = mean(roi);
        polylines(image, &p, &n, 1, true, color, 2, LINE_AA, shift);

        Point center( r.x + r.width/2, r.y + r.height/2 );
        ellipse( image, center, Size( r.width/2, r.height/2), 0, 0, 360, color, 2, LINE_AA );
    }
}

// returns sequence of squares detected on the image.
// the sequence is stored in the specified memory storage
static void findSquares( const Mat& image, vector<vector<Point> >& squares , bool inv=false)
{
    squares.clear();

    Mat gray,gray0;

    vector<vector<Point> > contours;

    cvtColor(image,gray0,COLOR_BGR2GRAY);
    GaussianBlur(gray0, gray0, Size(7,7), 1.5, 1.5);
    Canny(gray0,gray, 0, 30, 3);

    // find contours and store them all as a list
    findContours(gray, contours, RETR_LIST, CHAIN_APPROX_SIMPLE);

    vector<Point> approx;

    // test each contour
    for( size_t i = 0; i < contours.size(); i++ )
    {
        // approximate contour with accuracy proportional
        // to the contour perimeter
        approxPolyDP(Mat(contours[i]), approx, 9, true);

        // square contours should have 4 vertices after approximation
        // relatively large area (to filter out noisy contours)
        // and be convex.
        // Note: absolute value of an area is used because
        // area may be positive or negative - in accordance with the
        // contour orientation
        if( approx.size() == 4 &&
                fabs(contourArea(Mat(approx))) > 5 &&
                isContourConvex(Mat(approx)) )
        {
            double maxCosine = 0;

            for( int j = 2; j < 5; j++ )
            {
                // find the maximum cosine of the angle between joint edges
                double cosine = fabs(angle(approx[j%4], approx[j-2], approx[j-1]));
                maxCosine = MAX(maxCosine, cosine);
            }

            // if cosines of all angles are small
            // (all angles are ~90 degree) then write quandrange
            // vertices to resultant sequence
            if( maxCosine < 0.3 )
                squares.push_back(approx);
        }
    }
}

int main()
{
    VideoCapture cap(0); // opens default webcam

    if (!cap.isOpened())
    {
        return -1;
    }

    Mat frame;
    vector<vector<Point> > squares;

    for (;;)
    {
        cap >> frame;

        if (frame.empty())
        {
            return -1;
        }
        findSquares(frame, squares);
        drawSquares(frame, squares);
        imshow("Rubic Detection Demo", frame);
        waitKey ...
(more)
edit flag offensive delete link more

Comments

DId you edit the code yourself or did you grab it from somewhere? If so please provide the original link to give that person the credit that he deserves :)

StevenPuttemans gravatar imageStevenPuttemans ( 2015-09-17 06:06:44 -0600 )edit
2

edited myself :)

sturkmen gravatar imagesturkmen ( 2015-09-17 06:41:25 -0600 )edit

How can i save the value of colors of each side in a text file? Like = Red Green Green Green Green Green Yellow Yellow Yellow

golam_rabbi gravatar imagegolam_rabbi ( 2017-11-09 23:14:20 -0600 )edit
2

answered 2015-09-16 03:38:03 -0600

Yes this is possible with OpenCV. You will have to look at

  1. Making sure that you compensate for camera deformation.
  2. Defining the area of the rubics cube itself, by trying to find its outer boundaries.
  3. Then taking the corner points to transform the image to a standard squared area.
  4. Now find the crossing points of the seperate elements, defining individual regions of interest.
  5. Start doing color analysis on each position.

If you're just starting OpenCV, start by going through the basic tutorials first, then this might be a very nice project to start of with!

edit flag offensive delete link more

Comments

1

Wow, that was a really quick answer! Thanks a lot for your hints - I'll give it a try, really sounds promising!

nadley gravatar imagenadley ( 2015-09-16 03:50:24 -0600 )edit

That is because I am a forum admin and I had to accept your answer. You were lucky I was just browsing the website :)

StevenPuttemans gravatar imageStevenPuttemans ( 2015-09-16 03:55:12 -0600 )edit
1

answered 2017-08-12 20:35:02 -0600

dwalton76 gravatar image

I've been working on a mindstorms robot that takes pics of a rubiks cube via webcam and then solves it. For the question you ask, I broke it down into two problems: - find the cube in an image..openCV is awesome for this - take the RGB values for all of the squares you found and reduce each of those to one of the 6 colors of the cube. There isn't much use for OpenCV on this part

The code for the first part is at https://github.com/dwalton76/rubiks-c... and the code for the second part is at https://github.com/dwalton76/rubiks-c...

I did a blog post on how rubiks-cube-tracker works http://programmablebrick.blogspot.com...

You can run it on your laptop and hold the cube up to the webcam to scan the six sides and get a solution https://www.youtube.com/watch?v=3tWnl...

This is all open source, feel free to use it and/or contribute to it.

edit flag offensive delete link more

Question Tools

1 follower

Stats

Asked: 2015-09-16 03:30:46 -0600

Seen: 7,458 times

Last updated: Nov 29 '16