Skip to content

Commit d4b0f50

Browse files
committed
Code128: new decoding algorithm based on edge-2-edge patterns
This improves the reliability in situations with under/over exposed images. It basically adopts the reference algorithm from the specification. This 'fixes' the image discussed in #444.
1 parent d2293fe commit d4b0f50

File tree

5 files changed

+40
-58
lines changed

5 files changed

+40
-58
lines changed

core/src/Pattern.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,20 @@ PatternView FindLeftGuard(const PatternView& view, int minSize, const FixedPatte
245245
});
246246
}
247247

248+
template <int LEN, int SUM>
249+
std::array<int, LEN - 2> NormalizedE2EPattern(const PatternView& view)
250+
{
251+
float moduleSize = static_cast<float>(view.sum(LEN)) / SUM;
252+
std::array<int, LEN - 2> e2e;
253+
254+
for (int i = 0; i < LEN - 2; i++) {
255+
float v = (view[i] + view[i + 1]) / moduleSize;
256+
e2e[i] = int(v + .5f);
257+
}
258+
259+
return e2e;
260+
}
261+
248262
template <int LEN, int SUM>
249263
std::array<int, LEN> NormalizedPattern(const PatternView& view)
250264
{

core/src/oned/ODCode128Reader.cpp

Lines changed: 22 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ static const int CODE_FNC_2 = 97;
3434
static const int CODE_FNC_3 = 96;
3535

3636
static const int CODE_START_A = 103;
37-
static const int CODE_START_B = 104;
3837
static const int CODE_START_C = 105;
3938
static const int CODE_STOP = 106;
4039

@@ -157,76 +156,44 @@ class Raw2TxtDecoder
157156
bool readerInit() const { return _readerInit; }
158157
};
159158

160-
template <typename C>
161-
static int DetectStartCode(const C& c)
162-
{
163-
int bestCode = 0;
164-
float bestVariance = MAX_AVG_VARIANCE;
165-
for (int code : {CODE_START_A, CODE_START_B, CODE_START_C}) {
166-
float variance = RowReader::PatternMatchVariance(c, Code128::CODE_PATTERNS[code], MAX_INDIVIDUAL_VARIANCE);
167-
if (variance < bestVariance) {
168-
bestVariance = variance;
169-
bestCode = code;
170-
}
171-
}
172-
return bestVariance < MAX_AVG_VARIANCE ? bestCode : 0;
173-
}
174-
175159
// all 3 start patterns share the same 2-1-1 prefix
176160
constexpr auto START_PATTERN_PREFIX = FixedPattern<3, 4>{2, 1, 1};
177161
constexpr int CHAR_LEN = 6;
178162
constexpr float QUIET_ZONE = 5; // quiet zone spec is 10 modules, real world examples ignore that, see #138
179-
180-
//#define USE_FAST_1_TO_4_BIT_PATTERN_DECODING
181-
#ifdef USE_FAST_1_TO_4_BIT_PATTERN_DECODING
182163
constexpr int CHAR_SUM = 11;
183-
constexpr int CHARACTER_ENCODINGS[] = {
184-
0b11011001100, 0b11001101100, 0b11001100110, 0b10010011000, 0b10010001100, // 0
185-
0b10001001100, 0b10011001000, 0b10011000100, 0b10001100100, 0b11001001000, // 5
186-
0b11001000100, 0b11000100100, 0b10110011100, 0b10011011100, 0b10011001110, // 10
187-
0b10111001100, 0b10011101100, 0b10011100110, 0b11001110010, 0b11001011100, // 15
188-
0b11001001110, 0b11011100100, 0b11001110100, 0b11101101110, 0b11101001100, // 20
189-
0b11100101100, 0b11100100110, 0b11101100100, 0b11100110100, 0b11100110010, // 25
190-
0b11011011000, 0b11011000110, 0b11000110110, 0b10100011000, 0b10001011000, // 30
191-
0b10001000110, 0b10110001000, 0b10001101000, 0b10001100010, 0b11010001000, // 35
192-
0b11000101000, 0b11000100010, 0b10110111000, 0b10110001110, 0b10001101110, // 40
193-
0b10111011000, 0b10111000110, 0b10001110110, 0b11101110110, 0b11010001110, // 45
194-
0b11000101110, 0b11011101000, 0b11011100010, 0b11011101110, 0b11101011000, // 50
195-
0b11101000110, 0b11100010110, 0b11101101000, 0b11101100010, 0b11100011010, // 55
196-
0b11101111010, 0b11001000010, 0b11110001010, 0b10100110000, 0b10100001100, // 60
197-
0b10010110000, 0b10010000110, 0b10000101100, 0b10000100110, 0b10110010000, // 65
198-
0b10110000100, 0b10011010000, 0b10011000010, 0b10000110100, 0b10000110010, // 70
199-
0b11000010010, 0b11001010000, 0b11110111010, 0b11000010100, 0b10001111010, // 75
200-
0b10100111100, 0b10010111100, 0b10010011110, 0b10111100100, 0b10011110100, // 80
201-
0b10011110010, 0b11110100100, 0b11110010100, 0b11110010010, 0b11011011110, // 85
202-
0b11011110110, 0b11110110110, 0b10101111000, 0b10100011110, 0b10001011110, // 90
203-
0b10111101000, 0b10111100010, 0b11110101000, 0b11110100010, 0b10111011110, // 95
204-
0b10111101110, 0b11101011110, 0b11110101110, 0b11010000100, 0b11010010000, // 100
205-
0b11010011100, 0b11000111010, // 105
206-
};
207-
#endif
164+
165+
//TODO: make this a constexpr variable initialization
166+
static auto E2E_PATTERNS = [] {
167+
// This creates an array of ints for fast IndexOf lookup of the edge-2-edge patterns (ISO/IEC 15417:2007(E) Table 2)
168+
// e.g. a code pattern of { 2, 1, 2, 2, 2, 2 } becomes the e2e pattern { 3, 3, 4, 4 } and the value 0b11100011110000.
169+
std::array<int, 107> res;
170+
for (int i = 0; i < Size(res); ++i) {
171+
const auto& a = Code128::CODE_PATTERNS[i];
172+
std::array<int, 4> e2e;
173+
for (int j = 0; j < 4; j++)
174+
e2e[j] = a[j] + a[j + 1];
175+
res[i] = ToInt(e2e);
176+
}
177+
return res;
178+
}();
208179

