Removed dynamic allocation of new int[2] when searching for

guard patterns to improve performance.


git-svn-id: https://zxing.googlecode.com/svn/trunk@1563 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
dswitkin@google.com 2010-08-25 20:51:14 +00:00
parent 886b70e167
commit 0f431db54d
10 changed files with 72 additions and 85 deletions

View file

@ -29,13 +29,13 @@ namespace zxing {
EAN13Reader::EAN13Reader() { } EAN13Reader::EAN13Reader() { }
int EAN13Reader::decodeMiddle(Ref<BitArray> row, int startRange[], int startRangeLen, int EAN13Reader::decodeMiddle(Ref<BitArray> row, int startGuardBegin, int startGuardEnd,
std::string& resultString) { std::string& resultString) {
const int countersLen = 4; const int countersLen = 4;
int counters[countersLen] = { 0, 0, 0, 0 }; int counters[countersLen] = { 0, 0, 0, 0 };
int end = row->getSize(); int end = row->getSize();
int rowOffset = startRange[1]; int rowOffset = startGuardEnd;
int lgPatternFound = 0; int lgPatternFound = 0;
for (int x = 0; x < 6 && rowOffset < end; x++) { for (int x = 0; x < 6 && rowOffset < end; x++) {
@ -57,15 +57,15 @@ namespace zxing {
return -1; return -1;
} }
int* middleRange = findGuardPattern(row, rowOffset, true, (int*)getMIDDLE_PATTERN(), int middleRangeStart;
getMIDDLE_PATTERN_LEN()); int middleRangeEnd;
if (middleRange != NULL) { if (findGuardPattern(row, rowOffset, true, (int*)getMIDDLE_PATTERN(),
rowOffset = middleRange[1]; getMIDDLE_PATTERN_LEN(), &middleRangeStart, &middleRangeEnd)) {
rowOffset = middleRangeEnd;
for (int x = 0; x < 6 && rowOffset < end; x++) { for (int x = 0; x < 6 && rowOffset < end; x++) {
int bestMatch = decodeDigit(row, counters, countersLen, rowOffset, int bestMatch = decodeDigit(row, counters, countersLen, rowOffset,
UPC_EAN_PATTERNS_L_PATTERNS); UPC_EAN_PATTERNS_L_PATTERNS);
if (bestMatch < 0) { if (bestMatch < 0) {
delete [] middleRange;
return -1; return -1;
} }
resultString.append(1, (char) ('0' + bestMatch)); resultString.append(1, (char) ('0' + bestMatch));
@ -73,8 +73,6 @@ namespace zxing {
rowOffset += counters[i]; rowOffset += counters[i];
} }
} }
delete [] middleRange;
return rowOffset; return rowOffset;
} }
return -1; return -1;

View file

@ -33,7 +33,7 @@ namespace zxing {
public: public:
EAN13Reader(); EAN13Reader();
int decodeMiddle(Ref<BitArray> row, int startRange[], int startRangeLen, int decodeMiddle(Ref<BitArray> row, int startGuardBegin, int startGuardEnd,
std::string& resultString); std::string& resultString);
BarcodeFormat getBarcodeFormat(); BarcodeFormat getBarcodeFormat();

View file

@ -25,13 +25,13 @@ namespace zxing {
EAN8Reader::EAN8Reader(){ } EAN8Reader::EAN8Reader(){ }
int EAN8Reader::decodeMiddle(Ref<BitArray> row, int startRange[], int startRangeLen, int EAN8Reader::decodeMiddle(Ref<BitArray> row, int startGuardBegin, int startGuardEnd,
std::string& resultString){ std::string& resultString){
const int countersLen = 4; const int countersLen = 4;
int counters[countersLen] = { 0, 0, 0, 0 }; int counters[countersLen] = { 0, 0, 0, 0 };
int end = row->getSize(); int end = row->getSize();
int rowOffset = startRange[1]; int rowOffset = startGuardEnd;
for (int x = 0; x < 4 && rowOffset < end; x++) { for (int x = 0; x < 4 && rowOffset < end; x++) {
int bestMatch = decodeDigit(row, counters, countersLen, rowOffset, int bestMatch = decodeDigit(row, counters, countersLen, rowOffset,
@ -45,15 +45,15 @@ namespace zxing {
} }
} }
int* middleRange = findGuardPattern(row, rowOffset, true, (int*)getMIDDLE_PATTERN(), int middleRangeStart;
getMIDDLE_PATTERN_LEN()); int middleRangeEnd;
if (middleRange != NULL) { if (findGuardPattern(row, rowOffset, true, (int*)getMIDDLE_PATTERN(),
rowOffset = middleRange[1]; getMIDDLE_PATTERN_LEN(), &middleRangeStart, &middleRangeEnd)) {
rowOffset = middleRangeEnd;
for (int x = 0; x < 4 && rowOffset < end; x++) { for (int x = 0; x < 4 && rowOffset < end; x++) {
int bestMatch = decodeDigit(row, counters, countersLen, rowOffset, int bestMatch = decodeDigit(row, counters, countersLen, rowOffset,
UPC_EAN_PATTERNS_L_PATTERNS); UPC_EAN_PATTERNS_L_PATTERNS);
if (bestMatch < 0) { if (bestMatch < 0) {
delete [] middleRange;
return -1; return -1;
} }
resultString.append(1, (char) ('0' + bestMatch)); resultString.append(1, (char) ('0' + bestMatch));
@ -61,8 +61,6 @@ namespace zxing {
rowOffset += counters[i]; rowOffset += counters[i];
} }
} }
delete [] middleRange;
return rowOffset; return rowOffset;
} }
return -1; return -1;

View file

@ -30,7 +30,7 @@ namespace zxing {
public: public:
EAN8Reader(); EAN8Reader();
int decodeMiddle(Ref<BitArray> row, int startRange[], int startRangeLen, int decodeMiddle(Ref<BitArray> row, int startGuardBegin, int startGuardEnd,
std::string& resultString); std::string& resultString);
BarcodeFormat getBarcodeFormat(); BarcodeFormat getBarcodeFormat();

View file

@ -29,17 +29,19 @@ namespace zxing {
return maybeReturnResult(ean13Reader.decodeRow(rowNumber, row)); return maybeReturnResult(ean13Reader.decodeRow(rowNumber, row));
} }
Ref<Result> UPCAReader::decodeRow(int rowNumber, Ref<BitArray> row, int startGuardRange[]) { Ref<Result> UPCAReader::decodeRow(int rowNumber, Ref<BitArray> row, int startGuardBegin,
return maybeReturnResult(ean13Reader.decodeRow(rowNumber, row, startGuardRange)); int startGuardEnd) {
return maybeReturnResult(ean13Reader.decodeRow(rowNumber, row, startGuardBegin,
startGuardEnd));
} }
Ref<Result> UPCAReader::decode(Ref<BinaryBitmap> image, DecodeHints hints) { Ref<Result> UPCAReader::decode(Ref<BinaryBitmap> image, DecodeHints hints) {
return maybeReturnResult(ean13Reader.decode(image, hints)); return maybeReturnResult(ean13Reader.decode(image, hints));
} }
int UPCAReader::decodeMiddle(Ref<BitArray> row, int startRange[], int startRangeLen, int UPCAReader::decodeMiddle(Ref<BitArray> row, int startGuardBegin, int startGuardEnd,
std::string& resultString) { std::string& resultString) {
return ean13Reader.decodeMiddle(row, startRange, startRangeLen, resultString); return ean13Reader.decodeMiddle(row, startGuardBegin, startGuardEnd, resultString);
} }
Ref<Result> UPCAReader::maybeReturnResult(Ref<Result> result) { Ref<Result> UPCAReader::maybeReturnResult(Ref<Result> result) {

View file

@ -33,11 +33,12 @@ namespace zxing {
public: public:
UPCAReader(); UPCAReader();
int decodeMiddle(Ref<BitArray> row, int startRange[], int startRangeLen, int decodeMiddle(Ref<BitArray> row, int startGuardBegin, int startGuardEnd,
std::string& resultString); std::string& resultString);
Ref<Result> decodeRow(int rowNumber, Ref<BitArray> row); Ref<Result> decodeRow(int rowNumber, Ref<BitArray> row);
Ref<Result> decodeRow(int rowNumber, Ref<BitArray> row, int startGuardRange[]); Ref<Result> decodeRow(int rowNumber, Ref<BitArray> row, int startGuardBegin,
int startGuardEnd);
Ref<Result> decode(Ref<BinaryBitmap> image, DecodeHints hints); Ref<Result> decode(Ref<BinaryBitmap> image, DecodeHints hints);
BarcodeFormat getBarcodeFormat(); BarcodeFormat getBarcodeFormat();

View file

@ -95,50 +95,46 @@ namespace zxing {
Ref<Result> UPCEANReader::decodeRow(int rowNumber, Ref<BitArray> row) { Ref<Result> UPCEANReader::decodeRow(int rowNumber, Ref<BitArray> row) {
int* start = findStartGuardPattern(row); int rangeStart;
if (start != NULL) { int rangeEnd;
if (findStartGuardPattern(row, &rangeStart, &rangeEnd)) {
try { try {
Ref<Result> result = decodeRow(rowNumber, row, start); return decodeRow(rowNumber, row, rangeStart, rangeEnd);
delete [] start;
return result;
} catch (ReaderException const& re) { } catch (ReaderException const& re) {
delete [] start;
} }
} }
return Ref<Result>(); return Ref<Result>();
} }
Ref<Result> UPCEANReader::decodeRow(int rowNumber, Ref<BitArray> row, int startGuardRange[]) { Ref<Result> UPCEANReader::decodeRow(int rowNumber, Ref<BitArray> row, int startGuardBegin,
int startGuardEnd) {
std::string tmpResultString; std::string tmpResultString;
std::string& tmpResultStringRef = tmpResultString; std::string& tmpResultStringRef = tmpResultString;
int endStart = decodeMiddle(row, startGuardRange, 2 /*reference findGuardPattern*/ , int endStart = decodeMiddle(row, startGuardBegin, startGuardEnd, tmpResultStringRef);
tmpResultStringRef);
if (endStart < 0) { if (endStart < 0) {
return Ref<Result>(); return Ref<Result>();
} }
int* endRange = decodeEnd(row, endStart);
if (endRange == NULL) { int endGuardBegin;
int endGuardEnd;
if (!decodeEnd(row, endStart, &endGuardBegin, &endGuardEnd)) {
return Ref<Result>(); return Ref<Result>();
} }
// Make sure there is a quiet zone at least as big as the end pattern after the barcode. // Make sure there is a quiet zone at least as big as the end pattern after the barcode.
// The spec might want more whitespace, but in practice this is the maximum we can count on. // The spec might want more whitespace, but in practice this is the maximum we can count on.
size_t end = endRange[1]; size_t quietEnd = endGuardEnd + (endGuardEnd - endGuardBegin);
size_t quietEnd = end + (end - endRange[0]); if (quietEnd >= row->getSize() || !row->isRange(endGuardEnd, quietEnd, false)) {
if (quietEnd >= row->getSize() || !row->isRange(end, quietEnd, false)) {
delete [] endRange;
return Ref<Result>(); return Ref<Result>();
} }
if (!checkChecksum(tmpResultString)) { if (!checkChecksum(tmpResultString)) {
delete [] endRange;
return Ref<Result>(); return Ref<Result>();
} }
Ref<String> resultString(new String(tmpResultString)); Ref<String> resultString(new String(tmpResultString));
float left = (float) (startGuardBegin + startGuardEnd) / 2.0f;
float left = (float) (startGuardRange[1] + startGuardRange[0]) / 2.0f; float right = (float) (endGuardBegin + endGuardEnd) / 2.0f;
float right = (float) (endRange[1] + endRange[0]) / 2.0f;
std::vector< Ref<ResultPoint> > resultPoints(2); std::vector< Ref<ResultPoint> > resultPoints(2);
Ref<OneDResultPoint> resultPoint1(new OneDResultPoint(left, (float) rowNumber)); Ref<OneDResultPoint> resultPoint1(new OneDResultPoint(left, (float) rowNumber));
@ -147,38 +143,28 @@ namespace zxing {
resultPoints[1] = resultPoint2; resultPoints[1] = resultPoint2;
ArrayRef<unsigned char> resultBytes(1); ArrayRef<unsigned char> resultBytes(1);
Ref<Result> res(new Result(resultString, resultBytes, resultPoints, getBarcodeFormat())); return Ref<Result>(new Result(resultString, resultBytes, resultPoints, getBarcodeFormat()));
delete [] endRange;
return res;
} }
int* UPCEANReader::findStartGuardPattern(Ref<BitArray> row) { bool UPCEANReader::findStartGuardPattern(Ref<BitArray> row, int* rangeStart, int* rangeEnd) {
bool foundStart = false;
int* startRange = NULL;
int nextStart = 0; int nextStart = 0;
while (!foundStart) { while (findGuardPattern(row, nextStart, false, START_END_PATTERN,
delete [] startRange; sizeof(START_END_PATTERN) / sizeof(int), rangeStart, rangeEnd)) {
startRange = findGuardPattern(row, nextStart, false, START_END_PATTERN, int start = *rangeStart;
sizeof(START_END_PATTERN) / sizeof(int)); nextStart = *rangeEnd;
if (startRange == NULL) {
return NULL;
}
int start = startRange[0];
nextStart = startRange[1];
// Make sure there is a quiet zone at least as big as the start pattern before the barcode. // Make sure there is a quiet zone at least as big as the start pattern before the barcode.
// If this check would run off the left edge of the image, do not accept this barcode, // If this check would run off the left edge of the image, do not accept this barcode,
// as it is very likely to be a false positive. // as it is very likely to be a false positive.
int quietStart = start - (nextStart - start); int quietStart = start - (nextStart - start);
if (quietStart >= 0) { if (quietStart >= 0 && row->isRange(quietStart, start, false)) {
foundStart = row->isRange(quietStart, start, false); return true;
} }
} }
return startRange; return false;
} }
// TODO(flyashi): Return a pair<int, int> for return value to avoid using the heap. bool UPCEANReader::findGuardPattern(Ref<BitArray> row, int rowOffset, bool whiteFirst,
int* UPCEANReader::findGuardPattern(Ref<BitArray> row, int rowOffset, bool whiteFirst, const int pattern[], int patternLen, int* start, int* end) {
const int pattern[], int patternLen) {
int patternLength = patternLen; int patternLength = patternLen;
int counters[patternLength]; int counters[patternLength];
int countersCount = sizeof(counters) / sizeof(int); int countersCount = sizeof(counters) / sizeof(int);
@ -205,10 +191,9 @@ namespace zxing {
if (counterPosition == patternLength - 1) { if (counterPosition == patternLength - 1) {
if (patternMatchVariance(counters, countersCount, pattern, if (patternMatchVariance(counters, countersCount, pattern,
MAX_INDIVIDUAL_VARIANCE) < MAX_AVG_VARIANCE) { MAX_INDIVIDUAL_VARIANCE) < MAX_AVG_VARIANCE) {
int* resultValue = new int[2]; *start = patternStart;
resultValue[0] = patternStart; *end = x;
resultValue[1] = x; return true;
return resultValue;
} }
patternStart += counters[0] + counters[1]; patternStart += counters[0] + counters[1];
for (int y = 2; y < patternLength; y++) { for (int y = 2; y < patternLength; y++) {
@ -224,12 +209,13 @@ namespace zxing {
isWhite = !isWhite; isWhite = !isWhite;
} }
} }
return NULL; return false;
} }
int* UPCEANReader::decodeEnd(Ref<BitArray> row, int endStart) { bool UPCEANReader::decodeEnd(Ref<BitArray> row, int endStart, int* endGuardBegin,
int* endGuardEnd) {
return findGuardPattern(row, endStart, false, START_END_PATTERN, return findGuardPattern(row, endStart, false, START_END_PATTERN,
sizeof(START_END_PATTERN) / sizeof(int)); sizeof(START_END_PATTERN) / sizeof(int), endGuardBegin, endGuardEnd);
} }
int UPCEANReader::decodeDigit(Ref<BitArray> row, int counters[], int countersLen, int rowOffset, int UPCEANReader::decodeDigit(Ref<BitArray> row, int counters[], int countersLen, int rowOffset,

View file

@ -37,14 +37,14 @@ namespace zxing {
static const unsigned int MAX_AVG_VARIANCE = (unsigned int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.42f); static const unsigned int MAX_AVG_VARIANCE = (unsigned int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.42f);
static const int MAX_INDIVIDUAL_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.7f); static const int MAX_INDIVIDUAL_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.7f);
static int* findStartGuardPattern(Ref<BitArray> row); static bool findStartGuardPattern(Ref<BitArray> row, int* rangeStart, int* rangeEnd);
virtual int* decodeEnd(Ref<BitArray> row, int endStart); virtual bool decodeEnd(Ref<BitArray> row, int endStart, int* endGuardBegin, int* endGuardEnd);
static bool checkStandardUPCEANChecksum(std::string s); static bool checkStandardUPCEANChecksum(std::string s);
protected: protected:
static int* findGuardPattern(Ref<BitArray> row, int rowOffset, bool whiteFirst, static bool findGuardPattern(Ref<BitArray> row, int rowOffset, bool whiteFirst,
const int pattern[], int patternLen); const int pattern[], int patternLen, int* start, int* end);
virtual const int getMIDDLE_PATTERN_LEN(); virtual const int getMIDDLE_PATTERN_LEN();
virtual const int* getMIDDLE_PATTERN(); virtual const int* getMIDDLE_PATTERN();
@ -53,13 +53,14 @@ namespace zxing {
UPCEANReader(); UPCEANReader();
// Returns < 0 on failure, >= 0 on success. // Returns < 0 on failure, >= 0 on success.
virtual int decodeMiddle(Ref<BitArray> row, int startRange[], int startRangeLen, virtual int decodeMiddle(Ref<BitArray> row, int startGuardBegin, int startGuardEnd,
std::string& resultString) = 0; std::string& resultString) = 0;
Ref<Result> decodeRow(int rowNumber, Ref<BitArray> row); Ref<Result> decodeRow(int rowNumber, Ref<BitArray> row);
// TODO(dswitkin): Should this be virtual so that UPCAReader can override it? // TODO(dswitkin): Should this be virtual so that UPCAReader can override it?
Ref<Result> decodeRow(int rowNumber, Ref<BitArray> row, int startGuardRange[]); Ref<Result> decodeRow(int rowNumber, Ref<BitArray> row, int startGuardBegin,
int startGuardEnd);
// Returns < 0 on failure, >= 0 on success. // Returns < 0 on failure, >= 0 on success.
static int decodeDigit(Ref<BitArray> row, int counters[], int countersLen, int rowOffset, static int decodeDigit(Ref<BitArray> row, int counters[], int countersLen, int rowOffset,

View file

@ -42,13 +42,13 @@ namespace zxing {
UPCEReader::UPCEReader() { UPCEReader::UPCEReader() {
} }
int UPCEReader::decodeMiddle(Ref<BitArray> row, int startRange[], int startRangeLen, int UPCEReader::decodeMiddle(Ref<BitArray> row, int startGuardBegin, int startGuardEnd,
std::string& resultString) { std::string& resultString) {
const int countersLen = 4; const int countersLen = 4;
int counters[countersLen] = { 0, 0, 0, 0 }; int counters[countersLen] = { 0, 0, 0, 0 };
int end = row->getSize(); int end = row->getSize();
int rowOffset = startRange[1]; int rowOffset = startGuardEnd;
int lgPatternFound = 0; int lgPatternFound = 0;
for (int x = 0; x < 6 && rowOffset < end; x++) { for (int x = 0; x < 6 && rowOffset < end; x++) {
@ -72,9 +72,10 @@ namespace zxing {
return rowOffset; return rowOffset;
} }
int* UPCEReader::decodeEnd(Ref<BitArray> row, int endStart) { bool UPCEReader::decodeEnd(Ref<BitArray> row, int endStart, int* endGuardBegin,
int* endGuardEnd) {
return findGuardPattern(row, endStart, true, MIDDLE_END_PATTERN, return findGuardPattern(row, endStart, true, MIDDLE_END_PATTERN,
sizeof(MIDDLE_END_PATTERN) / sizeof(int)); sizeof(MIDDLE_END_PATTERN) / sizeof(int), endGuardBegin, endGuardEnd);
} }
bool UPCEReader::checkChecksum(std::string s){ bool UPCEReader::checkChecksum(std::string s){

View file

@ -30,12 +30,12 @@ namespace zxing {
private: private:
static bool determineNumSysAndCheckDigit(std::string& resultString, int lgPatternFound); static bool determineNumSysAndCheckDigit(std::string& resultString, int lgPatternFound);
protected: protected:
int* decodeEnd(Ref<BitArray> row, int endStart); bool decodeEnd(Ref<BitArray> row, int endStart, int* endGuardBegin, int* endGuardEnd);
bool checkChecksum(std::string s); bool checkChecksum(std::string s);
public: public:
UPCEReader(); UPCEReader();
int decodeMiddle(Ref<BitArray> row, int startRange[], int startRangeLen, int decodeMiddle(Ref<BitArray> row, int startGuardBegin, int startGuardEnd,
std::string& resultString); std::string& resultString);
static std::string convertUPCEtoUPCA(std::string upce); static std::string convertUPCEtoUPCA(std::string upce);