def dealHands(self, hands): """Deal out full hands.""" # Allow for a single hand if isinstance(hands, Hand): h = hands hands = Hands() hands.addHand(h) while True: cardDealt = False for hand in hands: if not isinstance(hand, Hand): raise InvalidHandTypeException("Bad hand type (%s)" % hand.__class__) if len(hand) < hand.getMaxCards(): try: hand.addCard(self.pop()) except IndexError: raise NotEnoughCardsException cardDealt = True if cardDealt == False: break
def __init__(self, packer, table_corners: tuple, packing_side, frame_size=(1366, 768)): self.animator = Animator(30) self.final_num_frames = WorkPlace.FINAL_FRAMES_NUM self.show_after_completion = True self.part_detections = [] self.active_wrist = None self.all_parts_are_in_box = False self.pack_task_completed = False self.all_visible_parts = [] self.box_detection = None self.previous_blurred_table = None self.part_tracker = ObjectTracker() self.part_detector = PartDetector() self.box_detector = BoxDetector() self.opened_box_tracker = ObjectTracker(distance_threshold=150) self.closed_box_tracker = ObjectTracker() self.next_pack_task_time = None self.cur_pack_task = None self.table_corners = { 'tl': table_corners[0], 'tr': table_corners[1], 'br': table_corners[2], 'bl': table_corners[3] } self.packer = packer self.packing_side = packing_side self.frame_size = frame_size self.rect_table_corners = self.calculate_rect_table_area() self.rect_work_place_corners = self.define_work_place_corners() self.worker_hands = Hands(self.rect_work_place_corners['tl']) self.width = self.rect_table_corners['br'][ 0] - self.rect_table_corners['tl'][0] self.height = self.rect_table_corners['br'][ 1] - self.rect_table_corners['tl'][1]
def __init__(self, numHands = 0, hands=None): assertInstance(numHands, int) self.deck = self.deckClass() if numHands and (numHands > self.getMaxHands()): raise TooManyHandsException self.numHands = numHands self.hands = Hands() self.lowHandsWin = (self.lowHandRankerClass != None) if self.lowHandRankerClass: self.lowHandRanker = self.lowHandRankerClass() self.highHandsWin = (self.highHandRankerClass != None) if self.highHandRankerClass: self.highHandRanker = self.highHandRankerClass() self.highWins = [] self.lowWins = [] self.scoops = [] if hands: self.addHands(hands)
def simulateGame(self): self.__checkStatArrays() self.gameNum += 1 # Make a copy of deck, hands and board deck = self.deck.copy() deck.shuffle() hands = Hands() for hand in self.hands: if isinstance(hand, HandGenerator): hands.addHand(hand.generateHand(deck = deck)) else: hands.addHand(hand.copy()) # If we have less than numHands, fill it out while len(hands) < self.numHands: hands.addHand(self.handClass()) if self.board is None: board = None else: board = self.board.copy() # Fill out hands and board deck.dealHands(hands) if board is not None: # Deal board deck.dealHands(board) for hand in hands: hand.setBoard(board) self.lastGameBoard = board self.lastGameHands = hands # Find winning hands if self.highHandsWin: (bestHighRank, highWinners) = self._findHighHands(hands, board) self.lastGameHighWinners = highWinners self.lastGameHighRank = bestHighRank for winner in highWinners: self.highWins[winner] += 1 if self.lowHandsWin is True: (bestLowRank, lowWinners) = self._findLowHands(hands, board) self.lastGameLowWinners = lowWinners self.lastGameLowRank = bestLowRank for winner in lowWinners: self.lowWins[winner] += 1 if self.lowHandsWin and self.highHandsWin: self.lastGameScooper = self._findScooper(lowWinners, highWinners) if self.lastGameScooper is not None: self.scoops[self.lastGameScooper] += 1
def simulate_game(self): # Make a copy of deck, hands and board deck = self.deck.copy() deck.shuffle() hands = Hands() # Deal out predefined hands if self.predefined_hands is not None: for hand in self.predefined_hands: if isinstance(hand, HandGenerator): hands.addHand(hand.generateHand(deck = deck)) else: hands.addHand(hand.copy()) deck.removeCards(hand) # If we have less than numHands, fill it out while len(hands) < self.number_of_hands: hands.addHand(self.HandClass()) if self.board is None: board = None else: board = self.board.copy() # Fill out hands and board deck.dealHands(hands) if board is not None: # Deal board deck.dealHands(board) for hand in hands: hand.setBoard(board) result = Result(hands, board=board) # Find winning hands if self.high_ranker is not None: (high_winners, bestHighRank) = self.high_ranker.bestHand(hands) result.high_winners = high_winners result.winning_high_rank = bestHighRank if self.low_ranker is not None: (low_winners, bestLowRank) = self.low_ranker.bestHand(hands) result.low_winners = low_winners result.winning_low_rank = bestLowRank return result
class PokerGame: # Type of hand used in this game, should be redefined in subclasses handClass = Hand # Type of Deck used in this game deckClass = Deck # Name of this game gameName = "Poker" # Support for board here, but don't allow setting in this class board = None # Class to use to determine rank for hi and/or low # If == None then no winner in that direction. highHandRankerClass = Ranker lowHandRankerClass = None # Ranker instances to use to determine hand ranks highHandRanker = None lowHandRanker = None # Low hand must be eight or berrer? lowHandEightOrBetter = False # For each hand, number of wins high highWins = [] # For each hand, number of wins low lowWins = [] # For each hand, number of scoops (wins both ways) scoops = [] # What game number are we playing gameNum = 0 # Hands from last game simulated lastGameHands = None # Board from last game simulated lastGameBoard = None # High winners for last game simulated lastGameHighWinners = None # High rank for last game simulated lastGameHighRank = None # Low winners for last game simulated lastGameLowWinners = None # Low rank for last game simulated lastGameLowRank = None # Scoopers for last game simulated lastGameScoopers = None def __init__(self, numHands = 0, hands=None): assertInstance(numHands, int) self.deck = self.deckClass() if numHands and (numHands > self.getMaxHands()): raise TooManyHandsException self.numHands = numHands self.hands = Hands() self.lowHandsWin = (self.lowHandRankerClass != None) if self.lowHandRankerClass: self.lowHandRanker = self.lowHandRankerClass() self.highHandsWin = (self.highHandRankerClass != None) if self.highHandRankerClass: self.highHandRanker = self.highHandRankerClass() self.highWins = [] self.lowWins = [] self.scoops = [] if hands: self.addHands(hands) def resetStats(self): numHands = max(len(self.hands), self.numHands) if self.highHandsWin: self.highWins = [ 0 ] * numHands if self.lowHandsWin: self.lowWins = [ 0 ] * numHands if self.lowHandsWin and self.highHandsWin: self.scoops = [ 0 ] * numHands self.gameNum = 0 def __checkStatArrays(self): """Make sure all the statistic arrays are long enough. In case a hand was added since we last simualted a game.""" if len(self.highWins) < len(self.hands): self.highWins.extend([ 0 ] * (len(self.hands)-len(self.highWins))) if len(self.lowWins) < len(self.hands): self.lowWins.extend([ 0 ] * (len(self.hands)-len(self.lowWins))) if len(self.scoops) < len(self.hands): self.scoops.extend([ 0 ] * (len(self.hands)-len(self.scoops))) @classmethod def getHandClass(cls): return cls.handClass def addHands(self, hands): if hands is None: return if isinstance(hands, Hand) or isinstance(hands, HandGenerator): hands = [ hands ] if len(self.hands) + len(hands) > self.getMaxHands(): raise TooManyHandsException for hand in hands: if hand is None: self.hands.addHand(self.handClass()) else: self.hands.addHand(hand) self.deck.removeCards(hand) def addHand(self, hand): assertInstance(hand, Hand) self.addHands(hand) def addHandGenerator(self, hg): assertInstance(hg, HandGenerator) self.hands.addHand(hg) @classmethod def getMaxHands(cls): cardsPerHand = cls.handClass.maxCards if cls.hasBoard(): boardCards = cls.handClass.boardClass.maxCards else: boardCards = 0 numCards = cls.deckClass.numCards - boardCards return int(numCards/cardsPerHand) def getNumHands(self): return max(self.numHands, len(self.hands)) def getHands(self): return self.hands @classmethod def hasBoard(cls): return (cls.handClass.boardClass != None) def setBoard(self, board): if not self.hasBoard(): raise HandHasNoBoardException() if board: assertInstance(board, Cards) self.deck.removeCards(board) self.board = board def getBoard(self): if not self.hasBoard(): raise HandHasNoBoardException() return self.board def getHighWins(self): """Return an array with how many times each hand won high.""" if not self.highHandsWin: return None return self.highWins def getLowWins(self): """Return an array with how many times each hand won low.""" if not self.lowHandsWin: return None return self.lowWins def getWins(self): """Return total wins by each hand (high or low).""" if not self.lowHandsWin: return self.highWins if not self.highHandsWin: return self.lowWins wins = [] for hand in self.highWins: wins = self.highWins[hand] + self.lowWins[hand] return wins def getScoops(self): """Return an array with how many times each hand won both ways.""" if not (self.highHandsWin and self.lowHandsWin): return None return self.scoops def simulateGames(self, numGames = 100, callback=None, callbackArg=None, resetStats = True): """Simulate a bunch of games with starting hands. Returns a array with number of wins for each hand.""" assertInstance(numGames, int) if self.getNumHands() == 0: raise PokerGameStateException("Zero hands defined.") if resetStats: self.resetStats() while self.gameNum < numGames: self.simulateGame() if callback is not None: if callbackArg: callback(self, callbackArg) else: callback(self) def simulateGame(self): self.__checkStatArrays() self.gameNum += 1 # Make a copy of deck, hands and board deck = self.deck.copy() deck.shuffle() hands = Hands() for hand in self.hands: if isinstance(hand, HandGenerator): hands.addHand(hand.generateHand(deck = deck)) else: hands.addHand(hand.copy()) # If we have less than numHands, fill it out while len(hands) < self.numHands: hands.addHand(self.handClass()) if self.board is None: board = None else: board = self.board.copy() # Fill out hands and board deck.dealHands(hands) if board is not None: # Deal board deck.dealHands(board) for hand in hands: hand.setBoard(board) self.lastGameBoard = board self.lastGameHands = hands # Find winning hands if self.highHandsWin: (bestHighRank, highWinners) = self._findHighHands(hands, board) self.lastGameHighWinners = highWinners self.lastGameHighRank = bestHighRank for winner in highWinners: self.highWins[winner] += 1 if self.lowHandsWin is True: (bestLowRank, lowWinners) = self._findLowHands(hands, board) self.lastGameLowWinners = lowWinners self.lastGameLowRank = bestLowRank for winner in lowWinners: self.lowWins[winner] += 1 if self.lowHandsWin and self.highHandsWin: self.lastGameScooper = self._findScooper(lowWinners, highWinners) if self.lastGameScooper is not None: self.scoops[self.lastGameScooper] += 1 def _findHighHands(self, hands, board): highWinners = [ 0 ] bestHighRank = self.highHandRanker.rankHand(hands[0]) for index in range(1,len(hands)): rank = self.highHandRanker.rankHand(hands[index]) if rank == bestHighRank: highWinners.append(index) elif rank > bestHighRank: highWinners = [index] bestHighRank = rank return (bestHighRank, highWinners) def _findLowHands(self, hands, board): if self.lowHandEightOrBetter and (board is not None): # See if low is possible given board if board.eightLowPossible() is False: # Nope, don't bother checking for low hands return (None, []) bestLowRank = None lowWinners = [] for index in range(len(hands)): hand = hands[index] if (self.lowHandEightOrBetter and (hand.eightLowPossible() is False)): # Hand cannot qualify for low, don't bother checking continue rank = self.lowHandRanker.rankHand(hand) if (self.lowHandEightOrBetter and (not rank.isEightOrBetterLow())): # Hand did not qualify for low continue if ((bestLowRank is None) or (rank < bestLowRank)): lowWinners = [index] bestLowRank = rank elif rank == bestLowRank: lowWinners.append(index) return (bestLowRank, lowWinners) def _findScooper(self, lowWinners, highWinners): """Was there one winner of the whole pot?""" if ((len(lowWinners) == 1) and (len(highWinners) == 1) and (lowWinners[0] == highWinners[0])): return lowWinners[0]; return None def lastGameToString(self): import string s="" if self.hasBoard(): s += "Board: " + str(self.lastGameBoard) + " " if self.highHandsWin: s += "High: %s " % self.lastGameHighRank s += "(" s += ",".join(["%d:%s" % (hand + 1, self.lastGameHands[hand]) for hand in self.lastGameHighWinners]) s += ") " if self.lowHandsWin and len(self.lastGameLowWinners): s += "Low: %s " % self.lastGameLowRank s += "(" s += ",".join(["%d:%s" % (hand + 1, self.lastGameHands[hand]) for hand in self.lastGameLowWinners]) s += ") " if self.lowHandsWin and self.highHandsWin: if self.lastGameScooper is not None: s += "(Hand %d scoops)" % (self.lastGameScooper + 1) s.strip() return s def statsToString(self): s = "" for hand in range(self.getNumHands()): s += "%2d:" % (hand + 1) if hand >= len(self.hands): handStr = "XX " * self.handClass.getMaxCards() s += handStr else: s += str(self.hands[hand]) + " " if self.highHandsWin: wins = self.highWins[hand] s += "High wins %4d (%3.0f%%)" % ( wins, 100.0 * wins / self.gameNum) if self.lowHandsWin: wins = self.lowWins[hand] s += " Low wins %4d (%3.0f%%)" % ( wins, 100.0 * wins / self.gameNum) if self.highHandsWin and self.lowHandsWin: s += " Scoops: %d" % self.scoops[hand] s += "\n" return s
def hand(): hand = Hands() return hand
class WorkPlace: WORKER_PLACE_SIZE = 300 FINAL_FRAMES_NUM = 60 def calculate_rect_table_area(self): tcs = self.table_corners min_x, min_y = min(tcs['tl'][0], tcs['bl'][0]), min(tcs['tl'][1], tcs['tr'][1]) max_x, max_y = max(tcs['tr'][0], tcs['br'][0]), max(tcs['bl'][1], tcs['br'][1]) rect_table_corners = {'tl': (min_x, min_y), 'br': (max_x, max_y)} return rect_table_corners font = ImageFont.truetype("arial.ttf", 16) bold_font = ImageFont.truetype("arial_bold.ttf", 16) large_font = ImageFont.truetype("arial.ttf", 20) line_height_size = 20 def get_table_view_from_frame(self, frame: np.ndarray): table_rect = self.rect_table_corners return frame[table_rect['tl'][1]:table_rect['br'][1], table_rect['tl'][0]:table_rect['br'][0]] def get_work_place_view_from_frame(self, frame: np.ndarray): work_pl_rect = self.rect_work_place_corners return frame[work_pl_rect['tl'][1]:work_pl_rect['br'][1], work_pl_rect['tl'][0]:work_pl_rect['br'][0]] def __init__(self, packer, table_corners: tuple, packing_side, frame_size=(1366, 768)): self.animator = Animator(30) self.final_num_frames = WorkPlace.FINAL_FRAMES_NUM self.show_after_completion = True self.part_detections = [] self.active_wrist = None self.all_parts_are_in_box = False self.pack_task_completed = False self.all_visible_parts = [] self.box_detection = None self.previous_blurred_table = None self.part_tracker = ObjectTracker() self.part_detector = PartDetector() self.box_detector = BoxDetector() self.opened_box_tracker = ObjectTracker(distance_threshold=150) self.closed_box_tracker = ObjectTracker() self.next_pack_task_time = None self.cur_pack_task = None self.table_corners = { 'tl': table_corners[0], 'tr': table_corners[1], 'br': table_corners[2], 'bl': table_corners[3] } self.packer = packer self.packing_side = packing_side self.frame_size = frame_size self.rect_table_corners = self.calculate_rect_table_area() self.rect_work_place_corners = self.define_work_place_corners() self.worker_hands = Hands(self.rect_work_place_corners['tl']) self.width = self.rect_table_corners['br'][ 0] - self.rect_table_corners['tl'][0] self.height = self.rect_table_corners['br'][ 1] - self.rect_table_corners['tl'][1] def set_cur_pack_task(self, cur_pack_task): self.cur_pack_task = cur_pack_task def set_next_pack_task_time(self, next_pack_task_time): self.next_pack_task_time = next_pack_task_time def reset_pack_task(self): self.part_tracker = ObjectTracker() self.closed_box_tracker = ObjectTracker() self.opened_box_tracker = ObjectTracker(distance_threshold=150) self.pack_task_completed = False self.all_parts_are_in_box = False self.part_detections = [] self.all_visible_parts = [] self.show_after_completion = True self.final_num_frames = WorkPlace.FINAL_FRAMES_NUM self.box_detection = None def define_work_place_corners(self): rect_table_corners_copy = copy.deepcopy(self.rect_table_corners) rect_table_corners_copy = { key: list(value) for key, value in rect_table_corners_copy.items() } rect_work_place_corners = calculate_work_place_size[self.packing_side]( rect_table_corners_copy) rect_work_place_corners['tl'][0] = 0 if rect_work_place_corners['tl'][ 0] < 0 else rect_work_place_corners['tl'][0] rect_work_place_corners['tl'][1] = 0 if rect_work_place_corners['tl'][ 1] < 0 else rect_work_place_corners['tl'][1] rect_work_place_corners['br'][0] = self.frame_size[0] if rect_work_place_corners['br'][0] > self.frame_size[ 0] else \ rect_work_place_corners['br'][0] rect_work_place_corners['br'][1] = self.frame_size[1] if rect_work_place_corners['br'][1] > self.frame_size[ 1] else \ rect_work_place_corners['br'][1] return rect_work_place_corners def detect_parts(self, frame, parts_detections: list): if not parts_detections or self.all_parts_are_in_box: return frame = self.get_work_place_view_from_frame(frame) parts_detections = [ detection for detection in parts_detections if self.is_rect_in_work_place(detection[2]) ] best_detections = self.part_detector.detect(self.cur_pack_task, parts_detections) table_best_detections = [] for best_detection in best_detections: best_detection.object_shape.set_box_rect( self.transform_coords_from_whole_frame_to_work_place_axis( best_detection.object_shape.box_rect)) table_best_detections.append(best_detection) self.part_detections = self.part_tracker.track(frame, table_best_detections) self.update_undetected_pack_items() self.update_detected_pack_items() def update_detected_pack_items(self): in_box_part_detections = [ (i, part_detection) for i, part_detection in enumerate(self.all_visible_parts) if part_detection.is_in_box() ] if len(in_box_part_detections) == len(self.cur_pack_task): self.all_parts_are_in_box = True return tracked_part_detections = [ (i, part_detection) for i, part_detection in enumerate(self.all_visible_parts) if part_detection.is_tracked() ] moved_part_detections = [ (i, part_detection) for i, part_detection in enumerate(self.all_visible_parts) if part_detection.is_moved() ] if self.box_detection: box_rect = self.box_detection.object_shape.tl_box_rect for j, (i, tracked_part_detection ) in enumerate(tracked_part_detections): part_box_rect = tracked_part_detection.object_shape.tl_box_rect if are_rectangles_intersect(box_rect, part_box_rect): percent_intersection = int( rect_square( rectangles_intersection(box_rect, part_box_rect)) / rect_square(part_box_rect) * 100) # 30 is an intersection of the part and the box in percent to consider part inside of the box if percent_intersection > 40: self.all_visible_parts[i].set_status_as_in_box() self.part_tracker.del_tracker( self.all_visible_parts[i].part) del tracked_part_detections[j] # make sure that worker moved only one item per time into the box assert len(moved_part_detections) < 2 for i, moved_part_detection in moved_part_detections: wrist_point, _ = self.get_active_wrist_point() if wrist_point and is_point_in_rect(wrist_point, box_rect): self.all_visible_parts[i].set_status_as_in_box() self.active_wrist = None for i, tracked_part_detection in tracked_part_detections: shift_history = self.part_tracker.get_shift_histories_by_part( tracked_part_detection.part) # part shift in through n-frames in pixels to consider the part as moved by a hand if sum(shift_history) > 20: nearest_wrist, dist = self.worker_hands.get_nearest_wrist_to_rect( tracked_part_detection.object_shape.box_rect) # 100 is empirical value if dist < 100: self.all_visible_parts[i].set_status_as_moved() self.part_tracker.del_tracker( self.all_visible_parts[i].part) pack_task = [ pack_task_item for pack_task_item in self.cur_pack_task if pack_task_item.part is tracked_part_detection.part ][0] self.active_wrist = nearest_wrist, pack_task self.animator.generate_animation( self.generate_color_by_index(pack_task.index), (255, 255, 255)) def get_active_wrist_point(self): if not self.active_wrist: return None, None wrist_point = self.worker_hands.points[self.active_wrist[0]] pack_task = self.active_wrist[1] return (wrist_point, pack_task) if wrist_point else (None, None) def update_undetected_pack_items(self): not_detected_parts = [ pack_task_item.part for pack_task_item in self.cur_pack_task if not pack_task_item.is_detected() ] for i, part_detection in enumerate(self.part_detections): if part_detection.part in not_detected_parts: index = [pack_task.part for pack_task in self.cur_pack_task ].index(part_detection.part) # NOT SMART BUT THAT IS WHAT IT IS if self.cur_pack_task[index].part_class == 'dt_pack_small': indices = [ i for i, pack_task in enumerate(self.cur_pack_task) if pack_task.part_class == 'dt_pack_small' ] position = indices[1] if index == indices[0] else indices[0] self.cur_pack_task[position].set_status_as_detected() self.all_parts_are_in_box = True self.cur_pack_task[index].set_status_as_detected() self.all_visible_parts.append(part_detection) def visualize_part_detections(self, frame): for i, part_detection in enumerate(self.part_tracker.get_detections()): shape = part_detection.object_shape points = [ shape.box_rect_center, shape.tm_point_rect, shape.rm_point_rect ] points = [(point[0] + self.rect_work_place_corners['tl'][0], point[1] + self.rect_work_place_corners['tl'][1]) for point in points] print_pos, index = \ [(next_pack_task.print_pos, next_pack_task.index) for next_pack_task in self.cur_pack_task if next_pack_task.part is part_detection.part][0] color = self.generate_color_by_index(index) box_rect = tuple( (shape.box_rect[0] + self.rect_work_place_corners['tl'][0], shape.box_rect[1] + self.rect_work_place_corners['tl'][1], *shape.box_rect[2:])) cv2.rectangle(frame, box_rect, color, 2) def putText(x, y, value: float): cv2.putText(frame, f'{int(value)} px', (x, y), cv2.FONT_HERSHEY_SIMPLEX, 0.65, (0, 0, 255), 2) putText(*points[0], sum(self.part_tracker.shift_histories[i])) print_pos = (print_pos[0] - 3, int(print_pos[1] + WorkPlace.line_height_size / 2 - 1)) cv2.circle(frame, print_pos, 3, color, -1) cv2.circle(frame, points[0], 3, color, -1) cv2.line(frame, print_pos, points[0], color, 2) def apply_tasks_on_frame(self, frame): im = Image.fromarray(frame) draw = ImageDraw.Draw(im) packed_parts = [ part_detection.part for part_detection in self.all_visible_parts if part_detection.is_in_box() ] def draw_text(x, y, task, color, is_labeling, is_bold=False): label = ' X ' if is_labeling else '' color = (0, 255, 0) if is_labeling else color font = WorkPlace.bold_font if is_bold else WorkPlace.font draw.text( (x, y), f"{label}{task.part.name} ({task.amount}), " f"{task.part.height}x{task.part.width}x{task.part.depth}", color, font=font) def draw_name_info(x, y, name, pack_number, color): font = WorkPlace.large_font color = (0, 255, 0) if self.pack_task_completed else color draw.text((x, y), f"Task #{pack_number}", color, font=font) x_value, y_value = None, None if self.packing_side == 'Left': y_value = 110 x_value = 5 elif self.packing_side == 'Right': y_value = 110 x_value = frame.shape[1] - 450 pack_number = self.cur_pack_task[0].part.pack_number draw_name_info(x_value, 10, self.packer.split(' ')[0], pack_number, (0, 255, 255)) for cur_task in self.cur_pack_task: bold = False # HARDCODE label_item = cur_task.part in packed_parts or self.all_parts_are_in_box color = self.generate_color_by_index( cur_task.index) if cur_task.is_detected() else (0, 0, 0) if cur_task.is_detected(): bold = True draw_text(x_value, y_value, cur_task, color, label_item, is_bold=bold) cur_task.print_pos = (x_value, y_value) y_value += WorkPlace.line_height_size frame = np.asarray(im) return frame def generate_color_by_index(self, index): if index is None: return None tasks_num = len(self.cur_pack_task) color_step = int(255 / (tasks_num / 3)) bgr = 255, 255, 255 lvl = index // 3 bgr = [channel - lvl * color_step for channel in bgr] bgr[index % 3] -= color_step return tuple(bgr) def visualize_box_detections(self, frame): table_part_of_frame = self.get_work_place_view_from_frame(frame) def draw_box(box, color): cv2.rectangle(table_part_of_frame, box.object_shape.box_rect, color, 2) cv2.putText( table_part_of_frame, f'{PackBox.reversed_statuses[box.status]} ({box.probability}%)', box.object_shape.box_rect_center, cv2.FONT_HERSHEY_COMPLEX, 0.7, color, 2) if self.opened_box_tracker: for box in self.opened_box_tracker.detections: draw_box(box, (255, 255, 255)) if self.closed_box_tracker: for box in self.closed_box_tracker.detections: draw_box(box, (0, 0, 255)) def visualize_closed_box(self, frame): def draw_box(box, color): table_part_of_frame = self.get_work_place_view_from_frame(frame) cv2.rectangle(table_part_of_frame, box.object_shape.box_rect, color, 2) cv2.putText( table_part_of_frame, f'{PackBox.reversed_statuses[box.status]} ({box.probability}%)', box.object_shape.box_rect_center, cv2.FONT_HERSHEY_COMPLEX, 0.7, color, 2) draw_box(self.box_detection, (255, 255, 255)) self.decrease_final_frames_num() def decrease_final_frames_num(self): self.final_num_frames -= 1 if self.final_num_frames <= 0: self.show_after_completion = False def detect_opened_boxes(self, frame, opened_box_detections): pack_box = self.get_pack_box_from_boxes(opened_box_detections, PackBox.statuses['Opened'], 0.40, None) return self.opened_box_tracker.track(frame, pack_box) def detect_closed_boxes(self, frame, closed_box_detections): pack_box = self.get_pack_box_from_boxes( closed_box_detections, PackBox.statuses['Closed'], 0.40, self.box_detection.object_shape.box_rect_center, distance=200) return self.closed_box_tracker.track(frame, pack_box) def get_pack_box_from_boxes(self, box_detections, status, probability, reference, distance=math.inf): opened_box_detections = [ detection for detection in box_detections if self.is_rect_in_work_place(detection[2]) ] pack_box = [] if opened_box_detections: opened_box_detections = [ (box_detection[1], self.transform_coords_from_whole_frame_to_work_place_axis( box_detection[2])) for box_detection in opened_box_detections ] opened_box_detections = [(box_dect[0], ObjectShape(box_dect[1])) for box_dect in opened_box_detections] if reference: # for bx in opened_box_detections: # print('dist', # dist.cdist([bx[1].box_rect_center], [self.box_detection.object_shape.box_rect_center])) opened_box_detections = [ (prob, shape) for prob, shape in opened_box_detections if dist.cdist([shape.box_rect_center], [ self.box_detection.object_shape.box_rect_center ])[0][0] < distance ] if opened_box_detections: best_box_detection = max(opened_box_detections, key=lambda detection: detection[0]) if best_box_detection[0] > probability: pack_box = [ PackBox(best_box_detection[1], status, int(best_box_detection[0] * 100)) ] return pack_box def is_rect_in_work_place(self, rect): wp = self.rect_work_place_corners xs = rect[0] - rect[2] / 2, rect[0] + rect[2] / 2 ys = rect[1] - rect[3] / 2, rect[1] + rect[3] / 2 return all([wp['tl'][0] <= x <= wp['br'][0] for x in xs]) and all( [wp['tl'][1] <= y <= wp['br'][1] for y in ys]) def is_point_in_work_place(self, point): tb = self.rect_work_place_corners return is_num_in_range(point[0], (tb['tl'][0], tb['br'][0])) and is_num_in_range( point[1], (tb['tl'][1], tb['br'][1])) def transform_coords_from_whole_frame_to_work_place_axis(self, rect): if not rect: return None wp = self.rect_work_place_corners new_rect = (rect[0] - wp['tl'][0], rect[1] - wp['tl'][1], *rect[2:]) return new_rect def transform_coords_from_work_place_axis_to_whole_frame(self, rect): if not rect: return None wp = self.rect_work_place_corners new_rect = (rect[0] + wp['tl'][0], rect[1] + wp['tl'][1], *rect[2:]) return new_rect def detect_boxes(self, frame, boxes_detections): frame = self.get_work_place_view_from_frame(frame) if not self.box_detection: boxes_detections = tuple(detection for detection in boxes_detections if detection[0] == 'pb_open') result = self.detect_opened_boxes(frame, boxes_detections) self.box_detection = result[0] if result else None elif self.box_detection.status == PackBox.statuses[ 'Opened'] and not self.all_parts_are_in_box: result = self.opened_box_tracker.update(frame) self.box_detection = result[0] if result else None elif self.box_detection.status == PackBox.statuses[ 'Opened'] and self.all_parts_are_in_box: self.opened_box_tracker = None boxes_detections = tuple(detection for detection in boxes_detections if detection[0] == 'pb_closed') result = self.detect_closed_boxes(frame, boxes_detections) if result: self.box_detection = result[0] self.pack_task_completed = True def visualize_hand_detections(self, frame): table_area_frame = self.get_work_place_view_from_frame(frame) self.worker_hands.draw_skeleton(table_area_frame) wrist_point, pack_task = self.get_active_wrist_point() if self.animator.is_animation_not_finished(): wrist_point = self.transform_coords_from_work_place_axis_to_whole_frame( wrist_point) label_point = pack_task.print_pos if pack_task else None self.animator.play_animation(frame, wrist_point, label_point) if wrist_point: color = self.generate_color_by_index(pack_task.index) cv2.circle(table_area_frame, wrist_point, 10, color, -1) def detect_hands(self, hands_detections): for hands_detection in hands_detections: for point in hands_detection.values(): if not point: continue if self.is_point_in_work_place(point): self.worker_hands.set_new_points(hands_detection) break
def play_game(): global DISPLAY_SCREEN, DEFAULT_FONT #declared display screen and a default font as global variables so they can be accessed in other functions #initialize pygame pygame.init() #loads music file file = 'music.wav' pygame.mixer.music.load(file) #plays music file pygame.mixer.music.play() FOOTBALL_SPEED = 0.1 POINTS_PER_CATCH = 2 ROUND_SIZE = 1 ROUND_LEVEL_UP = 8 SPEED_UP = 1.01 pygame.init() clock = pygame.time.Clock() DISPLAY_SCREEN = pygame.display.set_mode((DISPLAY_WIDTH, DISPLAY_HEIGHT), 0, 32) #creates display screen pygame.display.set_caption("PYCATCH 2K17") # set display screen caption DEFAULT_FONT = pygame.font.Font('freesansbold.ttf', 12) instructSurf = DEFAULT_FONT.render('Move Mouse Left and Right or Hold on to Mouse to Catch as Many Footballs As You Can! (K)Pause Screen (S)Unpause Screen', 1, BLUE) instructRect = instructSurf.get_rect() instructRect.topleft = (5, DISPLAY_HEIGHT - 40) #instructions will appear on the bottom of the screen while playing the game score = Score(DISPLAY_SCREEN, SCORE_HEIGHT) #create an instance of Score Class footballs = [Footballs(DISPLAY_SCREEN, FOOTBALL_SPEED)] #create an instance of Footballs class hands = Hands(DISPLAY_SCREEN, SCORE_HEIGHT) #create an instance of hand class gameOver = False gameLoop = False game_win = False while not gameLoop: time_elapsed = clock.tick(FPS) DISPLAY_SCREEN.fill(BACKGROUND_COLOR) #Fill in background of Display with a color mouse_x_pos, mouse_y_pos = pygame.mouse.get_pos()[0], pygame.mouse.get_pos()[1] #get mouse position DISPLAY_SCREEN.blit(instructSurf, instructRect) #blit the instructions onto screen hands.x_change = mouse_x_pos #img hands can be moved across the screen if clicked and held onto if hands.grabbed: hands.y_change = mouse_y_pos else: hands.y_change = hands.img_height / 2 + SCORE_HEIGHT hands.refresh() hands.output() #display hands and update check_events(hands, mouse_x_pos, mouse_y_pos) #calls check events function to check if mouse was clicked or held onto #if there are no footballs on the screen, speed up footballs and append onto screen if len(footballs) == 0: for x in range(0, ROUND_SIZE): FOOTBALL_SPEED *= SPEED_UP footballs.append(Footballs(DISPLAY_SCREEN, FOOTBALL_SPEED)) #if footballs missed is greater than footballs catched, game over loop runs if score.footballs_missed > score.footballs_catched: gameOver = True #gameover loop, outputs a message and gives user options to play again or quit while gameOver == True: DISPLAY_SCREEN.fill(BLUE) font = pygame.font.Font('freesansbold.ttf', 21) screen_text = font.render("GAME OVER! MISSED > CATCHED! (P) PLAY AGAIN" " (Q) QUIT GAME", 1, ORANGE) gameRect = screen_text.get_rect() gameRect.topleft = (20, DISPLAY_HEIGHT/2) DISPLAY_SCREEN.blit(screen_text, gameRect) #checks for events, if user presses p then the game starts again if q, then game exits. for event in pygame.event.get(): if event.type == pygame.QUIT: sys.exit() if event.type == pygame.KEYDOWN: if event.key == pygame.K_q: gameOver = False gameLoop = True if event.key == pygame.K_p: play_game() pygame.display.update() #if footballs catched is greater than 225 then game_win loop runs if score.footballs_catched > 225: game_win = True #displays a message on screen indicating that the winner has won. #Give user options to play again or quit while game_win == True: DISPLAY_SCREEN.fill(BLUE) font = pygame.font.Font('freesansbold.ttf', 19) screen_text = font.render("YOU WIN! Caught more than 225 FOOTBALLS! (P) PLAY AGAIN" " (Q) QUIT GAME", 1, ORANGE) gameRect = screen_text.get_rect() gameRect.topleft = (10, DISPLAY_HEIGHT/2) DISPLAY_SCREEN.blit(screen_text, gameRect) for event in pygame.event.get(): if event.type == pygame.QUIT: sys.exit() if event.type == pygame.KEYDOWN: if event.key == pygame.K_q: gameOver = False gameLoop = True if event.key == pygame.K_p: play_game() pygame.display.update() for event in pygame.event.get(): if event.type == pygame.QUIT: sys.exit() pressed = pygame.key.get_pressed() if pressed[pygame.K_p]: play_game() if pressed[pygame.K_q]: sys.exit() #updates score and removes it from the screen if it collided with hands. # This indicates that the basketball was catched # Basketball speed increases for ball in footballs: ball.update(time_elapsed) #score increases if objects collide if ball.rect.colliderect(hands.rect): score.footballs_catched += 1 score.score += POINTS_PER_CATCH footballs.remove(ball) FOOTBALL_SPEED *= 1.01 if score.footballs_catched % ROUND_LEVEL_UP == 0: ROUND_SIZE += 1 continue #if footballs goes off screen and has not collided with hands then the basketball was missed #missed score increments by 1 if ball.y_change < -ball.img_height / 2 + SCORE_HEIGHT: score.footballs_missed += 1 footballs.remove(ball) ball.output() #blits the football score.output() #displays the scoreboard pygame.display.update()