|
|
| (2 intermediate revisions by one 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]] |
This project is part of the ECE597 32-bit Embedded Linux class at Rose-Hulman Institute of Technology in Terre Haute, IN.
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.
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".
Below is an estimated list of tasks to complete Task list will be updated as necessary