Difference between revisions of "ECE597 Project Interactive Pong"

From eLinux.org
Jump to: navigation, search
(Added code)
(2 intermediate revisions by one other user not shown)
Line 12: Line 12:
  
 
Jian Li
 
Jian Li
 
==Code==
 
OpenCV (C++)
 
 
=== void loadTemplateImage() ===
 
Get the color of the hand, so that we can track the movement of the hand automatically.
 
<pre>
 
{
 
 
        IplImage *tempimage = cvLoadImage("/home/dica/workspace/cvex1/sshou.bmp",1);
 
 
cvCvtColor( tempimage, hsv, CV_BGR2HSV );
 
 
int _vmin = vmin, _vmax = vmax;
 
 
cvInRangeS( hsv, cvScalar(0,smin,MIN(_vmin,_vmax),0),
 
cvScalar(180,256,MAX(_vmin,_vmax),0), mask );
 
 
cvSplit( hsv, hue, 0, 0, 0 );
 
 
selection.x = 1;
 
 
selection.y = 1;
 
 
selection.width = 320-1;
 
 
selection.height= 240-1;
 
 
cvSetImageROI( hue, selection );
 
 
cvSetImageROI( mask, selection );
 
 
cvCalcHist( &hue, hist, 0, mask );
 
 
float max_val = 0.f;
 
 
cvGetMinMaxHistValue( hist, 0, &max_val, 0, 0 );
 
 
cvConvertScale( hist->bins, hist->bins, max_val ? 255. / max_val : 0., 0 );
 
 
cvResetImageROI( hue );
 
 
cvResetImageROI( mask );
 
 
track_window = selection;
 
 
track_object = 1;
 
 
 
cvZero( histimg );
 
 
int bin_w = histimg->width / hdims;
 
 
for(int i = 0; i < hdims; i++ )
 
 
 
{
 
 
int val = cvRound( cvGetReal1D(hist->bins,i)*histimg->height/255 );
 
 
CvScalar color = hsv2rgb(i*180.f/hdims);
 
 
cvRectangle( histimg, cvPoint(i*bin_w,histimg->height),
 
 
cvPoint((i+1)*bin_w,histimg->height - val),
 
 
color, -1, 8, 0 );
 
 
}
 
 
cvReleaseImage(&tempimage);
 
 
}
 
</pre>
 
 
 
 
 
=== int main( int argc, char** argv ) ===
 
create window, get the color of the hand and then track the movement of the hand
 
<pre>
 
{
 
    CvCapture* capture = 0;
 
 
    if( argc == 1 || (argc == 2 && strlen(argv[1]) == 1 && isdigit(argv[1][0])))
 
        capture = cvCaptureFromCAM( argc == 2 ? argv[1][0] - '0' : 0 );
 
    else if( argc == 2 )
 
        capture = cvCaptureFromAVI( argv[1] );
 
 
    if( !capture )
 
    {
 
        fprintf(stderr,"Could not initialize capturing...\n");
 
        return -1;
 
    }
 
   
 
    cvNamedWindow( "CamShiftDemo", 1 );
 
    cvNamedWindow( "Histogram", 1 );
 
   
 
    for(;;)
 
    {
 
        IplImage* frame = 0;
 
        int i, bin_w, c;
 
 
        frame = cvQueryFrame( capture );
 
        if( !frame )
 
            break;
 
 
        if( !image )
 
        {
 
            /* allocate all the buffers */
 
            image = cvCreateImage( cvGetSize(frame), 8, 3 );
 
            image->origin = frame->origin;
 
            hsv = cvCreateImage( cvGetSize(frame), 8, 3 );
 
            hue = cvCreateImage( cvGetSize(frame), 8, 1 );
 
            mask = cvCreateImage( cvGetSize(frame), 8, 1 );
 
            backproject = cvCreateImage( cvGetSize(frame), 8, 1 );
 
            hist = cvCreateHist( 1, &hdims, CV_HIST_ARRAY, &hranges, 1 );
 
            histimg = cvCreateImage( cvSize(320,200), 8, 3 );
 
            cvZero( histimg );
 
            loadTemplateImage();
 
        }
 
 
        cvCopy( frame, image, 0 );
 
        cvCvtColor( image, hsv, CV_BGR2HSV );
 
 
        if( track_object )
 
        {
 
            int _vmin = vmin, _vmax = vmax;
 
 
            cvInRangeS( hsv, cvScalar(0,smin,MIN(_vmin,_vmax),0),
 
                        cvScalar(180,256,MAX(_vmin,_vmax),0), mask );
 
            cvSplit( hsv, hue, 0, 0, 0 );
 
 
            if( track_object < 0 )
 
            {
 
                float max_val = 0.f;
 
                cvSetImageROI( hue, selection );
 
                cvSetImageROI( mask, selection );
 
                cvCalcHist( &hue, hist, 0, mask );
 
                cvGetMinMaxHistValue( hist, 0, &max_val, 0, 0 );
 
                cvConvertScale( hist->bins, hist->bins, max_val ? 255. / max_val : 0., 0 );
 
                cvResetImageROI( hue );
 
                cvResetImageROI( mask );
 
                track_window = selection;
 
                track_object = 1;
 
 
                cvZero( histimg );
 
                bin_w = histimg->width / hdims;
 
                for( i = 0; i < hdims; i++ )
 
                {
 
                    int val = cvRound( cvGetReal1D(hist->bins,i)*histimg->height/255 );
 
                    CvScalar color = hsv2rgb(i*180.f/hdims);
 
                    cvRectangle( histimg, cvPoint(i*bin_w,histimg->height),
 
                                cvPoint((i+1)*bin_w,histimg->height - val),
 
                                color, -1, 8, 0 );
 
                }
 
            }
 
 
            cvCalcBackProject( &hue, backproject, hist );
 
            cvAnd( backproject, mask, backproject, 0 );
 
            cvCamShift( backproject, track_window,
 
                        cvTermCriteria( CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 10, 1 ),
 
                        &track_comp, &track_box );
 
            track_window = track_comp.rect;
 
 
            if( backproject_mode )
 
                cvCvtColor( backproject, image, CV_GRAY2BGR );
 
            if( !image->origin )
 
                track_box.angle = -track_box.angle;
 
            cvEllipseBox( image, track_box, CV_RGB(255,0,0), 3, CV_AA, 0 );
 
        }
 
 
        if( select_object && selection.width > 0 && selection.height > 0 )
 
        {
 
            cvSetImageROI( image, selection );
 
            cvXorS( image, cvScalarAll(255), image, 0 );
 
            cvResetImageROI( image );
 
        }
 
 
        cvShowImage( "CamShiftDemo", image );
 
        cvShowImage( "Histogram", histimg );
 
 
        }
 
    }
 
 
    return 0;
 
}
 
 
</pre>
 
===PyPong.py===
 
<pre>
 
#! /usr/bin/env python
 
 
 
 
# PyPong - an arcade Pong game programmed in Python
 
 
# Created by pymike, released to the Public Domain
 
 
import sys, os
 
import random
 
 
import pygame
 
from pygame.locals import *
 
 
HUMAN = 1
 
COM  = 2
 
 
class Player(pygame.sprite.Sprite):
 
 
    def __init__(self):
 
        pygame.sprite.Sprite.__init__(self, self.containers)
 
        self.image = pygame.Surface((16, 64))
 
        self.image.fill((255, 255, 255), (2, 0, 12, 64))
 
        self.image.fill((255, 255, 255), (0, 2, 16, 60))
 
        self.rect = self.image.get_rect(midleft = (16, 240))
 
        self._rect = Rect(self.rect)
 
 
    def update(self):
 
        self._rect = Rect(self.rect)
 
 
        key = pygame.key.get_pressed()
 
        if key[K_UP]:
 
            self.rect.move_ip(0, -5)
 
        if key[K_DOWN]:
 
            self.rect.move_ip(0, 5)
 
 
        if self.rect.bottom > 480:
 
            self.rect.bottom = 480
 
        if self.rect.top < 0:
 
            self.rect.top = 0
 
 
class Computer(pygame.sprite.Sprite):
 
 
    def __init__(self, ball):
 
        pygame.sprite.Sprite.__init__(self, self.containers)
 
        self.image = pygame.Surface((16, 64))
 
        self.image.fill((255, 255, 255), (2, 0, 12, 64))
 
        self.image.fill((255, 255, 255), (0, 2, 16, 60))
 
        self.rect = self.image.get_rect(midleft = (640-32, 240))
 
        self._rect = Rect(self.rect)
 
        self.ball = ball
 
        self.speed = 4
 
        self.max_speed = self.speed
 
 
    def update(self):
 
        self._rect = Rect(self.rect)
 
 
        if abs(self.ball.vy) < self.max_speed:
 
            self.speed = abs(self.ball.vy)
 
        else:
 
            self.speed = self.max_speed
 
 
        if self.ball.rect.centery > self.rect.centery:
 
            self.rect.move_ip(0, self.speed)
 
        if self.ball.rect.centery < self.rect.centery:
 
            self.rect.move_ip(0, -self.speed)
 
 
        if self.rect.bottom > 480:
 
            self.rect.bottom = 480
 
        if self.rect.top < 0:
 
            self.rect.top = 0
 
 
    def set_ball(self, ball):
 
        self.ball = ball
 
 
class Ball(pygame.sprite.Sprite):
 
 
    def __init__(self):
 
        pygame.sprite.Sprite.__init__(self, self.containers)
 
        self.image = pygame.Surface((12, 12))
 
        self.image.fill((255, 255, 255), (2, 0, 8, 12))
 
        self.image.fill((255, 255, 255), (0, 2, 12, 8))
 
        self.rect = self.image.get_rect(midleft = (320, 240))
 
        self._rect = Rect(self.rect)
 
        self.vx = random.choice([5, -5])
 
        self.vy = random.choice([-2, -1, 1, 2])
 
        self.scored = 0
 
 
    def update(self):
 
        self._rect = Rect(self.rect)
 
        self.rect.move_ip(self.vx, self.vy)
 
 
        if self.rect.bottom > 480:
 
            self.rect.bottom = 480
 
            self.vy = -self.vy
 
        if self.rect.top < 0:
 
            self.rect.top = 0
 
            self.vy = -self.vy
 
        if self.rect.left < 0:
 
            self.kill()
 
            self.scored = COM
 
        if self.rect.right > 640:
 
            self.kill()
 
            self.scored = HUMAN
 
 
    def collide(self, bat):
 
        if self.rect.colliderect(bat.rect) and not self._rect.colliderect(bat._rect):
 
            if self._rect.right <= bat._rect.left and self.rect.right > bat.rect.left:
 
                self.rect.right = bat.rect.left
 
                self.vx = -self.vx
 
            if self._rect.left >= bat._rect.right and self.rect.left < bat.rect.right:
 
                self.rect.left = bat.rect.right
 
                self.vx = -self.vx
 
                self.vx += 1
 
                if self.rect.centery < bat.rect.centery:
 
                    self.vy = ((self.rect.centery-bat.rect.centery)/(bat.rect.height/2))*4.5
 
                    if self.vy >= -1:
 
                        self.vy = -1
 
                if self.rect.centery > bat.rect.centery:
 
                    self.vy = ((self.rect.centery-bat.rect.centery)/(bat.rect.height/2))*4.5
 
                    if self.vy <= 1:
 
                        self.vy = 1
 
            if self._rect.bottom <= bat._rect.top and self.rect.bottom > bat.rect.top:
 
                self.rect.bottom = bat.rect.top
 
                self.vy = -self.vy
 
            if self._rect.top >= bat._rect.bottom and self.rect.top < bat.rect.bottom:
 
                self.rect.top = bat.rect.bottom
 
                self.vy = -self.vy
 
 
class Menu:
 
 
    def __init__(self, screen):
 
        self.screen = screen
 
        self.font = pygame.font.SysFont("Comic Sans MS", 100)
 
        self.font2 = pygame.font.SysFont("Comic Sans MS", 50)
 
        self.font3 = pygame.font.SysFont("Comic Sans MS", 25)
 
 
        self.all = pygame.sprite.RenderUpdates()
 
        Computer.containers = self.all
 
        Ball.containers = self.all
 
 
        self.ball = Ball()
 
        self.com1 = Computer(self.ball)
 
        self.com2 = Computer(self.ball)
 
        self.com1.rect.left = 16
 
        self.clock = pygame.time.Clock()
 
        self.timer = 0
 
 
    def loop(self):
 
        while 1:
 
 
            self.clock.tick(60)
 
            self.all.update()
 
            self.timer += 1
 
            if self.timer >= 50:
 
                self.timer = 0
 
 
            for e in pygame.event.get():
 
                if e.type == QUIT:
 
                    pygame.quit()
 
                    sys.exit()
 
                if e.type == KEYDOWN:
 
                    if e.key == K_ESCAPE:
 
                        pygame.quit()
 
                        sys.exit()
 
                    if e.key == K_SPACE:
 
                        game = Game(self.screen)
 
                        game.loop()
 
 
            self.screen.fill((0, 0, 0))
 
            self.ball.collide(self.com1)
 
            self.ball.collide(self.com2)
 
            self.all.draw(self.screen)
 
            ren = self.font.render("PyPong", 1, (255, 255, 255))
 
            self.screen.blit(ren, (320-ren.get_width()/2, 20))
 
            ren = self.font3.render("March 2008", 1, (255, 255, 255))
 
            self.screen.blit(ren, (320-ren.get_width()/2, 220))
 
            ren = self.font3.render("by PyMike", 1, (255, 255, 255))
 
            self.screen.blit(ren, (320-ren.get_width()/2, 250))
 
            ren = self.font2.render("Press Space", 1, (255, 255, 255))
 
            if self.timer <= 25:
 
                self.screen.blit(ren, (320-ren.get_width()/2, 350))
 
            pygame.display.flip()
 
 
class Game:
 
 
    def __init__(self, screen):
 
        self.screen = screen
 
 
        self.all = pygame.sprite.RenderUpdates()
 
        Player.containers = self.all
 
        Computer.containers = self.all
 
        Ball.containers = self.all
 
 
        self.ball = Ball()
 
        self.player = Player()
 
        self.com = Computer(self.ball)
 
        self.clock = pygame.time.Clock()
 
 
        self.p1score = 0
 
        self.p2score = 0
 
        self.win_score = 21
 
        self.font = pygame.font.SysFont("Comic Sans MS", 50)
 
        self.font2 = pygame.font.SysFont("Comic Sans MS", 30)
 
        self.won = False
 
        self.served = False
 
        self.done = False
 
 
    def handle_input(self):
 
        for e in pygame.event.get():
 
            if e.type == QUIT:
 
                self.pygame.quit()
 
                sys.exit()
 
            if e.type == KEYDOWN:
 
                if e.key == K_ESCAPE:
 
                    self.done = True
 
                if e.key == K_SPACE:
 
                    self.served = True
 
                    self.ball = Ball()
 
                    self.com.set_ball(self.ball)
 
 
    def render(self):
 
        self.screen.fill((0, 0, 0))
 
        self.all.draw(self.screen)
 
        ren = self.font.render("%s:%s" % (self.p1score, self.p2score), 1, (255, 255, 255))
 
        self.screen.blit(ren, (320-ren.get_width()/2, 10))
 
        if self.won == HUMAN:
 
            ren = self.font.render("Player 1 won!", 1, (255, 255, 255))
 
            self.screen.blit(ren, (320-ren.get_width()/2, 240-ren.get_height()/2))           
 
        if self.won == COM:
 
            ren = self.font.render("Com won!", 1, (255, 255, 255))
 
            self.screen.blit(ren, (320-ren.get_width()/2, 240-ren.get_height()/2)) 
 
        if not self.served and not self.won:
 
            ren = self.font2.render("Press Space to Serve", 1, (255, 255, 255))
 
            self.screen.blit(ren, (320-ren.get_width()/2, 240-ren.get_height()/2)) 
 
        pygame.display.flip()
 
 
    def update(self):
 
        self.clock.tick(60)
 
        if not self.won and self.served:
 
            self.all.update()
 
        self.ball.collide(self.player)
 
        self.ball.collide(self.com)
 
 
        if self.p1score >= self.win_score:
 
            self.won = HUMAN
 
        if self.p2score >= self.win_score:
 
            self.won = COM
 
 
        if not self.ball.alive() and not self.won:
 
            if self.ball.scored == HUMAN:
 
                self.p1score += 1
 
            if self.ball.scored == COM:
 
                self.p2score += 1
 
            self.ball = Ball()
 
            self.com.set_ball(self.ball)
 
            self.served = False
 
 
        if self.won or not self.served:
 
            self.ball.kill()
 
 
    def loop(self):
 
        self.done = False
 
        while not self.done:
 
            self.update()
 
            self.handle_input()
 
            self.render()
 
 
def main():
 
    pygame.init()
 
    os.environ["SDL_VIDEO_CENTERED"] = "1"
 
    pygame.display.set_caption("PyPong")
 
    screen = pygame.display.set_mode((640, 480))
 
    menu = Menu(screen)
 
    menu.loop()
 
 
 
if __name__ == "__main__":
 
 
    main()
 
</pre>
 
  
 
==System Setup==
 
==System Setup==
Line 520: Line 48:
 
==Files==
 
==Files==
 
[[File:PyPong.tgz]]
 
[[File:PyPong.tgz]]
 +
 +
[[File:cvex1.zip]]
 +
 +
[[File:Ubuntu_9.10_opencv2.0.doc]]
  
 
==Links==
 
==Links==
 
[http://www.logitech.com/en-us/webcam_communications/webcams/devices/6333 Logitech Webcam Pro 9000]
 
[http://www.logitech.com/en-us/webcam_communications/webcams/devices/6333 Logitech Webcam Pro 9000]
 
[[Category:ECE597]]
 
[[Category:ECE597]]

Revision as of 16:34, 24 May 2010

This project is part of the ECE597 32-bit Embedded Linux class at Rose-Hulman Institute of Technology in Terre Haute, IN.

Project Goal

The goal of this project is to implement a simple game of "Pong" on the Beagle Board that allows a user to play the game by gesturing with their hands rather than using a mouse or keyboard.

Team Members

Elliot Simon

Mitch Garvin

Matt Luke

Jian Li

System Setup

Currently the hand-tracking and Pong games run in different processes. Hand-tracking requires a picture called "sshou.bmp" in the /home/user-name directory that is used as a reference for the histogram that tracks hands. The hand-tracking writes to a temporary pipe in /usr/yval, which the Pong game then reads the latest value from. To run, start the hand-tracking program in a root shell, then the Pong game in a separate root shell. Press [Spacebar] to begin a game, then [Spacebar] to release a ball. Moving a hand up and down in front of the camera causes the user's paddle to move and reflect that. The user's paddle will not move if there is not a ball "in play".

Task List

Below is an estimated list of tasks to complete Task list will be updated as necessary

Task Status Description
Pong on the Beagle Board Complete Port a simple game of classic pong onto the Beagle Board with keyboard/mouse input
Webcam interface with the Beagle Board and OpenCV Complete Get the Beagle Board to recognize the webcam and perform basic functionalities from OpenCV (connect to camera, snapshot, etc.)
Refactor Pong Complete Refactor Pong to work with a different input (camera)
Track hands with camera and OpenCV Complete Track user's hands using OpenCV library functions on the Beagle Board
Interface tracking camera with pong Complete Join the tracking and game into one system such that users can play pong with their hands

Files

File:PyPong.tgz

File:Cvex1.zip

File:Ubuntu 9.10 opencv2.0.doc

Links

Logitech Webcam Pro 9000