209180
Result Code128Reader::decodePattern(int rowNumber, PatternView& next, std::unique_ptr<DecodingState>&) const
210181
{
211182
int minCharCount = 4; // start + payload + checksum + stop
212-
auto decodePattern = [](const PatternView& view, bool start = false) {
213-
// TODO: the intention was to always use the way faster OneToFourBitPattern approach but it turned out
214-
// the old DecodeDigit currently detects more test samples. There could be gained another 20% in
215-
// in performance. This might work once the subpixel binarizer is in place.
216-
#ifdef USE_FAST_1_TO_4_BIT_PATTERN_DECODING
217-
return IndexOf(CHARACTER_ENCODINGS, OneToFourBitPattern<CHAR_LEN, CHAR_SUM>(view));
218-
#else
219-
return start ? DetectStartCode(view)
220-
: DecodeDigit(view, Code128::CODE_PATTERNS, MAX_AVG_VARIANCE, MAX_INDIVIDUAL_VARIANCE);
221-
#endif
183+
auto decodePattern = [](const PatternView& view) {
184+
// This is basically the reference algorithm from the specification
185+
int code = IndexOf(E2E_PATTERNS, ToInt(NormalizedE2EPattern<CHAR_LEN, CHAR_SUM>(view)));
186+
if (code == -1) // if the reference algo fails, give the original upstream version a try (required to decode a few samples)
187+
code = DecodeDigit(view, Code128::CODE_PATTERNS, MAX_AVG_VARIANCE, MAX_INDIVIDUAL_VARIANCE);
188+
return code;
222189
};
223190

224191
next = FindLeftGuard(next, minCharCount * CHAR_LEN, START_PATTERN_PREFIX, QUIET_ZONE);
225192
if (!next.isValid())
226193
return {};
227194

228195
next = next.subView(0, CHAR_LEN);
229-
int startCode = decodePattern(next, true);
196+
int startCode = decodePattern(next);
230197
if (!(CODE_START_A <= startCode && startCode <= CODE_START_C))
231198
return {};
232199

test/blackbox/BlackboxTestRunner.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -416,9 +416,9 @@ int runBlackBoxTests(const fs::path& testPathPrefix, const std::set<std::string>
416416
{ 6, 6, 180 },
417417
});
418418

419-
runTests("code128-2", "Code128", 21, {
420-
{ 18, 21, 0 },
421-
{ 19, 21, 180 },
419+
runTests("code128-2", "Code128", 22, {
420+
{ 19, 22, 0 },
421+
{ 20, 22, 180 },
422422
});
423423

424424
runTests("code128-3", "Code128", 2, {

test/samples/code128-2/#444.jpg

2.84 KB
Loading

test/samples/code128-2/#444.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
2-146-11

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy