Issue 1022: updating cpp port and making DataMatrixReader almost as good as java

git-svn-id: https://zxing.googlecode.com/svn/trunk@1992 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
luizcroc@gmail.com 2011-10-28 11:24:50 +00:00
parent d65dd54e03
commit 41daacd233
23 changed files with 1553 additions and 608 deletions

View file

@ -46,8 +46,7 @@ const DecodeHints DecodeHints::DEFAULT_HINT(
BARCODEFORMAT_CODE_128_HINT | BARCODEFORMAT_CODE_128_HINT |
BARCODEFORMAT_CODE_39_HINT | BARCODEFORMAT_CODE_39_HINT |
BARCODEFORMAT_ITF_HINT | BARCODEFORMAT_ITF_HINT |
// TODO: uncomment once this passes QA BARCODEFORMAT_DATA_MATRIX_HINT |
// BARCODEFORMAT_DATA_MATRIX_HINT |
BARCODEFORMAT_QR_CODE_HINT); BARCODEFORMAT_QR_CODE_HINT);
DecodeHints::DecodeHints() { DecodeHints::DecodeHints() {

View file

@ -0,0 +1,29 @@
/*
* NotFoundException.cpp
* zxing
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <zxing/NotFoundException.h>
namespace zxing {
NotFoundException::NotFoundException(const char *msg) :
Exception(msg) {
}
NotFoundException::~NotFoundException() throw() {
}
}

View file

@ -0,0 +1,32 @@
#ifndef __NOT_FOUND_EXCEPTION_H__
#define __NOT_FOUND_EXCEPTION_H__
/*
* NotFoundException.h
* zxing
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <zxing/Exception.h>
namespace zxing {
class NotFoundException : public Exception {
public:
NotFoundException(const char *msg);
~NotFoundException() throw();
};
}
#endif // __NOT_FOUND_EXCEPTION_H__

View file

@ -19,6 +19,7 @@
*/ */
#include <zxing/ResultPoint.h> #include <zxing/ResultPoint.h>
#include <math.h>
namespace zxing { namespace zxing {
@ -36,4 +37,64 @@ float ResultPoint::getY() const {
return posY_; return posY_;
} }
bool ResultPoint::equals(Ref<ResultPoint> other) {
return posX_ == other->getX() && posY_ == other->getY();
}
/**
* <p>Orders an array of three ResultPoints in an order [A,B,C] such that AB < AC and
* BC < AC and the angle between BC and BA is less than 180 degrees.
*/
void ResultPoint::orderBestPatterns(std::vector<Ref<ResultPoint> > &patterns) {
// Find distances between pattern centers
float zeroOneDistance = distance(patterns[0]->getX(), patterns[1]->getX(),patterns[0]->getY(), patterns[1]->getY());
float oneTwoDistance = distance(patterns[1]->getX(), patterns[2]->getX(),patterns[1]->getY(), patterns[2]->getY());
float zeroTwoDistance = distance(patterns[0]->getX(), patterns[2]->getX(),patterns[0]->getY(), patterns[2]->getY());
Ref<ResultPoint> pointA, pointB, pointC;
// Assume one closest to other two is B; A and C will just be guesses at first
if (oneTwoDistance >= zeroOneDistance && oneTwoDistance >= zeroTwoDistance) {
pointB = patterns[0];
pointA = patterns[1];
pointC = patterns[2];
} else if (zeroTwoDistance >= oneTwoDistance && zeroTwoDistance >= zeroOneDistance) {
pointB = patterns[1];
pointA = patterns[0];
pointC = patterns[2];
} else {
pointB = patterns[2];
pointA = patterns[0];
pointC = patterns[1];
}
// Use cross product to figure out whether A and C are correct or flipped.
// This asks whether BC x BA has a positive z component, which is the arrangement
// we want for A, B, C. If it's negative, then we've got it flipped around and
// should swap A and C.
if (crossProductZ(pointA, pointB, pointC) < 0.0f) {
Ref<ResultPoint> temp = pointA;
pointA = pointC;
pointC = temp;
}
patterns[0] = pointA;
patterns[1] = pointB;
patterns[2] = pointC;
}
float ResultPoint::distance(Ref<ResultPoint> point1, Ref<ResultPoint> point2) {
return distance(point1->getX(), point1->getY(), point2->getX(), point2->getY());
}
float ResultPoint::distance(float x1, float x2, float y1, float y2) {
float xDiff = x1 - x2;
float yDiff = y1 - y2;
return (float) sqrt((double) (xDiff * xDiff + yDiff * yDiff));
}
float ResultPoint::crossProductZ(Ref<ResultPoint> pointA, Ref<ResultPoint> pointB, Ref<ResultPoint> pointC) {
float bX = pointB->getX();
float bY = pointB->getY();
return ((pointC->getX() - bX) * (pointA->getY() - bY)) - ((pointC->getY() - bY) * (pointA->getX() - bX));
}
} }

View file

@ -22,6 +22,7 @@
*/ */
#include <zxing/common/Counted.h> #include <zxing/common/Counted.h>
#include <vector>
namespace zxing { namespace zxing {
@ -37,6 +38,15 @@ public:
virtual float getX() const; virtual float getX() const;
virtual float getY() const; virtual float getY() const;
bool equals(Ref<ResultPoint> other);
static void orderBestPatterns(std::vector<Ref<ResultPoint> > &patterns);
static float distance(Ref<ResultPoint> point1, Ref<ResultPoint> point2);
static float distance(float x1, float x2, float y1, float y2);
private:
static float crossProductZ(Ref<ResultPoint> pointA, Ref<ResultPoint> pointB, Ref<ResultPoint> pointC);
}; };
} }

View file

