From 6cd46b59fc0bb9f5ec6d8a681446794a26479475 Mon Sep 17 00:00:00 2001 From: PRIYANSHU SINGAWAT <146561097+PriyanshuJain1307@users.noreply.github.com> Date: Sun, 26 Nov 2023 19:43:31 +0530 Subject: [PATCH] erc assignment-4 --- main.py | 264 +++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 167 insertions(+), 97 deletions(-) diff --git a/main.py b/main.py index 8f1718c..a6f1de6 100644 --- a/main.py +++ b/main.py @@ -1,105 +1,175 @@ import cv2 import mediapipe as mp -import numpy as np +import random import time +# Importing required libraries -# Initialize webcam -#1 +# Initializing hand tracking module +mp_hands = mp.solutions.hands +hands = mp_hands.Hands() -# Initialize hand tracking -#2 - -# Initialize paddle and puck positions -#3 - -# Initial velocity -initial_puck_velocity = [10, 10] -puck_velocity = initial_puck_velocity.copy() - -# Load target image and resize it to 30,30 -#4 - -# Initialize 5 target positions randomly(remember assignment 2!!) -#5 - -# Initialize score -#6 - -# Initialize timer variables +# Now we are setting up score and time variables and their initial values +score = 0 +time_limit = 30 start_time = time.time() -game_duration = 30 # 1/2 minute in seconds - -# Function to check if the puck is within a 5% acceptance region of a target -def is_within_acceptance(puck, target, acceptance_percent=5): - #complete the function - #7 - return ( - 0#make changes here!! #8 - ) - -while True: - # Calculate remaining time and elapsed time in minutes and seconds - #9 - - # Read a frame from the webcam - #10 - - # Flip the frame horizontally for a later selfie-view display - #11 - - # Convert the BGR image to RGB - #12 - - # Process the frame with mediapipe hands - #13 - - # Update paddle position based on index finger tip - #14 - - # Update puck position based on its velocity - #15 - - # Check for collisions with the walls - #16 - - # Check for collisions with the paddle - #17 - - # Check for collisions with the targets(use is_within_acceptance) - #18 - # Increase the player's score - # Remove the hit target - # Increase puck velocity after each hit by 2(you will have to increase both x and y velocities - - # Draw paddle, puck, and targets on the frame and overlay target image on frame - #19 - - # FOR REFERENCE: - # for target_position in target_positions: - # target_roi = frame[target_position[1]:target_position[1] + target_image.shape[0], - # target_position[0]:target_position[0] + target_image.shape[1]] - # alpha = target_image[:, :, 3] / 255.0 - # beta = 1.0 - alpha - # for c in range(0, 3): - # target_roi[:, :, c] = (alpha * target_image[:, :, c] + - # beta * target_roi[:, :, c]) - - # Display the player's score on the frame - #20 - - # Display the remaining time on the frame - #21 - - # Check if all targets are hit or time is up - #22 - - # Display the resulting frame - #23 - - # Exit the game when 'q' is pressed - if cv2.waitKey(1) & 0xFF == ord('q'): - break -# Release the webcam and close all windows -#24 +# Screen dimensions +swidth = 640 +sheight = 480 + +# Initialize puck variables +puck_radius = 15 +puck_x = swidth // 2 +puck_y = sheight // 2 +puck_speed = 6 +''' This is the speed with which it will move, later on we will increase the speed as the game proceeds + to make it more challenging.''' +puck_velocity = [random.choice([-1, 1]) * puck_speed, random.choice([-1, 1]) * puck_speed] + +# Paddle dimensions +paddle_width = 150 +paddle_height = 10 +paddle_x = swidth // 2 +paddle_y = sheight - 50 +'''This is for the initial position of the paddle on the screen ''' + +# Load the target image with error checking +target_image = cv2.imread( + "C:\\Users\\Hi\\Downloads\\winlibs-x86_64-posix-seh-gcc-13.2.0-mingw-w64ucrt-11.0.0-r1\\mingw64\\lib\\python3.9\\venv\\scripts\\target.png") + +if target_image is None: + print("Error: Unable to read the image file.") +else: + # Resize the target image to 30x30 + target_image = cv2.resize(target_image, (30, 30)) + target_height, target_width, _ = target_image.shape + + # Opening the camera + cap = cv2.VideoCapture(0) + + # Initialize smoothing parameters + smoothing_factor = 0.99 + ''' I have included this to make tracking of the finger tip faster, the greater the smoothing factor the greater is the speed with which the hand is tracked''' + + # Initialize hand position for smoothing + smoothed_paddle_x = paddle_x + smoothed_paddle_y = paddle_y + + # Initialize target variables + target_radius = 20 + targets = [(random.randint(50, swidth - 50), random.randint(50, sheight - 200)) for i in range(5)] + + while cap.isOpened(): + ret, frame = cap.read() + if not ret: + break + + frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) + results = hands.process(frame_rgb) + + if results.multi_hand_landmarks: + hand_landmarks = results.multi_hand_landmarks[0] + index_finger_tip = hand_landmarks.landmark[mp_hands.HandLandmark.INDEX_FINGER_TIP] + new_paddle_x = int(index_finger_tip.x * swidth) + new_paddle_y = int(index_finger_tip.y * sheight) + + # Apply smoothing + smoothed_paddle_x = int(smoothed_paddle_x * (1 - smoothing_factor) + new_paddle_x * smoothing_factor) + smoothed_paddle_y = int(smoothed_paddle_y * (1 - smoothing_factor) + new_paddle_y * smoothing_factor) + + paddle_x = smoothed_paddle_x + paddle_y = smoothed_paddle_y + + # Update puck position + puck_x += puck_velocity[0] + puck_y += puck_velocity[1] + + # This is to check collision with walls and if there is any collision then change the direction of movement of puck + if puck_x - puck_radius <= 0 or puck_x + puck_radius >= swidth: + puck_velocity[0] = -puck_velocity[0] + + if puck_y - puck_radius <= 0 or puck_y + puck_radius >= sheight: + puck_velocity[1] = -puck_velocity[1] + + # Check collision with the paddle + if ( + paddle_x - paddle_width // 2 <= puck_x <= paddle_x + paddle_width // 2 + and paddle_y - paddle_height // 2 <= puck_y <= paddle_y + paddle_height // 2 + ): + puck_velocity[1] = -puck_velocity[1] + + # Check collision with targets + hit_targets = [] + for target in targets: + target_x, target_y = target + # Calculate distance from the puck to the center of the target + distance = ((puck_x - target_x) ** 2 + (puck_y - target_y) ** 2) ** 0.5 + + '''Here, I am considering that a target is hit only when it hits the donut(circle) + . That's why I have used the radius of the circle inscribed in the square.''' + inscribed_circle_radius = min(target_width, target_height) / 2 + + # Check if the distance is within the inscribed circle + if distance <= inscribed_circle_radius: + score += 1 + hit_targets.append(target) + # This is to decrease the paddle size by 20 with each target hit so as to make it more challenging + paddle_width = max(10, paddle_width - 20) + # As I have mentioned before, this line of code is to increase the speed of puck to make the game more challenging + puck_speed += 2 + puck_velocity = [random.choice([-1, 1]) * puck_speed, random.choice([-1, 1]) * puck_speed] + + # Removing hit targets + for hit_target in hit_targets: + targets.remove(hit_target) + '''This piece of code is to remove the targets that are hit, first we sort the targets that are hit in a list and then remove them from the targets list''' + '''This is for drawing the puck and paddle on the screen''' + cv2.circle(frame, (puck_x, puck_y), puck_radius, (255, 0, 0), -1) + cv2.rectangle(frame, (paddle_x - paddle_width // 2, paddle_y - paddle_height // 2), + (paddle_x + paddle_width // 2, paddle_y + paddle_height // 2), (0, 255, 0), -1) + + # This is for drawing the targets + for target in targets: + target_x, target_y = target + target_region = frame[target_y - 15:target_y + 15, target_x - 15:target_x + 15] + + # Check if the target region has the correct shape (30x30) + if target_region.shape == (30, 30, 3): + frame[target_y - 15:target_y + 15, target_x - 15:target_x + 15] = target_image + else: + print("Error: Incorrect target region shape") + + # Horizontally flip the frame for the selfie camera view + frame = cv2.flip(frame, 1) + '''I have done this to give a mirror-like feeling while playing the game, which is more convenient''' + + # Drawing score and timer on the screen + elapsed_time = int(time.time() - start_time) + remaining_time = max(0, time_limit - elapsed_time) + cv2.putText(frame, f"Score: {score}", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2) + cv2.putText(frame, f"Time: {remaining_time}s", (swidth - 150, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, + (255, 255, 255), 2) + + # Display the frame + cv2.imshow("Air Hockey Game", frame) + + ''' This is to check for game over conditions; there are two conditions either the time is over or all targets are hit''' + if not targets or remaining_time == 0: + if not targets: + cv2.putText(frame, "Congratulations! All targets hit!", (swidth // 5, sheight // 2), + cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2) + else: + cv2.putText(frame, f"Game Over. Final Score: {score}", (swidth // 4, sheight // 2), + cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2) + cv2.imshow("Air Hockey Game", frame) + cv2.waitKey(0) + break + + # For quitting the game (press 'q' to quit) + if cv2.waitKey(1) & 0xFF == ord('q'): + break + + # To release resources + cap.release() + cv2.destroyAllWindows()