The poker player performs 3 main steps: (1) identify cards, (2) identify hands, and (3) make bets. I will show how you can use MATLAB to program these steps and then deploy the algorithm onto a Raspberry Pi.
Hardware Used
Raspberry Pi: the brains of the project.*
USB webcam: to read images of the cards.
Raspberry Pi Display: to assist in visualization.
Push buttons: to call/fold bets.
Fig 1: Hardware used in project; shown is Raspberry Pi 3B+
*Keeping performance issues in mind, it's recommended to use RPi 3B+ and higher
Identify Cards
Fig 2: Webcam images are used as the input to the neural network that identifies cards
The first step is for the Raspberry Pi to identify cards. The webcam connected to the Pi captures images of the cards and a deep learning model identifies them. MATLAB supports several popular deep learning networks including SqueezeNet, AlexNet and GoogLeNet. SqueezeNet was chosen as it is sufficiently small to be deployed to a Raspberry Pi and it has relatively high prediction accuracy. Here is a simple doc example that shows how to perform transfer learning using AlexNet, but you could easily swap AlexNet for other (more modern) networks like SqueezeNet or ResNet.
Fig 3: Collect data for transfer learning
To train the deep learning algorithm, we need to collect images of the cards we want to be able to identify. We took a series of snapshots using a webcam making sure to show cards in different lighting and orientations. After manually selecting images that captured the features of each card with minimal blur / distortion, we rotated each image to avoid overfitting the network and to ensure it can recognize cards for different orientations.
The code for generating training data is fairly straightforward, and the full code is in generateCardData.m
%% Initialize variables
NumImages = 200; % Max = 1000
suits = ['D' 'C' 'H' 'S'];
rank = ['A' '2' '3' '4' '5' '6' '7' '8' '9' 'T' 'J' 'Q' 'K'];
%% Get input from command line and validate
disp('Show the card to the webcam and enter the card name in short form. ex: "2D" for Diamond-Two, AC for Club-Ace');
cardname = input('Enter card name in short form:','s');
if ~ischar(cardname) || (numel(cardname) ~= 2) || ~contains(rank, cardname(1)) || ~contains(suits, cardname(2))
error('Invalid cardname');
end
...
% Capture input from webcam and save to file.
for i = 1:1000
waitbar(i/1000,waitBarHandle,['Saving image: ' num2str(i)]);
im = snapshot(cam);
if mod(i,2)
im = imrotate(im,180);
end
if i <= NumImages
imwrite(im,fullfile(cardsDirectory,[cardname,num2str(i) '.png']));
else
imwrite(im,fullfile(unusedImgsDirectory,[cardname,num2str(i)
'.png']));
end
end
waitbar(1,waitBarHandle,['Capturing images for ',cardname,' completed.']);
We ended up with over 10,000 images which were used to train the model. Instead of loading each image file into memory during training, we used imageDatastore which let us work with the overall collection of images. The function augmentedImageDatastore was used to resize the images to the predefined input size of SqueezeNet. This function is efficient at quickly resizing images in one line of code as shown below.
net = squeezenet;
inputSize = net.Layers(1).InputSize;
audsTrain = augmentedImageDatastore(inputSize(1:2),imdsTrain);
augimdsValidation = augmentedImageDatastore(inputSize(1:2),imdsValidation);
After applying transfer learning using these images, our network was able to effectively identify cards for all test images.
Identify hands and make bets
After identifying individual cards, the Pi poker player is ready to identify hands. The flowchart in Figure 4 describes how this is implemented.
Fig 4: Flowchart to identify hands
Let’s use the example hands in the table below to better understand this flowchart. Note that the final 5 cards in each hand are community cards that are shared among all players.
After identifying cards and hands, the (Pi) Poker Player is ready to place bets. The betting algorithm is very simple and based solely on the identified hand. It starts at 1 USD for a Highcard and increases by 1 USD for each subsequent ranked hand up to 10 USD for a Royal flush. Of course, if you are working on this algorithm, you can rework the algorithm to be more (or less) aggressive depending on how you’re feeling.
Embed algorithm onto Raspberry Pi
We generate C++ code from our MATLAB algorithms and embed it onto the Raspberry Pi using MATLAB Coder. We wrote a function main_poker_player.cpp that serves as the main script of the executable, where we specify which functions to generate code for. The generated code and executable (including modified AlexNet and betting logic algorithm) are downloaded directly to the Pi for standalone execution – we just need to plug in a camera and run the .exe file.
Fig 5: Generate code and deploy to the Raspberry Pi using MATLAB Coder
To see this workflow in more detail and find additional resources, refer to the video here.
Conclusion
With that we have seen how to build a Raspberry Pi Poker Player in MATLAB. While this is a good start there are certainly areas for improvement, and I encourage you to modify the code to make this even better. For example, you could try to build a more sophisticated betting algorithm that is able to escalate bets or even bluff.
The code is available on FileExchange and GitHub. Share your comments below and ideas on how to improve the poker player!
Source: mathworks.com
The Tech Platform
Comments