dotcode-decoder 1.0.0__py3-none-any.whl
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.
- dotcode/__init__.py +9 -0
- dotcode/code.py +915 -0
- dotcode/codes.py +247 -0
- dotcode/decoder.py +953 -0
- dotcode/decoder_90.py +390 -0
- dotcode/image.py +3 -0
- dotcode/images.py +200 -0
- dotcode/rs.py +212 -0
- dotcode/setup.py +26 -0
- dotcode/utils.py +36 -0
- dotcode_decoder-1.0.0.dist-info/METADATA +248 -0
- dotcode_decoder-1.0.0.dist-info/RECORD +14 -0
- dotcode_decoder-1.0.0.dist-info/WHEEL +5 -0
- dotcode_decoder-1.0.0.dist-info/top_level.txt +1 -0
dotcode/rs.py
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Reed-Solomon error correction over GF(113)
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
P = 113
|
|
6
|
+
ALPHA = 3
|
|
7
|
+
|
|
8
|
+
DOT_PATTERNS = [
|
|
9
|
+
"101010101","010101011","010101101","010110101","011010101","101010110","101011010","101101010",
|
|
10
|
+
"110101010","010101110","010110110","010111010","011010110","011011010","011101010","100101011",
|
|
11
|
+
"100101101","100110101","101001011","101001101","101010011","101011001","101100101","101101001",
|
|
12
|
+
"110010101","110100101","110101001","001010111","001011011","001011101","001101011","001101101",
|
|
13
|
+
"001110101","010010111","010011011","010011101","010100111","010110011","010111001","011001011",
|
|
14
|
+
"011001101","011010011","011011001","011100101","011101001","100101110","100110110","100111010",
|
|
15
|
+
"101001110","101011100","101100110","101101100","101110010","101110100","110010110","110011010",
|
|
16
|
+
"110100110","110101100","110110010","110110100","111001010","111010010","111010100","001011110",
|
|
17
|
+
"001101110","001110110","001111010","010011110","010111100","011001110","011011100","011100110",
|
|
18
|
+
"011101100","011110010","011110100","100010111","100011011","100011101","100100111","100110011",
|
|
19
|
+
"100111001","101000111","101100011","101110001","110001011","110001101","110010011","110011001",
|
|
20
|
+
"110100011","110110001","111000101","111001001","111010001","000101111","000110111","000111011",
|
|
21
|
+
"000111101","001001111","001100111","001110011","001111001","010001111","011000111","011100011",
|
|
22
|
+
"011110001","100011110","100111100","101111000","110001110","110011100","110111000","111000110",
|
|
23
|
+
"111001100",
|
|
24
|
+
]
|
|
25
|
+
DOT_TO_VAL = {p: i for i, p in enumerate(DOT_PATTERNS)}
|
|
26
|
+
|
|
27
|
+
def gf_inv(a):
|
|
28
|
+
return pow(a, P-2, P)
|
|
29
|
+
|
|
30
|
+
def gf_add(a, b):
|
|
31
|
+
return (a + b) % P
|
|
32
|
+
|
|
33
|
+
def gf_sub(a, b):
|
|
34
|
+
return (a - b) % P
|
|
35
|
+
|
|
36
|
+
def gf_mul(a, b):
|
|
37
|
+
return (a * b) % P
|
|
38
|
+
|
|
39
|
+
def gf_div(a, b):
|
|
40
|
+
return gf_mul(a, gf_inv(b))
|
|
41
|
+
|
|
42
|
+
def gf_pow(a, k):
|
|
43
|
+
return pow(a, k, P) if k >= 0 else gf_inv(pow(a, -k, P))
|
|
44
|
+
|
|
45
|
+
def ptrim(p):
|
|
46
|
+
i = len(p)-1
|
|
47
|
+
while i > 0 and p[i] % P == 0:
|
|
48
|
+
i -= 1
|
|
49
|
+
return p[:i+1]
|
|
50
|
+
|
|
51
|
+
def pmul(a, b):
|
|
52
|
+
out = [0] * (len(a) + len(b) - 1)
|
|
53
|
+
for i, ai in enumerate(a):
|
|
54
|
+
if ai % P == 0:
|
|
55
|
+
continue
|
|
56
|
+
for j, bj in enumerate(b):
|
|
57
|
+
if bj % P == 0:
|
|
58
|
+
continue
|
|
59
|
+
out[i+j] = gf_add(out[i+j], gf_mul(ai, bj))
|
|
60
|
+
return ptrim(out)
|
|
61
|
+
|
|
62
|
+
def peval(p, x):
|
|
63
|
+
acc = 0
|
|
64
|
+
for c in reversed(p):
|
|
65
|
+
acc = gf_add(gf_mul(acc, x), c)
|
|
66
|
+
return acc
|
|
67
|
+
|
|
68
|
+
def pder(p):
|
|
69
|
+
if len(p) <= 1:
|
|
70
|
+
return [0]
|
|
71
|
+
out = [0] * (len(p)-1)
|
|
72
|
+
for i in range(1, len(p)):
|
|
73
|
+
out[i-1] = gf_mul(p[i], i % P)
|
|
74
|
+
return ptrim(out)
|
|
75
|
+
|
|
76
|
+
def pmod_xk(p, k):
|
|
77
|
+
q = p[:k] if len(p) > k else p[:]
|
|
78
|
+
if len(q) < k:
|
|
79
|
+
q += [0] * (k - len(q))
|
|
80
|
+
return q
|
|
81
|
+
|
|
82
|
+
def syndromes(r, NC):
|
|
83
|
+
S = []
|
|
84
|
+
for i in range(1, NC+1):
|
|
85
|
+
s = 0
|
|
86
|
+
for j, rj in enumerate(r):
|
|
87
|
+
if rj % P == 0:
|
|
88
|
+
continue
|
|
89
|
+
s = gf_add(s, gf_mul(rj, gf_pow(ALPHA, i * j)))
|
|
90
|
+
S.append(s)
|
|
91
|
+
return S
|
|
92
|
+
|
|
93
|
+
def erasure_locator(pos):
|
|
94
|
+
L = [1]
|
|
95
|
+
for j in pos:
|
|
96
|
+
L = pmul(L, [1, gf_sub(0, gf_pow(ALPHA, j))])
|
|
97
|
+
return L
|
|
98
|
+
|
|
99
|
+
def berlekamp_massey(S):
|
|
100
|
+
N = len(S)
|
|
101
|
+
if N == 0:
|
|
102
|
+
return [1]
|
|
103
|
+
|
|
104
|
+
def s(k):
|
|
105
|
+
return S[k] if 0 <= k < N else 0
|
|
106
|
+
|
|
107
|
+
C = [0]*(N+1)
|
|
108
|
+
C[0] = 1
|
|
109
|
+
B = [0]*(N+1)
|
|
110
|
+
B[0] = 1
|
|
111
|
+
L, m, b = 0, 1, 1
|
|
112
|
+
|
|
113
|
+
for n in range(N):
|
|
114
|
+
d = s(n)
|
|
115
|
+
for i in range(1, L+1):
|
|
116
|
+
d = gf_add(d, gf_mul(C[i], s(n-i)))
|
|
117
|
+
|
|
118
|
+
if d % P == 0:
|
|
119
|
+
m += 1
|
|
120
|
+
continue
|
|
121
|
+
|
|
122
|
+
fac = gf_div(d, b)
|
|
123
|
+
sB = [0]*(N+1)
|
|
124
|
+
for k in range(N+1-m):
|
|
125
|
+
sB[k+m] = B[k]
|
|
126
|
+
|
|
127
|
+
Cn = C[:]
|
|
128
|
+
for k in range(N+1):
|
|
129
|
+
Cn[k] = gf_sub(Cn[k], gf_mul(fac, sB[k]))
|
|
130
|
+
|
|
131
|
+
if 2*L <= n:
|
|
132
|
+
L = n+1-L
|
|
133
|
+
B = C[:]
|
|
134
|
+
b = d
|
|
135
|
+
m = 1
|
|
136
|
+
C = Cn
|
|
137
|
+
else:
|
|
138
|
+
m += 1
|
|
139
|
+
C = Cn
|
|
140
|
+
|
|
141
|
+
idx = N
|
|
142
|
+
while idx > 0 and C[idx] % P == 0:
|
|
143
|
+
idx -= 1
|
|
144
|
+
C = C[:idx+1]
|
|
145
|
+
|
|
146
|
+
if C and C[0] % P != 1:
|
|
147
|
+
inv = gf_inv(C[0])
|
|
148
|
+
C = [gf_mul(c, inv) for c in C]
|
|
149
|
+
|
|
150
|
+
return C
|
|
151
|
+
|
|
152
|
+
def rs_correct(mask_sym, vals, ND, NC, era_idx):
|
|
153
|
+
NW = len(vals)
|
|
154
|
+
r = [mask_sym] + [(v if v is not None else 0) for v in vals]
|
|
155
|
+
era = [1 + i for i in era_idx if 0 <= i < NW]
|
|
156
|
+
S = syndromes(r, NC)
|
|
157
|
+
|
|
158
|
+
if all(s % P == 0 for s in S) and not era:
|
|
159
|
+
return [v if v is not None else 0 for v in vals], []
|
|
160
|
+
|
|
161
|
+
if len(era) > NC:
|
|
162
|
+
return None
|
|
163
|
+
|
|
164
|
+
Le = erasure_locator(era)
|
|
165
|
+
SLe = pmod_xk(pmul(S[:], Le), NC)
|
|
166
|
+
Lu = berlekamp_massey(SLe)
|
|
167
|
+
Lam = ptrim(pmul(Le, Lu))
|
|
168
|
+
Om = pmod_xk(pmul(S[:], Lam), NC)
|
|
169
|
+
Ld = pder(Lam)
|
|
170
|
+
|
|
171
|
+
err_pos = []
|
|
172
|
+
err_mag = {}
|
|
173
|
+
|
|
174
|
+
for j in range(len(r)):
|
|
175
|
+
x = gf_pow(ALPHA, -j)
|
|
176
|
+
if peval(Lam, x) % P == 0:
|
|
177
|
+
if j == 0:
|
|
178
|
+
continue
|
|
179
|
+
num = peval(Om, x)
|
|
180
|
+
den = peval(Ld, x)
|
|
181
|
+
if den % P == 0:
|
|
182
|
+
continue
|
|
183
|
+
mag = gf_sub(0, gf_div(num, den))
|
|
184
|
+
if mag % P != 0:
|
|
185
|
+
err_pos.append(j)
|
|
186
|
+
err_mag[j] = mag
|
|
187
|
+
|
|
188
|
+
rc = r[:]
|
|
189
|
+
for j in err_pos:
|
|
190
|
+
rc[j] = gf_sub(rc[j], err_mag[j])
|
|
191
|
+
|
|
192
|
+
Sa = syndromes(rc, NC)
|
|
193
|
+
if any(s % P != 0 for s in Sa):
|
|
194
|
+
return None
|
|
195
|
+
|
|
196
|
+
return rc[1:], [p-1 for p in err_pos]
|
|
197
|
+
|
|
198
|
+
def solve_ND_NC(NW):
|
|
199
|
+
for ND in range(0, NW+1):
|
|
200
|
+
NC = 3 + ((ND+1)//2)
|
|
201
|
+
if ND + NC == NW:
|
|
202
|
+
return (ND, NC)
|
|
203
|
+
|
|
204
|
+
for ND in range(0, NW+1):
|
|
205
|
+
NC = 3 + (ND//2)
|
|
206
|
+
if ND + NC == NW:
|
|
207
|
+
return (ND, NC)
|
|
208
|
+
|
|
209
|
+
return None, None
|
|
210
|
+
|
|
211
|
+
def mask_step(mid):
|
|
212
|
+
return [0, 3, 7, 17][mid]
|
dotcode/setup.py
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from setuptools import find_packages, setup
|
|
2
|
+
|
|
3
|
+
setup(
|
|
4
|
+
name="dotcode-decoder",
|
|
5
|
+
version="1.0.0",
|
|
6
|
+
description="Fast DotCode 2D barcode decoder with iterative regression",
|
|
7
|
+
author="Anish karki",
|
|
8
|
+
packages=find_packages(),
|
|
9
|
+
install_requires=[
|
|
10
|
+
"opencv-python>=4.5.0",
|
|
11
|
+
"numpy>=1.19.0",
|
|
12
|
+
],
|
|
13
|
+
python_requires=">=3.7",
|
|
14
|
+
classifiers=[
|
|
15
|
+
"Programming Language :: Python :: 3",
|
|
16
|
+
"Programming Language :: Python :: 3.7",
|
|
17
|
+
"Programming Language :: Python :: 3.8",
|
|
18
|
+
"Programming Language :: Python :: 3.9",
|
|
19
|
+
"Programming Language :: Python :: 3.10",
|
|
20
|
+
"License :: OSI Approved :: MIT License",
|
|
21
|
+
"Operating System :: OS Independent",
|
|
22
|
+
"Topic :: Multimedia :: Graphics",
|
|
23
|
+
"Topic :: Scientific/Engineering :: Image Recognition",
|
|
24
|
+
],
|
|
25
|
+
keywords="barcode dotcode decoder 2d",
|
|
26
|
+
)
|
dotcode/utils.py
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Shared types, constants, and result objects
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from enum import Enum
|
|
7
|
+
from typing import Optional
|
|
8
|
+
|
|
9
|
+
# Constants
|
|
10
|
+
GRID_ROWS = 10
|
|
11
|
+
GRID_COLS = 47
|
|
12
|
+
MIN_DOTS = 12
|
|
13
|
+
EARLY_EXIT_CONFIDENCE = 0.30
|
|
14
|
+
REGRESSION_ITERATIONS = 2
|
|
15
|
+
|
|
16
|
+
class DecodeStage(Enum):
|
|
17
|
+
REGRESSION = 1
|
|
18
|
+
ANGLE_SWEEP = 2
|
|
19
|
+
INVERT = 3
|
|
20
|
+
|
|
21
|
+
@dataclass
|
|
22
|
+
class DecodeResult:
|
|
23
|
+
success: bool
|
|
24
|
+
message: Optional[str] = None
|
|
25
|
+
error: Optional[str] = None
|
|
26
|
+
file: Optional[str] = None
|
|
27
|
+
method: Optional[str] = None
|
|
28
|
+
elapsed_ms: float = 0.0
|
|
29
|
+
stage: Optional[DecodeStage] = None
|
|
30
|
+
confidence: float = 0.0
|
|
31
|
+
timed_out: bool = False
|
|
32
|
+
|
|
33
|
+
def __repr__(self):
|
|
34
|
+
if self.success:
|
|
35
|
+
return f"DecodeResult(success=True, msg='{self.message}', time={self.elapsed_ms:.0f}ms)"
|
|
36
|
+
return f"DecodeResult(success=False, error='{self.error}', time={self.elapsed_ms:.0f}ms)"
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: dotcode-decoder
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Fast DotCode 2D barcode decoder
|
|
5
|
+
Author: Anish karki
|
|
6
|
+
Keywords: barcode dotcode decoder 2d
|
|
7
|
+
Classifier: Programming Language :: Python :: 3
|
|
8
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Topic :: Multimedia :: Graphics
|
|
15
|
+
Classifier: Topic :: Scientific/Engineering :: Image Recognition
|
|
16
|
+
Requires-Python: >=3.7
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
Requires-Dist: opencv-python>=4.5.0
|
|
19
|
+
Requires-Dist: numpy>=1.19.0
|
|
20
|
+
Requires-Dist: scipy>=1.7.0
|
|
21
|
+
Dynamic: author
|
|
22
|
+
Dynamic: classifier
|
|
23
|
+
Dynamic: description
|
|
24
|
+
Dynamic: description-content-type
|
|
25
|
+
Dynamic: keywords
|
|
26
|
+
Dynamic: requires-dist
|
|
27
|
+
Dynamic: requires-python
|
|
28
|
+
Dynamic: summary
|
|
29
|
+
|
|
30
|
+
# DotCode Decoder
|
|
31
|
+
|
|
32
|
+
[](https://python.org)
|
|
33
|
+
[](LICENSE)
|
|
34
|
+
[](https://pypi.org/project/dotcode)
|
|
35
|
+
|
|
36
|
+
**Fast, accurate DotCode 2D barcode decoder for industrial and commercial applications.**
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## 📦 Installation
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
pip install dotcode
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Or install from source:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
git clone https://github.com/yourusername/dotcode.git
|
|
50
|
+
cd dotcode
|
|
51
|
+
pip install -e .
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## 🚀 Quick Start
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
from dotcode import decode, DecodeResult
|
|
60
|
+
|
|
61
|
+
# Single image
|
|
62
|
+
result = decode("image.jpg")
|
|
63
|
+
print(result.message) # "25E13KXUKSXG1313"
|
|
64
|
+
|
|
65
|
+
# With details
|
|
66
|
+
result: DecodeResult = decode("image.jpg")
|
|
67
|
+
print(f"Message: {result.message}")
|
|
68
|
+
print(f"Time: {result.elapsed_ms:.0f}ms")
|
|
69
|
+
print(f"Confidence: {result.confidence:.2f}")
|
|
70
|
+
print(f"Method: {result.method}")
|
|
71
|
+
|
|
72
|
+
# Batch decode
|
|
73
|
+
results = decode_batch(["img1.jpg", "img2.jpg", "img3.jpg"])
|
|
74
|
+
for r in results:
|
|
75
|
+
print(f"{r.file}: {r.message} ({r.elapsed_ms:.0f}ms)")
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## ⚙️ Advanced Usage
|
|
81
|
+
|
|
82
|
+
```python
|
|
83
|
+
from dotcode import DotCodeDecoder
|
|
84
|
+
|
|
85
|
+
# Custom configuration
|
|
86
|
+
decoder = DotCodeDecoder(
|
|
87
|
+
timeout_ms=500, # Max time per image
|
|
88
|
+
confidence=0.35, # Confidence threshold (0.20-0.40)
|
|
89
|
+
fast_mode=True, # Fast decode (6 angles) or accurate (12 angles)
|
|
90
|
+
use_sauvola=False # Sauvola thresholding for poor lighting
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
# Decode with custom settings
|
|
94
|
+
result = decoder.decode("image.jpg")
|
|
95
|
+
print(result.message)
|
|
96
|
+
|
|
97
|
+
# Disable fast mode for better accuracy on difficult images
|
|
98
|
+
decoder = DotCodeDecoder(fast_mode=False)
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## 📊 Performance
|
|
104
|
+
|
|
105
|
+
| Metric | Value |
|
|
106
|
+
|--------|-------|
|
|
107
|
+
| **Accuracy** | **96.2%** (381/396 images) |
|
|
108
|
+
| **Average Speed** | **41ms** per image |
|
|
109
|
+
| **Success Rate** | 96%+ |
|
|
110
|
+
| **Timeout** | 300ms (configurable) |
|
|
111
|
+
| **Stage Distribution** | Regression: 27% \| Angle Sweep: 73% |
|
|
112
|
+
|
|
113
|
+
### Performance by Stage
|
|
114
|
+
|
|
115
|
+
| Stage | Images | Avg Time | Description |
|
|
116
|
+
|-------|--------|----------|-------------|
|
|
117
|
+
| **Regression** | 103 (27%) | ~20ms | Fast path - direct grid fit |
|
|
118
|
+
| **Angle Sweep** | 278 (73%) | ~45ms | Slower path - angle correction |
|
|
119
|
+
| **Invert Fallback** | 0 | N/A | Last resort for inverted images |
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## 🔧 How It Works
|
|
124
|
+
|
|
125
|
+
1. **Dot Detection**
|
|
126
|
+
Extracts dot centroids using adaptive thresholding (Otsu/fixed) with morphological erosion to separate touching dots.
|
|
127
|
+
|
|
128
|
+
2. **Iterative Regression**
|
|
129
|
+
Straightens tilted/skewed grids using per-row polynomial fitting with early exit when angle stabilizes.
|
|
130
|
+
|
|
131
|
+
3. **Grid Snapping**
|
|
132
|
+
Fits detected dots to a 10×47 checkerboard grid using k-means clustering (or optional Procrustes + RANSAC for difficult images).
|
|
133
|
+
|
|
134
|
+
4. **Reed-Solomon Error Correction**
|
|
135
|
+
Corrects errors in the extracted bitstream using Reed-Solomon decoding over GF(113) - handles up to 7 errors per code.
|
|
136
|
+
|
|
137
|
+
5. **Text Decoding**
|
|
138
|
+
Converts corrected values to readable text using DotCode code sets (A, B, C) with state machine for character encoding.
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## 📁 Project Structure
|
|
143
|
+
|
|
144
|
+
```
|
|
145
|
+
dotcode/
|
|
146
|
+
├── __init__.py # Main exports
|
|
147
|
+
├── decoder.py # Core decoding logic
|
|
148
|
+
├── image.py # Image processing (thresholding, blob detection)
|
|
149
|
+
├── codes.py # DotCode code sets (A, B, C)
|
|
150
|
+
├── rs.py # Reed-Solomon error correction
|
|
151
|
+
└── utils.py # Utility classes and constants
|
|
152
|
+
|
|
153
|
+
examples/
|
|
154
|
+
├── basic_usage.py # Simple decode example
|
|
155
|
+
└── batch_usage.py # Batch processing example
|
|
156
|
+
|
|
157
|
+
tests/
|
|
158
|
+
└── test_decoder.py # Unit tests
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## 🔬 Algorithm Details
|
|
164
|
+
|
|
165
|
+
### Reed-Solomon Error Correction
|
|
166
|
+
- Field: **GF(113)**
|
|
167
|
+
- Primitive element: **3**
|
|
168
|
+
- Corrects up to **~5-7 errors** per code
|
|
169
|
+
- Uses Berlekamp-Massey algorithm for error location
|
|
170
|
+
|
|
171
|
+
### Iterative Regression
|
|
172
|
+
- **2 iterations** (configurable)
|
|
173
|
+
- **Early exit** when angle change < 0.1°
|
|
174
|
+
- **Per-row quadratic fit** for curvature correction
|
|
175
|
+
|
|
176
|
+
### Threshold Selection
|
|
177
|
+
- **Otsu's method** (automatic)
|
|
178
|
+
- **Fixed thresholds**: 105, 115, 125, 135, 145, 155, 165, 175
|
|
179
|
+
- **Sauvola threshold** (local adaptive) - optional
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## 🛠️ Requirements
|
|
184
|
+
|
|
185
|
+
- Python 3.7+
|
|
186
|
+
- OpenCV >= 4.5.0
|
|
187
|
+
- NumPy >= 1.19.0
|
|
188
|
+
- SciPy >= 1.7.0 (for KDTree)
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## 📝 License
|
|
193
|
+
|
|
194
|
+
MIT License - see [LICENSE](LICENSE) file for details.
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
## 🤝 Contributing
|
|
199
|
+
|
|
200
|
+
Contributions are welcome! Please:
|
|
201
|
+
|
|
202
|
+
1. Fork the repository
|
|
203
|
+
2. Create a feature branch
|
|
204
|
+
3. Submit a pull request
|
|
205
|
+
|
|
206
|
+
### Development Setup
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
# Clone the repository
|
|
210
|
+
git clone https://github.com/yourusername/dotcode.git
|
|
211
|
+
cd dotcode
|
|
212
|
+
|
|
213
|
+
# Install in development mode
|
|
214
|
+
pip install -e .
|
|
215
|
+
|
|
216
|
+
# Run tests
|
|
217
|
+
python test.py
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## 📚 References
|
|
223
|
+
|
|
224
|
+
- [DotCode Specification (AIM)](https://www.aimglobal.org/dotcode)
|
|
225
|
+
- [Wikipedia: DotCode](https://en.wikipedia.org/wiki/DotCode)
|
|
226
|
+
- [Reed-Solomon Error Correction](https://en.wikipedia.org/wiki/Reed%E2%80%93Solomon_error_correction)
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
## 📧 Contact
|
|
231
|
+
|
|
232
|
+
For questions or support:
|
|
233
|
+
- GitHub Issues: [https://github.com/yourusername/dotcode/issues](https://github.com/yourusername/dotcode/issues)
|
|
234
|
+
- Email: your.email@example.com
|
|
235
|
+
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
## ⭐ Acknowledgments
|
|
239
|
+
|
|
240
|
+
This project builds on research in 2D barcode decoding and industrial computer vision. Special thanks to:
|
|
241
|
+
|
|
242
|
+
- The open-source community for OpenCV, NumPy, and SciPy
|
|
243
|
+
- AIM Global for the DotCode specification
|
|
244
|
+
- Contributors who helped test and improve the decoder
|
|
245
|
+
|
|
246
|
+
---
|
|
247
|
+
|
|
248
|
+
**Made with ❤️ for industrial automation and barcode enthusiasts.**
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
dotcode/__init__.py,sha256=fg8H7arLGK6Yj_mbvCqSsehUWM_cXSEx4mRNW6mQomQ,256
|
|
2
|
+
dotcode/code.py,sha256=EhVIS3BIMy1esjIrSQcyTM2EOFLrJwDMiD1XkQVMwsE,35755
|
|
3
|
+
dotcode/codes.py,sha256=9I9R9pCj8uV2PFdN3XDIunZMVj5H6QcqopPTrtzxM8M,6445
|
|
4
|
+
dotcode/decoder.py,sha256=eyl4ODb6fLxIvXO1aOR-jfVv-bICqrqsn9-c0iF9I8s,37055
|
|
5
|
+
dotcode/decoder_90.py,sha256=v99mhQX_WS1zuNLC5XiZt_mk5ml_R2FIQKqSzuQhbfQ,15138
|
|
6
|
+
dotcode/image.py,sha256=N7RuvnPHusTEF0RlEbN1wS350qA_-J_IYkY55DmTK7o,87
|
|
7
|
+
dotcode/images.py,sha256=o59vWCrrdUD_CKh4eKdFCn5BDn7LWNEHb2p2LDV8oUw,6255
|
|
8
|
+
dotcode/rs.py,sha256=p6u7kAknqcpVulYigJ-XrfG0E36qqd1LhvoinxWxvSQ,5876
|
|
9
|
+
dotcode/setup.py,sha256=yLk8trMdvHNSAPr47lr1hD2je-kGMdCMsZWZpzzKODo,891
|
|
10
|
+
dotcode/utils.py,sha256=jL8e03M_027OTKzHwHhJACzDBOtuQC6yromc20mL6Cs,920
|
|
11
|
+
dotcode_decoder-1.0.0.dist-info/METADATA,sha256=Xjq8im_7UibDLSXHQ97UPprIxKGiW4UDVFsAVHf5Dnc,6727
|
|
12
|
+
dotcode_decoder-1.0.0.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
|
|
13
|
+
dotcode_decoder-1.0.0.dist-info/top_level.txt,sha256=2hWaRw8BGxQazH72zDHPMH8vrPyPQe5v81kJKxB7uzo,8
|
|
14
|
+
dotcode_decoder-1.0.0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
dotcode
|