mirror of
https://github.com/zxing/zxing.git
synced 2025-03-05 20:48:51 -08:00
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:
parent
d65dd54e03
commit
41daacd233
|
@ -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() {
|
||||
|
|
29
cpp/core/src/zxing/NotFoundException.cpp
Normal file
29
cpp/core/src/zxing/NotFoundException.cpp
Normal 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() {
|
||||
}
|
||||
|
||||
}
|
32
cpp/core/src/zxing/NotFoundException.h
Normal file
32
cpp/core/src/zxing/NotFoundException.h
Normal 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__
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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_;
|
||||
|
|
|
@ -47,6 +47,9 @@ public:
|
|||
bytes_(bytes), byteOffset_(0), bitOffset_(0) {
|
||||
}
|
||||
|
||||
int getByteOffset() {
|
||||
return byteOffset_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param numBits number of bits to read
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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__
|
315
cpp/core/src/zxing/common/detector/WhiteRectangleDetector.cpp
Normal file
315
cpp/core/src/zxing/common/detector/WhiteRectangleDetector.cpp
Normal 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;
|
||||
}
|
||||
}
|
56
cpp/core/src/zxing/common/detector/WhiteRectangleDetector.h
Normal file
56
cpp/core/src/zxing/common/detector/WhiteRectangleDetector.h
Normal 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
|
|
@ -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)))));
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
23
cpp/core/src/zxing/datamatrix/detector/DetectorException.cpp
Normal file
23
cpp/core/src/zxing/datamatrix/detector/DetectorException.cpp
Normal 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 */
|
23
cpp/core/src/zxing/datamatrix/detector/DetectorException.h
Normal file
23
cpp/core/src/zxing/datamatrix/detector/DetectorException.h
Normal 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_ */
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue