码迷,mamicode.com
首页 > 其他好文 > 详细

Motion sensing game (Ping Pong Game)

时间:2015-06-26 22:28:04      阅读:235      评论:0      收藏:0      [点我收藏+]

标签:c++   opencv   source code   motion sensing game   ubuntu   


Project Demonstration



Here is the source code of the project based on OpenCV anc C++.

Before you run this code on Linux, you should install the OpenCV library  first.

#include<opencv/highgui.h>
#include<opencv2/opencv.hpp>
#include<string>
#include<sstream>
#include<stdlib.h>
#include<time.h>
#include<stdio.h>
using namespace std;
using namespace cv;
// The length and width of window frame
const int FRAME_LENGTH =  640, FRAME_WIDTH = 480;

// The stating point of BALL
const int BALL_START_X = 320, BALL_START_Y = 26;
// the constant value of PI
const double PI = acos(-1);
// The speed of the ball
double SPEED = 35;
// The redius of the ball
int RADIUS = 20;

// the diagonal points of the board
int recX1 = 225, recY1 = 460;
int recX2 = 415, recY2 = 480;
const int boardLength = recX2 - recX1;
const int boardWidth = recY2 - recY1;

// The initial min and max of HSV filter values
int H_MIN = 0;
int H_MAX = 256;
int S_MIN = 0;
int S_MAX = 256;
int V_MIN = 0;
int V_MAX = 256;

// The maximum number of object to be detected
const int MAX_NUM_OBJECT = 50;
// Minimum and maximum area of object
const int MIN_OBJECT_AREA = 20 * 20;
const int MAX_OBJECT_AREA = FRAME_LENGTH * FRAME_WIDTH / 1.5;

// Name of different windows
const string originalImage = "Original Image";
const string hsvImage = "HSV Image";
const string thresholdImage = "Threshold image";
const string trackbarName = "Trackbars";
// The flag to control whether tracking object
bool trackObject = true;

// Scoreboard
int scoreBoard = 0;

// GameOver
bool gameOver = false;

// Select the game mode
int choice = 0;

// acceleration
int acc = 0;

// This function will be called when a trackbar position is changed
void onTrackbar(int, void *){	
}
// Convert the integer to string
string intToString(int);
// Create trackbars
void createTrackbars();
// Draw crosshair to locate the position of the target
void drawObject(int ,int , Mat&);
// Reduce noise
void morphOps(Mat&);
// Locate the position of the object
void trackFilteredObject(int& ,int&, Mat, Mat&);
// Depict the board
void depictBoard(Mat, Point, Point);
// Depict Generator to generate the ball
void depictGenerator(Mat);
// Limit the board in case of the board out of border
void limitBoard(int&, int&, int);
// Class of BALL
class NewBall{
	private:
	// The driction of the ball at the beginning
	double angle;
	// the moving vector of the ball for each frame
	int Vx, Vy;
	// the center point of the ball
	Point point;
	public:
		NewBall();
		void reset();
		// Movement the ball like baseball
		void baseballMoving(Point, Point);
		// Movement the ball like ping pong ball
		void pingpongMoving(Point, Point);
		// Depict the ball
		void depictBall(Mat);
		void accelerate();
};
NewBall::NewBall(){
		// the center point of the ball
		point = Point(BALL_START_X, BALL_START_Y);
		// Initialize the random seed
		srand(time(NULL));
		// The driction of the ball at the beginning
		// Filter the angle of the driection let it between PI/4 and PI/4*3
		angle = (rand() % 51 + 25) / 100.0 * PI;
		// the moving vector of the ball for each frame
		Vx = (int)(cos(angle) * SPEED);
		Vy = (int)(sin(angle) * SPEED);
}
void NewBall::accelerate(){
		Vx = (int)(cos(angle) * SPEED);
		Vy = (int)(sin(angle) * SPEED);
}
void NewBall::reset(){
		// the center point of the ball
		point = Point(BALL_START_X, BALL_START_Y);
		// Initialize the random seed
		// The driction of the ball at the beginning
		angle = (rand() % 51 + 25) / 100.0 * PI;
		// the moving vector of the ball for each frame
		Vx = (int)(cos(angle) * SPEED);
		Vy = (int)(sin(angle) * SPEED);
}
// Depict the ball on the frame
void NewBall::depictBall(Mat img){
	int lineType = 8;
	circle(img, point, RADIUS, Scalar(0,0,255), CV_FILLED, lineType);
}
// Movement of the ball
void NewBall::baseballMoving(Point a, Point b){
	if(point.x - RADIUS < 0 || point.x + RADIUS > FRAME_LENGTH){
		Vx = -Vx;	
	}	
	if(point.y + RADIUS > FRAME_WIDTH + 5){
		// the ball will dispear and then appear in the original position
		gameOver = true;
	}
	if((point.y + RADIUS > FRAME_WIDTH - boardWidth - 10) && (point.x >= a.x - 12 && point.x <= b.x + 12)){
		cout << a.x - 12<< " " << b.x + 12<< endl;
		scoreBoard++;
		if(scoreBoard == 5 && acc == 0){
			SPEED += 5;
		}else if (scoreBoard == 10 && acc == 1){
		    SPEED += 5;
		}else if (scoreBoard == 15 && acc == 2){
		    SPEED += 5;
		}else if (scoreBoard == 20 && acc == 3){
		    SPEED += 5;
		}
		Vy = -Vy;
	}
	if(point.y - RADIUS < 0){
		this->reset();	
	}
	point.x = point.x + Vx;
	point.y = point.y + Vy;
}

// Movement of the ball
void NewBall::pingpongMoving(Point a, Point b){
	if(point.x - RADIUS < 0 || point.x + RADIUS > FRAME_LENGTH){
		Vx = -Vx;	
	}	
	if(point.y + RADIUS > FRAME_WIDTH + 5){
		// the ball will dispear and then appear in the original position
		gameOver = true;
	}
	if((point.y + RADIUS > FRAME_WIDTH - boardWidth - 10) && (point.x >= a.x - 12 && point.x <= b.x + 12)){
		cout << a.x - 12<< " " << b.x + 12<< endl;
		cout << Vx << " " << Vy << endl;
		scoreBoard++;
		if(scoreBoard == 5 && acc == 0){
		    SPEED += 5;
			this->accelerate();
		}else if (scoreBoard == 10 && acc == 1){
			SPEED += 5;
			this->accelerate();
		}else if (scoreBoard == 15 && acc == 2){
			SPEED += 5;
			this->accelerate();
			acc++;
		}else if (scoreBoard == 20 & acc == 3){
			SPEED += 5;
			this->accelerate();
			acc++;
		}
		Vy = -Vy;
	}
	if(point.y - RADIUS < 0){
		Vy = -Vy;	
	}
	point.x = point.x + Vx;
	point.y = point.y + Vy;
}


int main(int argc, char*argv[]){
		// two boolean variables to control the two functions, one is to track object and the other 
		//reduce noise
		bool useMorphOps = true;
		//Matrix to store each frame from the webcam feed
		Mat cameraFeed;
		//Martrix storage for HSV image
		Mat HSV;
		//Matrix sotrage for binary threshold image
		Mat threshold;
		//x and y values for the current location of the object
		int x = 0, y = 0;
		//The position of the object on the last frame
		int lastX = 0, lastY = 0;
		//Create slider bars for HSV filtering
		createTrackbars();
		//video capture object to acquire webcam feed
		VideoCapture cap(0);
		char name[] = "camera";
		if(!cap.isOpened()){
			cout << "Camera can not opened." << endl;
			return -1;
		}
		//Window of original image
		namedWindow(originalImage, WINDOW_AUTOSIZE);
		//Window of HSV image
		namedWindow(hsvImage, WINDOW_AUTOSIZE);
		//Window of threshold image
		namedWindow(thresholdImage, WINDOW_AUTOSIZE);
		// move windows to its proper location
		moveWindow(originalImage, 20, 20);
		moveWindow(hsvImage, 20, 600);
		moveWindow(thresholdImage, 700, 20);
		// flag to control the movement of the ball
		bool ballMoveFlag = 0;
		NewBall ball;

		while(1){
			bool bSuccess = cap.read(cameraFeed);
			if(!bSuccess){
				cout << "Can not read a frame from video stream" << endl;
				break;
			}
			//Convert the original image to HSV
			cvtColor(cameraFeed, HSV, COLOR_BGR2HSV);
			//Select a range of H,S,V properties and then it can filter the
			//specific color
			inRange(HSV, Scalar(H_MIN, S_MIN, V_MIN), Scalar(H_MAX,S_MAX,V_MAX), threshold);
			//Reduce noise
			if(useMorphOps){
				morphOps(threshold);	
			}
			// press the button to go on the game
			if(waitKey(30) == 27){  // press the ESC button
				cout << "You exit the game" << endl;
				break;
			}
			if(waitKey(30) == 32){  // press the space button
				ballMoveFlag = 1;
				ball.reset();
				gameOver = false;
				acc = 0;
				SPEED = 35;
			}
			if(waitKey(30) == 49){
				choice = 1;	
			}
			if(waitKey(30) == 50){
				choice = 2;
			}

			//On the last frame keep the location of the frame
			lastX = x;
			lastY = y;
			//Parameters x and y record the current position of the objcet
			if(trackObject){
				trackFilteredObject(x, y, threshold, cameraFeed);
				int diffX = x - lastX, diffY = y - lastY;
				//Control the movement of the rectangle and do not let it out of the boarder
				limitBoard(recX1, recX2, diffX);
			}
			// Depict the image of the board and the ball
			depictGenerator(cameraFeed);
			depictBoard(cameraFeed, Point(recX1, recY1), Point(recX2, recY2));
			ball.depictBall(cameraFeed);
			putText(cameraFeed,"Your Score " + intToString(scoreBoard), Point(350,50),1,2,Scalar(0,255,255),2);		
			if(ballMoveFlag == false){
				putText(cameraFeed, "Press space bar to start", Point(30,400),2,1,Scalar(0,0,255),4);		
			}
			if(choice != 1 && choice != 2){
				putText(cameraFeed, "Press 1 to select baseball mode", Point(30,200),2,1,Scalar(0,0,255),4);	
				putText(cameraFeed, "Press 2 to select pingpong mode", Point(30,300),2,1,Scalar(0,0,255),4);	
			}
			if(ballMoveFlag == 1){
				// Generate the ball
				//Move the center fo the circle to the next position
				if(choice == 1){
					ball.baseballMoving(Point(recX1, recY1), Point(recX2, recY2));
				}else if(choice == 2){
					ball.pingpongMoving(Point(recX1, recY1), Point(recX2, recY2));	
				}
				if(gameOver == true){
					choice = 0;
					ballMoveFlag = 0;
					scoreBoard = 0;
				}
			}
			//If the ball is out of boarder, GameOver
			if(gameOver == true && choice == 0 && ballMoveFlag == 0){
				putText(cameraFeed, "GAME OVER", Point(30,100),2,1,Scalar(0,0,255),4);	
			}
			imshow(originalImage, cameraFeed);
			imshow(hsvImage, HSV);
			imshow(thresholdImage, threshold);
		}
		return 0;
}
// Limit the board in case of the board out of border
void limitBoard(int &recX1, int &recX2, int diffX){
	if(recX1 + diffX < 0){
		recX1 = 0;
		recX2 = boardLength;
	}else if(recX2 + diffX > FRAME_LENGTH){
		recX2 = FRAME_LENGTH;
		recX1 = FRAME_LENGTH - boardLength;
	}else{
		recX1 += diffX;
		recX2 += diffX;
	}
}

// Depict the generator 
void depictGenerator(Mat img){
	int thickness = CV_FILLED;
	int lineType = 8;
	Point a(300,0);
	Point b(340,5);
	rectangle(img, a, b, Scalar(0,255,0), thickness, lineType);
}

void depictBoard(Mat img, Point a, Point b){
	int thickness = CV_FILLED;
	int lineType = 8;
	rectangle(img, a, b, Scalar(255,0,0), thickness, lineType);
}
void createTrackbars(){
	namedWindow(trackbarName, 0);
	moveWindow(trackbarName, 800, 500);
	createTrackbar("H_MIN", trackbarName, &H_MIN, H_MAX, onTrackbar);
	createTrackbar("H_MAX", trackbarName, &H_MAX, H_MAX, onTrackbar);
	createTrackbar("S_MIN", trackbarName, &S_MIN, S_MAX, onTrackbar);
	createTrackbar("S_MAX", trackbarName, &S_MAX, S_MAX, onTrackbar);
	createTrackbar("V_MIN", trackbarName, &V_MIN, V_MAX, onTrackbar);
	createTrackbar("V_MAX", trackbarName, &V_MAX, V_MAX, onTrackbar);
}
// Draw crosshair to locate the position of the target
void drawObject(int x,int y, Mat &frame){
	circle(frame,Point(x, y), 20, Scalar(255,0,0), 2);
	if(y - 25 > 0){
		line(frame, Point(x, y), Point(x, y-25), Scalar(255,0,0), 2);	
	}else{
		line(frame, Point(x, y), Point(x, 0), Scalar(255,0,0), 2);	
	}
	if(y + 25 < FRAME_WIDTH){
		line(frame, Point(x,y), Point(x,y+25),Scalar(255,0,0), 2);	
	}else{
		line(frame, Point(x,y), Point(x,FRAME_WIDTH),Scalar(255,0,0), 2);	
	}
	if(x - 25 > 0){
		line(frame, Point(x,y), Point(x-25, y), Scalar(255,0,0), 2);	
	}else{
		line(frame, Point(x,y), Point(0, y), Scalar(255,0,0), 2);	
	}
	if(x + 25 < FRAME_LENGTH){
		line(frame, Point(x,y), Point(x+25,y), Scalar(255,0,0),2);	
	}else{
		line(frame,Point(x,y), Point(FRAME_LENGTH,y), Scalar(255,0,0),2);	
	}
	putText(frame, intToString(x)+","+intToString(y), Point(x,y+30),1,1,Scalar(255,0,0),2);
}

// Locate the position of the object
void trackFilteredObject(int& x,int& y, Mat threshold, Mat& cameraFeed){
	Mat temp;
	threshold.copyTo(temp);
	// these two vectors needed for output of findContours
	vector< vector<Point> > contours;
	vector< Vec4i > hierarchy;
	// find contours of filtered image using openCV findContours function
    findContours(temp, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);
	// use moments method to find our filtered object
	double refArea = 0;
	bool objectFound = false;
	if(hierarchy.size() > 0){
		int numObjects = hierarchy.size();
		// if number of objects greater than MAX_NUM_OBJECTS we have noisy filter
		if(numObjects < MAX_NUM_OBJECT){
			for(int index = 0; index >= 0; index = hierarchy[index][0]){
				Moments moment = moments((cv::Mat)contours[index]);
				double area = moment.m00;
				if(area > MIN_OBJECT_AREA && area < MAX_OBJECT_AREA && area > refArea){
				 	x = moment.m10 / area;
					y = moment.m01 / area;
					objectFound = true;
					refArea = area;
				}else{
					objectFound = false;	
				}
				if(objectFound == true){
					putText(cameraFeed, "Tracking Object", Point(0,50),2,1,Scalar(0,255,0),2);
					drawObject(x,y,cameraFeed);
				}

			}
		}
		else{
			putText(cameraFeed,"TOO MUCH NOISE! ADJUST FILTER", Point(0,50),1,2,Scalar(0,0,255),2);		
		}	
	}
}

// Convert the integer to string
string intToString(int number){
	std::stringstream ss;
	ss << number;
	return ss.str();
}
void morphOps(Mat &thresh){
	Mat erodeElement = getStructuringElement( MORPH_RECT, Size(3,3));
	Mat dilateElement = getStructuringElement( MORPH_RECT, Size(8,8));
	erode(thresh, thresh, erodeElement);
	erode(thresh, thresh, erodeElement);
	dilate(thresh, thresh, dilateElement);
	dilate(thresh, thresh, dilateElement);
}






版权声明:本文为博主原创文章,未经博主允许不得转载。

Motion sensing game (Ping Pong Game)

标签:c++   opencv   source code   motion sensing game   ubuntu   

原文地址:http://blog.csdn.net/worldmakewayfordream/article/details/46654423

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!