From 72284155ecad46e1c99a7ebe873a50ae1d9715e4 Mon Sep 17 00:00:00 2001 From: v3rchi3l Date: Mon, 29 Jan 2024 00:29:24 -0300 Subject: [PATCH 1/2] The function to recognize the cards on the table with the NN is added, it is left disabled for the general user, for collaborators the option must only be enabled in "QT designer". Parameters for training the NN are modified since it will be used to recognize the hand and the table. Simple conflicts are resolved in the TEST. ---.--- The result of the NN on the table was verified with an efficiency of 99.98%, the recognition is done by cutting the area of cards on the table by 10 and processing that image (eliminating cloth and other colors) to result in 0/3/4/5 cards corresponding to the game states, I only configured this in GGpoker, that part needs to be improved. --- poker/gui/ui/table_setup_form.ui | 3451 +++++++++-------- poker/scraper/table_scraper.py | 97 +- poker/scraper/table_scraper_nn.py | 58 +- poker/scraper/table_screen_based.py | 5 - .../table_setup_actions_and_signals.py | 25 + poker/tests/test_montecarlo.py | 4 +- poker/tests/test_tensorflow.py | 33 +- 7 files changed, 1933 insertions(+), 1740 deletions(-) diff --git a/poker/gui/ui/table_setup_form.ui b/poker/gui/ui/table_setup_form.ui index e373eb4c..02fcd303 100644 --- a/poker/gui/ui/table_setup_form.ui +++ b/poker/gui/ui/table_setup_form.ui @@ -28,7 +28,7 @@ - 0 + 2 @@ -805,1749 +805,1780 @@ Cards - - - - - - - For Tables where cards may be different at times (e.g. rotated) - - - - - - - <html><head/><body><p>If this is ticked, my cards will be recognized via neural network instead of exact temlate matching. This will have a higher tolerance for recognition and allow cards to be slightly different or rotated. </p></body></html> - - - Neural Network based recognition for My Cards - - - - - - - - - <html><head/><body><p>Exact location of the card the bot is holding. This should be as close to the same size as the card templates so it's easier for recognition with neural network. </p></body></html> - - - Right Card Area - - - - - - - - 4 - 0 - - - - <html><head/><body><p>Exact location of the card the bot is holding. This should be as close to the same size as the card templates so it's easier for recognition with neural network. </p></body></html> - - - Left Card Area - - - - - - - Show - - - - - - - Show - - - - - - - - - - - Ensure to mark as narrowly as possible. Don't mark the full card, but only the number and the symbol. - - - Images - - + + + + 9 + 9 + 352 + 751 + + + + Ensure to mark as narrowly as possible. Don't mark the full card, but only the number and the symbol. + + + Images + + + + - - - - - - - - 16 - - - - - - - Qt::AlignCenter - - - - - - - - 35 - 16777215 - - - - 2C - - - false - - - - - - - - 35 - 16777215 - - - - 3C - - - - - - - - 35 - 16777215 - - - - 4C - - - - - - - - 35 - 16777215 - - - - 5C - - - - - - - - 35 - 16777215 - - - - 6C - - - - - - - - 35 - 16777215 - - - - 7C - - - - - - - - 35 - 16777215 - - - - 8C - - - - - - - - 35 - 16777215 - - - - 9C - - - - - - - - 35 - 16777215 - - - - TC - - - - - - - - 35 - 16777215 - - - - JC - - - - - - - - 35 - 16777215 - - - - QC - - - - - - - - 35 - 16777215 - - - - KC - - - - - - - - 35 - 16777215 - - - - AC - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - + + + + + + 16 + + + + + + + Qt::AlignCenter + + - - - - - - - 16 - - - - - - - Qt::AlignCenter - - - - - - - - 35 - 16777215 - - - - 2D - - - - - - - - 35 - 16777215 - - - - 3D - - - - - - - - 35 - 16777215 - - - - 4D - - - - - - - - 35 - 16777215 - - - - 5D - - - - - - - - 35 - 16777215 - - - - 6D - - - - - - - - 35 - 16777215 - - - - 7D - - - - - - - - 35 - 16777215 - - - - 8D - - - - - - - - 35 - 16777215 - - - - 9D - - - - - - - - 35 - 16777215 - - - - TD - - - - - - - - 35 - 16777215 - - - - JD - - - - - - - - 35 - 16777215 - - - - QD - - - - - - - - 35 - 16777215 - - - - KD - - - - - - - - 35 - 16777215 - - - - AD - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - + + + + + 35 + 16777215 + + + + 2C + + + false + + - - - - - - - 16 - - - - - - - Qt::AlignCenter - - - - - - - - 35 - 16777215 - - - - 2S - - - - - - - - 35 - 16777215 - - - - 3S - - - - - - - - 35 - 16777215 - - - - 4S - - - - - - - - 35 - 16777215 - - - - 5S - - - - - - - - 35 - 16777215 - - - - 6S - - - - - - - - 35 - 16777215 - - - - 7S - - - - - - - - 35 - 16777215 - - - - 8S - - - - - - - - 35 - 16777215 - - - - 9S - - - - - - - - 35 - 16777215 - - - - TS - - - - - - - - 35 - 16777215 - - - - JS - - - - - - - - 35 - 16777215 - - - - QS - - - - - - - - 35 - 16777215 - - - - KS - - - - - - - - 35 - 16777215 - - - - AS - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - + + + + + 35 + 16777215 + + + + 3C + + + + + + + + 35 + 16777215 + + + + 4C + + + + + + + + 35 + 16777215 + + + + 5C + + + + + + + + 35 + 16777215 + + + + 6C + + + + + + + + 35 + 16777215 + + + + 7C + + + + + + + + 35 + 16777215 + + + + 8C + + + + + + + + 35 + 16777215 + + + + 9C + + + + + + + + 35 + 16777215 + + + + TC + + + + + + + + 35 + 16777215 + + + + JC + + + + + + + + 35 + 16777215 + + + + QC + + + + + + + + 35 + 16777215 + + + + KC + + + + + + + + 35 + 16777215 + + + + AC + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + + + + + + 16 + + + + + + + Qt::AlignCenter + + + + + + + + 35 + 16777215 + + + + 2D + + + + + + + + 35 + 16777215 + + + + 3D + + + + + + + + 35 + 16777215 + + + + 4D + + + + + + + + 35 + 16777215 + + + + 5D + + + + + + + + 35 + 16777215 + + + + 6D + + + + + + + + 35 + 16777215 + + + + 7D + + + + + + + + 35 + 16777215 + + + + 8D + + + + + + + + 35 + 16777215 + + + + 9D + + + + + + + + 35 + 16777215 + + + + TD + + + + + + + + 35 + 16777215 + + + + JD + + + + + + + + 35 + 16777215 + + + + QD + + + + + + + + 35 + 16777215 + + + + KD + + + + + + + + 35 + 16777215 + + + + AD + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + + + + + + 16 + + + + + + + Qt::AlignCenter + + + + + + + + 35 + 16777215 + + + + 2S + + + + + + + + 35 + 16777215 + + + + 3S + + + + + + + + 35 + 16777215 + + + + 4S + + + + + + + + 35 + 16777215 + + + + 5S + + + + + + + + 35 + 16777215 + + + + 6S + + + + + + + + 35 + 16777215 + + + + 7S + + + + + + + + 35 + 16777215 + + + + 8S + + + + + + + + 35 + 16777215 + + + + 9S + + + + + + + + 35 + 16777215 + + + + TS + + + + + + + + 35 + 16777215 + + + + JS + + + + + + + + 35 + 16777215 + + + + QS + + + + + + + + 35 + 16777215 + + + + KS + + + + + + + + 35 + 16777215 + + + + AS + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + + 35 + 16777215 + + + + 3H + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + + 35 + 16777215 + + + + 7H + + + + + + + false + + + + 35 + 16777215 + + + + V + + - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - - 35 - 16777215 - - - - 3H - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - - 35 - 16777215 - - - - 7H - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - - 35 - 16777215 - - - - 8H - - - - - - - - 35 - 16777215 - - - - 5H - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - - 35 - 16777215 - - - - 9H - - - - - - - - 35 - 16777215 - - - - JH - - - - - - - - 16 - - - - - - - Qt::AlignCenter - - - - - - - - 35 - 16777215 - - - - 4H - - - - - - - - 35 - 16777215 - - - - QH - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - - 35 - 16777215 - - - - TH - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - - 35 - 16777215 - - - - KH - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - - 35 - 16777215 - - - - AH - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - - 35 - 16777215 - - - - 6H - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - - 35 - 16777215 - - - - 2H - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - + + + + + 35 + 16777215 + + + + 8H + + - - - - - - - - Used to recognize which players are still in the game. Mark very narrowly to ensure it's the same for all players. + + + + + 35 + 16777215 + - Covered card + 5H - - - - Qt::Vertical + + + + false + + + + 35 + 16777215 + - + + V + + + + + + - 20 - 40 + 35 + 16777215 - + + 9H + + - - - - <html><head/><body><p>The dealer button image. Make sure to select very narrowly and don't include any background that might change depending on it's location</p></body></html> + + + + + 35 + 16777215 + - Dealer button + JH - - + + + + + 16 + + + + + + + Qt::AlignCenter + + + + + + + + 35 + 16777215 + + + + 4H + + + + + + + + 35 + 16777215 + + + + QH + + + + + false + + + 35 + 16777215 + + - Show + V - - + + + + + 35 + 16777215 + + + + TH + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + + 35 + 16777215 + + + + KH + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + false + + + 35 + 16777215 + + - Show + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + + 35 + 16777215 + + + + AH + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + + 35 + 16777215 + + + + 6H + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + + 35 + 16777215 + + + + 2H + + + + + + + false + + + + 35 + 16777215 + + + + V - - - - - - - 0 - 0 - - - - <html><head/><body><p>Train the Neural Network to recognize the cards. This can take several minutes. For faster speed install CUDA and CUDNN (To find out more google Tensorflow GPU setup). The whole process can take up to 30 minutes. Please be patient.</p><p><br/></p></body></html> - - - Train Neural Network - - - - + + + + + + + false + + + Show + + + + + + + Used to recognize which players are still in the game. Mark very narrowly to ensure it's the same for all players. + + + Covered card + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 13 + 13 + + + + + + + + <html><head/><body><p>The dealer button image. Make sure to select very narrowly and don't include any background that might change depending on it's location</p></body></html> + + + Dealer button + + + + + + + false + + + Show + + + + + + + + + + + 20 + 750 + 329 + 162 + + + + + + + For Tables where cards may be different at times (e.g. rotated) + + + + + + + <html><head/><body><p>If this is ticked, my cards will be recognized via neural network instead of exact temlate matching. This will have a higher tolerance for recognition and allow cards to be slightly different or rotated. </p></body></html> + + + Neural Network based recognition for My Cards + + + + + + + false + + + <html><head/><body><p>If this is ticked, table cards will be recognized via neural network instead of exact temlate matching. This will have a higher tolerance for recognition and allow cards to be slightly different or rotated. </p></body></html> + + + 0 + + + Neural Network based recognition for Table Cards + + + + + + + + + <html><head/><body><p>Exact location of the card the bot is holding. This should be as close to the same size as the card templates so it's easier for recognition with neural network. </p></body></html> + + + Right Card Area + + + + + + + + 4 + 0 + + + + <html><head/><body><p>Exact location of the card the bot is holding. This should be as close to the same size as the card templates so it's easier for recognition with neural network. </p></body></html> + + + Left Card Area + + + + + + + Show + + + + + + + Show + + + + + + + + 0 + 0 + + + + <html><head/><body><p>Train the Neural Network to recognize the cards. This can take several minutes. For faster speed install CUDA and CUDNN (To find out more google Tensorflow GPU setup). The whole process can take up to 30 minutes. Please be patient.</p><p><br/></p></body></html> + + + Train Neural Network + + + + + + + @@ -3157,7 +3188,7 @@ Saving screenshots will not override exisiting screenshots. 0 0 - 879 + 890 69 @@ -3215,8 +3246,8 @@ Saving screenshots will not override exisiting screenshots. 0 0 - 879 - 666 + 890 + 655 diff --git a/poker/scraper/table_scraper.py b/poker/scraper/table_scraper.py index fa838632..1d2144bb 100644 --- a/poker/scraper/table_scraper.py +++ b/poker/scraper/table_scraper.py @@ -1,5 +1,7 @@ """Recognize table""" import logging +from PIL import Image +import numpy as np from poker.scraper.table_scraper_nn import predict from poker.scraper.table_setup_actions_and_signals import CARD_SUITES, CARD_VALUES @@ -110,11 +112,95 @@ def get_my_cards_nn(self): def get_table_cards2(self): """Get the cards on the table""" self.table_cards = [] - for value in CARD_VALUES: - for suit in CARD_SUITES: - if is_template_in_search_area(self.table_dict, self.screenshot, - value.lower() + suit.lower(), 'table_cards_area'): - self.table_cards.append(value + suit) + if 'use_neural_network_table' in self.table_dict and ( + self.table_dict['use_neural_network_table'] == '2' or self.table_dict[ + 'use_neural_network_table'] == 'CheckState.Checked'): + self.get_table_cards_nn() + return True + else: + for value in CARD_VALUES: + for suit in CARD_SUITES: + if is_template_in_search_area(self.table_dict, self.screenshot, + value.lower() + suit.lower(), 'table_cards_area'): + self.table_cards.append(value + suit) + log.info(f"Table cards: {self.table_cards}") + if len(self.table_cards) == 1 or len(self.table_cards) == 2: + log.warning(f"Only recognized {len(self.table_cards)} cards on the table. " + f"This can happen if cards are sliding in or if some of the templates are wrong") + return False + return True + + def get_table_cards_nn(self): + # Sacamos una foto de la zona de las cartas en la mesa + nn_image_area = self.table_dict['table_cards_area'] + nn_image = self.screenshot.crop( + (nn_image_area['x1'], nn_image_area['y1'], nn_image_area['x2'], nn_image_area['y2'])) + nn_image_rgb = nn_image.convert('RGB') + + # Define los colores a reemplazar y el color de reemplazo + target_colors = [(37, 82, 29), (105, 136, 98), (86, 65, 31)] + lower_replace_range = (226, 226, 226) + replacement_color = (255, 255, 255) + + # Convertimos la imagen a un array de numpy para un procesamiento más chido + np_image = np.array(nn_image_rgb) + + # Inicializamos la máscara con False + mask = np.zeros(np_image.shape[:2], dtype=bool) + + # Iteramos sobre cada color objetivo y actualizamos la máscara + for color in target_colors: + mask |= np.all(np.abs(np_image - color) <= 20, axis=-1) + + # Reemplazamos los píxeles encontrados con el color de reemplazo + np_image[mask] = replacement_color + + # Encontramos los píxeles en el rango de colores a reemplazar por blanco + replace_mask = np.all((np_image >= lower_replace_range) & (np_image <= replacement_color), axis=-1) + + # Reemplazamos los píxeles encontrados con el color blanco + np_image[replace_mask] = replacement_color + + # Convertimos el array de nuevo a una imagen PIL + nn_image_result = Image.fromarray(np_image) + + # Dividimos la imagen en 10 partes a lo ancho + cantidad_de_cortes = 10 + width_per_card = nn_image_result.width // cantidad_de_cortes + + + # Lista para almacenar las imágenes finales + final_images = [] + + # Iteramos sobre las partes de la imagen original + for i in range(cantidad_de_cortes): + left = i * width_per_card + right = (i + 1) * width_per_card + + # Extraemos cada parte de la imagen original + image_part = nn_image_result.crop((left, 0, right, nn_image_result.height)) + + # Convertir la parte de la imagen a formato OpenCV (numpy array) + image_array = np.array(image_part) + + # Definir el color blanco y la tolerancia permitida + color_blanco = (255, 255, 255) + tolerancia = 30 # Puedes ajustar este valor según tus necesidades + + # Calcular el porcentaje de píxeles blancos en la imagen + white_percentage = np.sum(np.all(np.abs(image_array - color_blanco) < tolerancia, axis=-1)) / np.prod(image_array.shape[:-1]) + + # Si el porcentaje es menor al 72%, añadimos la imagen a la lista final + if white_percentage < 0.83: + final_images.append(image_part) + + # Procesamos y guardamos las imágenes que cumplen con la condición + for i, image_part in enumerate(final_images, start=1): + # Procesamos la carta con la red neuronal y almacenamos el resultado + card_result = predict(image_part, self.nn_model, self.table_dict['_class_mapping']) + self.table_cards.append(card_result) + # Guardamos la imagen directamente con el nombre predicho + image_part.save(get_dir('log') + f'/pics/table/{card_result}.png') log.info(f"Table cards: {self.table_cards}") if len(self.table_cards) == 1 or len(self.table_cards) == 2: log.warning(f"Only recognized {len(self.table_cards)} cards on the table. " @@ -122,6 +208,7 @@ def get_table_cards2(self): return False return True + def get_dealer_position2(self): # pylint: disable=inconsistent-return-statements """Determines position of dealer, where 0=myself, continous counter clockwise""" for i in range(self.total_players): diff --git a/poker/scraper/table_scraper_nn.py b/poker/scraper/table_scraper_nn.py index 24b8670c..0edc364d 100644 --- a/poker/scraper/table_scraper_nn.py +++ b/poker/scraper/table_scraper_nn.py @@ -16,6 +16,7 @@ TRAIN_FOLDER = get_dir('pics', "training_cards") VALIDATE_FOLDER = get_dir('pics', "validate_cards") TEST_FOLDER = get_dir('tests', "test_cards") +TEST_FOLDER_TRAIN = get_dir('pics', "test_cards") log = logging.getLogger(__name__) @@ -54,9 +55,10 @@ def adjust_colors(a, tol=120): # tol - tolerance to decides on the "-ish" facto class CardNeuralNetwork(): @staticmethod - def create_augmented_images(table_name): + def create_augmented_images(table_name, train_count=600, validate_count=600, test_count=500): shutil.rmtree(TRAIN_FOLDER, ignore_errors=True) shutil.rmtree(VALIDATE_FOLDER, ignore_errors=True) + shutil.rmtree(TEST_FOLDER_TRAIN, ignore_errors=True) log.info("Augmenting data with random pictures based on templates") @@ -66,14 +68,14 @@ def create_augmented_images(table_name): width_shift_range=0.05, height_shift_range=0.05, shear_range=0.02, - zoom_range=0.05, + zoom_range=[0.9, 1.5], horizontal_flip=False, fill_mode='nearest') mongo = MongoManager() table = mongo.get_table(table_name) - for folder in [TRAIN_FOLDER, VALIDATE_FOLDER]: + for folder, count in zip([TRAIN_FOLDER, VALIDATE_FOLDER, TEST_FOLDER_TRAIN], [train_count, validate_count, test_count]): card_ranks_original = '23456789TJQKA' original_suits = 'CDHS' @@ -101,8 +103,8 @@ def create_augmented_images(table_name): save_format='png', ): i += 1 - if i > 500: - break # otherwise the generator would loop indefinitely + if i >= count: + break # Limit the number of generated images def train_neural_network(self): from tensorflow.keras.preprocessing.image import ImageDataGenerator @@ -128,17 +130,31 @@ def train_neural_network(self): class_mode='binary', color_mode='rgb') + self.test_generator = ImageDataGenerator( + rescale=0.00, + shear_range=0.00, + zoom_range=0.00, + horizontal_flip=False).flow_from_directory( + directory=os.path.join(SCRAPER_DIR, TEST_FOLDER_TRAIN), + target_size=(img_height, img_width), + batch_size=128, + class_mode='binary', + color_mode='rgb', + shuffle=False) + num_classes = 52 input_shape = (50, 15, 3) epochs = 50 - from tensorflow.keras.callbacks import TensorBoard, EarlyStopping, LearningRateScheduler + from tensorflow.keras.callbacks import TensorBoard, EarlyStopping from tensorflow.keras.constraints import MaxNorm - from tensorflow.keras.layers import Conv2D, MaxPooling2D, BatchNormalization + from tensorflow.keras.layers import Conv2D, MaxPooling2D from tensorflow.keras.layers import Dropout, Flatten, Dense from tensorflow.keras.models import Sequential - from tensorflow.keras.losses import sparse_categorical_crossentropy - from tensorflow.keras import optimizers - from tensorflow.math import exp + from tensorflow.keras.optimizers import Adam + + # Configurar el optimizador con una tasa de aprendizaje específica + custom_optimizer = Adam(learning_rate=0.001) + model = Sequential() model.add(Conv2D(64, (3, 3), input_shape=input_shape, activation='relu', padding='same')) model.add(Conv2D(64, (3, 3), activation='relu', padding='same')) @@ -161,11 +177,13 @@ def train_neural_network(self): from tensorflow.keras.losses import sparse_categorical_crossentropy from tensorflow.keras import optimizers model.compile(loss=sparse_categorical_crossentropy, - optimizer=optimizers.Adam(), + optimizer=custom_optimizer, metrics=['accuracy']) log.info(model.summary()) + self.model = model + early_stop = EarlyStopping(monitor='val_accuracy', min_delta=0, patience=5, # increased patience as sometimes more epochs are beneficial @@ -184,9 +202,27 @@ def train_neural_network(self): validation_data=self.validation_generator, callbacks=[early_stop]) self.model = model + score = model.evaluate(self.validation_generator, steps=52) print('Validation loss:', score[0]) print('Validation accuracy:', score[1]) + log.info(model.summary()) + self.test_neural_network() + + def test_neural_network(self): + log.info("Testing the neural network") + + if self.model is not None: + # Evaluar el modelo en el conjunto de prueba + test_score = self.model.evaluate(self.test_generator, steps=52) + log.info('Test loss: %f', test_score[0]) + log.info('Test accuracy: %f', test_score[1]) + + # Devolver el porcentaje de resultados de la prueba + return test_score[1] + else: + log.error("Model not trained. Please train the model before testing.") + return None def save_model_to_disk(self): # serialize model to JSON diff --git a/poker/scraper/table_screen_based.py b/poker/scraper/table_screen_based.py index 17ff6609..7def5404 100644 --- a/poker/scraper/table_screen_based.py +++ b/poker/scraper/table_screen_based.py @@ -568,7 +568,6 @@ def get_new_hand(self, mouse, h, p): self.Game_Number = 0 h.game_number_on_screen = 0 self.get_my_funds(h, p) - h.lastGameID = str(h.GameID) h.GameID = int(round(np.random.uniform(0, 999999999), 0)) cards = ' '.join(self.mycards) @@ -581,23 +580,19 @@ def get_new_hand(self, mouse, h, p): t_algo = threading.Thread(name='Algo', target=self.call_genetic_algorithm, args=(p,)) t_algo.daemon = True t_algo.start() - self.gui_signals.signal_funds_chart_update.emit(self.game_logger) self.gui_signals.signal_bar_chart_update.emit(self.game_logger, p.current_strategy) - h.myLastBet = 0 h.myFundsHistory.append(self.myFunds) h.previousCards = self.mycards h.lastSecondRoundAdjustment = 0 h.last_round_bluff = False # reset the bluffing marker h.round_number = 0 - mouse.move_mouse_away_from_buttons_jump() self.take_screenshot(False, p) else: log.debug("Game number on screen: " + str(h.game_number_on_screen)) self.get_my_funds(h, p) - return True def upload_collusion_wrapper(self, p, h): diff --git a/poker/scraper/table_setup_actions_and_signals.py b/poker/scraper/table_setup_actions_and_signals.py index 528b5cef..f5069a7f 100644 --- a/poker/scraper/table_setup_actions_and_signals.py +++ b/poker/scraper/table_setup_actions_and_signals.py @@ -98,6 +98,7 @@ def connect_signals_with_slots(self): self.ui.topleft_corner.clicked.connect(lambda: self.save_topleft_corner()) self.ui.current_player.currentIndexChanged[int].connect(lambda: self._update_selected_player()) self.ui.use_neural_network.clicked.connect(lambda: self._save_use_nerual_network_checkbox()) + self.ui.use_neural_network_table.clicked.connect(lambda: self._save_use_nerual_network_table_checkbox()) self.ui.max_players.currentIndexChanged[int].connect(lambda: self._save_max_players()) self.ui.spinBox_nthSecond.valueChanged.connect(lambda: self._update_nth_second()) self.ui.spinBox_xTimes.valueChanged.connect(lambda: self._update_x_times()) @@ -231,6 +232,18 @@ def _save_use_nerual_network_checkbox(self): mongo.update_state(state=is_set, label=label, table_name=self.table_name) log.info("Saving complete") + def _save_use_nerual_network_table_checkbox(self): + owner = mongo.get_table_owner(self.table_name) + if owner != COMPUTER_NAME: + pop_up("Not authorized.", + "You can only edit your own tables. Please create a new copy or start with a new blank table") + return + label = 'use_neural_network_table' + is_set = self.ui.use_neural_network_table.checkState() + log.info(f"Saving use neural network table tickbox {is_set}") + mongo.update_state(state=is_set, label=label, table_name=self.table_name) + log.info("Saving complete") + def _connect_cards_with_save_slot(self): # contains cards in the deck deck = [x.lower() + y.lower() for x in CARD_VALUES for y in CARD_SUITES] @@ -739,6 +752,18 @@ def load(self): log.info(f"No available data for {check_box}") self.signal_check_box.emit(check_box, 0) + check_boxes = ['use_neural_network_table'] + for check_box in check_boxes: + try: + if isinstance(table[check_box], int): + nn = 1 if table[check_box] > 0 else 0 + if isinstance(table[check_box], str): + nn = 1 if table[check_box] == 'CheckState.Checked' else 0 + self.signal_check_box.emit(check_box, int(nn)) + except KeyError: + log.info(f"No available data for {check_box}") + self.signal_check_box.emit(check_box, 0) + try: all_values = [self.ui.max_players.itemText(i) for i in range(self.ui.max_players.count())] index = all_values.index(str(table['max_players']['value'])) diff --git a/poker/tests/test_montecarlo.py b/poker/tests/test_montecarlo.py index 54431c47..795f0d13 100644 --- a/poker/tests/test_montecarlo.py +++ b/poker/tests/test_montecarlo.py @@ -149,7 +149,7 @@ def test_evaluator( # Unittest to ensure correct winning probabilities are returned def test_monteCarlo(self): # pylint: disable=too-many-statements def testRun(Simulation, my_cards, cards_on_table, players, expected_results, opponent_range=1): - maxRuns = 15000 # maximum number of montecarlo runs + maxruns = 15000 # maximum number of montecarlo runs testRuns = 5 # make several testruns to get standard deviation of winning probability secs = 1 # cut simulation short if amount of seconds are exceeded @@ -157,7 +157,7 @@ def testRun(Simulation, my_cards, cards_on_table, players, expected_results, opp for _ in range(testRuns): start_time = time.time() + secs logger = MagicMock() - Simulation.run_montecarlo(logger, my_cards, cards_on_table, players, 1, maxRuns=maxRuns, + Simulation.run_montecarlo(logger, my_cards, cards_on_table, players, 1, max_runs=maxruns, timeout=start_time, ghost_cards='', opponent_range=opponent_range) equity = Simulation.equity total_result.append(equity * 100) diff --git a/poker/tests/test_tensorflow.py b/poker/tests/test_tensorflow.py index 25f28184..514e2498 100644 --- a/poker/tests/test_tensorflow.py +++ b/poker/tests/test_tensorflow.py @@ -3,6 +3,7 @@ import pytest from PIL import Image +import os from poker.scraper.table_scraper_nn import TEST_FOLDER, predict from poker.tools.helper import ON_CI @@ -27,16 +28,34 @@ def test_load_nn_model(): @pytest.mark.skipif(ON_CI, reason='too long for ci') def test_train_card_neural_network_and_predict(): - from poker.scraper.table_scraper_nn import CardNeuralNetwork + from poker.scraper.table_scraper_nn import CardNeuralNetwork, predict n = CardNeuralNetwork() - n.create_augmented_images('GG Poker2') + n.create_augmented_images('GGpoker') n.train_neural_network() n.save_model_to_disk() n.load_model() for card in ['AH', '5C', 'QS', '6C', 'JC', '2H']: - filename = f'{TEST_FOLDER}/' + card + '.png' - img = Image.open(filename) - prediction = predict(img, n.loaded_model, n.class_mapping) - log.info(f"Prediction: {prediction} vs actual: {card}") - assert card == prediction + # Obtener el nombre de la carpeta específica + folder_name = card + + # Acceder a la carpeta correspondiente + folder_path = os.path.join(TEST_FOLDER, folder_name) + + # Buscar archivos en la carpeta + for file_name in os.listdir(folder_path): + if file_name.startswith(card) and file_name.endswith('.png'): + # La imagen coincide con el nombre de la tarjeta + file_path = os.path.join(folder_path, file_name) + img = Image.open(file_path) + prediction = predict(img, n.loaded_model, n.class_mapping) + log.info(f"Prediction: {prediction} vs actual: {card}") + assert card == prediction + + elif card in file_name and file_name.endswith('.png'): + # La imagen tiene el nombre similar a "5C_0_27" + file_path = os.path.join(folder_path, file_name) + img = Image.open(file_path) + prediction = predict(img, n.loaded_model, n.class_mapping) + log.info(f"Prediction for similar name: {prediction} vs actual: {card}") + assert card == prediction From a474a3cd989daad31173bade3629d65a88c898b9 Mon Sep 17 00:00:00 2001 From: v3rchi3l Date: Fri, 23 Feb 2024 11:23:57 -0300 Subject: [PATCH 2/2] The translation function for several languages is added within Setting (place only the first 5, any can be added within Google Translate) NN recognition of table cards is added, the cloth must be mapped to avoid false positives --- poker/gui/action_and_signals.py | 92 +- poker/gui/ui/setup_form.ui | 151 +- poker/gui/ui/table_setup_form.ui | 4562 +++++++++-------- poker/scraper/table_scraper.py | 53 +- .../table_setup_actions_and_signals.py | 12 +- poker/tools/strategy_handler.py | 3 +- requirements_win.txt | 1 + 7 files changed, 2479 insertions(+), 2395 deletions(-) diff --git a/poker/gui/action_and_signals.py b/poker/gui/action_and_signals.py index bdab9421..6d3dfe60 100644 --- a/poker/gui/action_and_signals.py +++ b/poker/gui/action_and_signals.py @@ -36,7 +36,6 @@ import logging - # pylint: disable=unnecessary-lambda class UIActionAndSignals(QObject): # pylint: disable=undefined-variable @@ -377,6 +376,9 @@ def open_table_setup(self): def open_setup(self): self.ui_setup = SetupForm() self.ui_setup.pushButton_save.clicked.connect(lambda: self.save_setup()) + self.ui_setup.pushButton_Translates.clicked.connect(lambda: self.translate()) + + vm_list = ['Direct mouse control'] try: vm = VirtualBoxController() @@ -387,23 +389,34 @@ def open_setup(self): self.ui_setup.comboBox_vm.addItems(vm_list) timeouts = ['8', '9', '10', '11', '12'] self.ui_setup.comboBox_2.addItems(timeouts) + translates_list = ['en', 'es', 'hi', 'fr', 'zh-TW'] + self.ui_setup.comboBox_Translates.addItems(translates_list) config = get_config() try: mouse_control = config.config.get('main', 'control') except: mouse_control = 'Direct mouse control' - for i in [i for i, x in enumerate(vm_list) if x == mouse_control]: - idx = i - self.ui_setup.comboBox_vm.setCurrentIndex(idx) + for i, x in enumerate(vm_list): + if x == mouse_control: + self.ui_setup.comboBox_vm.setCurrentIndex(i) try: timeout = config.config.get('main', 'montecarlo_timeout') except: - timeout = 10 - for i in [i for i, x in enumerate(timeouts) if x == timeout]: - idx = i - self.ui_setup.comboBox_2.setCurrentIndex(idx) + timeout = '10' + for i, x in enumerate(timeouts): + if x == timeout: + self.ui_setup.comboBox_2.setCurrentIndex(i) + + try: + translate_config = config.config.get('main', 'Translates') + except: + translate_config = 'en' + for i, x in enumerate(translates_list): + if x == translate_config: + self.ui_setup.comboBox_Translates.setCurrentIndex(i) + login = config.config.get('main', 'login') password = config.config.get('main', 'password') @@ -412,12 +425,75 @@ def open_setup(self): self.ui_setup.login.setText(login) self.ui_setup.password.setText(password) + def translate(self): + import xml.etree.ElementTree as ET + from googletrans import Translator + from tqdm import tqdm + import os + + def translate_text(self, text, source_language='en', target_language=None): + exceptions = {'2C', '3C', '4C', '5C', '6C', '7C', '8C', '9C', 'TC', 'JC', 'QC', 'KC', 'AC', + '2S', '3S', '4S', '5S', '6S', '7S', '8S', '9S', 'TS', 'JS', 'QS', 'KS', 'AS', + '2H', '3H', '4H', '5H', '6H', '7H', '8H', '9H', 'TH', 'JH', 'QH', 'KH', 'AH', + '2D', '3D', '4D', '5D', '6D', '7D', '8D', '9D', 'TD', 'JD', 'QD', 'KD', 'AD'} + + if target_language is None: + selected_translate = self.ui_setup.comboBox_Translates.currentText() + target_language = selected_translate + if text in exceptions: + return text + translator = Translator() + translated_text = translator.translate(text, dest=target_language) + translated_text = translated_text.text + # Realizar los reemplazos específicos + translated_text = translated_text.replace("

