Skip to content

Instantly share code, notes, and snippets.

@henvic
Created July 11, 2015 01:53
Show Gist options
  • Save henvic/2c78320dd509af384e39 to your computer and use it in GitHub Desktop.
Save henvic/2c78320dd509af384e39 to your computer and use it in GitHub Desktop.
Tic-tac-toe
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/core/core.hpp"
#include <math.h>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <vector>
using namespace cv;
using namespace std;
char MAIN_WINDOW[] = "tictactoe";
char board[9];
RNG rng(12345);
int iLowH = 0;
int iHighH = 179;
int iLowS = 0;
int iHighS = 255;
int iLowV = 0;
int iHighV = 255;
int iLastX = -1;
int iLastY = -1;
int selectedPosition = -1;
int piece = 'o';
void printBoard(Mat& frame, int width, int height) {
// 1 = firstLine + secondLine + (2 * thickness)
double firstLine = 0.33;
double secondLine = 0.66;
double thicknessLine = 0.005;
int thicknessWidth = thicknessLine * width;
int thicknessHeight = thicknessLine * height;
Point p0 = Point(firstLine * width, 0);
Point p1 = Point(firstLine * width, height);
Point p3 = Point(secondLine * width, 0);
Point p4 = Point(secondLine * width, height);
Point p5 = Point(0, firstLine * height);
Point p6 = Point(width, firstLine * height);
Point p7 = Point(0, secondLine * height);
Point p8 = Point(width, secondLine * height);
Scalar color = Scalar(10, 10, 10);
line(frame, p0, p1, color, thicknessWidth, CV_AA);
line(frame, p3, p4, color, thicknessWidth, CV_AA);
line(frame, p5, p6, color, thicknessHeight, CV_AA);
line(frame, p7, p8, color, thicknessHeight, CV_AA);
}
void printMeta(Mat& frame, double t) {
char text [100];
sprintf(text, "v - toggle view | space to play | c - clear board %fs", t);
putText(frame, text, Point(40, 40),
CV_FONT_HERSHEY_SIMPLEX,
1,
Scalar(255, 255, 255),
1,
1);
}
int getPosX(int x, Size board) {
return ((2 * x) + 1) * (board.width / 6);
}
int getPosY(int y, Size board) {
return ((2 * y) + 1) * (board.height / 6);
}
void printCircle(Mat& frame, int x, int y, Size boardSize) {
Point center = Point(getPosX(x, boardSize), getPosY(y, boardSize));
Scalar color = Scalar(0, 255, 200);
circle(frame, center, 50, color, CV_FILLED, CV_AA);
}
void printCross(Mat& frame, int x, int y, Size boardSize) {
int off = 50;
int thickness = 20;
int centerX = getPosX(x, boardSize);
int centerY = getPosY(y, boardSize);
Point topLeft = Point(centerX - off, centerY - off);
Point topRight = Point(centerX + off, centerY - off);
Point bottomLeft = Point(centerX - off, centerY + off);
Point bottomRight = Point(centerX + off, centerY + off);
Scalar color = Scalar(30, 55, 200);
line(frame, topLeft, bottomRight, color, thickness, CV_AA);
line(frame, topRight, bottomLeft, color, thickness, CV_AA);
}
void printPieces(Mat& frame, Size boardSize) {
for (int counter = 0; counter < 9; counter += 1) {
int x = counter % 3;
int y = counter / 3;
if (board[counter] == 'o') {
printCircle(frame, x, y, boardSize);
continue;
}
if (board[counter] == 'x') {
printCross(frame, x, y, boardSize);
}
}
}
void findPieces(Mat& frame, Mat& imgThresholded, Size boardSize) {
Mat frameHSV;
// based on http://opencv-srf.blogspot.com.br/2010/09/object-detection-using-color-seperation.html
cvtColor(frame, frameHSV, COLOR_BGR2HSV);
inRange(frameHSV, Scalar(iLowH, iLowS, iLowV), Scalar(iHighH, iHighS, iHighV), imgThresholded);
erode(imgThresholded, imgThresholded, getStructuringElement(MORPH_ELLIPSE, Size(5, 5)) );
dilate( imgThresholded, imgThresholded, getStructuringElement(MORPH_ELLIPSE, Size(5, 5)) );
dilate(imgThresholded, imgThresholded, getStructuringElement(MORPH_ELLIPSE, Size(5, 5)) );
erode(imgThresholded, imgThresholded, getStructuringElement(MORPH_ELLIPSE, Size(5, 5)) );
Moments oMoments = moments(imgThresholded);
double dM01 = oMoments.m01;
double dM10 = oMoments.m10;
double dArea = oMoments.m00;
if (dArea > 100000 && dArea < 100000000) {
int posX = dM10 / dArea;
int posY = dM01 / dArea;
if (iLastX >= 0 && iLastY >= 0 && posX >= 0 && posY >= 0)
{
line(frame, Point(posX, posY), Point(iLastX, iLastY), Scalar(0, 0, 255), 7, CV_AA);
line(imgThresholded, Point(posX, posY), Point(iLastX, iLastY), Scalar(0, 0, 0), 60, CV_AA);
}
iLastX = posX;
iLastY = posY;
// +1 deliberately added to avoid the edge case of division by zero
int quadX = (iLastX / (boardSize.width / 3));
int quadY = (iLastY / (boardSize.height / 3));
selectedPosition = (quadY * 3) + quadX;
// printf("(X, Y, pos) = (%d, %d, %d)\n", quadX, quadY, selectedPosition);
// printf("selected position = %d\n", selectedPosition);
} else {
selectedPosition = -1;
}
}
void clearPieces() {
for (int counter = 0; counter < 9; counter += 1) {
board[counter] = '\0';
}
}
void printWinner(Mat& frame, vector<int> winners, Size boardSize) {
int thickness = 70;
Scalar color = Scalar(0, 0, 0);
Point piece1Point = Point(getPosX(winners[0] % 3, boardSize), getPosY(winners[0] / 3, boardSize));
Point piece3Point = Point(getPosX(winners[2] % 3, boardSize), getPosY(winners[2] / 3, boardSize));
line(frame, piece1Point, piece3Point, color, thickness, CV_AA);
}
bool hasPiece(char place) {
return place == 'o' || place == 'x';
}
vector<int> getWinner() {
char pivotD = board[4];
char pivotV;
char pivotH;
// diagonal 1
if (hasPiece(pivotD) && board[0] == pivotD && board[8] == pivotD) {
return {0, 4, 8};
}
// diagonal 2
if (hasPiece(pivotD) && board[2] == pivotD && board[6] == pivotD) {
return {2, 4, 6};
}
// vertical and horizontal
for (int counter = 0; counter < 3; counter += 1) {
pivotV = board[counter];
pivotH = board[3 * counter];
if (!hasPiece(pivotV)) {
continue;
}
if (board[counter + 3] == pivotV && board[counter + 6] == pivotV) {
return {counter, counter + 3, counter + 6};
}
if (board[(3 * counter) + 1] == pivotH && board[(3 * counter) + 2] == pivotH) {
return {3 * counter, board[(3 * counter) + 1], (3 * counter) + 2};
}
}
return {};
}
void play() {
if (selectedPosition < 0 || board[selectedPosition] == 'o' || board[selectedPosition] == 'x') {
return;
}
board[selectedPosition] = piece;
if (piece == 'o') {
printf("setting new piece");
piece = 'x';
} else {
piece = 'o';
}
}
int main( int argc, char**) {
VideoCapture cap(0);
if(!cap.isOpened()) {
return -1;
}
Size size = Size(cap.get(CV_CAP_PROP_FRAME_WIDTH),
cap.get(CV_CAP_PROP_FRAME_HEIGHT));
cout << size;
cout << cap.get(CV_CAP_PROP_FPS);
namedWindow(MAIN_WINDOW, CV_WINDOW_AUTOSIZE);
Mat edges;
Mat imgThresholded;
bool v = false;
vector<int> winners;
// http://opencv-srf.blogspot.com.br/2010/09/object-detection-using-color-seperation.html
cvCreateTrackbar("LowHue", MAIN_WINDOW, &iLowH, 179); //Hue (0 - 179)
cvCreateTrackbar("HighHue", MAIN_WINDOW, &iHighH, 179);
cvCreateTrackbar("LowSaturation", MAIN_WINDOW, &iLowS, 255); //Saturation (0 - 255)
cvCreateTrackbar("HighSaturation", MAIN_WINDOW, &iHighS, 255);
cvCreateTrackbar("LowValue", MAIN_WINDOW, &iLowV, 255); //Value (0 - 255)
cvCreateTrackbar("HighValue", MAIN_WINDOW, &iHighV, 255);
for(;;) {
double t = (double)getTickCount();
cap >> edges;
cv::flip(edges, edges, 1);
if (winners.size() < 3) {
findPieces(edges, imgThresholded, size);
}
printBoard(edges, size.width, size.height);
printPieces(edges, size);
winners = getWinner();
if (winners.size() == 3) {
printWinner(edges, winners, size);
}
int key = waitKey(30);
if(key >= 0) {
switch (key) {
case 'v':
v = !v;
break;
case 'c':
clearPieces();
break;
case ' ':
if (winners.size() < 3) {
play();
}
break;
}
}
t = ((double)getTickCount() - t)/getTickFrequency();
printMeta(edges, t);
if (v) {
imshow(MAIN_WINDOW, imgThresholded);
} else {
imshow(MAIN_WINDOW, edges);
}
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment