Automatic coin detection, counting and value estimation using classical Digital Image Processing techniques.
This project was developed for the PDI / Digital Image Processing course. The system receives an image containing Brazilian coins, applies a complete processing pipeline, detects coin candidates and estimates the final monetary value.
The project can be used in two main ways:
- Single image test — useful to visually inspect each Digital Image Processing step.
- Batch dataset evaluation — useful to randomly test 20% of a dataset and calculate accuracy metrics.
| # | Technique | Purpose |
|---|---|---|
| 1 | Grayscale Conversion | Reduces the image to one intensity channel |
| 2 | CLAHE / Contrast Enhancement | Improves local contrast before segmentation |
| 3 | Gaussian Blur | Reduces noise before thresholding |
| 4 | Adaptive + Otsu Thresholding | Separates coin regions from the background |
| 5 | Morphological Operations | Removes noise and fills small gaps |
| 6 | Contour Detection | Detects object boundaries and coin candidates |
| 7 | Shape Filtering | Filters candidates using area, circularity, solidity and aspect ratio |
| 8 | Hough Circle Transform | Detects circular shapes and validates coin candidates |
| 9 | Watershed Segmentation | Separates touching or overlapping regions |
| 10 | HSV Color Analysis | Helps classify the monetary value of each coin |
| 11 | Candidate Fusion | Combines contour, Hough and Watershed detections |
| 12 | Batch Evaluation | Tests a random percentage of the dataset and calculates accuracy metrics |
Expected project structure:
pdi/
├── coin_test.py
├── coin_counter.py
├── batch_evaluate.py
├── generate_test_image.py
├── requirements.txt
├── README.md
└── pipeline_steps.png
Example dataset structure:
dataset/
├── classification_dataset/
│ └── all/
├── COCO_labelme_classification/
│ └── classification/
├── COCO_labelme_regression/
│ └── regression/
├── regression_dataset/
└── regression_sample/
The dataset folder does not need to be inside the project folder. However, the path used in the terminal commands must point correctly to where the dataset is located on your computer.
| File | Description |
|---|---|
coin_test.py |
Main script for testing one image and visualizing the pipeline |
coin_counter.py |
Alternative script for running the coin counter |
batch_evaluate.py |
Script for automatic dataset evaluation |
generate_test_image.py |
Generates a synthetic coin image for testing |
requirements.txt |
Python dependencies |
pipeline_steps.png |
Output image showing the processing steps |
Main dependencies:
opencv-python
numpy
matplotlib
Install them with:
pip install -r requirements.txtOpen the terminal inside the project folder:
cd path/to/pdiExample:
cd /Users/your_user/coding/Uni/pdiCreate a virtual environment:
python3 -m venv .venvActivate the virtual environment:
source .venv/bin/activateInstall the dependencies:
python -m pip install --upgrade pip
python -m pip install -r requirements.txtTest if OpenCV is working:
python -c "import cv2; print(cv2.__version__)"If a version number appears, the setup is correct.
Open PowerShell or Command Prompt inside the project folder:
cd path\to\pdiExample:
cd C:\Users\your_user\Documents\pdiCreate a virtual environment:
py -m venv .venvActivate it:
.\.venv\Scripts\Activate.ps1If PowerShell blocks the activation script, run:
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass
.\.venv\Scripts\Activate.ps1.venv\Scripts\activateInstall the dependencies:
python -m pip install --upgrade pip
python -m pip install -r requirements.txtTest if OpenCV is working:
python -c "import cv2; print(cv2.__version__)"If a version number appears, the setup is correct.
Use coin_test.py when you want to test one image and see the full visual pipeline.
This is the best option to understand how the PDI steps are working.
python coin_test.py ../dataset/classification_dataset/all/5_1477290318.jpgpython coin_test.py ..\dataset\classification_dataset\all\5_1477290318.jpgImportant: the path depends on where your dataset is located.
If your dataset is not next to the pdi folder, use the full path.
python coin_test.py "/Users/your_user/coding/Uni/dataset/classification_dataset/all/5_1477290318.jpg"python coin_test.py "C:\Users\your_user\Documents\dataset\classification_dataset\all\5_1477290318.jpg"Use --no-show if you only want the console result and do not want Matplotlib to open the figure window.
python coin_test.py ../dataset/classification_dataset/all/5_1477290318.jpg --no-showpython coin_test.py ..\dataset\classification_dataset\all\5_1477290318.jpg --no-showThe program prints a summary similar to this:
COIN COUNTER — RESULTS
[ contour ] color=copper_dark area=3246 radius=32.1 HSV=(21°, 227, 42) -> R$0.05
Raw contours: 1
Valid contour candidates: 1
Fused candidates: 1
Hough Circles filtered: 1
Watershed objects filtered: 1
Final fused count: 1
Estimated Total Value: R$ 0.05
The most important fields are:
| Field | Meaning |
|---|---|
| Raw contours | Total raw contours found after segmentation |
| Valid contour candidates | Contours that passed the shape filters |
| Fused candidates | Final candidate list after merging detections |
| Hough Circles filtered | Circular objects detected by Hough Circle Transform |
| Watershed objects filtered | Objects detected after Watershed segmentation |
| Final fused count | Final number of coins detected |
| Estimated Total Value | Estimated monetary value in Brazilian reais |
The script also saves:
pipeline_steps.png
This image shows the main processing steps used by the system.
If you do not have a real image available, you can generate a synthetic test image.
python generate_test_image.pyThis creates:
coins.jpg
Then run:
python coin_test.py coins.jpgor:
python coin_counter.py coins.jpgThe batch evaluator estimates the expected value from the image filename.
Examples:
| Filename example | Expected value |
|---|---|
5_1477290318.jpg |
R$0.05 |
10_1477290318.jpg |
R$0.10 |
25_1477290318.jpg |
R$0.25 |
50_1477290318.jpg |
R$0.50 |
100_1477290318.jpg |
R$1.00 |
This means that the first number before _ is interpreted as the coin class.
The file batch_evaluate.py automatically evaluates multiple images from a dataset.
It can:
- Find images recursively inside a dataset folder.
- Randomly select a percentage of the dataset.
- Run the PDI pipeline on each selected image.
- Compare the detected result with the expected value from the filename.
- Generate counting accuracy metrics.
- Generate value estimation accuracy metrics.
- Save a CSV file.
- Save a summary report.
- Save annotated images.
This is recommended before running a full dataset evaluation.
python batch_evaluate.py ../dataset/classification_dataset --ratio 0.20 --seed 42 --max-images 200 --save-imagespython batch_evaluate.py ..\dataset\classification_dataset --ratio 0.20 --seed 42 --max-images 200 --save-imagesExplanation:
| Argument | Meaning |
|---|---|
../dataset/classification_dataset |
Dataset folder to evaluate |
--ratio 0.20 |
Randomly selects 20% of the available images |
--seed 42 |
Makes the random selection reproducible |
--max-images 200 |
Limits the test to 200 images |
--save-images |
Saves annotated result images |
To evaluate a true 20% random sample, remove --max-images.
python batch_evaluate.py ../dataset/classification_dataset --ratio 0.20 --seed 42 --save-imagespython batch_evaluate.py ..\dataset\classification_dataset --ratio 0.20 --seed 42 --save-imagesDepending on your dataset structure, each folder can be evaluated separately.
This is recommended because different dataset folders may have different image characteristics.
macOS / Linux:
python batch_evaluate.py ../dataset/classification_dataset --ratio 0.20 --seed 42 --max-images 200 --save-imagesWindows:
python batch_evaluate.py ..\dataset\classification_dataset --ratio 0.20 --seed 42 --max-images 200 --save-imagesmacOS / Linux:
python batch_evaluate.py ../dataset/COCO_labelme_classification --ratio 0.20 --seed 42 --max-images 200 --save-imagesWindows:
python batch_evaluate.py ..\dataset\COCO_labelme_classification --ratio 0.20 --seed 42 --max-images 200 --save-imagesmacOS / Linux:
python batch_evaluate.py ../dataset/COCO_labelme_regression --ratio 0.20 --seed 42 --max-images 200 --save-imagesWindows:
python batch_evaluate.py ..\dataset\COCO_labelme_regression --ratio 0.20 --seed 42 --max-images 200 --save-imagesIf you want to test all subfolders together:
python batch_evaluate.py ../dataset --ratio 0.20 --seed 42 --max-images 200 --save-imagespython batch_evaluate.py ..\dataset --ratio 0.20 --seed 42 --max-images 200 --save-imagesFor the full 20% sample:
python batch_evaluate.py ../dataset --ratio 0.20 --seed 42 --save-imagespython batch_evaluate.py ..\dataset --ratio 0.20 --seed 42 --save-imagesBy default, the batch evaluator assumes that the dataset images contain one coin per image.
This is correct for datasets such as:
classification_dataset
COCO_labelme_classification
COCO_labelme_regression
In this default mode, if the detector finds more than one candidate in a dataset image, the evaluator still checks whether the main coin was found correctly.
This is useful because these datasets are designed for classification/regression of one visible coin per image.
If you want to evaluate images that may contain multiple coins in the same photo, use:
python batch_evaluate.py ../dataset --ratio 0.20 --seed 42 --max-images 200 --save-images --multi-coin-modepython batch_evaluate.py ..\dataset --ratio 0.20 --seed 42 --max-images 200 --save-images --multi-coin-modeUse --multi-coin-mode only when the images are expected to contain multiple coins.
By default, batch results are saved in:
batch_results/
If you want to save the results of different experiments separately, use --output-dir.
Example:
python batch_evaluate.py ../dataset/classification_dataset --ratio 0.20 --seed 42 --max-images 200 --save-images --output-dir results_classificationWindows:
python batch_evaluate.py ..\dataset\classification_dataset --ratio 0.20 --seed 42 --max-images 200 --save-images --output-dir results_classificationAfter running batch_evaluate.py, the following folder is created:
batch_results/
Inside it, the main files are:
batch_results/evaluation_results.csv
batch_results/summary.txt
batch_results/annotated/
| Output | Description |
|---|---|
evaluation_results.csv |
Detailed result for each tested image |
summary.txt |
Accuracy summary |
annotated/ |
Images with visual detection annotations |
cat batch_results/summary.txtor:
open batch_results/summary.txttype batch_results\summary.txtYou can also open the file manually using VS Code, Notepad or another text editor.
The summary file contains metrics such as:
COUNT ACCURACY
--------------
Contour Detection accuracy
Hough Circle accuracy
Watershed accuracy
Fused Candidate accuracy
Final Count accuracy
VALUE ACCURACY
--------------
Rule-based value accuracy
Calibrated value accuracy
Color+area value accuracy
| Metric | Meaning |
|---|---|
| Contour Detection accuracy | Accuracy using only contour candidates |
| Hough Circle accuracy | Accuracy using only Hough Circle Transform |
| Watershed accuracy | Accuracy using only Watershed segmentation |
| Fused Candidate accuracy | Accuracy after merging candidate detections |
| Final Count accuracy | Final counting accuracy used as the main result |
The most important counting metric is:
Final Count accuracy
| Metric | Meaning |
|---|---|
| Rule-based value accuracy | Value accuracy using fixed color/area rules |
| Calibrated value accuracy | Value accuracy using area calibration from the dataset |
| Color+area value accuracy | Value accuracy combining color and detected area |
The value classification is harder than counting because it depends on:
- illumination;
- shadows;
- reflections;
- coin color variation;
- image scale;
- visual similarity between coin classes.
Therefore, the system is expected to perform better in coin counting than in monetary value classification.
The following results were obtained using a random sample of 200 images with seed 42.
The tests were executed separately for each dataset folder.
Valid processed images: 200
Errors: 0
COUNT ACCURACY
--------------
Contour Detection accuracy: 90.00%
Hough Circle accuracy: 79.00%
Watershed accuracy: 64.50%
Fused Candidate accuracy: 88.00%
Final Count accuracy: 100.00%
VALUE ACCURACY
--------------
Rule-based value accuracy: 50.00%
Calibrated value accuracy: 60.00%
Color+area value accuracy: 56.00%
Rule-based mean abs. value error: R$ 0.19
Calibrated mean abs. value error: R$ 0.16
Color+area mean abs. value error: R$ 0.17
Per-class results:
R$ 0.05: count_acc=100.00%, value_acc_calibrated=46.51%
R$ 0.10: count_acc=100.00%, value_acc_calibrated=68.89%
R$ 0.25: count_acc=100.00%, value_acc_calibrated=58.06%
R$ 0.50: count_acc=100.00%, value_acc_calibrated=46.15%
R$ 1.00: count_acc=100.00%, value_acc_calibrated=78.57%
Valid processed images: 200
Errors: 0
COUNT ACCURACY
--------------
Contour Detection accuracy: 88.50%
Hough Circle accuracy: 78.00%
Watershed accuracy: 58.50%
Fused Candidate accuracy: 90.00%
Final Count accuracy: 99.50%
VALUE ACCURACY
--------------
Rule-based value accuracy: 44.50%
Calibrated value accuracy: 47.50%
Color+area value accuracy: 49.50%
Rule-based mean abs. value error: R$ 0.21
Calibrated mean abs. value error: R$ 0.21
Color+area mean abs. value error: R$ 0.20
Per-class results:
R$ 0.05: count_acc=97.50%, value_acc_calibrated=37.50%
R$ 0.10: count_acc=100.00%, value_acc_calibrated=60.00%
R$ 0.25: count_acc=100.00%, value_acc_calibrated=50.00%
R$ 0.50: count_acc=100.00%, value_acc_calibrated=25.00%
R$ 1.00: count_acc=100.00%, value_acc_calibrated=74.29%
Valid processed images: 200
Errors: 0
COUNT ACCURACY
--------------
Contour Detection accuracy: 63.50%
Hough Circle accuracy: 44.00%
Watershed accuracy: 41.00%
Fused Candidate accuracy: 54.00%
Final Count accuracy: 80.00%
VALUE ACCURACY
--------------
Rule-based value accuracy: 45.69%
Calibrated value accuracy: 53.45%
Color+area value accuracy: 50.00%
Rule-based mean abs. value error: R$ 0.31
Calibrated mean abs. value error: R$ 0.22
Color+area mean abs. value error: R$ 0.27
Per-class results:
R$ 0.05: count_acc=95.83%, value_acc_calibrated=50.00%
R$ 0.10: count_acc=95.45%, value_acc_calibrated=72.73%
R$ 0.25: count_acc=100.00%, value_acc_calibrated=52.38%
R$ 0.50: count_acc=100.00%, value_acc_calibrated=40.00%
R$ 1.00: count_acc=87.50%, value_acc_calibrated=54.17%
The experimental results show that the system performs better in coin detection and counting than in monetary value classification.
The best counting results were obtained in:
classification_dataset
COCO_labelme_classification
In these folders, the final counting accuracy reached approximately 100% in the sampled evaluation.
The value estimation task was more difficult. This is expected because Brazilian coins may have similar colors and sizes, and the images contain variations in:
- lighting;
- shadows;
- reflections;
- scale;
- coin position;
- background texture.
The system still provides value estimation, but the value accuracy is lower than the counting accuracy.
A complete evaluation workflow is:
macOS / Linux:
source .venv/bin/activateWindows PowerShell:
.\.venv\Scripts\Activate.ps1macOS / Linux:
python coin_test.py ../dataset/classification_dataset/all/5_1477290318.jpgWindows:
python coin_test.py ..\dataset\classification_dataset\all\5_1477290318.jpgmacOS / Linux:
python batch_evaluate.py ../dataset/classification_dataset --ratio 0.20 --seed 42 --max-images 200 --save-imagesWindows:
python batch_evaluate.py ..\dataset\classification_dataset --ratio 0.20 --seed 42 --max-images 200 --save-imagesmacOS / Linux:
cat batch_results/summary.txtWindows:
type batch_results\summary.txtThis means OpenCV was not installed in the Python environment being used.
Make sure the virtual environment is activated, then run:
python -m pip install -r requirements.txtThen test:
python -c "import cv2; print(cv2.__version__)"This usually means the image path is wrong.
Check if the file exists.
macOS / Linux:
ls ../dataset/classification_dataset/allWindows:
dir ..\dataset\classification_dataset\allIf the dataset is in another location, use the full path.
Paths are different on each computer.
Example macOS path:
/Users/your_user/coding/Uni/dataset/classification_dataset/all/5_1477290318.jpgExample Windows path:
C:\Users\your_user\Documents\dataset\classification_dataset\all\5_1477290318.jpgUse quotation marks if the path contains spaces:
python coin_test.py "/Users/your_user/My Dataset/image.jpg"Windows:
python coin_test.py "C:\Users\your_user\My Dataset\image.jpg"By default, each batch run writes to:
batch_results/
To avoid overwriting previous results, use a different output folder:
python batch_evaluate.py ../dataset/classification_dataset --ratio 0.20 --seed 42 --max-images 200 --save-images --output-dir results_classificationWindows:
python batch_evaluate.py ..\dataset\classification_dataset --ratio 0.20 --seed 42 --max-images 200 --save-images --output-dir results_classificationThis project demonstrates a complete classical Digital Image Processing pipeline for coin detection, counting and value estimation.
The system uses grayscale conversion, contrast enhancement, Gaussian blur, adaptive thresholding, morphological operations, contour detection, Hough Circle Transform, Watershed segmentation, HSV color analysis and candidate fusion.
The best results were obtained for coin counting, reaching very high accuracy in the classification datasets. Monetary value estimation was more challenging because it depends on color, scale and lighting conditions.
Overall, the project shows that classical Digital Image Processing techniques can be combined to build a functional coin detection and counting system without requiring a trained deep learning model.