", "

") + translated_text = translated_text.replace(".

", "

") + return translated_text + + def translate_ui_files(ui_directory='gui/ui'): + ui_files = [os.path.join(ui_directory, filename) for filename in os.listdir(ui_directory) if + filename.endswith('.ui')] + processed_files = [] + with tqdm(total=len(ui_files), desc="Processing files") as pbar: + for ui_file in ui_files: + processed_files.extend(translate_ui_file(self, ui_file)) + pbar.update(1) + print('Please reboot for the changes to take effect.') + return processed_files + + def translate_ui_file(self, file_path): + tree = ET.parse(file_path) + root = tree.getroot() + + processed_files = [] + + for string_tag in root.iter('string'): + try: + if string_tag.text is not None and isinstance(string_tag.text, str): + cleaned_text = string_tag.text.strip().replace('<', '<').replace('>', '>') + translated_text = translate_text(self, cleaned_text) + string_tag.text = translated_text + except Exception as e: + print("\n") + print(f"File error {file_path}: {e}") + print(f"Problematic line: {string_tag.text}") + + tree.write(file_path, encoding='utf-8', xml_declaration=True) + processed_files.append(file_path) + + return processed_files + + # Llamar a la función interna translate_ui_files + + return translate_ui_files() + def save_setup(self): config = get_config() config.config.set('main', 'control', self.ui_setup.comboBox_vm.currentText()) config.config.set('main', 'montecarlo_timeout', self.ui_setup.comboBox_2.currentText()) config.config.set('main', 'login', self.ui_setup.login.text()) config.config.set('main', 'password', self.ui_setup.password.text()) + config.config.set('main', 'Translate', self.ui_setup.Translates.currentText()) config.update_file() self.ui_setup.close() diff --git a/poker/gui/ui/setup_form.ui b/poker/gui/ui/setup_form.ui index 62ea3265..e9f3056a 100644 --- a/poker/gui/ui/setup_form.ui +++ b/poker/gui/ui/setup_form.ui @@ -1,4 +1,4 @@ - + setup_form @@ -6,8 +6,8 @@ 0 0 - 263 - 326 + 249 + 292
@@ -23,7 +23,7 @@ Setup - + @@ -41,24 +41,57 @@ - + - 9 - 9 - 201 - 257 + 10 + 10 + 228 + 272 - - - + + + - Direct Mouse control and Virtual Machines + Timeout - + + + + Qt::Vertical + + + QSizePolicy::Preferred + + + + 20 + 40 + + + + + + + + Password + + + + + + + + + + Login + + + + <html><head/><body><p>Choose if you want to have direct access to VirtualBox via API or whether the bot should simply move the mouse.</p><p>The dropdown will automatically show all available virtualbox virtualmachines.</p></body></html> @@ -70,73 +103,65 @@ wahtst this - + - + - - + + - Timeout + Direct Mouse control and Virtual Machines - - - - Shows after how many seconds of discovering the buttons a timeout will be triggered, assuming you have reached the montecarlo simulation by then. - - + + - - + + - Login + Save - - - - - - - Password + + + + Shows after how many seconds of discovering the buttons a timeout will be triggered, assuming you have reached the montecarlo simulation by then. - - - - - - - Qt::Vertical - - - QSizePolicy::Preferred - - - - 20 - 40 - - - - - - - - Save - - + + + + + + Translate + + + + + + + Shows after how many seconds of discovering the buttons a timeout will be triggered, assuming you have reached the montecarlo simulation by then. + + + + + + + Translate + + + + - - - + + + \ No newline at end of file diff --git a/poker/gui/ui/table_setup_form.ui b/poker/gui/ui/table_setup_form.ui index 02fcd303..d936bfcd 100644 --- a/poker/gui/ui/table_setup_form.ui +++ b/poker/gui/ui/table_setup_form.ui @@ -6,8 +6,8 @@ 0 0 - 1303 - 979 + 1189 + 926 @@ -36,333 +36,25 @@
- - + + Button Images and their search areas - - - - - - - - 0 - 0 - - - - <html><head/><body><p>Only select the raise text, without the chainging element of the raise amount </p></body></html> - - - Raise Button - - - - - - - false - - - Show - - - - - - - Ensure to only select the portion that never changes - - - All in call Button - - - - - - - Select an area where to look for a single sign that it's your turn - - - "My turn" search area - - - - - - - false - - - Show - - - - - - - false - - - Show - - - - - - - false - - - Show - - - - - - - <html><head/><body><p>Select the text of the fast fold button.</p></body></html> - - - Fast Fold Button - - - - - - - <html><head/><body><p>Select small part of the fold button text.</p></body></html> - - - Fold Button - - - - - - - <html><head/><body><p>Select the check button, or a small part of it that is unique.</p></body></html> - - - Check Button - - - - - - - Resume Hand - - - - - - - Best select the top left corner of the call button, or any other element that is always identical for all situations when it's your turn - - - "My Turn" image - - - - - - - false - - - Show - - - - - - - Image showing I'm back, in case of tha time out - - - I'm back - - - - - - - <html><head/><body><p>Only select a small portion of the button (e.g. the call text), without the actual call amount </p></body></html> - - - Call Button - - - - - - - false - - - Show - - - - - - - false - - - Show - - - - - - - false - - - Show - - - - - - - Select area to look for a sign that all funds are lost. This is usually the area of the player's left funds. - - - Lost everything search area - - - - - - - false - - - Show - - - - - - - An image showing no funds left: e.g. 0.00 - - - Lost everything image - - - - - - - Area where fold, call and raise buttons are located - - - Buttons search area - - - - - - - false - - - Show - - - - - - - false - - - Show - - - - - - - false - - - Show - - - - - - - false - - - Show - - - - - - - - 0 - 0 - - - - <html><head/><body><p>This is optional for tables where the raise button is sometimes called bet button. Here as well, just select the text without the number, to ensure it's the same all the time.</p></body></html> - - - Bet Button - - - - - - - false - - - Show - - - - - - - - - - - - Search areas for cards - - - - - - - 0 - 0 - - + + + - Area where the cards appear on the table at flop, turn and river + Ensure to only select the portion that never changes - Table Cards area + All in call Button - - + + false @@ -371,47 +63,58 @@ - - + + - Area where the player holds his cards + <html><head/><body><p>Select the check button, or a small part of it that is unique.</p></body></html> - My Cards area + Check Button - - - - false + + + + Best select the top left corner of the call button, or any other element that is always identical for all situations when it's your turn - Show + "My Turn" image - - - - - - - Values - - - - + + - Game number for collusion, in partypoker available on top right + Image showing I'm back, in case of tha time out - Game Number + I'm back - - + + + + <html><head/><body><p>Select small part of the fold button text.</p></body></html> + + + Fold Button + + + + + + + An image showing no funds left: e.g. 0.00 + + + Lost everything image + + + + + false @@ -420,18 +123,18 @@ - - + + - The all in call value may be in a different place in case the all in call button appears. Make sure to select the value narrowly and test it with the recognize number button + Select area to look for a sign that all funds are lost. This is usually the area of the player's left funds. - All in call value + Lost everything search area - + false @@ -440,18 +143,28 @@ - - + + + + false + + + Show + + + + + - Value on the call button, make sure to select narrowly and then test by pressing the recognize number button + <html><head/><body><p>Select the text of the fast fold button.</p></body></html> - Call value + Fast Fold Button - - + + false @@ -460,21 +173,28 @@ - - + + - The value on the raise button. Make sure to select very narrowly and then test with the recognize number button + <html><head/><body><p>Only select a small portion of the button (e.g. the call text), without the actual call amount </p></body></html> - Raise Value + Call Button - + + + + + false + + Show + - - + + false @@ -483,18 +203,54 @@ - - + + + + false + + + Show + + + + + + + false + + + Show + + + + + + + false + + + Show + + + + + + + + 0 + 0 + + - The pot of the current rount (e.g. flop). Select the area very narrowly and test it by pressing the recognize number button + <html><head/><body><p>This is optional for tables where the raise button is sometimes called bet button. Here as well, just select the text without the number, to ensure it's the same all the time.</p></body></html> - Current Round Pot value + Bet Button - - + + false @@ -503,8 +259,8 @@ - - + + 0 @@ -512,15 +268,15 @@ - Total pot. Make sure to only select the numbers very narrowly and test it by pressing the recognize number or text button + <html><head/><body><p>Only select the raise text, without the chainging element of the raise amount </p></body></html> - Total Pot value + Raise Button - - + + false @@ -529,2056 +285,2304 @@ - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - -
- - - Players - - - - - - - - - - Player (0=myself) - - - - - - - 0 is the bot, then clockwise the other players. If max player is 6, you only need to populate Player 0 to 5 - - + + - 0 + Resume Hand - - - - 1 + + + + + + Select an area where to look for a single sign that it's your turn - - - 2 + "My turn" search area - - - - 3 + + + + + + false - - - 4 + Show - - - - 5 + + + + + + Area where fold, call and raise buttons are located - - - 6 + Buttons search area - - - - 7 + + + + + + false - - - 8 + Show - - - - + + + + - - - - - - Table size - - - - - - - Select the amount of players on the table - - - - 6 - - - - - 2 + + + + Search areas for cards + + + + + + false - - - 3 + Show - - - - 4 + + + + + + false - - - 5 + Show - - - - 7 + + + + + + Area where the player holds his cards - - - 8 + My Cards area - - - - 9 + + + + + + + 0 + 0 + - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - Where the given player would have the button to indicate he is the dealer. - - - Dealer button search area - - - - - - - Qt::NoContextMenu - - - Area where the player has the cards, so the bot can detect if he is still in the game - - - 9 - - - Covered card area (cards upside down) - - - - - - - Pot of the player - - - Player pot area - - - - - - - area where the remaining player funds are shown. Use narrow selection and test it by pressing the Recognize number button - - - Player funds area - - - - - - - Player name area - - - - - - - false - - - Show - - - - - - - false - - - Show - - - - - - - false - - - Show - - - - - - - false - - - Show - - - - - - - false - - - Show - - - - - - - - - - - - Cards - - - - - 9 - 9 - 352 - 751 - - - - Ensure to mark as narrowly as possible. Don't mark the full card, but only the number and the symbol. - - - Images - - - - - - - - - - - 16 - + + Area where the cards appear on the table at flop, turn and river - - - - Qt::AlignCenter + Table Cards area - - - - 35 - 16777215 - + + + <html><head/><body><p>Select the same "Table Cards area" but without the cards, just the cloth (this is for the recognition of the NN on the cards on the table). </p></body></html> - 2C - - - false + Card area on table (cloth only) - - - - - 35 - 16777215 - + + + + false - 3C + Show - - - - - 35 - 16777215 - + + + + + + + Values + + + + + + Game number for collusion, in partypoker available on top right - 4C + Game Number - - - - - 35 - 16777215 - + + + + false - 5C + Show - - - - - 35 - 16777215 - + + + + The all in call value may be in a different place in case the all in call button appears. Make sure to select the value narrowly and test it with the recognize number button - 6C + All in call value - - - - - 35 - 16777215 - + + + + false - 7C + Show - - - - - 35 - 16777215 - + + + + Value on the call button, make sure to select narrowly and then test by pressing the recognize number button - 8C + Call value - - - - - 35 - 16777215 - + + + + false - 9C + Show - - - - - 35 - 16777215 - + + + + The value on the raise button. Make sure to select very narrowly and then test with the recognize number button - TC + Raise Value + + + false - - - - - 35 - 16777215 - + + + + false - JC - - - - - - - - 35 - 16777215 - - - - QC - - - - - - - - 35 - 16777215 - - - - KC + Show - - - - - 35 - 16777215 - + + + + The pot of the current rount (e.g. flop). Select the area very narrowly and test it by pressing the recognize number button - AC + Current Round Pot value - - + + false - - - 35 - 16777215 - - - V + Show - - - - false + + + + + 0 + 0 + - - - 35 - 16777215 - + + Total pot. Make sure to only select the numbers very narrowly and test it by pressing the recognize number or text button - V + Total Pot value - - + + false - - - 35 - 16777215 - - - V + Show - - - - false + + + + Qt::Vertical - + - 35 - 16777215 + 20 + 40 - - V - - + - - - - false - - - - 35 - 16777215 - - + + + + + + + + + + Players + + + + + + + + + + Player (0=myself) + + + + + + + 0 is the bot, then clockwise the other players. If max player is 6, you only need to populate Player 0 to 5 + + - V - - - - - - - false - - - - 35 - 16777215 - + 0 + + - V - - - - - - - false - - - - 35 - 16777215 - + 1 + + - V - - - - - - - false - - - - 35 - 16777215 - + 2 + + - V - - - - - - - false - - - - 35 - 16777215 - + 3 + + - V - - - - - - - false - - - - 35 - 16777215 - + 4 + + - V - - - - - - - false - - - - 35 - 16777215 - + 5 + + - V - - - - - - - false - - - - 35 - 16777215 - + 6 + + - V - - - - - - - false + 7 - - - 35 - 16777215 - + + + + 8 + + + + + + + + + + + Table size + + + + + + + Select the amount of players on the table + + - V + 6 - - - - - - - - - - - 16 - + + + + 2 + + - + 3 - - Qt::AlignCenter + + + + 4 - - - - - - - 35 - 16777215 - + + + + 5 + + - 2D + 7 - - - - - - - 35 - 16777215 - + + + + 8 + + - 3D + 9 - - - - - - - 35 - 16777215 - - - - 4D - - - - - - - - 35 - 16777215 - - - - 5D - - - - - - - - 35 - 16777215 - - - - 6D - - - - - - - - 35 - 16777215 - - - - 7D - - - - - - - - 35 - 16777215 - - - - 8D - - - - - - - - 35 - 16777215 - - - - 9D - - - - - - - - 35 - 16777215 - - - - TD - - - - - - - - 35 - 16777215 - - - - JD - - - - - - - - 35 - 16777215 - - - - QD - - - - - - - - 35 - 16777215 - - - - KD - - - - - - - - 35 - 16777215 - - - - AD - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - - - - - - 16 - - - - - - - Qt::AlignCenter - - - - - - - - 35 - 16777215 - - - - 2S - - - - - - - - 35 - 16777215 - - - - 3S - - - - - - - - 35 - 16777215 - - - - 4S - - - - - - - - 35 - 16777215 - - - - 5S - - - - - - - - 35 - 16777215 - - - - 6S - - - - - - - - 35 - 16777215 - - - - 7S - - - - - - - - 35 - 16777215 - - - - 8S - - - - - - - - 35 - 16777215 - - - - 9S - - - - - - - - 35 - 16777215 - - - - TS - - - - - - - - 35 - 16777215 - - - - JS - - - - - - - - 35 - 16777215 - - - - QS - - - - - - - - 35 - 16777215 - - - - KS - - - - - - - - 35 - 16777215 - - - - AS - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - - 35 - 16777215 - - - - 3H - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - - 35 - 16777215 - - - - 7H - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - - 35 - 16777215 - - - - 8H - - - - - - - - 35 - 16777215 - - - - 5H - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - - 35 - 16777215 - - - - 9H - - - - - - - - 35 - 16777215 - - - - JH - - - - - - - - 16 - - - - - - - Qt::AlignCenter - - - - - - - - 35 - 16777215 - - - - 4H - - - - - - - - 35 - 16777215 - - - - QH - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - - 35 - 16777215 - - - - TH - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - - 35 - 16777215 - - - - KH - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - - 35 - 16777215 - - - - AH - - - - - - - false - - - - 35 - 16777215 - - - - V - - - - - - - - 35 - 16777215 - - - - 6H - - - - - - - false - - - - 35 - 16777215 - - - - V - - + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + Where the given player would have the button to indicate he is the dealer. + + + Dealer button search area + + + + + + + Qt::NoContextMenu + + + Area where the player has the cards, so the bot can detect if he is still in the game + + + 9 + + + Covered card area (cards upside down) + + + + + + + Pot of the player + + + Player pot area + + + + + + + area where the remaining player funds are shown. Use narrow selection and test it by pressing the Recognize number button + + + Player funds area + + + + + + + Player name area + + + + + + + false + + + Show + + + + + + + false + + + Show + + + + + + + false + + + Show + + + + + + + false + + + Show + + + + + + + false + + + Show + + + + + + + + + + + + Cards + + + + + + Ensure to mark as narrowly as possible. Don't mark the full card, but only the number and the symbol. + + + Images + + + + + + + + + + + + + 35 + 16777215 + + + + TC + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + + 35 + 16777215 + + + + JC + + + + + + + + 35 + 16777215 + + + + 5C + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + + 35 + 16777215 + + + + 6C + + + + + + + + 35 + 16777215 + + + + 2C + + + false + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + + 35 + 16777215 + + + + AC + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + + 35 + 16777215 + + + + 7C + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + + 35 + 16777215 + + + + 9C + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + + 35 + 16777215 + + + + KC + + + + + + + + 35 + 16777215 + + + + QC + + + + + + + + 35 + 16777215 + + + + 3C + + + + + + + + 16 + + + + + + + Qt::AlignCenter + + + + + + + + 35 + 16777215 + + + + 4C + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + + 35 + 16777215 + + + + 8C + + + + + + + + + + + + 16 + + + + + + + Qt::AlignCenter + + + + + + + + 35 + 16777215 + + + + 2D + + + + + + + + 35 + 16777215 + + + + 3D + + + + + + + + 35 + 16777215 + + + + 4D + + + + + + + + 35 + 16777215 + + + + 5D + + + + + + + + 35 + 16777215 + + + + 6D + + + + + + + + 35 + 16777215 + + + + 7D + + + + + + + + 35 + 16777215 + + + + 8D + + + + + + + + 35 + 16777215 + + + + 9D + + + + + + + + 35 + 16777215 + + + + TD + + + + + + + + 35 + 16777215 + + + + JD + + + + + + + + 35 + 16777215 + + + + QD + + + + + + + + 35 + 16777215 + + + + KD + + + + + + + + 35 + 16777215 + + + + AD + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + + + + + + 16 + + + + + + + Qt::AlignCenter + + + + + + + + 35 + 16777215 + + + + 2S + + + + + + + + 35 + 16777215 + + + + 3S + + + + + + + + 35 + 16777215 + + + + 4S + + + + + + + + 35 + 16777215 + + + + 5S + + + + + + + + 35 + 16777215 + + + + 6S + + + + + + + + 35 + 16777215 + + + + 7S + + + + + + + + 35 + 16777215 + + + + 8S + + + + + + + + 35 + 16777215 + + + + 9S + + + + + + + + 35 + 16777215 + + + + TS + + + + + + + + 35 + 16777215 + + + + JS + + + + + + + + 35 + 16777215 + + + + QS + + + + + + + + 35 + 16777215 + + + + KS + + + + + + + + 35 + 16777215 + + + + AS + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + + 35 + 16777215 + + + + 3H + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + + 35 + 16777215 + + + + 7H + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + + 35 + 16777215 + + + + 8H + + + + + + + + 35 + 16777215 + + + + 5H + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + + 35 + 16777215 + + + + 9H + + + + + + + + 35 + 16777215 + + + + JH + + + + + + + + 16 + + + + + + + Qt::AlignCenter + + + + + + + + 35 + 16777215 + + + + 4H + + + + + + + + 35 + 16777215 + + + + QH + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + + 35 + 16777215 + + + + TH + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + + 35 + 16777215 + + + + KH + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + + 35 + 16777215 + + + + AH + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + + 35 + 16777215 + + + + 6H + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + + + 35 + 16777215 + + + + 2H + + + + + + + false + + + + 35 + 16777215 + + + + V + + + + + + - - - - 35 - 16777215 - - - - 2H - - + + + + + Used to recognize which players are still in the game. Mark very narrowly to ensure it's the same for all players. + + + Covered card + + + + + + + false + + + Show + + + + + + + <html><head/><body><p>The dealer button image. Make sure to select very narrowly and don't include any background that might change depending on it's location</p></body></html> + + + Dealer button + + + + + + + false + + + Show + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 13 + 13 + + + + + - - - - false - - - - 35 - 16777215 - - - - V - - + + + + + + For Tables where cards may be different at times (e.g. rotated) + + + + + + + <html><head/><body><p>If this is ticked, my cards will be recognized via neural network instead of exact temlate matching. This will have a higher tolerance for recognition and allow cards to be slightly different or rotated. </p></body></html> + + + Neural Network based recognition for My Cards + + + + + + + true + + + <html><head/><body><p>If this is ticked, table cards will be recognized via neural network instead of exact temlate matching. This will have a higher tolerance for recognition and allow cards to be slightly different or rotated. </p></body></html> + + + 0 + + + Neural Network based recognition for Table Cards + + + + + + + + 4 + 0 + + + + <html><head/><body><p>Exact location of the card the bot is holding. This should be as close to the same size as the card templates so it's easier for recognition with neural network. </p></body></html> + + + Left Card Area + + + + + + + Show + + + + + + + <html><head/><body><p>Exact location of the card the bot is holding. This should be as close to the same size as the card templates so it's easier for recognition with neural network. </p></body></html> + + + Right Card Area + + + + + + + Show + + + + + + + + 0 + 0 + + + + <html><head/><body><p>Train the Neural Network to recognize the cards. This can take several minutes. For faster speed install CUDA and CUDNN (To find out more google Tensorflow GPU setup). The whole process can take up to 30 minutes. Please be patient.</p><p><br/></p></body></html> + + + Train Neural Network + + + + - - - - - - - false - - - Show - - - - - - - Used to recognize which players are still in the game. Mark very narrowly to ensure it's the same for all players. - - - Covered card - - - - - - - Qt::Vertical - - - QSizePolicy::Expanding - - - - 13 - 13 - - - - - - - - <html><head/><body><p>The dealer button image. Make sure to select very narrowly and don't include any background that might change depending on it's location</p></body></html> - - - Dealer button - - - - - - - false - - - Show - - - - - - - - - - - 20 - 750 - 329 - 162 - - - - - - - For Tables where cards may be different at times (e.g. rotated) - - - - - - - <html><head/><body><p>If this is ticked, my cards will be recognized via neural network instead of exact temlate matching. This will have a higher tolerance for recognition and allow cards to be slightly different or rotated. </p></body></html> - - - Neural Network based recognition for My Cards - - - - - - - false - - - <html><head/><body><p>If this is ticked, table cards will be recognized via neural network instead of exact temlate matching. This will have a higher tolerance for recognition and allow cards to be slightly different or rotated. </p></body></html> - - - 0 - - - Neural Network based recognition for Table Cards - - - - - - - - - <html><head/><body><p>Exact location of the card the bot is holding. This should be as close to the same size as the card templates so it's easier for recognition with neural network. </p></body></html> - - - Right Card Area - - - - - - - - 4 - 0 - - - - <html><head/><body><p>Exact location of the card the bot is holding. This should be as close to the same size as the card templates so it's easier for recognition with neural network. </p></body></html> - - - Left Card Area - - - - - - - Show - - - - - - - Show - - - - - - - - 0 - 0 - - - - <html><head/><body><p>Train the Neural Network to recognize the cards. This can take several minutes. For faster speed install CUDA and CUDNN (To find out more google Tensorflow GPU setup). The whole process can take up to 30 minutes. Please be patient.</p><p><br/></p></body></html> - - - Train Neural Network - - - - - - - + + + @@ -3188,7 +3192,7 @@ Saving screenshots will not override exisiting screenshots. 0 0 - 890 + 763 69 @@ -3246,8 +3250,8 @@ Saving screenshots will not override exisiting screenshots. 0 0 - 890 - 655 + 763 + 602 diff --git a/poker/scraper/table_scraper.py b/poker/scraper/table_scraper.py index 1d2144bb..07c08cf8 100644 --- a/poker/scraper/table_scraper.py +++ b/poker/scraper/table_scraper.py @@ -131,83 +131,60 @@ def get_table_cards2(self): return True def get_table_cards_nn(self): - # Sacamos una foto de la zona de las cartas en la mesa + from io import BytesIO nn_image_area = self.table_dict['table_cards_area'] nn_image = self.screenshot.crop( (nn_image_area['x1'], nn_image_area['y1'], nn_image_area['x2'], nn_image_area['y2'])) nn_image_rgb = nn_image.convert('RGB') - # Define los colores a reemplazar y el color de reemplazo - target_colors = [(37, 82, 29), (105, 136, 98), (86, 65, 31)] + ##Cloth area + cloth_area_coordinates = self.table_dict['cloth_area'] + cloth_area_image = Image.open(BytesIO(cloth_area_coordinates)) + cloth_area_rgb = np.array(cloth_area_image.convert('RGB')) + cloth_area_remove = np.unique(cloth_area_rgb.reshape(-1, cloth_area_rgb.shape[2]), axis=0) + + target_colors = [cloth_area_remove] lower_replace_range = (226, 226, 226) replacement_color = (255, 255, 255) - - # Convertimos la imagen a un array de numpy para un procesamiento más chido np_image = np.array(nn_image_rgb) - - # Inicializamos la máscara con False - mask = np.zeros(np_image.shape[:2], dtype=bool) - - # Iteramos sobre cada color objetivo y actualizamos la máscara - for color in target_colors: - mask |= np.all(np.abs(np_image - color) <= 20, axis=-1) - - # Reemplazamos los píxeles encontrados con el color de reemplazo + mask = np.any(np.all(np.abs(np_image[:, :, None, :] - target_colors) <= 20, axis=-1), axis=-1) np_image[mask] = replacement_color - - # Encontramos los píxeles en el rango de colores a reemplazar por blanco replace_mask = np.all((np_image >= lower_replace_range) & (np_image <= replacement_color), axis=-1) - - # Reemplazamos los píxeles encontrados con el color blanco np_image[replace_mask] = replacement_color - - # Convertimos el array de nuevo a una imagen PIL nn_image_result = Image.fromarray(np_image) - # Dividimos la imagen en 10 partes a lo ancho cantidad_de_cortes = 10 width_per_card = nn_image_result.width // cantidad_de_cortes - - - # Lista para almacenar las imágenes finales final_images = [] # Iteramos sobre las partes de la imagen original for i in range(cantidad_de_cortes): left = i * width_per_card right = (i + 1) * width_per_card - - # Extraemos cada parte de la imagen original image_part = nn_image_result.crop((left, 0, right, nn_image_result.height)) - - # Convertir la parte de la imagen a formato OpenCV (numpy array) image_array = np.array(image_part) - # Definir el color blanco y la tolerancia permitida color_blanco = (255, 255, 255) tolerancia = 30 # Puedes ajustar este valor según tus necesidades + white_percentage = np.sum(np.all(np.abs(image_array - color_blanco) < tolerancia, axis=-1)) / np.prod( + image_array.shape[:-1]) - # Calcular el porcentaje de píxeles blancos en la imagen - white_percentage = np.sum(np.all(np.abs(image_array - color_blanco) < tolerancia, axis=-1)) / np.prod(image_array.shape[:-1]) - - # Si el porcentaje es menor al 72%, añadimos la imagen a la lista final if white_percentage < 0.83: final_images.append(image_part) - # Procesamos y guardamos las imágenes que cumplen con la condición for i, image_part in enumerate(final_images, start=1): - # Procesamos la carta con la red neuronal y almacenamos el resultado card_result = predict(image_part, self.nn_model, self.table_dict['_class_mapping']) self.table_cards.append(card_result) - # Guardamos la imagen directamente con el nombre predicho image_part.save(get_dir('log') + f'/pics/table/{card_result}.png') + log.info(f"Table cards: {self.table_cards}") - if len(self.table_cards) == 1 or len(self.table_cards) == 2: + + if 1 <= len(self.table_cards) <= 2: log.warning(f"Only recognized {len(self.table_cards)} cards on the table. " f"This can happen if cards are sliding in or if some of the templates are wrong") return False - return True + return True def get_dealer_position2(self): # pylint: disable=inconsistent-return-statements """Determines position of dealer, where 0=myself, continous counter clockwise""" diff --git a/poker/scraper/table_setup_actions_and_signals.py b/poker/scraper/table_setup_actions_and_signals.py index f5069a7f..0c467822 100644 --- a/poker/scraper/table_setup_actions_and_signals.py +++ b/poker/scraper/table_setup_actions_and_signals.py @@ -120,9 +120,9 @@ def load_screenshots(self): new_cropped = check_cropping(images, self.top_left_corner_img) if len(self.screenshot_list) == 0: - self.cropped = new_cropped + self.cropped = new_cropped else: - self.cropped = self.cropped and new_cropped + self.cropped = self.cropped and new_cropped if not self.cropped: log.info("Images are not cropped or do not fit to the loaded template.") @@ -255,11 +255,11 @@ def _connect_cards_with_save_slot(self): button_show_property = getattr(self.ui, 'card_' + card + '_show') button_show_property.clicked.connect(lambda state, x=card: self.load_image(x)) - save_image_buttons = ['call_button', 'raise_button', 'bet_button', 'check_button', 'fold_button', + save_image_buttons = {'call_button', 'raise_button', 'bet_button', 'check_button', 'fold_button', 'fast_fold_button', 'all_in_call_button', - 'my_turn', - 'lost_everything', 'im_back', 'resume_hand', 'dealer_button', 'covered_card'] + 'my_turn', 'cloth_area', + 'lost_everything', 'im_back', 'resume_hand', 'dealer_button', 'covered_card'} for button in save_image_buttons: button_property = getattr(self.ui, button) button_property.clicked.connect(lambda state, x=button: self.save_image(x)) @@ -710,7 +710,7 @@ def load(self): log.info(f"UnFlattening button {'card_' + card}") self.signal_flatten_button.emit('card_' + card, False) - all_buttons = ['call_value', 'raise_value', 'all_in_call_value', 'game_number', 'current_round_pot', + all_buttons = ['cloth_area', 'call_value', 'raise_value', 'all_in_call_value', 'game_number', 'current_round_pot', 'total_pot_area', 'my_turn_search_area', 'lost_everything_search_area', 'table_cards_area', 'my_cards_area', 'mouse_fold', 'mouse_fast_fold', 'mouse_raise', 'mouse_full_pot', 'mouse_call', 'mouse_increase', 'mouse_call2', 'mouse_check', 'mouse_imback', 'mouse_resume_hand', diff --git a/poker/tools/strategy_handler.py b/poker/tools/strategy_handler.py index 09c9ed9d..9893d06f 100644 --- a/poker/tools/strategy_handler.py +++ b/poker/tools/strategy_handler.py @@ -151,7 +151,8 @@ def save_strategy_genetic_algorithm(self): self.new_strategy_name = stringPart + str(numberPart) + suffix self.selected_strategy['Strategy'] = self.new_strategy_name self.current_strategy = self.new_strategy_name - del self.selected_strategy['_id'] + if '_id' in self.selected_strategy: + del self.selected_strategy['_id'] response = requests.post( URL + "save_strategy", json={'strategy': json.dumps(self.selected_strategy), 'login': login, 'password': password}).json() diff --git a/requirements_win.txt b/requirements_win.txt index 3ee8d875..0153850a 100644 --- a/requirements_win.txt +++ b/requirements_win.txt @@ -28,3 +28,4 @@ flask_jwt_extended fastapi_auth uvicorn==0.23.2 tesserocr +googletrans