pharmacode-toolkit 0.2.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pharmacode_toolkit-0.2.1/.github/workflows/publish.yml +41 -0
- pharmacode_toolkit-0.2.1/.github/workflows/test.yml +64 -0
- pharmacode_toolkit-0.2.1/.gitignore +15 -0
- pharmacode_toolkit-0.2.1/CHANGELOG.md +35 -0
- pharmacode_toolkit-0.2.1/LICENSE +21 -0
- pharmacode_toolkit-0.2.1/PKG-INFO +129 -0
- pharmacode_toolkit-0.2.1/README.md +99 -0
- pharmacode_toolkit-0.2.1/docs/algorithm.md +285 -0
- pharmacode_toolkit-0.2.1/docs/benchmark.md +138 -0
- pharmacode_toolkit-0.2.1/docs/cli.md +138 -0
- pharmacode_toolkit-0.2.1/docs/limitations.md +56 -0
- pharmacode_toolkit-0.2.1/docs/provenance.md +34 -0
- pharmacode_toolkit-0.2.1/examples/README.md +5 -0
- pharmacode_toolkit-0.2.1/examples/annotated/three_codes_scanned.jpg +0 -0
- pharmacode_toolkit-0.2.1/examples/annotated/value_1234.jpg +0 -0
- pharmacode_toolkit-0.2.1/examples/annotated/value_12345_rotated_90.jpg +0 -0
- pharmacode_toolkit-0.2.1/examples/expected/three_codes_scanned.json +117 -0
- pharmacode_toolkit-0.2.1/examples/expected/value_1234.json +49 -0
- pharmacode_toolkit-0.2.1/examples/expected/value_12345_rotated_90.json +55 -0
- pharmacode_toolkit-0.2.1/examples/generated/three_codes_scanned.png +0 -0
- pharmacode_toolkit-0.2.1/examples/generated/value_1234.png +0 -0
- pharmacode_toolkit-0.2.1/examples/generated/value_12345_rotated_90.png +0 -0
- pharmacode_toolkit-0.2.1/pyproject.toml +78 -0
- pharmacode_toolkit-0.2.1/src/pharmacode/__init__.py +71 -0
- pharmacode_toolkit-0.2.1/src/pharmacode/__main__.py +10 -0
- pharmacode_toolkit-0.2.1/src/pharmacode/benchmark.py +248 -0
- pharmacode_toolkit-0.2.1/src/pharmacode/cli.py +214 -0
- pharmacode_toolkit-0.2.1/src/pharmacode/decoding.py +33 -0
- pharmacode_toolkit-0.2.1/src/pharmacode/detection.py +318 -0
- pharmacode_toolkit-0.2.1/src/pharmacode/encoding.py +59 -0
- pharmacode_toolkit-0.2.1/src/pharmacode/imageops.py +59 -0
- pharmacode_toolkit-0.2.1/src/pharmacode/io.py +41 -0
- pharmacode_toolkit-0.2.1/src/pharmacode/models.py +280 -0
- pharmacode_toolkit-0.2.1/src/pharmacode/pipeline.py +77 -0
- pharmacode_toolkit-0.2.1/src/pharmacode/rendering.py +233 -0
- pharmacode_toolkit-0.2.1/src/pharmacode/segmentation.py +377 -0
- pharmacode_toolkit-0.2.1/src/pharmacode/visualization.py +68 -0
- pharmacode_toolkit-0.2.1/tests/__init__.py +0 -0
- pharmacode_toolkit-0.2.1/tests/conftest.py +20 -0
- pharmacode_toolkit-0.2.1/tests/unit/__init__.py +0 -0
- pharmacode_toolkit-0.2.1/tests/unit/test_benchmark.py +71 -0
- pharmacode_toolkit-0.2.1/tests/unit/test_cli.py +198 -0
- pharmacode_toolkit-0.2.1/tests/unit/test_decoding.py +21 -0
- pharmacode_toolkit-0.2.1/tests/unit/test_detection.py +149 -0
- pharmacode_toolkit-0.2.1/tests/unit/test_direction.py +32 -0
- pharmacode_toolkit-0.2.1/tests/unit/test_encoding.py +85 -0
- pharmacode_toolkit-0.2.1/tests/unit/test_examples.py +27 -0
- pharmacode_toolkit-0.2.1/tests/unit/test_io.py +37 -0
- pharmacode_toolkit-0.2.1/tests/unit/test_models.py +97 -0
- pharmacode_toolkit-0.2.1/tests/unit/test_pipeline.py +66 -0
- pharmacode_toolkit-0.2.1/tests/unit/test_rendering.py +176 -0
- pharmacode_toolkit-0.2.1/tests/unit/test_segmentation.py +225 -0
- pharmacode_toolkit-0.2.1/tests/unit/test_validation.py +67 -0
- pharmacode_toolkit-0.2.1/tests/unit/test_visualization.py +26 -0
- pharmacode_toolkit-0.2.1/tests/vision/__init__.py +0 -0
- pharmacode_toolkit-0.2.1/tests/vision/test_blur_and_noise.py +54 -0
- pharmacode_toolkit-0.2.1/tests/vision/test_captions.py +93 -0
- pharmacode_toolkit-0.2.1/tests/vision/test_framing.py +156 -0
- pharmacode_toolkit-0.2.1/tests/vision/test_multiple_codes.py +46 -0
- pharmacode_toolkit-0.2.1/tests/vision/test_negative_images.py +47 -0
- pharmacode_toolkit-0.2.1/tests/vision/test_perspective.py +21 -0
- pharmacode_toolkit-0.2.1/tests/vision/test_quiet_zone.py +67 -0
- pharmacode_toolkit-0.2.1/tests/vision/test_rotations.py +45 -0
- pharmacode_toolkit-0.2.1/tests/vision/test_roundtrip.py +51 -0
- pharmacode_toolkit-0.2.1/tests/vision/test_scale_and_dpi.py +34 -0
- pharmacode_toolkit-0.2.1/tools/generate_samples.py +60 -0
- pharmacode_toolkit-0.2.1/tools/run_benchmark.py +10 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
name: publish
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags: ["v*"]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
build:
|
|
9
|
+
name: build sdist and wheel
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/checkout@v7
|
|
13
|
+
- uses: actions/setup-python@v7
|
|
14
|
+
with:
|
|
15
|
+
python-version: "3.12"
|
|
16
|
+
- name: Build
|
|
17
|
+
run: python -m pip install --upgrade pip build twine && python -m build
|
|
18
|
+
- name: Check the archives and the README rendering
|
|
19
|
+
run: python -m twine check dist/*
|
|
20
|
+
- uses: actions/upload-artifact@v7
|
|
21
|
+
with:
|
|
22
|
+
name: dist
|
|
23
|
+
path: dist/
|
|
24
|
+
|
|
25
|
+
publish:
|
|
26
|
+
name: publish to PyPI
|
|
27
|
+
needs: build
|
|
28
|
+
runs-on: ubuntu-latest
|
|
29
|
+
environment:
|
|
30
|
+
name: pypi
|
|
31
|
+
url: https://pypi.org/project/pharmacode-toolkit/
|
|
32
|
+
permissions:
|
|
33
|
+
id-token: write
|
|
34
|
+
contents: read
|
|
35
|
+
steps:
|
|
36
|
+
- uses: actions/download-artifact@v8
|
|
37
|
+
with:
|
|
38
|
+
name: dist
|
|
39
|
+
path: dist/
|
|
40
|
+
- name: Publish (trusted publishing, no token)
|
|
41
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
name: test
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
tags: ["v*"]
|
|
7
|
+
pull_request:
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
name: ${{ matrix.os }} / py${{ matrix.python }}
|
|
12
|
+
runs-on: ${{ matrix.os }}
|
|
13
|
+
strategy:
|
|
14
|
+
fail-fast: false
|
|
15
|
+
matrix:
|
|
16
|
+
os: [ubuntu-latest, windows-latest]
|
|
17
|
+
python: ["3.10", "3.12"]
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v7
|
|
20
|
+
- uses: actions/setup-python@v7
|
|
21
|
+
with:
|
|
22
|
+
python-version: ${{ matrix.python }}
|
|
23
|
+
- name: Install
|
|
24
|
+
run: python -m pip install --upgrade pip && python -m pip install -e .[dev]
|
|
25
|
+
- name: Lint
|
|
26
|
+
run: ruff check . && ruff format --check .
|
|
27
|
+
- name: Tests
|
|
28
|
+
run: pytest
|
|
29
|
+
- name: Quick benchmark
|
|
30
|
+
run: pharmacode benchmark --seed 20260919 --output benchmark-output --quick
|
|
31
|
+
- name: Upload benchmark failures
|
|
32
|
+
if: always()
|
|
33
|
+
uses: actions/upload-artifact@v7
|
|
34
|
+
with:
|
|
35
|
+
name: benchmark-failures-${{ matrix.os }}-py${{ matrix.python }}
|
|
36
|
+
path: benchmark-output/failures
|
|
37
|
+
if-no-files-found: ignore
|
|
38
|
+
|
|
39
|
+
package:
|
|
40
|
+
name: build and install smoke test
|
|
41
|
+
runs-on: ${{ matrix.os }}
|
|
42
|
+
strategy:
|
|
43
|
+
matrix:
|
|
44
|
+
os: [ubuntu-latest, windows-latest]
|
|
45
|
+
steps:
|
|
46
|
+
- uses: actions/checkout@v7
|
|
47
|
+
- uses: actions/setup-python@v7
|
|
48
|
+
with:
|
|
49
|
+
python-version: "3.12"
|
|
50
|
+
- name: Build wheel
|
|
51
|
+
run: python -m pip install --upgrade pip build && python -m build
|
|
52
|
+
- name: Install wheel into a fresh environment and decode a generated code
|
|
53
|
+
shell: bash
|
|
54
|
+
run: |
|
|
55
|
+
python -m venv smoke
|
|
56
|
+
if [ -x smoke/bin/python ]; then PY=smoke/bin/python; else PY=smoke/Scripts/python.exe; fi
|
|
57
|
+
"$PY" -m pip install --quiet dist/*.whl
|
|
58
|
+
"$PY" -m pharmacode generate --value 12345 --dpi 300 --output smoke.png
|
|
59
|
+
"$PY" -m pharmacode decode smoke.png --dpi 300 --json smoke.json
|
|
60
|
+
"$PY" -c "import json; d = json.load(open('smoke.json')); assert d['detections'][0]['value'] == 12345, d"
|
|
61
|
+
- uses: actions/upload-artifact@v7
|
|
62
|
+
with:
|
|
63
|
+
name: wheel-${{ matrix.os }}
|
|
64
|
+
path: dist/*.whl
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.2.1 - 2026-09-20
|
|
4
|
+
|
|
5
|
+
- Documentation describes the real-world sample check made before each release.
|
|
6
|
+
- README renders on PyPI: absolute image and documentation links, `pip install pharmacode-toolkit`.
|
|
7
|
+
- Releases are published to PyPI by a tag-triggered workflow using trusted publishing.
|
|
8
|
+
- CI actions updated to their current major versions.
|
|
9
|
+
|
|
10
|
+
## 0.2.0 - 2026-09-19
|
|
11
|
+
|
|
12
|
+
Fixes and options that came out of checking the decoder on publicly available
|
|
13
|
+
sample images.
|
|
14
|
+
|
|
15
|
+
- Human-readable captions printed next to a code no longer break the bar-height check.
|
|
16
|
+
- Codes that fill the frame keep their wide bars: the background kernel is sized from the strokes.
|
|
17
|
+
- A thin rule crossing the bars is removed by a directional opening when nothing else is found.
|
|
18
|
+
- `decode --allow-cropped-quiet-zone` downgrades a quiet zone cut by the image edge to a warning.
|
|
19
|
+
- `decode --min-confidence` reports weak detections as `LOW_CONFIDENCE` errors.
|
|
20
|
+
- The documentation states how the decoder was checked beyond the synthetic benchmark.
|
|
21
|
+
|
|
22
|
+
## 0.1.0 - 2026-09-18
|
|
23
|
+
|
|
24
|
+
First release.
|
|
25
|
+
|
|
26
|
+
- Encoding and decoding of one-track Pharmacode values 3..131070 with both reading directions.
|
|
27
|
+
- Synthetic renderer with Laetus standard and miniature dimensions, DPI, rotation, blur, noise,
|
|
28
|
+
JPEG, contrast, illumination, perspective, scaling, multi-code scenes and negative samples.
|
|
29
|
+
- Detector and decoder for PNG, JPEG and TIFF: 0/90/180/270 degrees and small tilts,
|
|
30
|
+
quiet-zone and geometry validation, stable error codes, confidence.
|
|
31
|
+
- `pharmacode generate`, `pharmacode decode` (JSON, annotated image, exit codes) and
|
|
32
|
+
`pharmacode benchmark` (condition matrix with failure artefacts); `python -m pharmacode ...`
|
|
33
|
+
is equivalent to the `pharmacode` console script.
|
|
34
|
+
- Documentation: algorithm and threshold provenance, CLI, benchmark, limitations, provenance.
|
|
35
|
+
- CI on Linux and Windows with a wheel install smoke test.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Konstantin Dotsenko
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: pharmacode-toolkit
|
|
3
|
+
Version: 0.2.1
|
|
4
|
+
Summary: Generate, detect and decode one-track Pharmacode barcodes in images
|
|
5
|
+
Project-URL: Homepage, https://github.com/Dotsen/pharmacode-toolkit
|
|
6
|
+
Project-URL: Repository, https://github.com/Dotsen/pharmacode-toolkit
|
|
7
|
+
Project-URL: Issues, https://github.com/Dotsen/pharmacode-toolkit/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/Dotsen/pharmacode-toolkit/blob/main/CHANGELOG.md
|
|
9
|
+
Project-URL: Author, https://www.linkedin.com/in/dotsen/
|
|
10
|
+
Author-email: Konstantin Dotsenko <konstantin@dotsenko.pro>
|
|
11
|
+
License-Expression: MIT
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Keywords: barcode,computer-vision,laetus,opencv,pharmacode
|
|
14
|
+
Classifier: Development Status :: 3 - Alpha
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Topic :: Scientific/Engineering :: Image Recognition
|
|
22
|
+
Requires-Python: >=3.10
|
|
23
|
+
Requires-Dist: numpy>=1.26
|
|
24
|
+
Requires-Dist: opencv-python-headless>=4.8
|
|
25
|
+
Provides-Extra: dev
|
|
26
|
+
Requires-Dist: build>=1.2; extra == 'dev'
|
|
27
|
+
Requires-Dist: pytest>=8; extra == 'dev'
|
|
28
|
+
Requires-Dist: ruff>=0.5; extra == 'dev'
|
|
29
|
+
Description-Content-Type: text/markdown
|
|
30
|
+
|
|
31
|
+
# pharmacode-toolkit
|
|
32
|
+
|
|
33
|
+
Generate, detect and decode one-track [Pharmacode](https://en.wikipedia.org/wiki/Pharmacode)
|
|
34
|
+
barcodes in PNG, JPEG and TIFF images. Pure Python on numpy and OpenCV.
|
|
35
|
+
|
|
36
|
+

|
|
37
|
+
|
|
38
|
+
```json
|
|
39
|
+
{
|
|
40
|
+
"detections": [
|
|
41
|
+
{"bbox": {"x": 45, "y": 63, "width": 149, "height": 94}, "orientation_deg": 0.0,
|
|
42
|
+
"bars": ["narrow", "wide", "wide", "wide", "narrow", "narrow"],
|
|
43
|
+
"bar_widths_px": [3, 9, 9, 9, 3, 3],
|
|
44
|
+
"value": 91, "mirror_value": 77, "confidence": 1.0, "warnings": []}
|
|
45
|
+
],
|
|
46
|
+
"errors": []
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## What it does
|
|
51
|
+
|
|
52
|
+
- Encodes any value from 3 to 131070 into the 2..16 narrow/wide bars of the format.
|
|
53
|
+
- Renders synthetic codes with the Laetus physical dimensions at any DPI, with
|
|
54
|
+
optional rotation, blur, noise, JPEG artefacts, contrast loss, uneven lighting,
|
|
55
|
+
perspective and scaling, all seeded and reproducible.
|
|
56
|
+
- Finds one or more codes in an image at 0, 90, 180 and 270 degrees and small tilts.
|
|
57
|
+
- Classifies bars, checks quiet zones and geometry, and reports **both** reading
|
|
58
|
+
directions, because the format has no start or stop pattern.
|
|
59
|
+
- Writes a JSON result with stable error codes and an annotated image.
|
|
60
|
+
- Ships a benchmark that reports a matrix of conditions, not one number.
|
|
61
|
+
|
|
62
|
+
## Install
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
pip install pharmacode-toolkit
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
From a clone of the repository: `pip install .` (or `pip install -e .[dev]` for
|
|
69
|
+
development). Requires Python 3.10 or newer. Runtime dependencies: numpy,
|
|
70
|
+
opencv-python-headless.
|
|
71
|
+
|
|
72
|
+
## Quick start
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
pharmacode generate --value 12345 --dpi 300 --output sample.png
|
|
76
|
+
pharmacode decode sample.png --dpi 300
|
|
77
|
+
pharmacode decode sample.png --dpi 300 --json result.json --annotated result.png
|
|
78
|
+
pharmacode decode sample.png --dpi 300 --min-confidence 0.8
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
`python -m pharmacode ...` works the same as the `pharmacode` command above,
|
|
82
|
+
for environments where installing a console script is inconvenient.
|
|
83
|
+
|
|
84
|
+
From Python:
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
from pharmacode import DecoderConfig, decode_image, load_image
|
|
88
|
+
|
|
89
|
+
result = decode_image(load_image("sample.png"), DecoderConfig(dpi=300))
|
|
90
|
+
for code in result.detections:
|
|
91
|
+
print(code.value, code.mirror_value, code.confidence)
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Supported input
|
|
95
|
+
|
|
96
|
+
8-bit grayscale or colour PNG, JPEG and TIFF; dark bars on a light background;
|
|
97
|
+
codes upright, rotated by multiples of 90 degrees, or tilted a few degrees.
|
|
98
|
+
Pass `--dpi` whenever you know the resolution: it enables physical checks and
|
|
99
|
+
reliable classification of codes that use a single bar width.
|
|
100
|
+
|
|
101
|
+
## Limitations
|
|
102
|
+
|
|
103
|
+
See [docs/limitations.md](https://github.com/Dotsen/pharmacode-toolkit/blob/main/docs/limitations.md). In short: no inverted codes, no
|
|
104
|
+
two-track or colour Pharmacode, no DPI from file metadata. Thresholds come from the
|
|
105
|
+
specification and a synthetic benchmark; on top of that the decoder is checked
|
|
106
|
+
against real-world sample images (codes as they appear in the wild: with captions,
|
|
107
|
+
tightly cropped, with a rule drawn across the bars, inside a chart of symbologies).
|
|
108
|
+
|
|
109
|
+
## Documentation
|
|
110
|
+
|
|
111
|
+
- [Algorithm and threshold provenance](https://github.com/Dotsen/pharmacode-toolkit/blob/main/docs/algorithm.md)
|
|
112
|
+
- [Command line and exit codes](https://github.com/Dotsen/pharmacode-toolkit/blob/main/docs/cli.md)
|
|
113
|
+
- [Benchmark](https://github.com/Dotsen/pharmacode-toolkit/blob/main/docs/benchmark.md)
|
|
114
|
+
- [Provenance](https://github.com/Dotsen/pharmacode-toolkit/blob/main/docs/provenance.md)
|
|
115
|
+
- [Changelog](https://github.com/Dotsen/pharmacode-toolkit/blob/main/CHANGELOG.md)
|
|
116
|
+
|
|
117
|
+
## Disclaimer
|
|
118
|
+
|
|
119
|
+
This project is an independent implementation from public descriptions of the
|
|
120
|
+
format. It is **not validated** for regulated pharmaceutical packaging control and
|
|
121
|
+
must not be used as the sole check in such a process.
|
|
122
|
+
|
|
123
|
+
## Author
|
|
124
|
+
|
|
125
|
+
Konstantin Dotsenko ([LinkedIn](https://www.linkedin.com/in/dotsen/)).
|
|
126
|
+
|
|
127
|
+
## License
|
|
128
|
+
|
|
129
|
+
MIT, see [LICENSE](https://github.com/Dotsen/pharmacode-toolkit/blob/main/LICENSE).
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# pharmacode-toolkit
|
|
2
|
+
|
|
3
|
+
Generate, detect and decode one-track [Pharmacode](https://en.wikipedia.org/wiki/Pharmacode)
|
|
4
|
+
barcodes in PNG, JPEG and TIFF images. Pure Python on numpy and OpenCV.
|
|
5
|
+
|
|
6
|
+

|
|
7
|
+
|
|
8
|
+
```json
|
|
9
|
+
{
|
|
10
|
+
"detections": [
|
|
11
|
+
{"bbox": {"x": 45, "y": 63, "width": 149, "height": 94}, "orientation_deg": 0.0,
|
|
12
|
+
"bars": ["narrow", "wide", "wide", "wide", "narrow", "narrow"],
|
|
13
|
+
"bar_widths_px": [3, 9, 9, 9, 3, 3],
|
|
14
|
+
"value": 91, "mirror_value": 77, "confidence": 1.0, "warnings": []}
|
|
15
|
+
],
|
|
16
|
+
"errors": []
|
|
17
|
+
}
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## What it does
|
|
21
|
+
|
|
22
|
+
- Encodes any value from 3 to 131070 into the 2..16 narrow/wide bars of the format.
|
|
23
|
+
- Renders synthetic codes with the Laetus physical dimensions at any DPI, with
|
|
24
|
+
optional rotation, blur, noise, JPEG artefacts, contrast loss, uneven lighting,
|
|
25
|
+
perspective and scaling, all seeded and reproducible.
|
|
26
|
+
- Finds one or more codes in an image at 0, 90, 180 and 270 degrees and small tilts.
|
|
27
|
+
- Classifies bars, checks quiet zones and geometry, and reports **both** reading
|
|
28
|
+
directions, because the format has no start or stop pattern.
|
|
29
|
+
- Writes a JSON result with stable error codes and an annotated image.
|
|
30
|
+
- Ships a benchmark that reports a matrix of conditions, not one number.
|
|
31
|
+
|
|
32
|
+
## Install
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
pip install pharmacode-toolkit
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
From a clone of the repository: `pip install .` (or `pip install -e .[dev]` for
|
|
39
|
+
development). Requires Python 3.10 or newer. Runtime dependencies: numpy,
|
|
40
|
+
opencv-python-headless.
|
|
41
|
+
|
|
42
|
+
## Quick start
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
pharmacode generate --value 12345 --dpi 300 --output sample.png
|
|
46
|
+
pharmacode decode sample.png --dpi 300
|
|
47
|
+
pharmacode decode sample.png --dpi 300 --json result.json --annotated result.png
|
|
48
|
+
pharmacode decode sample.png --dpi 300 --min-confidence 0.8
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
`python -m pharmacode ...` works the same as the `pharmacode` command above,
|
|
52
|
+
for environments where installing a console script is inconvenient.
|
|
53
|
+
|
|
54
|
+
From Python:
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
from pharmacode import DecoderConfig, decode_image, load_image
|
|
58
|
+
|
|
59
|
+
result = decode_image(load_image("sample.png"), DecoderConfig(dpi=300))
|
|
60
|
+
for code in result.detections:
|
|
61
|
+
print(code.value, code.mirror_value, code.confidence)
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Supported input
|
|
65
|
+
|
|
66
|
+
8-bit grayscale or colour PNG, JPEG and TIFF; dark bars on a light background;
|
|
67
|
+
codes upright, rotated by multiples of 90 degrees, or tilted a few degrees.
|
|
68
|
+
Pass `--dpi` whenever you know the resolution: it enables physical checks and
|
|
69
|
+
reliable classification of codes that use a single bar width.
|
|
70
|
+
|
|
71
|
+
## Limitations
|
|
72
|
+
|
|
73
|
+
See [docs/limitations.md](https://github.com/Dotsen/pharmacode-toolkit/blob/main/docs/limitations.md). In short: no inverted codes, no
|
|
74
|
+
two-track or colour Pharmacode, no DPI from file metadata. Thresholds come from the
|
|
75
|
+
specification and a synthetic benchmark; on top of that the decoder is checked
|
|
76
|
+
against real-world sample images (codes as they appear in the wild: with captions,
|
|
77
|
+
tightly cropped, with a rule drawn across the bars, inside a chart of symbologies).
|
|
78
|
+
|
|
79
|
+
## Documentation
|
|
80
|
+
|
|
81
|
+
- [Algorithm and threshold provenance](https://github.com/Dotsen/pharmacode-toolkit/blob/main/docs/algorithm.md)
|
|
82
|
+
- [Command line and exit codes](https://github.com/Dotsen/pharmacode-toolkit/blob/main/docs/cli.md)
|
|
83
|
+
- [Benchmark](https://github.com/Dotsen/pharmacode-toolkit/blob/main/docs/benchmark.md)
|
|
84
|
+
- [Provenance](https://github.com/Dotsen/pharmacode-toolkit/blob/main/docs/provenance.md)
|
|
85
|
+
- [Changelog](https://github.com/Dotsen/pharmacode-toolkit/blob/main/CHANGELOG.md)
|
|
86
|
+
|
|
87
|
+
## Disclaimer
|
|
88
|
+
|
|
89
|
+
This project is an independent implementation from public descriptions of the
|
|
90
|
+
format. It is **not validated** for regulated pharmaceutical packaging control and
|
|
91
|
+
must not be used as the sole check in such a process.
|
|
92
|
+
|
|
93
|
+
## Author
|
|
94
|
+
|
|
95
|
+
Konstantin Dotsenko ([LinkedIn](https://www.linkedin.com/in/dotsen/)).
|
|
96
|
+
|
|
97
|
+
## License
|
|
98
|
+
|
|
99
|
+
MIT, see [LICENSE](https://github.com/Dotsen/pharmacode-toolkit/blob/main/LICENSE).
|