@ -32,7 +32,6 @@ int BitSource::readBits(int numBits) {
int result = 0; int result = 0;
// First, read remainder from current byte // First, read remainder from current byte
if (bitOffset_ > 0) { if (bitOffset_ > 0) {
int bitsLeft = 8 - bitOffset_; int bitsLeft = 8 - bitOffset_;

View file

@ -47,6 +47,9 @@ public:
bytes_(bytes), byteOffset_(0), bitOffset_(0) { bytes_(bytes), byteOffset_(0), bitOffset_(0) {
} }
int getByteOffset() {
return byteOffset_;
}
/** /**
* @param numBits number of bits to read * @param numBits number of bits to read

View file

@ -53,6 +53,27 @@ Ref<BitMatrix> GridSampler::sampleGrid(Ref<BitMatrix> image, int dimension, Ref<
return bits; return bits;
} }
Ref<BitMatrix> GridSampler::sampleGrid(Ref<BitMatrix> image, int dimensionX, int dimensionY, Ref<PerspectiveTransform> transform) {
Ref<BitMatrix> bits(new BitMatrix(dimensionX, dimensionY));
vector<float> points(dimensionX << 1, (const float)0.0f);
for (int y = 0; y < dimensionY; y++) {
int max = points.size();
float yValue = (float)y + 0.5f;
for (int x = 0; x < max; x += 2) {
points[x] = (float)(x >> 1) + 0.5f;
points[x + 1] = yValue;
}
transform->transformPoints(points);
checkAndNudgePoints(image, points);
for (int x = 0; x < max; x += 2) {
if (image->get((int)points[x], (int)points[x + 1])) {
bits->set(x >> 1, y);
}
}
}
return bits;
}
Ref<BitMatrix> GridSampler::sampleGrid(Ref<BitMatrix> image, int dimension, float p1ToX, float p1ToY, float p2ToX, Ref<BitMatrix> GridSampler::sampleGrid(Ref<BitMatrix> image, int dimension, float p1ToX, float p1ToY, float p2ToX,
float p2ToY, float p3ToX, float p3ToY, float p4ToX, float p4ToY, float p1FromX, float p1FromY, float p2FromX, float p2ToY, float p3ToX, float p3ToY, float p4ToX, float p4ToY, float p1FromX, float p1FromY, float p2FromX,
float p2FromY, float p3FromX, float p3FromY, float p4FromX, float p4FromY) { float p2FromY, float p3FromX, float p3FromY, float p4FromX, float p4FromY) {

View file

@ -32,6 +32,8 @@ private:
public: public:
Ref<BitMatrix> sampleGrid(Ref<BitMatrix> image, int dimension, Ref<PerspectiveTransform> transform); Ref<BitMatrix> sampleGrid(Ref<BitMatrix> image, int dimension, Ref<PerspectiveTransform> transform);
Ref<BitMatrix> sampleGrid(Ref<BitMatrix> image, int dimensionX, int dimensionY, Ref<PerspectiveTransform> transform);
Ref<BitMatrix> sampleGrid(Ref<BitMatrix> image, int dimension, float p1ToX, float p1ToY, float p2ToX, float p2ToY, Ref<BitMatrix> sampleGrid(Ref<BitMatrix> image, int dimension, float p1ToX, float p1ToY, float p2ToX, float p2ToY,
float p3ToX, float p3ToY, float p4ToX, float p4ToY, float p1FromX, float p1FromY, float p2FromX, float p3ToX, float p3ToY, float p4ToX, float p4ToY, float p1FromX, float p1FromY, float p2FromX,
float p2FromY, float p3FromX, float p3FromY, float p4FromX, float p4FromY); float p2FromY, float p3FromX, float p3FromY, float p4FromX, float p4FromY);

View file

@ -0,0 +1,171 @@
/*
* MonochromeRectangleDetector.cpp
* y_wmk
*
* Created by Luiz Silva on 09/02/2010.
* Copyright 2010 y_wmk authors All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <zxing/NotFoundException.h>
#include <zxing/common/detector/MonochromeRectangleDetector.h>
#include <sstream>
namespace zxing {
using namespace std;
std::vector<Ref<ResultPoint> > MonochromeRectangleDetector::detect() {
int height = image_->getHeight();
int width = image_->getWidth();
int halfHeight = height >> 1;
int halfWidth = width >> 1;
int deltaY = max(1, height / (MAX_MODULES << 3));
int deltaX = max(1, width / (MAX_MODULES << 3));
int top = 0;
int bottom = height;
int left = 0;
int right = width;
Ref<ResultPoint> pointA(findCornerFromCenter(halfWidth, 0, left, right,
halfHeight, -deltaY, top, bottom, halfWidth >> 1));
top = (int) pointA->getY() - 1;;
Ref<ResultPoint> pointB(findCornerFromCenter(halfWidth, -deltaX, left, right,
halfHeight, 0, top, bottom, halfHeight >> 1));
left = (int) pointB->getX() - 1;
Ref<ResultPoint> pointC(findCornerFromCenter(halfWidth, deltaX, left, right,
halfHeight, 0, top, bottom, halfHeight >> 1));
right = (int) pointC->getX() + 1;
Ref<ResultPoint> pointD(findCornerFromCenter(halfWidth, 0, left, right,
halfHeight, deltaY, top, bottom, halfWidth >> 1));
bottom = (int) pointD->getY() + 1;
// Go try to find point A again with better information -- might have been off at first.
pointA.reset(findCornerFromCenter(halfWidth, 0, left, right,
halfHeight, -deltaY, top, bottom, halfWidth >> 2));
std::vector<Ref<ResultPoint> > corners(4);
corners[0].reset(pointA);
corners[1].reset(pointB);
corners[2].reset(pointC);
corners[3].reset(pointD);
return corners;
}
Ref<ResultPoint> MonochromeRectangleDetector::findCornerFromCenter(int centerX, int deltaX, int left, int right,
int centerY, int deltaY, int top, int bottom, int maxWhiteRun) {
Ref<TwoInts> lastRange(NULL);
for (int y = centerY, x = centerX;
y < bottom && y >= top && x < right && x >= left;
y += deltaY, x += deltaX) {
Ref<TwoInts> range(NULL);
if (deltaX == 0) {
// horizontal slices, up and down
range = blackWhiteRange(y, maxWhiteRun, left, right, true);
} else {
// vertical slices, left and right
range = blackWhiteRange(x, maxWhiteRun, top, bottom, false);
}
if (range == NULL) {
if (lastRange == NULL) {
throw NotFoundException("Couldn't find corners (lastRange = NULL) ");
} else {
// lastRange was found
if (deltaX == 0) {
int lastY = y - deltaY;
if (lastRange->start < centerX) {
if (lastRange->end > centerX) {
// straddle, choose one or the other based on direction
Ref<ResultPoint> result(new ResultPoint(deltaY > 0 ? lastRange->start : lastRange->end, lastY));
return result;
}
Ref<ResultPoint> result(new ResultPoint(lastRange->start, lastY));
return result;
} else {
Ref<ResultPoint> result(new ResultPoint(lastRange->end, lastY));
return result;
}
} else {
int lastX = x - deltaX;
if (lastRange->start < centerY) {
if (lastRange->end > centerY) {
Ref<ResultPoint> result(new ResultPoint(lastX, deltaX < 0 ? lastRange->start : lastRange->end));
return result;
}
Ref<ResultPoint> result(new ResultPoint(lastX, lastRange->start));
return result;
} else {
Ref<ResultPoint> result(new ResultPoint(lastX, lastRange->end));
return result;
}
}
}
}
lastRange = range;
}
throw NotFoundException("Couldn't find corners");
}
Ref<TwoInts> MonochromeRectangleDetector::blackWhiteRange(int fixedDimension, int maxWhiteRun, int minDim, int maxDim,
bool horizontal) {
int center = (minDim + maxDim) >> 1;
// Scan left/up first
int start = center;
while (start >= minDim) {
if (horizontal ? image_->get(start, fixedDimension) : image_->get(fixedDimension, start)) {
start--;
} else {
int whiteRunStart = start;
do {
start--;
} while (start >= minDim && !(horizontal ? image_->get(start, fixedDimension) :
image_->get(fixedDimension, start)));
int whiteRunSize = whiteRunStart - start;
if (start < minDim || whiteRunSize > maxWhiteRun) {
start = whiteRunStart;
break;
}
}
}
start++;
// Then try right/down
int end = center;
while (end < maxDim) {
if (horizontal ? image_->get(end, fixedDimension) : image_->get(fixedDimension, end)) {
end++;
} else {
int whiteRunStart = end;
do {
end++;
} while (end < maxDim && !(horizontal ? image_->get(end, fixedDimension) :
image_->get(fixedDimension, end)));
int whiteRunSize = end - whiteRunStart;
if (end >= maxDim || whiteRunSize > maxWhiteRun) {
end = whiteRunStart;
break;
}
}
}
end--;
Ref<TwoInts> result(NULL);
if (end > start) {
result = new TwoInts;
result->start = start;
result->end = end;
}
return result;
}
}

View file

@ -0,0 +1,60 @@
#ifndef __MONOCHROMERECTANGLEDETECTOR_H__
#define __MONOCHROMERECTANGLEDETECTOR_H__
/*
* MonochromeRectangleDetector.h
* y_wmk
*
* Created by Luiz Silva on 09/02/2010.
* Copyright 2010 y_wmk authors All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <vector>
#include <zxing/NotFoundException.h>
#include <zxing/ResultPoint.h>
#include <zxing/common/BitMatrix.h>
#include <zxing/common/Counted.h>
#include <zxing/ResultPoint.h>
namespace zxing {
struct TwoInts: public Counted {
int start;
int end;
};
class MonochromeRectangleDetector : public Counted {
private:
static const int MAX_MODULES = 32;
Ref<BitMatrix> image_;
public:
MonochromeRectangleDetector(Ref<BitMatrix> image) : image_(image) { };
std::vector<Ref<ResultPoint> > detect();
private:
Ref<ResultPoint> findCornerFromCenter(int centerX, int deltaX, int left, int right,
int centerY, int deltaY, int top, int bottom, int maxWhiteRun);
Ref<TwoInts> blackWhiteRange(int fixedDimension, int maxWhiteRun, int minDim, int maxDim,
bool horizontal);
int max(int a, float b) { return (float) a > b ? a : (int) b;};
};
}
#endif // __MONOCHROMERECTANGLEDETECTOR_H__

View file

@ -0,0 +1,315 @@
/*
* WhiteRectangleDetector.cpp
* y_wmk
*
* Created by Luiz Silva on 09/02/2010.
* Copyright 2010 y_wmk authors All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <zxing/NotFoundException.h>
#include <zxing/common/detector/WhiteRectangleDetector.h>
#include <math.h>
#include <sstream>
namespace zxing {
using namespace std;
int WhiteRectangleDetector::INIT_SIZE = 30;
int WhiteRectangleDetector::CORR = 1;
WhiteRectangleDetector::WhiteRectangleDetector(Ref<BitMatrix> image) : image_(image) {
width_ = image->getWidth();
height_ = image->getHeight();
};
/**
* <p>
* Detects a candidate barcode-like rectangular region within an image. It
* starts around the center of the image, increases the size of the candidate
* region until it finds a white rectangular region.
* </p>
*
* @return {@link vector<Ref<ResultPoint> >} describing the corners of the rectangular
* region. The first and last points are opposed on the diagonal, as
* are the second and third. The first point will be the topmost
* point and the last, the bottommost. The second point will be
* leftmost and the third, the rightmost
* @throws NotFoundException if no Data Matrix Code can be found
*/
std::vector<Ref<ResultPoint> > WhiteRectangleDetector::detect() {
int left = (width_ - INIT_SIZE) >> 1;
int right = (width_ + INIT_SIZE) >> 1;
int up = (height_ - INIT_SIZE) >> 1;
int down = (height_ + INIT_SIZE) >> 1;
if (up < 0 || left < 0 || down >= height_ || right >= width_) {
throw NotFoundException("Invalid dimensions WhiteRectangleDetector");
}
bool sizeExceeded = false;
bool aBlackPointFoundOnBorder = true;
bool atLeastOneBlackPointFoundOnBorder = false;
while (aBlackPointFoundOnBorder) {
aBlackPointFoundOnBorder = false;
// .....
// . |
// .....
bool rightBorderNotWhite = true;
while (rightBorderNotWhite && right < width_) {
rightBorderNotWhite = containsBlackPoint(up, down, right, false);
if (rightBorderNotWhite) {
right++;
aBlackPointFoundOnBorder = true;
}
}
if (right >= width_) {
sizeExceeded = true;
break;
}
// .....
// . .
// .___.
bool bottomBorderNotWhite = true;
while (bottomBorderNotWhite && down < height_) {
bottomBorderNotWhite = containsBlackPoint(left, right, down, true);
if (bottomBorderNotWhite) {
down++;
aBlackPointFoundOnBorder = true;
}
}
if (down >= height_) {
sizeExceeded = true;
break;
}
// .....
// | .
// .....
bool leftBorderNotWhite = true;
while (leftBorderNotWhite && left >= 0) {
leftBorderNotWhite = containsBlackPoint(up, down, left, false);
if (leftBorderNotWhite) {
left--;
aBlackPointFoundOnBorder = true;
}
}
if (left < 0) {
sizeExceeded = true;
break;
}
// .___.
// . .
// .....
bool topBorderNotWhite = true;
while (topBorderNotWhite && up >= 0) {
topBorderNotWhite = containsBlackPoint(left, right, up, true);
if (topBorderNotWhite) {
up--;
aBlackPointFoundOnBorder = true;
}
}
if (up < 0) {
sizeExceeded = true;
break;
}
if (aBlackPointFoundOnBorder) {
atLeastOneBlackPointFoundOnBorder = true;
}
}
if (!sizeExceeded && atLeastOneBlackPointFoundOnBorder) {
int maxSize = right - left;
Ref<ResultPoint> z(NULL);
//go up right
for (int i = 1; i < maxSize; i++) {
z = getBlackPointOnSegment(left, down - i, left + i, down);
if (z != NULL) {
break;
}
}
if (z == NULL) {
throw NotFoundException("z == NULL");
}
Ref<ResultPoint> t(NULL);
//go down right
for (int i = 1; i < maxSize; i++) {
t = getBlackPointOnSegment(left, up + i, left + i, up);
if (t != NULL) {
break;
}
}
if (t == NULL) {
throw NotFoundException("t == NULL");
}
Ref<ResultPoint> x(NULL);
//go down left
for (int i = 1; i < maxSize; i++) {
x = getBlackPointOnSegment(right, up + i, right - i, up);
if (x != NULL) {
break;
}
}
if (x == NULL) {
throw NotFoundException("x == NULL");
}
Ref<ResultPoint> y(NULL);
//go up left
for (int i = 1; i < maxSize; i++) {
y = getBlackPointOnSegment(right, down - i, right - i, down);
if (y != NULL) {
break;
}
}
if (y == NULL) {
throw NotFoundException("y == NULL");
}
return centerEdges(y, z, x, t);
} else {
throw NotFoundException("No black point found on border");
}
}
/**
* Ends up being a bit faster than Math.round(). This merely rounds its
* argument to the nearest int, where x.5 rounds up.
*/
int WhiteRectangleDetector::round(float d) {
return (int) (d + 0.5f);
}
Ref<ResultPoint> WhiteRectangleDetector::getBlackPointOnSegment(float aX, float aY, float bX, float bY) {
int dist = distanceL2(aX, aY, bX, bY);
float xStep = (bX - aX) / dist;
float yStep = (bY - aY) / dist;
for (int i = 0; i < dist; i++) {
int x = round(aX + i * xStep);
int y = round(aY + i * yStep);
if (image_->get(x, y)) {
Ref<ResultPoint> point(new ResultPoint(x, y));
return point;
}
}
Ref<ResultPoint> point(NULL);
return point;
}
int WhiteRectangleDetector::distanceL2(float aX, float aY, float bX, float bY) {
float xDiff = aX - bX;
float yDiff = aY - bY;
return round((float)sqrt(xDiff * xDiff + yDiff * yDiff));
}
/**
* recenters the points of a constant distance towards the center
*
* @param y bottom most point
* @param z left most point
* @param x right most point
* @param t top most point
* @return {@link vector<Ref<ResultPoint> >} describing the corners of the rectangular
* region. The first and last points are opposed on the diagonal, as
* are the second and third. The first point will be the topmost
* point and the last, the bottommost. The second point will be
* leftmost and the third, the rightmost
*/
vector<Ref<ResultPoint> > WhiteRectangleDetector::centerEdges(Ref<ResultPoint> y, Ref<ResultPoint> z,
Ref<ResultPoint> x, Ref<ResultPoint> t) {
//
// t t
// z x
// x OR z
// y y
//
float yi = y->getX();
float yj = y->getY();
float zi = z->getX();
float zj = z->getY();
float xi = x->getX();
float xj = x->getY();
float ti = t->getX();
float tj = t->getY();
std::vector<Ref<ResultPoint> > corners(4);
if (yi < (float)width_/2) {
Ref<ResultPoint> pointA(new ResultPoint(ti - CORR, tj + CORR));
Ref<ResultPoint> pointB(new ResultPoint(zi + CORR, zj + CORR));
Ref<ResultPoint> pointC(new ResultPoint(xi - CORR, xj - CORR));
Ref<ResultPoint> pointD(new ResultPoint(yi + CORR, yj - CORR));
corners[0].reset(pointA);
corners[1].reset(pointB);
corners[2].reset(pointC);
corners[3].reset(pointD);
} else {
Ref<ResultPoint> pointA(new ResultPoint(ti + CORR, tj + CORR));
Ref<ResultPoint> pointB(new ResultPoint(zi + CORR, zj - CORR));
Ref<ResultPoint> pointC(new ResultPoint(xi - CORR, xj + CORR));
Ref<ResultPoint> pointD(new ResultPoint(yi - CORR, yj - CORR));
corners[0].reset(pointA);
corners[1].reset(pointB);
corners[2].reset(pointC);
corners[3].reset(pointD);
}
return corners;
}
/**
* Determines whether a segment contains a black point
*
* @param a min value of the scanned coordinate
* @param b max value of the scanned coordinate
* @param fixed value of fixed coordinate
* @param horizontal set to true if scan must be horizontal, false if vertical
* @return true if a black point has been found, else false.
*/
bool WhiteRectangleDetector::containsBlackPoint(int a, int b, int fixed, bool horizontal) {
if (horizontal) {
for (int x = a; x <= b; x++) {
if (image_->get(x, fixed)) {
return true;
}
}
} else {
for (int y = a; y <= b; y++) {
if (image_->get(fixed, y)) {
return true;
}
}
}
return false;
}
}

View file

@ -0,0 +1,56 @@
#ifndef __WHITERECTANGLEDETECTOR_H__
#define __WHITERECTANGLEDETECTOR_H__
/*
* WhiteRectangleDetector.h
*
*
* Created by Luiz Silva on 09/02/2010.
* Copyright 2010 authors All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <vector>
#include <zxing/ReaderException.h>
#include <zxing/ResultPoint.h>
#include <zxing/common/BitMatrix.h>
#include <zxing/common/Counted.h>
#include <zxing/ResultPoint.h>
namespace zxing {
class WhiteRectangleDetector : public Counted {
private:
static int INIT_SIZE;
static int CORR;
Ref<BitMatrix> image_;
int width_;
int height_;
public:
WhiteRectangleDetector(Ref<BitMatrix> image);
std::vector<Ref<ResultPoint> > detect();
private:
int round(float a);
Ref<ResultPoint> getBlackPointOnSegment(float aX, float aY, float bX, float bY);
int distanceL2(float aX, float aY, float bX, float bY);
std::vector<Ref<ResultPoint> > centerEdges(Ref<ResultPoint> y, Ref<ResultPoint> z,
Ref<ResultPoint> x, Ref<ResultPoint> t);
bool containsBlackPoint(int a, int b, int fixed, bool horizontal);
};
}
#endif

View file

@ -189,7 +189,7 @@ int Version::buildVersions() {
new ECBlocks(14, new ECB(1, 16))))); new ECBlocks(14, new ECB(1, 16)))));
VERSIONS.push_back(Ref<Version>(new Version(28, 12, 36, 10, 16, VERSIONS.push_back(Ref<Version>(new Version(28, 12, 36, 10, 16,
new ECBlocks(18, new ECB(1, 22))))); new ECBlocks(18, new ECB(1, 22)))));
VERSIONS.push_back(Ref<Version>(new Version(29, 16, 36, 10, 16, VERSIONS.push_back(Ref<Version>(new Version(29, 16, 36, 14, 16,
new ECBlocks(24, new ECB(1, 32))))); new ECBlocks(24, new ECB(1, 32)))));
VERSIONS.push_back(Ref<Version>(new Version(30, 16, 48, 14, 22, VERSIONS.push_back(Ref<Version>(new Version(30, 16, 48, 14, 22,
new ECBlocks(28, new ECB(1, 49))))); new ECBlocks(28, new ECB(1, 49)))));

View file

@ -21,6 +21,8 @@
#include <zxing/datamatrix/decoder/BitMatrixParser.h> #include <zxing/datamatrix/decoder/BitMatrixParser.h>
#include <zxing/common/IllegalArgumentException.h> #include <zxing/common/IllegalArgumentException.h>
#include <iostream>
namespace zxing { namespace zxing {
namespace datamatrix { namespace datamatrix {
@ -32,13 +34,12 @@ BitMatrixParser::BitMatrixParser(Ref<BitMatrix> bitMatrix) : bitMatrix_(NULL),
parsedVersion_(NULL), parsedVersion_(NULL),
readBitMatrix_(NULL) { readBitMatrix_(NULL) {
size_t dimension = bitMatrix->getDimension(); size_t dimension = bitMatrix->getDimension();
if (dimension < 10 || dimension > 144 || (dimension & 0x01) != 0) if (dimension < 8 || dimension > 144 || (dimension & 0x01) != 0)
throw ReaderException("Dimension must be even, > 10 < 144"); throw ReaderException("Dimension must be even, > 8 < 144");
parsedVersion_ = readVersion(bitMatrix); parsedVersion_ = readVersion(bitMatrix);
bitMatrix_ = extractDataRegion(bitMatrix); bitMatrix_ = extractDataRegion(bitMatrix);
// TODO(bbrown): Make this work for rectangular symbols readBitMatrix_ = new BitMatrix(bitMatrix_->getWidth(), bitMatrix_->getHeight());
readBitMatrix_ = new BitMatrix(bitMatrix_->getDimension());
} }
Ref<Version> BitMatrixParser::readVersion(Ref<BitMatrix> bitMatrix) { Ref<Version> BitMatrixParser::readVersion(Ref<BitMatrix> bitMatrix) {
@ -46,9 +47,8 @@ Ref<Version> BitMatrixParser::readVersion(Ref<BitMatrix> bitMatrix) {
return parsedVersion_; return parsedVersion_;
} }
// TODO(bbrown): make this work for rectangular dimensions as well. int numRows = bitMatrix->getHeight();//getDimension();
int numRows = bitMatrix->getDimension(); int numColumns = bitMatrix->getWidth();//numRows;
int numColumns = numRows;
Ref<Version> version = parsedVersion_->getVersionForDimensions(numRows, numColumns); Ref<Version> version = parsedVersion_->getVersionForDimensions(numRows, numColumns);
if (version != 0) { if (version != 0) {
@ -63,9 +63,8 @@ ArrayRef<unsigned char> BitMatrixParser::readCodewords() {
int row = 4; int row = 4;
int column = 0; int column = 0;
// TODO(bbrown): Data Matrix can be rectangular, assuming square for now int numRows = bitMatrix_->getHeight();
int numRows = bitMatrix_->getDimension(); int numColumns = bitMatrix_->getWidth();
int numColumns = numRows;
bool corner1Read = false; bool corner1Read = false;
bool corner2Read = false; bool corner2Read = false;
@ -324,9 +323,8 @@ Ref<BitMatrix> BitMatrixParser::extractDataRegion(Ref<BitMatrix> bitMatrix) {
int symbolSizeRows = parsedVersion_->getSymbolSizeRows(); int symbolSizeRows = parsedVersion_->getSymbolSizeRows();
int symbolSizeColumns = parsedVersion_->getSymbolSizeColumns(); int symbolSizeColumns = parsedVersion_->getSymbolSizeColumns();
// TODO(bbrown): Make this work with rectangular codes if ((int)bitMatrix->getHeight() != symbolSizeRows) {
if ((int)bitMatrix->getDimension() != symbolSizeRows) { throw IllegalArgumentException("Dimension of bitMatrix must match the version size");
throw IllegalArgumentException("Dimension of bitMarix must match the version size");
} }
int dataRegionSizeRows = parsedVersion_->getDataRegionSizeRows(); int dataRegionSizeRows = parsedVersion_->getDataRegionSizeRows();
@ -336,10 +334,9 @@ Ref<BitMatrix> BitMatrixParser::extractDataRegion(Ref<BitMatrix> bitMatrix) {
int numDataRegionsColumn = symbolSizeColumns / dataRegionSizeColumns; int numDataRegionsColumn = symbolSizeColumns / dataRegionSizeColumns;
int sizeDataRegionRow = numDataRegionsRow * dataRegionSizeRows; int sizeDataRegionRow = numDataRegionsRow * dataRegionSizeRows;
//int sizeDataRegionColumn = numDataRegionsColumn * dataRegionSizeColumns; int sizeDataRegionColumn = numDataRegionsColumn * dataRegionSizeColumns;
// TODO(bbrown): Make this work with rectangular codes Ref<BitMatrix> bitMatrixWithoutAlignment(new BitMatrix(sizeDataRegionColumn, sizeDataRegionRow));
Ref<BitMatrix> bitMatrixWithoutAlignment(new BitMatrix(sizeDataRegionRow));
for (int dataRegionRow = 0; dataRegionRow < numDataRegionsRow; ++dataRegionRow) { for (int dataRegionRow = 0; dataRegionRow < numDataRegionsRow; ++dataRegionRow) {
int dataRegionRowOffset = dataRegionRow * dataRegionSizeRows; int dataRegionRowOffset = dataRegionRow * dataRegionSizeRows;
for (int dataRegionColumn = 0; dataRegionColumn < numDataRegionsColumn; ++dataRegionColumn) { for (int dataRegionColumn = 0; dataRegionColumn < numDataRegionsColumn; ++dataRegionColumn) {

View file

@ -18,9 +18,10 @@
* limitations under the License. * limitations under the License.
*/ */
#include <zxing/ReaderException.h> #include <zxing/FormatException.h>
#include <zxing/datamatrix/decoder/DecodedBitStreamParser.h> #include <zxing/datamatrix/decoder/DecodedBitStreamParser.h>
#include <iostream> #include <iostream>
#include <zxing/common/DecoderResult.h>
namespace zxing { namespace zxing {
namespace datamatrix { namespace datamatrix {
@ -31,7 +32,7 @@ const char DecodedBitStreamParser::C40_BASIC_SET_CHARS[] = {
'*', '*', '*', ' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '*', '*', '*', ' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
}; };
const char DecodedBitStreamParser::C40_SHIFT2_SET_CHARS[] = { const char DecodedBitStreamParser::C40_SHIFT2_SET_CHARS[] = {
'!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.',
@ -42,18 +43,18 @@ const char DecodedBitStreamParser::TEXT_BASIC_SET_CHARS[] = {
'*', '*', '*', ' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '*', '*', '*', ' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
}; };
const char DecodedBitStreamParser::TEXT_SHIFT3_SET_CHARS[] = { const char DecodedBitStreamParser::TEXT_SHIFT3_SET_CHARS[] = {
'\'', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', '\'', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '{', '|', '}', '~', (char) 127 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '{', '|', '}', '~', (char) 127
}; };
std::string DecodedBitStreamParser::decode(ArrayRef<unsigned char> bytes) { Ref<DecoderResult> DecodedBitStreamParser::decode(ArrayRef<unsigned char> bytes) {
Ref<BitSource> bits(new BitSource(bytes)); Ref<BitSource> bits(new BitSource(bytes));
ostringstream result; ostringstream result;
ostringstream resultTrailer; ostringstream resultTrailer;
// bool trailer = false; vector<unsigned char> byteSegments;
int mode = ASCII_ENCODE; int mode = ASCII_ENCODE;
do { do {
if (mode == ASCII_ENCODE) { if (mode == ASCII_ENCODE) {
@ -73,19 +74,21 @@ std::string DecodedBitStreamParser::decode(ArrayRef<unsigned char> bytes) {
decodeEdifactSegment(bits, result); decodeEdifactSegment(bits, result);
break; break;
case BASE256_ENCODE: case BASE256_ENCODE:
decodeBase256Segment(bits, result); decodeBase256Segment(bits, result, byteSegments);
break; break;
default: default:
throw ReaderException("Unsupported mode indicator"); throw FormatException("Unsupported mode indicator");
} }
mode = ASCII_ENCODE; mode = ASCII_ENCODE;
} }
} while (mode != PAD_ENCODE && bits->available() > 0); } while (mode != PAD_ENCODE && bits->available() > 0);
/* if (trailer) {
result << resultTrailer; if (resultTrailer.str().size() > 0) {
result << resultTrailer.str();
} }
*/ ArrayRef<unsigned char> rawBytes(bytes);
return result.str(); Ref<String> text(new String(result.str()));
return Ref<DecoderResult>(new DecoderResult(rawBytes, text));
} }
int DecodedBitStreamParser::decodeAsciiSegment(Ref<BitSource> bits, ostringstream & result, int DecodedBitStreamParser::decodeAsciiSegment(Ref<BitSource> bits, ostringstream & result,
@ -94,7 +97,7 @@ int DecodedBitStreamParser::decodeAsciiSegment(Ref<BitSource> bits, ostringstrea
do { do {
int oneByte = bits->readBits(8); int oneByte = bits->readBits(8);
if (oneByte == 0) { if (oneByte == 0) {
throw ReaderException("Not enough bits to decode"); throw FormatException("Not enough bits to decode");
} else if (oneByte <= 128) { // ASCII data (ASCII value + 1) } else if (oneByte <= 128) { // ASCII data (ASCII value + 1)
oneByte = upperShift ? (oneByte + 128) : oneByte; oneByte = upperShift ? (oneByte + 128) : oneByte;
// upperShift = false; // upperShift = false;
@ -113,27 +116,20 @@ int DecodedBitStreamParser::decodeAsciiSegment(Ref<BitSource> bits, ostringstrea
} else if (oneByte == 231) { // Latch to Base 256 encodation } else if (oneByte == 231) { // Latch to Base 256 encodation
return BASE256_ENCODE; return BASE256_ENCODE;
} else if (oneByte == 232) { // FNC1 } else if (oneByte == 232) { // FNC1
//throw ReaderException.getInstance(); result << ((char) 29); // translate as ASCII 29
// Ignore this symbol for now } else if (oneByte == 233 || oneByte == 234) {
} else if (oneByte == 233) { // Structured Append // Structured Append, Reader Programming
//throw ReaderException.getInstance(); // Ignore these symbols for now
// Ignore this symbol for now // throw FormatException.getInstance();
} else if (oneByte == 234) { // Reader Programming
//throw ReaderException.getInstance();
// Ignore this symbol for now
} else if (oneByte == 235) { // Upper Shift (shift to Extended ASCII) } else if (oneByte == 235) { // Upper Shift (shift to Extended ASCII)
upperShift = true; upperShift = true;
} else if (oneByte == 236) { // 05 Macro } else if (oneByte == 236) { // 05 Macro
/* trailer = false; result << ("[)>RS05GS");
result << "[)>\u001E05\u001D"; resultTrailer << ("RSEOT");
resultTrailer << "\u001E\u0004"; } else if (oneByte == 237) { // 06 Macro
// Ignore this symbol for now result << ("[)>RS06GS");
*/ } else if (oneByte == 237) { // 06 Macro resultTrailer << ("RSEOT");
/* trailer = false; } else if (oneByte == 238) { // Latch to ANSI X12 encodation
result << "[)>\u001E06\u001D";
resultTrailer << "\u001E\u0004";
// Ignore this symbol for now
*/ } else if (oneByte == 238) { // Latch to ANSI X12 encodation
return ANSIX12_ENCODE; return ANSIX12_ENCODE;
} else if (oneByte == 239) { // Latch to Text encodation } else if (oneByte == 239) { // Latch to Text encodation
return TEXT_ENCODE; return TEXT_ENCODE;
@ -141,10 +137,15 @@ int DecodedBitStreamParser::decodeAsciiSegment(Ref<BitSource> bits, ostringstrea
return EDIFACT_ENCODE; return EDIFACT_ENCODE;
} else if (oneByte == 241) { // ECI Character } else if (oneByte == 241) { // ECI Character
// TODO(bbrown): I think we need to support ECI // TODO(bbrown): I think we need to support ECI
//throw ReaderException.getInstance(); // throw FormatException.getInstance();
// Ignore this symbol for now // Ignore this symbol for now
} else if (oneByte >= 242) { // Not to be used in ASCII encodation } else if (oneByte >= 242) { // Not to be used in ASCII encodation
throw ReaderException("Not to be used in ASCII encodation"); // ... but work around encoders that end with 254, latch back to ASCII
if (oneByte == 254 && bits->available() == 0) {
// Ignore
} else {
throw FormatException("Not to be used in ASCII encodation");
}
} }
} while (bits->available() > 0); } while (bits->available() > 0);
return ASCII_ENCODE; return ASCII_ENCODE;
@ -157,6 +158,7 @@ void DecodedBitStreamParser::decodeC40Segment(Ref<BitSource> bits, ostringstream
bool upperShift = false; bool upperShift = false;
int* cValues = new int[3]; int* cValues = new int[3];
int shift = 0;
do { do {
// If there is only one byte left then it will be encoded as ASCII // If there is only one byte left then it will be encoded as ASCII
if (bits->available() == 8) { if (bits->available() == 8) {
@ -169,7 +171,6 @@ void DecodedBitStreamParser::decodeC40Segment(Ref<BitSource> bits, ostringstream
parseTwoBytes(firstByte, bits->readBits(8), cValues); parseTwoBytes(firstByte, bits->readBits(8), cValues);
int shift = 0;
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
int cValue = cValues[i]; int cValue = cValues[i];
switch (shift) { switch (shift) {
@ -187,10 +188,10 @@ void DecodedBitStreamParser::decodeC40Segment(Ref<BitSource> bits, ostringstream
break; break;
case 1: case 1:
if (upperShift) { if (upperShift) {
result << cValue + 128; result << (char) (cValue + 128);
upperShift = false; upperShift = false;
} else { } else {
result << cValue; result << (char) cValue;
} }
shift = 0; shift = 0;
break; break;
@ -203,11 +204,11 @@ void DecodedBitStreamParser::decodeC40Segment(Ref<BitSource> bits, ostringstream
result << C40_SHIFT2_SET_CHARS[cValue]; result << C40_SHIFT2_SET_CHARS[cValue];
} }
} else if (cValue == 27) { // FNC1 } else if (cValue == 27) { // FNC1
throw ReaderException("FNC1"); result << ((char) 29); // translate as ASCII 29
} else if (cValue == 30) { // Upper Shift } else if (cValue == 30) { // Upper Shift
upperShift = true; upperShift = true;
} else { } else {
throw ReaderException("Upper Shift"); throw FormatException("decodeC40Segment: Upper Shift");
} }
shift = 0; shift = 0;
break; break;
@ -221,7 +222,7 @@ void DecodedBitStreamParser::decodeC40Segment(Ref<BitSource> bits, ostringstream
shift = 0; shift = 0;
break; break;
default: default:
throw ReaderException(""); throw FormatException("decodeC40Segment: no case");
} }
} }
} while (bits->available() > 0); } while (bits->available() > 0);
@ -234,6 +235,7 @@ void DecodedBitStreamParser::decodeTextSegment(Ref<BitSource> bits, ostringstrea
bool upperShift = false; bool upperShift = false;
int* cValues = new int[3]; int* cValues = new int[3];
int shift = 0;
do { do {
// If there is only one byte left then it will be encoded as ASCII // If there is only one byte left then it will be encoded as ASCII
if (bits->available() == 8) { if (bits->available() == 8) {
@ -246,7 +248,6 @@ void DecodedBitStreamParser::decodeTextSegment(Ref<BitSource> bits, ostringstrea
parseTwoBytes(firstByte, bits->readBits(8), cValues); parseTwoBytes(firstByte, bits->readBits(8), cValues);
int shift = 0;
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
int cValue = cValues[i]; int cValue = cValues[i];
switch (shift) { switch (shift) {
@ -267,7 +268,7 @@ void DecodedBitStreamParser::decodeTextSegment(Ref<BitSource> bits, ostringstrea
result << (char) (cValue + 128); result << (char) (cValue + 128);
upperShift = false; upperShift = false;
} else { } else {
result << (cValue); result << (char) (cValue);
} }
shift = 0; shift = 0;
break; break;
@ -281,11 +282,11 @@ void DecodedBitStreamParser::decodeTextSegment(Ref<BitSource> bits, ostringstrea
result << (C40_SHIFT2_SET_CHARS[cValue]); result << (C40_SHIFT2_SET_CHARS[cValue]);
} }
} else if (cValue == 27) { // FNC1 } else if (cValue == 27) { // FNC1
throw ReaderException("FNC1"); result << ((char) 29); // translate as ASCII 29
} else if (cValue == 30) { // Upper Shift } else if (cValue == 30) { // Upper Shift
upperShift = true; upperShift = true;
} else { } else {
throw ReaderException("Upper Shift"); throw FormatException("decodeTextSegment: Upper Shift");
} }
shift = 0; shift = 0;
break; break;
@ -299,7 +300,7 @@ void DecodedBitStreamParser::decodeTextSegment(Ref<BitSource> bits, ostringstrea
shift = 0; shift = 0;
break; break;
default: default:
throw ReaderException(""); throw FormatException("decodeTextSegment: no case");
} }
} }
} while (bits->available() > 0); } while (bits->available() > 0);
@ -337,7 +338,7 @@ void DecodedBitStreamParser::decodeAnsiX12Segment(Ref<BitSource> bits, ostringst
} else if (cValue < 40) { // A - Z } else if (cValue < 40) { // A - Z
result << (char) (cValue + 51); result << (char) (cValue + 51);
} else { } else {
throw ReaderException(""); throw FormatException("decodeAnsiX12Segment: no case");
} }
} }
} while (bits->available() > 0); } while (bits->available() > 0);
@ -372,32 +373,44 @@ void DecodedBitStreamParser::decodeEdifactSegment(Ref<BitSource> bits, ostringst
} }
if (!unlatch) { if (!unlatch) {
if ((edifactValue & 32) == 0) { // no 1 in the leading (6th) bit if ((edifactValue & 0x20) == 0) { // no 1 in the leading (6th) bit
edifactValue |= 64; // Add a leading 01 to the 6 bit binary value edifactValue |= 0x40; // Add a leading 01 to the 6 bit binary value
} }
result << (edifactValue); result << (char)(edifactValue);
} }
} }
} while (!unlatch && bits->available() > 0); } while (!unlatch && bits->available() > 0);
} }
void DecodedBitStreamParser::decodeBase256Segment(Ref<BitSource> bits, ostringstream & result){//, vector<unsigned char> byteSegments) void DecodedBitStreamParser::decodeBase256Segment(Ref<BitSource> bits, ostringstream& result, vector<unsigned char> byteSegments) {
// Figure out how long the Base 256 Segment is. // Figure out how long the Base 256 Segment is.
int d1 = bits->readBits(8); int codewordPosition = 1 + bits->getByteOffset(); // position is 1-indexed
int d1 = unrandomize255State(bits->readBits(8), codewordPosition++);
int count; int count;
if (d1 == 0) { // Read the remainder of the symbol if (d1 == 0) { // Read the remainder of the symbol
count = bits->available() / 8; count = bits->available() / 8;
} else if (d1 < 250) { } else if (d1 < 250) {
count = d1; count = d1;
} else { } else {
count = 250 * (d1 - 249) + bits->readBits(8); count = 250 * (d1 - 249) + unrandomize255State(bits->readBits(8), codewordPosition++);
} }
// We're seeing NegativeArraySizeException errors from users.
if (count < 0) {
throw FormatException("NegativeArraySizeException");
}
unsigned char* bytes = new unsigned char[count]; unsigned char* bytes = new unsigned char[count];
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
bytes[i] = unrandomize255State(bits->readBits(8), i); // Have seen this particular error in the wild, such as at
// http://www.bcgen.com/demo/IDAutomationStreamingDataMatrix.aspx?MODE=3&D=Fred&PFMT=3&PT=F&X=0.3&O=0&LM=0.2
if (bits->available() < 8) {
throw FormatException("byteSegments");
}
bytes[i] = unrandomize255State(bits->readBits(8), codewordPosition++);
byteSegments.push_back(bytes[i]);
result << (char)bytes[i];
} }
//byteSegments.push_back(bytes);
result << bytes;
} }
} }
} }

View file

@ -23,9 +23,10 @@
#include <string> #include <string>
#include <sstream> #include <sstream>
#include <zxing/common/Array.h>
#include <zxing/common/BitSource.h> #include <zxing/common/BitSource.h>
#include <zxing/common/Counted.h> #include <zxing/common/Counted.h>
#include <zxing/common/Array.h> #include <zxing/common/DecoderResult.h>
namespace zxing { namespace zxing {
@ -78,7 +79,7 @@ private:
/** /**
* See ISO 16022:2006, 5.2.9 and Annex B, B.2 * See ISO 16022:2006, 5.2.9 and Annex B, B.2
*/ */
void decodeBase256Segment(Ref<BitSource> bits, std::ostringstream &result);//,std::vector<unsigned char> byteSegments); void decodeBase256Segment(Ref<BitSource> bits, std::ostringstream &result, std::vector<unsigned char> byteSegments);
void parseTwoBytes(int firstByte, int secondByte, int*& result); void parseTwoBytes(int firstByte, int secondByte, int*& result);
/** /**
@ -94,7 +95,7 @@ private:
public: public:
DecodedBitStreamParser() { }; DecodedBitStreamParser() { };
std::string decode(ArrayRef<unsigned char> bytes); Ref<DecoderResult> decode(ArrayRef<unsigned char> bytes);
}; };
} }

View file

@ -43,14 +43,14 @@ void Decoder::correctErrors(ArrayRef<unsigned char> codewordBytes, int numDataCo
codewordInts[i] = codewordBytes[i] & 0xff; codewordInts[i] = codewordBytes[i] & 0xff;
} }
int numECCodewords = numCodewords - numDataCodewords; int numECCodewords = numCodewords - numDataCodewords;
try { try {
rsDecoder_.decode(codewordInts, numECCodewords); rsDecoder_.decode(codewordInts, numECCodewords);
} catch (ReedSolomonException const& ex) { } catch (ReedSolomonException const& ex) {
ReaderException rex(ex.what()); ReaderException rex(ex.what());
throw rex; throw rex;
} }
// Copy back into array of bytes -- only need to worry about the bytes that were data
// We don't care about errors in the error-correction codewords
for (int i = 0; i < numDataCodewords; i++) { for (int i = 0; i < numDataCodewords; i++) {
codewordBytes[i] = (unsigned char)codewordInts[i]; codewordBytes[i] = (unsigned char)codewordInts[i];
} }
@ -66,31 +66,29 @@ Ref<DecoderResult> Decoder::decode(Ref<BitMatrix> bits) {
// Separate into data blocks // Separate into data blocks
std::vector<Ref<DataBlock> > dataBlocks = DataBlock::getDataBlocks(codewords, version); std::vector<Ref<DataBlock> > dataBlocks = DataBlock::getDataBlocks(codewords, version);
int dataBlocksCount = dataBlocks.size();
// Count total number of data bytes // Count total number of data bytes
int totalBytes = 0; int totalBytes = 0;
for (unsigned int i = 0; i < dataBlocks.size(); i++) { for (int i = 0; i < dataBlocksCount; i++) {
totalBytes += dataBlocks[i]->getNumDataCodewords(); totalBytes += dataBlocks[i]->getNumDataCodewords();
} }
ArrayRef<unsigned char> resultBytes(totalBytes); ArrayRef<unsigned char> resultBytes(totalBytes);
int resultOffset = 0;
// Error-correct and copy data blocks together into a stream of bytes // Error-correct and copy data blocks together into a stream of bytes
for (unsigned int j = 0; j < dataBlocks.size(); j++) { for (int j = 0; j < dataBlocksCount; j++) {
Ref<DataBlock> dataBlock(dataBlocks[j]); Ref<DataBlock> dataBlock(dataBlocks[j]);
ArrayRef<unsigned char> codewordBytes = dataBlock->getCodewords(); ArrayRef<unsigned char> codewordBytes = dataBlock->getCodewords();
int numDataCodewords = dataBlock->getNumDataCodewords(); int numDataCodewords = dataBlock->getNumDataCodewords();
correctErrors(codewordBytes, numDataCodewords); correctErrors(codewordBytes, numDataCodewords);
for (int i = 0; i < numDataCodewords; i++) { for (int i = 0; i < numDataCodewords; i++) {
resultBytes[resultOffset++] = codewordBytes[i]; // De-interlace data blocks.
resultBytes[i * dataBlocksCount + j] = codewordBytes[i];
} }
} }
// Decode the contents of that stream of bytes // Decode the contents of that stream of bytes
DecodedBitStreamParser decodedBSParser; DecodedBitStreamParser decodedBSParser;
Ref<String> text(new String(decodedBSParser.decode(resultBytes))); return Ref<DecoderResult> (decodedBSParser.decode(resultBytes));
Ref<DecoderResult> result(new DecoderResult(resultBytes, text));
return result;
} }
} }
} }

View file

@ -19,6 +19,7 @@
* limitations under the License. * limitations under the License.
*/ */
#include <zxing/ResultPoint.h>
#include <zxing/common/GridSampler.h> #include <zxing/common/GridSampler.h>
#include <zxing/datamatrix/detector/Detector.h> #include <zxing/datamatrix/detector/Detector.h>
#include <cmath> #include <cmath>
@ -30,21 +31,23 @@ namespace datamatrix {
using namespace std; using namespace std;
ResultPointsAndTransitions::ResultPointsAndTransitions() : to_(), from_(), transitions_(0) { ResultPointsAndTransitions::ResultPointsAndTransitions() {
Ref<CornerPoint> ref(new CornerPoint(0,0)); Ref<ResultPoint> ref(new ResultPoint(0, 0));
from_ = ref; from_ = ref;
to_ = ref; to_ = ref;
transitions_ = 0;
} }
ResultPointsAndTransitions::ResultPointsAndTransitions(Ref<CornerPoint> from, Ref<CornerPoint> to, int transitions) : ResultPointsAndTransitions::ResultPointsAndTransitions(Ref<ResultPoint> from, Ref<ResultPoint> to,
to_(to), from_(from), transitions_(transitions) { int transitions)
: to_(to), from_(from), transitions_(transitions) {
} }
Ref<CornerPoint> ResultPointsAndTransitions::getFrom() { Ref<ResultPoint> ResultPointsAndTransitions::getFrom() {
return from_; return from_;
} }
Ref<CornerPoint> ResultPointsAndTransitions::getTo() { Ref<ResultPoint> ResultPointsAndTransitions::getTo() {
return to_; return to_;
} }
@ -52,19 +55,21 @@ int ResultPointsAndTransitions::getTransitions() {
return transitions_; return transitions_;
} }
Detector::Detector(Ref<BitMatrix> image) : image_(image) { } Detector::Detector(Ref<BitMatrix> image)
: image_(image) {
}
Ref<BitMatrix> Detector::getImage() { Ref<BitMatrix> Detector::getImage() {
return image_; return image_;
} }
Ref<DetectorResult> Detector::detect() { Ref<DetectorResult> Detector::detect() {
Ref<MonochromeRectangleDetector> rectangleDetector_(new MonochromeRectangleDetector(image_)); Ref<WhiteRectangleDetector> rectangleDetector_(new WhiteRectangleDetector(image_));
std::vector<Ref<CornerPoint> > cornerPoints = rectangleDetector_->detect(); std::vector<Ref<ResultPoint> > ResultPoints = rectangleDetector_->detect();
Ref<CornerPoint> pointA = cornerPoints[0]; Ref<ResultPoint> pointA = ResultPoints[0];
Ref<CornerPoint> pointB = cornerPoints[1]; Ref<ResultPoint> pointB = ResultPoints[1];
Ref<CornerPoint> pointC = cornerPoints[2]; Ref<ResultPoint> pointC = ResultPoints[2];
Ref<CornerPoint> pointD = cornerPoints[3]; Ref<ResultPoint> pointD = ResultPoints[3];
// Point A and D are across the diagonal from one another, // Point A and D are across the diagonal from one another,
// as are B and C. Figure out which are the solid black lines // as are B and C. Figure out which are the solid black lines
@ -83,97 +88,255 @@ Ref<DetectorResult> Detector::detect() {
// Figure out which point is their intersection by tallying up the number of times we see the // Figure out which point is their intersection by tallying up the number of times we see the
// endpoints in the four endpoints. One will show up twice. // endpoints in the four endpoints. One will show up twice.
Ref<CornerPoint> maybeTopLeft; Ref<ResultPoint> maybeTopLeft;
Ref<CornerPoint> bottomLeft; Ref<ResultPoint> bottomLeft;
Ref<CornerPoint> maybeBottomRight; Ref<ResultPoint> maybeBottomRight;
if (lSideOne->getFrom()->equals(lSideOne->getTo())) { if (lSideOne->getFrom()->equals(lSideOne->getTo())) {
bottomLeft = lSideOne->getFrom(); bottomLeft = lSideOne->getFrom();
maybeTopLeft = lSideTwo->getFrom(); maybeTopLeft = lSideTwo->getFrom();
maybeBottomRight = lSideTwo->getTo(); maybeBottomRight = lSideTwo->getTo();
} } else if (lSideOne->getFrom()->equals(lSideTwo->getFrom())) {
else if (lSideOne->getFrom()->equals(lSideTwo->getFrom())) {
bottomLeft = lSideOne->getFrom(); bottomLeft = lSideOne->getFrom();
maybeTopLeft = lSideOne->getTo(); maybeTopLeft = lSideOne->getTo();
maybeBottomRight = lSideTwo->getTo(); maybeBottomRight = lSideTwo->getTo();
} } else if (lSideOne->getFrom()->equals(lSideTwo->getTo())) {
else if (lSideOne->getFrom()->equals(lSideTwo->getTo())) {
bottomLeft = lSideOne->getFrom(); bottomLeft = lSideOne->getFrom();
maybeTopLeft = lSideOne->getTo(); maybeTopLeft = lSideOne->getTo();
maybeBottomRight = lSideTwo->getFrom(); maybeBottomRight = lSideTwo->getFrom();
} } else if (lSideOne->getTo()->equals(lSideTwo->getFrom())) {
else if (lSideOne->getTo()->equals(lSideTwo->getFrom())) {
bottomLeft = lSideOne->getTo(); bottomLeft = lSideOne->getTo();
maybeTopLeft = lSideOne->getFrom(); maybeTopLeft = lSideOne->getFrom();
maybeBottomRight = lSideTwo->getTo(); maybeBottomRight = lSideTwo->getTo();
} } else if (lSideOne->getTo()->equals(lSideTwo->getTo())) {
else if (lSideOne->getTo()->equals(lSideTwo->getTo())) {
bottomLeft = lSideOne->getTo(); bottomLeft = lSideOne->getTo();
maybeTopLeft = lSideOne->getFrom(); maybeTopLeft = lSideOne->getFrom();
maybeBottomRight = lSideTwo->getFrom(); maybeBottomRight = lSideTwo->getFrom();
} } else {
else {
bottomLeft = lSideTwo->getFrom(); bottomLeft = lSideTwo->getFrom();
maybeTopLeft = lSideOne->getTo(); maybeTopLeft = lSideOne->getTo();
maybeBottomRight = lSideOne->getFrom(); maybeBottomRight = lSideOne->getFrom();
} }
// Bottom left is correct but top left and bottom right might be switched // Bottom left is correct but top left and bottom right might be switched
std::vector<Ref<CornerPoint> > corners(3); std::vector<Ref<ResultPoint> > corners(3);
corners[0].reset(maybeTopLeft); corners[0].reset(maybeTopLeft);
corners[1].reset(bottomLeft); corners[1].reset(bottomLeft);
corners[2].reset(maybeBottomRight); corners[2].reset(maybeBottomRight);
// Use the dot product trick to sort them out // Use the dot product trick to sort them out
orderBestPatterns(corners); ResultPoint::orderBestPatterns(corners);
// Now we know which is which: // Now we know which is which:
Ref<CornerPoint> bottomRight(corners[0]); Ref<ResultPoint> bottomRight(corners[0]);
bottomLeft = corners[1]; bottomLeft = corners[1];
Ref<CornerPoint> topLeft(corners[2]); Ref<ResultPoint> topLeft(corners[2]);
// Which point didn't we find in relation to the "L" sides? that's the top right corner // Which point didn't we find in relation to the "L" sides? that's the top right corner
Ref<CornerPoint> topRight; Ref<ResultPoint> topRight;
if (!(pointA->equals(bottomRight) || pointA->equals(bottomLeft) || pointA->equals(topLeft))) { if (!(pointA->equals(bottomRight) || pointA->equals(bottomLeft) || pointA->equals(topLeft))) {
topRight = pointA; topRight = pointA;
} else if (!(pointB->equals(bottomRight) || pointB->equals(bottomLeft) || pointB->equals(topLeft))) { } else if (!(pointB->equals(bottomRight) || pointB->equals(bottomLeft)
|| pointB->equals(topLeft))) {
topRight = pointB; topRight = pointB;
} else if (!(pointC->equals(bottomRight) || pointC->equals(bottomLeft) || pointC->equals(topLeft))) { } else if (!(pointC->equals(bottomRight) || pointC->equals(bottomLeft)
|| pointC->equals(topLeft))) {
topRight = pointC; topRight = pointC;
} else { } else {
topRight = pointD; topRight = pointD;
} }
float topRightX = (bottomRight->getX() - bottomLeft->getX()) + topLeft->getX();
float topRightY = (bottomRight->getY() - bottomLeft->getY()) + topLeft->getY();
Ref<CornerPoint> topR(new CornerPoint(topRightX,topRightY));
// Next determine the dimension by tracing along the top or right side and counting black/white // Next determine the dimension by tracing along the top or right side and counting black/white
// transitions. Since we start inside a black module, we should see a number of transitions // transitions. Since we start inside a black module, we should see a number of transitions
// equal to 1 less than the code dimension. Well, actually 2 less, because we are going to // equal to 1 less than the code dimension. Well, actually 2 less, because we are going to
// end on a black module: // end on a black module:
// The top right point is actually the corner of a module, which is one of the two black modules // The top right point is actually the corner of a module, which is one of the two black modules
// adjacent to the white module at the top right. Tracing to that corner from either the top left // adjacent to the white module at the top right. Tracing to that corner from either the top left
// or bottom right should work here. The number of transitions could be higher than it should be // or bottom right should work here.
// due to noise. So we try both and take the min.
int dimension = min(transitionsBetween(topLeft, topRight)->getTransitions(), int dimensionTop = transitionsBetween(topLeft, topRight)->getTransitions();
transitionsBetween(bottomRight, topRight)->getTransitions()); int dimensionRight = transitionsBetween(bottomRight, topRight)->getTransitions();
if ((dimension & 0x01) == 1) {
// it can't be odd, so, round... up? //dimensionTop++;
dimension++; if ((dimensionTop & 0x01) == 1) {
} // it can't be odd, so, round... up?
dimension += 2; dimensionTop++;
}
dimensionTop += 2;
//dimensionRight++;
if ((dimensionRight & 0x01) == 1) {
// it can't be odd, so, round... up?
dimensionRight++;
}
dimensionRight += 2;
Ref<BitMatrix> bits;
Ref<PerspectiveTransform> transform;
Ref<ResultPoint> correctedTopRight;
// Rectanguar symbols are 6x16, 6x28, 10x24, 10x32, 14x32, or 14x44. If one dimension is more
// than twice the other, it's certainly rectangular, but to cut a bit more slack we accept it as
// rectangular if the bigger side is at least 7/4 times the other:
if (4 * dimensionTop >= 7 * dimensionRight || 4 * dimensionRight >= 7 * dimensionTop) {
// The matrix is rectangular
correctedTopRight = correctTopRightRectangular(bottomLeft, bottomRight, topLeft, topRight,
dimensionTop, dimensionRight);
if (correctedTopRight == NULL) {
correctedTopRight = topRight;
}
dimensionTop = transitionsBetween(topLeft, correctedTopRight)->getTransitions();
dimensionRight = transitionsBetween(bottomRight, correctedTopRight)->getTransitions();
if ((dimensionTop & 0x01) == 1) {
// it can't be odd, so, round... up?
dimensionTop++;
}
if ((dimensionRight & 0x01) == 1) {
// it can't be odd, so, round... up?
dimensionRight++;
}
transform = createTransform(topLeft, correctedTopRight, bottomLeft, bottomRight, dimensionTop,
dimensionRight);
bits = sampleGrid(image_, dimensionTop, dimensionRight, transform);
} else {
// The matrix is square
int dimension = min(dimensionRight, dimensionTop);
// correct top right point to match the white module
correctedTopRight = correctTopRight(bottomLeft, bottomRight, topLeft, topRight, dimension);
if (correctedTopRight == NULL) {
correctedTopRight = topRight;
}
// Redetermine the dimension using the corrected top right point
int dimensionCorrected = max(transitionsBetween(topLeft, correctedTopRight)->getTransitions(),
transitionsBetween(bottomRight, correctedTopRight)->getTransitions());
dimensionCorrected++;
if ((dimensionCorrected & 0x01) == 1) {
dimensionCorrected++;
}
transform = createTransform(topLeft, correctedTopRight, bottomLeft, bottomRight,
dimensionCorrected, dimensionCorrected);
bits = sampleGrid(image_, dimensionCorrected, dimensionCorrected, transform);
}
Ref<PerspectiveTransform> transform = createTransform(topLeft, topR, bottomLeft, bottomRight, dimension);
Ref<BitMatrix> bits(sampleGrid(image_, dimension, transform));
std::vector<Ref<ResultPoint> > points(4); std::vector<Ref<ResultPoint> > points(4);
points[0].reset(pointA); points[0].reset(topLeft);
points[1].reset(pointB); points[1].reset(bottomLeft);
points[2].reset(pointC); points[2].reset(correctedTopRight);
points[3].reset(pointD); points[3].reset(bottomRight);
Ref<DetectorResult> detectorResult(new DetectorResult(bits, points, transform)); Ref<DetectorResult> detectorResult(new DetectorResult(bits, points, transform));
return detectorResult; return detectorResult;
} }
Ref<ResultPointsAndTransitions> Detector::transitionsBetween(Ref<CornerPoint> from, Ref<CornerPoint> to) { /**
* Calculates the position of the white top right module using the output of the rectangle detector
* for a rectangular matrix
*/
Ref<ResultPoint> Detector::correctTopRightRectangular(Ref<ResultPoint> bottomLeft,
Ref<ResultPoint> bottomRight, Ref<ResultPoint> topLeft, Ref<ResultPoint> topRight,
int dimensionTop, int dimensionRight) {
float corr = distance(bottomLeft, bottomRight) / (float) dimensionTop;
int norm = distance(topLeft, topRight);
float cos = (topRight->getX() - topLeft->getX()) / norm;
float sin = (topRight->getY() - topLeft->getY()) / norm;
Ref<ResultPoint> c1(
new ResultPoint(topRight->getX() + corr * cos, topRight->getY() + corr * sin));
corr = distance(bottomLeft, topLeft) / (float) dimensionRight;
norm = distance(bottomRight, topRight);
cos = (topRight->getX() - bottomRight->getX()) / norm;
sin = (topRight->getY() - bottomRight->getY()) / norm;
Ref<ResultPoint> c2(
new ResultPoint(topRight->getX() + corr * cos, topRight->getY() + corr * sin));
if (!isValid(c1)) {
if (isValid(c2)) {
return c2;
}
return Ref<ResultPoint>(NULL);
}
if (!isValid(c2)) {
return c1;
}
int l1 = abs(dimensionTop - transitionsBetween(topLeft, c1)->getTransitions())
+ abs(dimensionRight - transitionsBetween(bottomRight, c1)->getTransitions());
int l2 = abs(dimensionTop - transitionsBetween(topLeft, c2)->getTransitions())
+ abs(dimensionRight - transitionsBetween(bottomRight, c2)->getTransitions());
return l1 <= l2 ? c1 : c2;
}
/**
* Calculates the position of the white top right module using the output of the rectangle detector
* for a square matrix
*/
Ref<ResultPoint> Detector::correctTopRight(Ref<ResultPoint> bottomLeft,
Ref<ResultPoint> bottomRight, Ref<ResultPoint> topLeft, Ref<ResultPoint> topRight,
int dimension) {
float corr = distance(bottomLeft, bottomRight) / (float) dimension;
int norm = distance(topLeft, topRight);
float cos = (topRight->getX() - topLeft->getX()) / norm;
float sin = (topRight->getY() - topLeft->getY()) / norm;
Ref<ResultPoint> c1(
new ResultPoint(topRight->getX() + corr * cos, topRight->getY() + corr * sin));
corr = distance(bottomLeft, bottomRight) / (float) dimension;
norm = distance(bottomRight, topRight);
cos = (topRight->getX() - bottomRight->getX()) / norm;
sin = (topRight->getY() - bottomRight->getY()) / norm;
Ref<ResultPoint> c2(
new ResultPoint(topRight->getX() + corr * cos, topRight->getY() + corr * sin));
if (!isValid(c1)) {
if (isValid(c2)) {
return c2;
}
return Ref<ResultPoint>(NULL);
}
if (!isValid(c2)) {
return c1;
}
int l1 = abs(
transitionsBetween(topLeft, c1)->getTransitions()
- transitionsBetween(bottomRight, c1)->getTransitions());
int l2 = abs(
transitionsBetween(topLeft, c2)->getTransitions()
- transitionsBetween(bottomRight, c2)->getTransitions());
return l1 <= l2 ? c1 : c2;
}
bool Detector::isValid(Ref<ResultPoint> p) {
return p->getX() >= 0 && p->getX() < image_->getWidth() && p->getY() > 0
&& p->getY() < image_->getHeight();
}
// L2 distance
int Detector::distance(Ref<ResultPoint> a, Ref<ResultPoint> b) {
return round(
(float) sqrt(
(double) (a->getX() - b->getX()) * (a->getX() - b->getX())
+ (a->getY() - b->getY()) * (a->getY() - b->getY())));
}
Ref<ResultPointsAndTransitions> Detector::transitionsBetween(Ref<ResultPoint> from,
Ref<ResultPoint> to) {
// See QR Code Detector, sizeOfBlackWhiteBlackRun() // See QR Code Detector, sizeOfBlackWhiteBlackRun()
int fromX = (int) from->getX(); int fromX = (int) from->getX();
int fromY = (int) from->getY(); int fromY = (int) from->getY();
@ -213,20 +376,22 @@ Ref<ResultPointsAndTransitions> Detector::transitionsBetween(Ref<CornerPoint> fr
} }
Ref<ResultPointsAndTransitions> result(new ResultPointsAndTransitions(from, to, transitions)); Ref<ResultPointsAndTransitions> result(new ResultPointsAndTransitions(from, to, transitions));
return result; return result;
} }
Ref<PerspectiveTransform> Detector::createTransform(Ref<ResultPoint> topLeft, Ref<ResultPoint> topRight, Ref < Ref<PerspectiveTransform> Detector::createTransform(Ref<ResultPoint> topLeft,
ResultPoint > bottomLeft, Ref<ResultPoint> bottomRight, int dimension) { Ref<ResultPoint> topRight, Ref<ResultPoint> bottomLeft, Ref<ResultPoint> bottomRight,
int dimensionX, int dimensionY) {
Ref<PerspectiveTransform> transform(PerspectiveTransform::quadrilateralToQuadrilateral( Ref<PerspectiveTransform> transform(
0.0f, PerspectiveTransform::quadrilateralToQuadrilateral(
0.0f, 0.5f,
dimension, 0.5f,
0.0f, dimensionX - 0.5f,
dimension, 0.5f,
dimension, dimensionX - 0.5f,
0.0f, dimensionY - 0.5f,
dimension, 0.5f,
dimensionY - 0.5f,
topLeft->getX(), topLeft->getX(),
topLeft->getY(), topLeft->getY(),
topRight->getX(), topRight->getX(),
@ -238,9 +403,10 @@ Ref<PerspectiveTransform> Detector::createTransform(Ref<ResultPoint> topLeft, Re
return transform; return transform;
} }
Ref<BitMatrix> Detector::sampleGrid(Ref<BitMatrix> image, int dimension, Ref<PerspectiveTransform> transform) { Ref<BitMatrix> Detector::sampleGrid(Ref<BitMatrix> image, int dimensionX, int dimensionY,
Ref<PerspectiveTransform> transform) {
GridSampler &sampler = GridSampler::getInstance(); GridSampler &sampler = GridSampler::getInstance();
return sampler.sampleGrid(image, dimension, transform); return sampler.sampleGrid(image, dimensionX, dimensionY, transform);
} }
void Detector::insertionSort(std::vector<Ref<ResultPointsAndTransitions> > &vector) { void Detector::insertionSort(std::vector<Ref<ResultPointsAndTransitions> > &vector) {
@ -251,66 +417,18 @@ void Detector::insertionSort(std::vector<Ref<ResultPointsAndTransitions> > &vect
do { do {
swapped = false; swapped = false;
for (int i = 1; i < max; i++) { for (int i = 1; i < max; i++) {
value = vector[i-1]; value = vector[i - 1];
if (compare(value, (valueB = vector[i])) > 0) { if (compare(value, (valueB = vector[i])) > 0){
swapped = true; swapped = true;
vector[i-1].reset(valueB); vector[i - 1].reset(valueB);
vector[i].reset(value); vector[i].reset(value);
} }
} }
} while (swapped); } while (swapped);
} }
void Detector::orderBestPatterns(std::vector<Ref<CornerPoint> > &patterns) {
// Find distances between pattern centers
float zeroOneDistance = distance(patterns[0]->getX(), patterns[1]->getX(),patterns[0]->getY(), patterns[1]->getY());
float oneTwoDistance = distance(patterns[1]->getX(), patterns[2]->getX(),patterns[1]->getY(), patterns[2]->getY());
float zeroTwoDistance = distance(patterns[0]->getX(), patterns[2]->getX(),patterns[0]->getY(), patterns[2]->getY());
Ref<CornerPoint> pointA, pointB, pointC;
// Assume one closest to other two is B; A and C will just be guesses at first
if (oneTwoDistance >= zeroOneDistance && oneTwoDistance >= zeroTwoDistance) {
pointB = patterns[0];
pointA = patterns[1];
pointC = patterns[2];
} else if (zeroTwoDistance >= oneTwoDistance && zeroTwoDistance >= zeroOneDistance) {
pointB = patterns[1];
pointA = patterns[0];
pointC = patterns[2];
} else {
pointB = patterns[2];
pointA = patterns[0];
pointC = patterns[1];
}
// Use cross product to figure out whether A and C are correct or flipped.
// This asks whether BC x BA has a positive z component, which is the arrangement
// we want for A, B, C. If it's negative, then we've got it flipped around and
// should swap A and C.
if (crossProductZ(pointA, pointB, pointC) < 0.0f) {
Ref<CornerPoint> temp = pointA;
pointA = pointC;
pointC = temp;
}
patterns[0] = pointA;
patterns[1] = pointB;
patterns[2] = pointC;
}
float Detector::distance(float x1, float x2, float y1, float y2) {
float xDiff = x1 - x2;
float yDiff = y1 - y2;
return (float) sqrt((double) (xDiff * xDiff + yDiff * yDiff));
}
int Detector::compare(Ref<ResultPointsAndTransitions> a, Ref<ResultPointsAndTransitions> b) { int Detector::compare(Ref<ResultPointsAndTransitions> a, Ref<ResultPointsAndTransitions> b) {
return a->getTransitions() - b->getTransitions(); return a->getTransitions() - b->getTransitions();
} }
float Detector::crossProductZ(Ref<ResultPoint> pointA, Ref<ResultPoint> pointB, Ref<ResultPoint> pointC) {
float bX = pointB->getX();
float bY = pointB->getY();
return ((pointC->getX() - bX) * (pointA->getY() - bY)) - ((pointC->getY() - bY) * (pointA->getX() - bX));
}
} }
} }

View file

@ -22,56 +22,70 @@
* limitations under the License. * limitations under the License.
*/ */
#include <zxing/common/Counted.h> #include <zxing/common/Counted.h>
#include <zxing/common/DetectorResult.h> #include <zxing/common/DetectorResult.h>
#include <zxing/common/BitMatrix.h> #include <zxing/common/BitMatrix.h>
#include <zxing/common/PerspectiveTransform.h> #include <zxing/common/PerspectiveTransform.h>
#include <zxing/datamatrix/detector/MonochromeRectangleDetector.h> #include <zxing/common/detector/WhiteRectangleDetector.h>
namespace zxing { namespace zxing {
namespace datamatrix { namespace datamatrix {
class ResultPointsAndTransitions : public Counted { class ResultPointsAndTransitions: public Counted {
private: private:
Ref<CornerPoint> to_; Ref<ResultPoint> to_;
Ref<CornerPoint> from_; Ref<ResultPoint> from_;
int transitions_; int transitions_;
public: public:
ResultPointsAndTransitions(); ResultPointsAndTransitions();
ResultPointsAndTransitions(Ref<CornerPoint> from, Ref<CornerPoint> to, int transitions); ResultPointsAndTransitions(Ref<ResultPoint> from, Ref<ResultPoint> to, int transitions);
Ref<CornerPoint> getFrom(); Ref<ResultPoint> getFrom();
Ref<CornerPoint> getTo(); Ref<ResultPoint> getTo();
int getTransitions(); int getTransitions();
}; };
class Detector : public Counted { class Detector: public Counted {
private: private:
Ref<BitMatrix> image_; Ref<BitMatrix> image_;
protected: protected:
Ref<BitMatrix> sampleGrid(Ref<BitMatrix> image, int dimension, Ref<PerspectiveTransform> transform); Ref<BitMatrix> sampleGrid(Ref<BitMatrix> image, int dimensionX, int dimensionY,
Ref<PerspectiveTransform> transform);
void insertionSort(std::vector<Ref<ResultPointsAndTransitions> >& vector); void insertionSort(std::vector<Ref<ResultPointsAndTransitions> >& vector);
Ref<ResultPointsAndTransitions> transitionsBetween(Ref<CornerPoint> from, Ref<CornerPoint> to); Ref<ResultPoint> correctTopRightRectangular(Ref<ResultPoint> bottomLeft,
int min(int a, int b) { return a > b ? b : a; }; Ref<ResultPoint> bottomRight, Ref<ResultPoint> topLeft, Ref<ResultPoint> topRight,
int dimensionTop, int dimensionRight);
Ref<ResultPoint> correctTopRight(Ref<ResultPoint> bottomLeft, Ref<ResultPoint> bottomRight,
Ref<ResultPoint> topLeft, Ref<ResultPoint> topRight, int dimension);
bool isValid(Ref<ResultPoint> p);
int distance(Ref<ResultPoint> a, Ref<ResultPoint> b);
Ref<ResultPointsAndTransitions> transitionsBetween(Ref<ResultPoint> from, Ref<ResultPoint> to);
int min(int a, int b) {
return a > b ? b : a;
}
/**
* Ends up being a bit faster than round(). This merely rounds its
* argument to the nearest int, where x.5 rounds up.
*/
int round(float d) {
return (int) (d + 0.5f);
}
public: public:
Ref<BitMatrix> getImage(); Ref<BitMatrix> getImage();
Detector(Ref<BitMatrix> image); Detector(Ref<BitMatrix> image);
virtual Ref<PerspectiveTransform> createTransform(Ref<ResultPoint> topLeft, Ref<ResultPoint> topRight, Ref < virtual Ref<PerspectiveTransform> createTransform(Ref<ResultPoint> topLeft,
ResultPoint > bottomLeft, Ref<ResultPoint> bottomRight, int dimension); Ref<ResultPoint> topRight, Ref<ResultPoint> bottomLeft, Ref<ResultPoint> bottomRight,
int dimensionX, int dimensionY);
Ref<DetectorResult> detect(); Ref<DetectorResult> detect();
void orderBestPatterns(std::vector<Ref<CornerPoint> > &patterns);
float distance(float x1, float x2, float y1, float y2); private:
private:
int compare(Ref<ResultPointsAndTransitions> a, Ref<ResultPointsAndTransitions> b); int compare(Ref<ResultPointsAndTransitions> a, Ref<ResultPointsAndTransitions> b);
float crossProductZ(Ref<ResultPoint> pointA, Ref<ResultPoint> pointB, Ref<ResultPoint> pointC);
}; };
} }

View file

@ -0,0 +1,23 @@
/*
* DetectorException.cpp
*
* Created on: Aug 26, 2011
* Author: luiz
*/
#include "DetectorException.h"
namespace zxing {
namespace datamatrix {
DetectorException::DetectorException(const char *msg) :
Exception(msg) {
}
DetectorException::~DetectorException() throw () {
// TODO Auto-generated destructor stub
}
}
} /* namespace zxing */

View file

@ -0,0 +1,23 @@
/*
* DetectorException.h
*
* Created on: Aug 26, 2011
* Author: luiz
*/
#ifndef DETECTOREXCEPTION_H_
#define DETECTOREXCEPTION_H_
#include <zxing/Exception.h>
namespace zxing {
namespace datamatrix {
class DetectorException : public Exception {
public:
DetectorException(const char *msg);
virtual ~DetectorException() throw();
};
} /* namespace nexxera */
} /* namespace zxing */
#endif /* DETECTOREXCEPTION_H_ */

View file

@ -55,7 +55,7 @@ static bool tryHarder = false;
static bool show_filename = false; static bool show_filename = false;
static bool search_multi = false; static bool search_multi = false;
static const int MAX_EXPECTED = 1024; static const int MAX_EXPECTED = 4096;
Ref<Result> decode(Ref<BinaryBitmap> image, DecodeHints hints) { Ref<Result> decode(Ref<BinaryBitmap> image, DecodeHints hints) {
Ref<Reader> reader(new MultiFormatReader); Ref<Reader> reader(new MultiFormatReader);