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_39_HINT |
BARCODEFORMAT_ITF_HINT |
// TODO: uncomment once this passes QA
// BARCODEFORMAT_DATA_MATRIX_HINT |
BARCODEFORMAT_DATA_MATRIX_HINT |
BARCODEFORMAT_QR_CODE_HINT);
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 <math.h>
namespace zxing {
@ -36,4 +37,64 @@ float ResultPoint::getY() const {
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 <vector>
namespace zxing {
@ -37,6 +38,15 @@ public:
virtual float getX() 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;
// First, read remainder from current byte
if (bitOffset_ > 0) {
int bitsLeft = 8 - bitOffset_;

View file

@ -47,6 +47,9 @@ public:
bytes_(bytes), byteOffset_(0), bitOffset_(0) {
}
int getByteOffset() {
return byteOffset_;
}
/**
* @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;
}
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,
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) {

View file

@ -32,6 +32,8 @@ private:
public:
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,
float p3ToX, float p3ToY, float p4ToX, float p4ToY, float p1FromX, float p1FromY, float p2FromX,
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)))));
VERSIONS.push_back(Ref<Version>(new Version(28, 12, 36, 10, 16,
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)))));
VERSIONS.push_back(Ref<Version>(new Version(30, 16, 48, 14, 22,
new ECBlocks(28, new ECB(1, 49)))));

View file

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

View file

@ -18,9 +18,10 @@
* limitations under the License.
*/
#include <zxing/ReaderException.h>
#include <zxing/FormatException.h>
#include <zxing/datamatrix/decoder/DecodedBitStreamParser.h>
#include <iostream>
#include <zxing/common/DecoderResult.h>
namespace zxing {
namespace datamatrix {
@ -49,11 +50,11 @@ const char DecodedBitStreamParser::TEXT_SHIFT3_SET_CHARS[] = {
'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));
ostringstream result;
ostringstream resultTrailer;
// bool trailer = false;
vector<unsigned char> byteSegments;
int mode = ASCII_ENCODE;
do {
if (mode == ASCII_ENCODE) {
@ -73,19 +74,21 @@ std::string DecodedBitStreamParser::decode(ArrayRef<unsigned char> bytes) {
decodeEdifactSegment(bits, result);
break;
case BASE256_ENCODE:
decodeBase256Segment(bits, result);
decodeBase256Segment(bits, result, byteSegments);
break;
default:
throw ReaderException("Unsupported mode indicator");
throw FormatException("Unsupported mode indicator");
}
mode = ASCII_ENCODE;
}
} while (mode != PAD_ENCODE && bits->available() > 0);
/* if (trailer) {
result << resultTrailer;
if (resultTrailer.str().size() > 0) {
result << resultTrailer.str();
}
*/
return result.str();
ArrayRef<unsigned char> rawBytes(bytes);
Ref<String> text(new String(result.str()));
return Ref<DecoderResult>(new DecoderResult(rawBytes, text));
}
int DecodedBitStreamParser::decodeAsciiSegment(Ref<BitSource> bits, ostringstream & result,
@ -94,7 +97,7 @@ int DecodedBitStreamParser::decodeAsciiSegment(Ref<BitSource> bits, ostringstrea
do {
int oneByte = bits->readBits(8);
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)
oneByte = upperShift ? (oneByte + 128) : oneByte;
// upperShift = false;
@ -113,27 +116,20 @@ int DecodedBitStreamParser::decodeAsciiSegment(Ref<BitSource> bits, ostringstrea
} else if (oneByte == 231) { // Latch to Base 256 encodation
return BASE256_ENCODE;
} else if (oneByte == 232) { // FNC1
//throw ReaderException.getInstance();
// Ignore this symbol for now
} else if (oneByte == 233) { // Structured Append
//throw ReaderException.getInstance();
// Ignore this symbol for now
} else if (oneByte == 234) { // Reader Programming
//throw ReaderException.getInstance();
// Ignore this symbol for now
result << ((char) 29); // translate as ASCII 29
} else if (oneByte == 233 || oneByte == 234) {
// Structured Append, Reader Programming
// Ignore these symbols for now
// throw FormatException.getInstance();
} else if (oneByte == 235) { // Upper Shift (shift to Extended ASCII)
upperShift = true;
} else if (oneByte == 236) { // 05 Macro
/* trailer = false;
result << "[)>\u001E05\u001D";
resultTrailer << "\u001E\u0004";
// Ignore this symbol for now
*/ } else if (oneByte == 237) { // 06 Macro
/* trailer = false;
result << "[)>\u001E06\u001D";
resultTrailer << "\u001E\u0004";
// Ignore this symbol for now
*/ } else if (oneByte == 238) { // Latch to ANSI X12 encodation
result << ("[)>RS05GS");
resultTrailer << ("RSEOT");
} else if (oneByte == 237) { // 06 Macro
result << ("[)>RS06GS");
resultTrailer << ("RSEOT");
} else if (oneByte == 238) { // Latch to ANSI X12 encodation
return ANSIX12_ENCODE;
} else if (oneByte == 239) { // Latch to Text encodation
return TEXT_ENCODE;
@ -141,10 +137,15 @@ int DecodedBitStreamParser::decodeAsciiSegment(Ref<BitSource> bits, ostringstrea
return EDIFACT_ENCODE;
} else if (oneByte == 241) { // ECI Character
// TODO(bbrown): I think we need to support ECI
//throw ReaderException.getInstance();
// throw FormatException.getInstance();
// Ignore this symbol for now
} 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);
return ASCII_ENCODE;
@ -157,6 +158,7 @@ void DecodedBitStreamParser::decodeC40Segment(Ref<BitSource> bits, ostringstream
bool upperShift = false;
int* cValues = new int[3];
int shift = 0;
do {
// If there is only one byte left then it will be encoded as ASCII
if (bits->available() == 8) {
@ -169,7 +171,6 @@ void DecodedBitStreamParser::decodeC40Segment(Ref<BitSource> bits, ostringstream
parseTwoBytes(firstByte, bits->readBits(8), cValues);
int shift = 0;
for (int i = 0; i < 3; i++) {
int cValue = cValues[i];
switch (shift) {
@ -187,10 +188,10 @@ void DecodedBitStreamParser::decodeC40Segment(Ref<BitSource> bits, ostringstream
break;
case 1:
if (upperShift) {
result << cValue + 128;
result << (char) (cValue + 128);
upperShift = false;
} else {
result << cValue;
result << (char) cValue;
}
shift = 0;
break;
@ -203,11 +204,11 @@ void DecodedBitStreamParser::decodeC40Segment(Ref<BitSource> bits, ostringstream
result << C40_SHIFT2_SET_CHARS[cValue];
}
} else if (cValue == 27) { // FNC1
throw ReaderException("FNC1");
result << ((char) 29); // translate as ASCII 29
} else if (cValue == 30) { // Upper Shift
upperShift = true;
} else {
throw ReaderException("Upper Shift");
throw FormatException("decodeC40Segment: Upper Shift");
}
shift = 0;
break;
@ -221,7 +222,7 @@ void DecodedBitStreamParser::decodeC40Segment(Ref<BitSource> bits, ostringstream
shift = 0;
break;
default:
throw ReaderException("");
throw FormatException("decodeC40Segment: no case");
}
}
} while (bits->available() > 0);
@ -234,6 +235,7 @@ void DecodedBitStreamParser::decodeTextSegment(Ref<BitSource> bits, ostringstrea
bool upperShift = false;
int* cValues = new int[3];
int shift = 0;
do {
// If there is only one byte left then it will be encoded as ASCII
if (bits->available() == 8) {
@ -246,7 +248,6 @@ void DecodedBitStreamParser::decodeTextSegment(Ref<BitSource> bits, ostringstrea
parseTwoBytes(firstByte, bits->readBits(8), cValues);
int shift = 0;
for (int i = 0; i < 3; i++) {
int cValue = cValues[i];
switch (shift) {
@ -267,7 +268,7 @@ void DecodedBitStreamParser::decodeTextSegment(Ref<BitSource> bits, ostringstrea
result << (char) (cValue + 128);
upperShift = false;
} else {
result << (cValue);
result << (char) (cValue);
}
shift = 0;
break;
@ -281,11 +282,11 @@ void DecodedBitStreamParser::decodeTextSegment(Ref<BitSource> bits, ostringstrea
result << (C40_SHIFT2_SET_CHARS[cValue]);
}
} else if (cValue == 27) { // FNC1
throw ReaderException("FNC1");
result << ((char) 29); // translate as ASCII 29
} else if (cValue == 30) { // Upper Shift
upperShift = true;
} else {
throw ReaderException("Upper Shift");
throw FormatException("decodeTextSegment: Upper Shift");
}
shift = 0;
break;
@ -299,7 +300,7 @@ void DecodedBitStreamParser::decodeTextSegment(Ref<BitSource> bits, ostringstrea
shift = 0;
break;
default:
throw ReaderException("");
throw FormatException("decodeTextSegment: no case");
}
}
} while (bits->available() > 0);
@ -337,7 +338,7 @@ void DecodedBitStreamParser::decodeAnsiX12Segment(Ref<BitSource> bits, ostringst
} else if (cValue < 40) { // A - Z
result << (char) (cValue + 51);
} else {
throw ReaderException("");
throw FormatException("decodeAnsiX12Segment: no case");
}
}
} while (bits->available() > 0);
@ -372,32 +373,44 @@ void DecodedBitStreamParser::decodeEdifactSegment(Ref<BitSource> bits, ostringst
}
if (!unlatch) {
if ((edifactValue & 32) == 0) { // no 1 in the leading (6th) bit
edifactValue |= 64; // Add a leading 01 to the 6 bit binary value
if ((edifactValue & 0x20) == 0) { // no 1 in the leading (6th) bit
edifactValue |= 0x40; // Add a leading 01 to the 6 bit binary value
}
result << (edifactValue);
result << (char)(edifactValue);
}
}
} 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.
int d1 = bits->readBits(8);
int codewordPosition = 1 + bits->getByteOffset(); // position is 1-indexed
int d1 = unrandomize255State(bits->readBits(8), codewordPosition++);
int count;
if (d1 == 0) { // Read the remainder of the symbol
count = bits->available() / 8;
} else if (d1 < 250) {
count = d1;
} 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];
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 <sstream>
#include <zxing/common/Array.h>
#include <zxing/common/BitSource.h>
#include <zxing/common/Counted.h>
#include <zxing/common/Array.h>
#include <zxing/common/DecoderResult.h>
namespace zxing {
@ -78,7 +79,7 @@ private:
/**
* 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);
/**
@ -94,7 +95,7 @@ private:
public:
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;
}
int numECCodewords = numCodewords - numDataCodewords;
try {
rsDecoder_.decode(codewordInts, numECCodewords);
} catch (ReedSolomonException const& ex) {
ReaderException rex(ex.what());
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++) {
codewordBytes[i] = (unsigned char)codewordInts[i];
}
@ -66,31 +66,29 @@ Ref<DecoderResult> Decoder::decode(Ref<BitMatrix> bits) {
// Separate into data blocks
std::vector<Ref<DataBlock> > dataBlocks = DataBlock::getDataBlocks(codewords, version);
int dataBlocksCount = dataBlocks.size();
// Count total number of data bytes
int totalBytes = 0;
for (unsigned int i = 0; i < dataBlocks.size(); i++) {
for (int i = 0; i < dataBlocksCount; i++) {
totalBytes += dataBlocks[i]->getNumDataCodewords();
}
ArrayRef<unsigned char> resultBytes(totalBytes);
int resultOffset = 0;
// 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]);
ArrayRef<unsigned char> codewordBytes = dataBlock->getCodewords();
int numDataCodewords = dataBlock->getNumDataCodewords();
correctErrors(codewordBytes, numDataCodewords);
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
DecodedBitStreamParser decodedBSParser;
Ref<String> text(new String(decodedBSParser.decode(resultBytes)));
Ref<DecoderResult> result(new DecoderResult(resultBytes, text));
return result;
return Ref<DecoderResult> (decodedBSParser.decode(resultBytes));
}
}
}

View file

@ -19,6 +19,7 @@
* limitations under the License.
*/
#include <zxing/ResultPoint.h>
#include <zxing/common/GridSampler.h>
#include <zxing/datamatrix/detector/Detector.h>
#include <cmath>
@ -30,21 +31,23 @@ namespace datamatrix {
using namespace std;
ResultPointsAndTransitions::ResultPointsAndTransitions() : to_(), from_(), transitions_(0) {
Ref<CornerPoint> ref(new CornerPoint(0,0));
ResultPointsAndTransitions::ResultPointsAndTransitions() {
Ref<ResultPoint> ref(new ResultPoint(0, 0));
from_ = ref;
to_ = ref;
transitions_ = 0;
}
ResultPointsAndTransitions::ResultPointsAndTransitions(Ref<CornerPoint> from, Ref<CornerPoint> to, int transitions) :
to_(to), from_(from), transitions_(transitions) {
ResultPointsAndTransitions::ResultPointsAndTransitions(Ref<ResultPoint> from, Ref<ResultPoint> to,
int transitions)
: to_(to), from_(from), transitions_(transitions) {
}
Ref<CornerPoint> ResultPointsAndTransitions::getFrom() {
Ref<ResultPoint> ResultPointsAndTransitions::getFrom() {
return from_;
}
Ref<CornerPoint> ResultPointsAndTransitions::getTo() {
Ref<ResultPoint> ResultPointsAndTransitions::getTo() {
return to_;
}
@ -52,19 +55,21 @@ int ResultPointsAndTransitions::getTransitions() {
return transitions_;
}
Detector::Detector(Ref<BitMatrix> image) : image_(image) { }
Detector::Detector(Ref<BitMatrix> image)
: image_(image) {
}
Ref<BitMatrix> Detector::getImage() {
return image_;
}
Ref<DetectorResult> Detector::detect() {
Ref<MonochromeRectangleDetector> rectangleDetector_(new MonochromeRectangleDetector(image_));
std::vector<Ref<CornerPoint> > cornerPoints = rectangleDetector_->detect();
Ref<CornerPoint> pointA = cornerPoints[0];
Ref<CornerPoint> pointB = cornerPoints[1];
Ref<CornerPoint> pointC = cornerPoints[2];
Ref<CornerPoint> pointD = cornerPoints[3];
Ref<WhiteRectangleDetector> rectangleDetector_(new WhiteRectangleDetector(image_));
std::vector<Ref<ResultPoint> > ResultPoints = rectangleDetector_->detect();
Ref<ResultPoint> pointA = ResultPoints[0];
Ref<ResultPoint> pointB = ResultPoints[1];
Ref<ResultPoint> pointC = ResultPoints[2];
Ref<ResultPoint> pointD = ResultPoints[3];
// Point A and D are across the diagonal from one another,
// 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
// endpoints in the four endpoints. One will show up twice.
Ref<CornerPoint> maybeTopLeft;
Ref<CornerPoint> bottomLeft;
Ref<CornerPoint> maybeBottomRight;
Ref<ResultPoint> maybeTopLeft;
Ref<ResultPoint> bottomLeft;
Ref<ResultPoint> maybeBottomRight;
if (lSideOne->getFrom()->equals(lSideOne->getTo())) {
bottomLeft = lSideOne->getFrom();
maybeTopLeft = lSideTwo->getFrom();
maybeBottomRight = lSideTwo->getTo();
}
else if (lSideOne->getFrom()->equals(lSideTwo->getFrom())) {
} else if (lSideOne->getFrom()->equals(lSideTwo->getFrom())) {
bottomLeft = lSideOne->getFrom();
maybeTopLeft = lSideOne->getTo();
maybeBottomRight = lSideTwo->getTo();
}
else if (lSideOne->getFrom()->equals(lSideTwo->getTo())) {
} else if (lSideOne->getFrom()->equals(lSideTwo->getTo())) {
bottomLeft = lSideOne->getFrom();
maybeTopLeft = lSideOne->getTo();
maybeBottomRight = lSideTwo->getFrom();
}
else if (lSideOne->getTo()->equals(lSideTwo->getFrom())) {
} else if (lSideOne->getTo()->equals(lSideTwo->getFrom())) {
bottomLeft = lSideOne->getTo();
maybeTopLeft = lSideOne->getFrom();
maybeBottomRight = lSideTwo->getTo();
}
else if (lSideOne->getTo()->equals(lSideTwo->getTo())) {
} else if (lSideOne->getTo()->equals(lSideTwo->getTo())) {
bottomLeft = lSideOne->getTo();
maybeTopLeft = lSideOne->getFrom();
maybeBottomRight = lSideTwo->getFrom();
}
else {
} else {
bottomLeft = lSideTwo->getFrom();
maybeTopLeft = lSideOne->getTo();
maybeBottomRight = lSideOne->getFrom();
}
// 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[1].reset(bottomLeft);
corners[2].reset(maybeBottomRight);
// Use the dot product trick to sort them out
orderBestPatterns(corners);
ResultPoint::orderBestPatterns(corners);
// Now we know which is which:
Ref<CornerPoint> bottomRight(corners[0]);
Ref<ResultPoint> bottomRight(corners[0]);
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
Ref<CornerPoint> topRight;
Ref<ResultPoint> topRight;
if (!(pointA->equals(bottomRight) || pointA->equals(bottomLeft) || pointA->equals(topLeft))) {
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;
} else if (!(pointC->equals(bottomRight) || pointC->equals(bottomLeft) || pointC->equals(topLeft))) {
} else if (!(pointC->equals(bottomRight) || pointC->equals(bottomLeft)
|| pointC->equals(topLeft))) {
topRight = pointC;
} else {
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
// 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
// end on a black module:
// 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
// or bottom right should work here. The number of transitions could be higher than it should be
// due to noise. So we try both and take the min.
int dimension = min(transitionsBetween(topLeft, topRight)->getTransitions(),
transitionsBetween(bottomRight, topRight)->getTransitions());
if ((dimension & 0x01) == 1) {
// it can't be odd, so, round... up?
dimension++;
}
dimension += 2;
// or bottom right should work here.
int dimensionTop = transitionsBetween(topLeft, topRight)->getTransitions();
int dimensionRight = transitionsBetween(bottomRight, topRight)->getTransitions();
//dimensionTop++;
if ((dimensionTop & 0x01) == 1) {
// it can't be odd, so, round... up?
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);
points[0].reset(pointA);
points[1].reset(pointB);
points[2].reset(pointC);
points[3].reset(pointD);
points[0].reset(topLeft);
points[1].reset(bottomLeft);
points[2].reset(correctedTopRight);
points[3].reset(bottomRight);
Ref<DetectorResult> detectorResult(new DetectorResult(bits, points, transform));
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()
int fromX = (int) from->getX();
int fromY = (int) from->getY();
@ -215,18 +378,20 @@ Ref<ResultPointsAndTransitions> Detector::transitionsBetween(Ref<CornerPoint> fr
return result;
}
Ref<PerspectiveTransform> Detector::createTransform(Ref<ResultPoint> topLeft, Ref<ResultPoint> topRight, Ref <
ResultPoint > bottomLeft, Ref<ResultPoint> bottomRight, int dimension) {
Ref<PerspectiveTransform> Detector::createTransform(Ref<ResultPoint> topLeft,
Ref<ResultPoint> topRight, Ref<ResultPoint> bottomLeft, Ref<ResultPoint> bottomRight,
int dimensionX, int dimensionY) {
Ref<PerspectiveTransform> transform(PerspectiveTransform::quadrilateralToQuadrilateral(
0.0f,
0.0f,
dimension,
0.0f,
dimension,
dimension,
0.0f,
dimension,
Ref<PerspectiveTransform> transform(
PerspectiveTransform::quadrilateralToQuadrilateral(
0.5f,
0.5f,
dimensionX - 0.5f,
0.5f,
dimensionX - 0.5f,
dimensionY - 0.5f,
0.5f,
dimensionY - 0.5f,
topLeft->getX(),
topLeft->getY(),
topRight->getX(),
@ -238,9 +403,10 @@ Ref<PerspectiveTransform> Detector::createTransform(Ref<ResultPoint> topLeft, Re
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();
return sampler.sampleGrid(image, dimension, transform);
return sampler.sampleGrid(image, dimensionX, dimensionY, transform);
}
void Detector::insertionSort(std::vector<Ref<ResultPointsAndTransitions> > &vector) {
@ -260,57 +426,9 @@ void Detector::insertionSort(std::vector<Ref<ResultPointsAndTransitions> > &vect
}
} 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) {
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,28 +22,26 @@
* limitations under the License.
*/
#include <zxing/common/Counted.h>
#include <zxing/common/DetectorResult.h>
#include <zxing/common/BitMatrix.h>
#include <zxing/common/PerspectiveTransform.h>
#include <zxing/datamatrix/detector/MonochromeRectangleDetector.h>
#include <zxing/common/detector/WhiteRectangleDetector.h>
namespace zxing {
namespace datamatrix {
class ResultPointsAndTransitions: public Counted {
private:
Ref<CornerPoint> to_;
Ref<CornerPoint> from_;
Ref<ResultPoint> to_;
Ref<ResultPoint> from_;
int transitions_;
public:
ResultPointsAndTransitions();
ResultPointsAndTransitions(Ref<CornerPoint> from, Ref<CornerPoint> to, int transitions);
Ref<CornerPoint> getFrom();
Ref<CornerPoint> getTo();
ResultPointsAndTransitions(Ref<ResultPoint> from, Ref<ResultPoint> to, int transitions);
Ref<ResultPoint> getFrom();
Ref<ResultPoint> getTo();
int getTransitions();
};
@ -52,26 +50,42 @@ private:
Ref<BitMatrix> image_;
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);
Ref<ResultPointsAndTransitions> transitionsBetween(Ref<CornerPoint> from, Ref<CornerPoint> to);
int min(int a, int b) { return a > b ? b : a; };
Ref<ResultPoint> correctTopRightRectangular(Ref<ResultPoint> bottomLeft,
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:
Ref<BitMatrix> getImage();
Detector(Ref<BitMatrix> image);
virtual Ref<PerspectiveTransform> createTransform(Ref<ResultPoint> topLeft, Ref<ResultPoint> topRight, Ref <
ResultPoint > bottomLeft, Ref<ResultPoint> bottomRight, int dimension);
virtual Ref<PerspectiveTransform> createTransform(Ref<ResultPoint> topLeft,
Ref<ResultPoint> topRight, Ref<ResultPoint> bottomLeft, Ref<ResultPoint> bottomRight,
int dimensionX, int dimensionY);
Ref<DetectorResult> detect();
void orderBestPatterns(std::vector<Ref<CornerPoint> > &patterns);
float distance(float x1, float x2, float y1, float y2);
private:
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 search_multi = false;
static const int MAX_EXPECTED = 1024;
static const int MAX_EXPECTED = 4096;
Ref<Result> decode(Ref<BinaryBitmap> image, DecodeHints hints) {
Ref<Reader> reader(new MultiFormatReader);