Skip to content

Instantly share code, notes, and snippets.

@qgolsteyn
Last active October 8, 2023 08:27
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save qgolsteyn/261289d999a8d6288ce8c0b8472e5354 to your computer and use it in GitHub Desktop.
Save qgolsteyn/261289d999a8d6288ce8c0b8472e5354 to your computer and use it in GitHub Desktop.
A small Python script that reads dice rolls out loud. See https://golsteyn.com/projects/dice/ for more info!
import cv2
import numpy as np
from sklearn import cluster
params = cv2.SimpleBlobDetector_Params()
params.filterByInertia
params.minInertiaRatio = 0.6
detector = cv2.SimpleBlobDetector_create(params)
def get_blobs(frame):
frame_blurred = cv2.medianBlur(frame, 7)
frame_gray = cv2.cvtColor(frame_blurred, cv2.COLOR_BGR2GRAY)
blobs = detector.detect(frame_gray)
return blobs
def get_dice_from_blobs(blobs):
# Get centroids of all blobs
X = []
for b in blobs:
pos = b.pt
if pos != None:
X.append(pos)
X = np.asarray(X)
if len(X) > 0:
# Important to set min_sample to 0, as a dice may only have one dot
clustering = cluster.DBSCAN(eps=40, min_samples=0).fit(X)
# Find the largest label assigned + 1, that's the number of dice found
num_dice = max(clustering.labels_) + 1
dice = []
# Calculate centroid of each dice, the average between all a dice's dots
for i in range(num_dice):
X_dice = X[clustering.labels_ == i]
centroid_dice = np.mean(X_dice, axis=0)
dice.append([len(X_dice), *centroid_dice])
return dice
else:
return []
def overlay_info(frame, dice, blobs):
# Overlay blobs
for b in blobs:
pos = b.pt
r = b.size / 2
cv2.circle(frame, (int(pos[0]), int(pos[1])),
int(r), (255, 0, 0), 2)
# Overlay dice number
for d in dice:
# Get textsize for text centering
textsize = cv2.getTextSize(
str(d[0]), cv2.FONT_HERSHEY_PLAIN, 3, 2)[0]
cv2.putText(frame, str(d[0]),
(int(d[1] - textsize[0] / 2),
int(d[2] + textsize[1] / 2)),
cv2.FONT_HERSHEY_PLAIN, 3, (0, 255, 0), 2)
# Initialize a video feed
cap = cv2.VideoCapture(0)
while(True):
# Grab the latest image from the video feed
ret, frame = cap.read()
# We'll define these later
blobs = get_blobs(frame)
dice = get_dice_from_blobs(blobs)
out_frame = overlay_info(frame, dice, blobs)
cv2.imshow("frame", frame)
res = cv2.waitKey(1)
# Stop if the user presses "q"
if res & 0xFF == ord('q'):
break
# When everything is done, release the capture
cap.release()
cv2.destroyAllWindows()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment