T. Yang
Case study · 02

pkr.img

Chip photo → payouts. A web app that reads player stacks from a single image and generates a minimal settlement graph.

Status
MVP working · vision pipeline in progress
Year
Dec 2025 - now
Stack
Next.js · TypeScript · FastAPI · SQLAlchemy · YOLOv8
Source
github.com/tianyiy-tim/pkr.img

1.0 Summary

Settling a home poker game is a counting problem followed by a graph problem, and both get done by hand at the end of the night. Every player ends up with a pile of mixed denomination chips, someone tallies the totals on paper, and the table figures out who pays whom. That usually takes more transfers than it needs to.

pkr.img takes a photo of each player's stack instead. It segments the individual chips, converts each stack to a cash total, and generates a minimal settlement graph, which is the smallest set of transfers that clears every balance, which is what actually gets paid out over Venmo. The counting step is a segmentation model trained on a Roboflow labeled dataset (Section 5.0). Around it sits a Next.js front end over a FastAPI service (Section 4.0), with role-aware routing and persistent sessions for up to eight concurrent players. The full-stack platform works end to end and the vision pipeline is still being tightened.

2.0 Background & Problem

A game ends with chips spread across the table and no running record of who bought in for what. Turning that into payments takes three steps, all of them manual:

  1. Count every stack by denomination.
  2. Convert each stack to a cash figure and compare it against that player's buy-in.
  3. Find a set of transfers that settles the resulting balances.

None of the three is hard on its own. The problem is that they all happen late, with everyone waiting, and two of them are easy to get wrong without anyone noticing.

2.1 Counting

Step 1 is the bottleneck and it is harder to automate than it looks. A stack of chips on felt is an awkward scene for a detector. Each chip covers most of the one under it, denominations are told apart by color and edge pattern instead of shape, the surfaces are glossy enough to throw specular highlights, and home game lighting is whatever the room happens to have.

Two stacks of mixed-denomination poker chips on a grey felt table
Fig. 01 · input, two stacks of mixed denominations

Two stacks of the same height can hold completely different amounts, so counting chips is not enough. Each chip has to be separated cleanly enough to be classified. That is what drives the model choice in Section 5.2.

2.2 Settlement

Step 3 is a small optimization problem, and at the table it usually gets solved greedily. Whoever is down pays whoever is up until the books balance. That settles correctly but it produces more transfers than necessary, which you notice when six people are paying each other back one at a time. Given each player's net balance, the app computes a minimal settlement graph instead.

3.0 Goals & Scope

3.1 Goal

Photo in, payouts out. A player photographs their stack and the app produces per-player totals plus the transfers that settle the game, with no manual counting and no end of night math.

3.2 In Scope

  • Room creation, and players joining a room.
  • Per-player photo upload, including resubmission, since the first photo is often the bad one.
  • Chip segmentation from a single photo, and the per-player totals that come out of it.
  • A minimal settlement graph over the resulting balances.
  • A host dashboard listing players and their submissions.

3.3 Out of Scope

  • Moving money. The app produces the transfers and settling up happens outside it.
  • Card recognition, hand history, or any in-play analysis. It only looks at chips, and only at the end.
  • Tournament structures, blind levels, and multi-table play.

4.0 System Design

Simple MVP stack, picked to be easy to extend.

4.1 Components

PathRole
web/Next.js UI and routing
api/ FastAPI endpoints and SQLAlchemy models
db SQLite, with an upgrade path to Postgres

SQLite is enough for one host running one game, and going through SQLAlchemy means moving to Postgres is a config change instead of a rewrite.

pkr.img system architecture: Next.js web client, FastAPI service, database, and the segmentation model
Fig. 02 · system architecture

4.2 Flow

A game moves through four states: create → join → submit → settle.

  1. Create. The host opens a room.
  2. Join. Players join it.
  3. Submit. Each player photographs their stack and uploads it, resubmitting if the shot is unusable.
  4. Settle. Once the submissions are in, the app totals each stack and produces the transfers.

5.0 Computer Vision

5.1 Pipeline

  1. Label chip instances in Roboflow as segmentation masks.
  2. Export the dataset with train / validation / test splits.
  3. Fine-tune a segmentation model on it for chip masks. SAM3 first; YOLOv8 segmentation is what runs now.
  4. Post-process the masks into chip counts and per-player totals.

5.2 Why Segmentation, Not Boxes

Bounding-box detectors struggle on the scene in Section 2.1. Under this much occlusion, a box around a chip that is mostly hidden overlaps almost exactly with the boxes around its neighbors, so non-maximum suppression either merges chips together or invents ones that are not there. A box also says nothing about where one chip ends and the next begins, which is the only thing the counting step needs.

Segmentation gets around that. A segmentation-first approach produces cleaner chip boundaries in these cluttered, overlapping cases, and a mask per chip is the right input for post-processing into counts and values.

Fine-tuning instead of using the base model off the shelf lets it adapt to specific chip colors and lighting while keeping the generalization that makes it hold up on a table it has not seen.

Segmentation output, with a separate mask outlining each poker chip in two stacks
Fig. 03 · prediction, chip masks over a real table image

6.0 Status & Next Steps

The full-stack MVP works. Rooms, joins, uploads and settlement all run end to end. The vision pipeline is the part still in progress. Labeling and fine-tuning produce masks like Fig. 03, but turning those masks into values is the step that still needs work.

NextWhy
Counting & calibration Map masks → chip values reliably across angles and occlusion.
Realtime host dashboard Push updates the moment a player resubmits a photo.

7.0 References

  • Source repository: github.com/tianyiy-tim/pkr.img
  • Roboflow, used for dataset labeling and export.
  • SAM3, the base segmentation model, fine-tuned for chip masks.