Reimplemented CameraImageWrapper to internally use GreyscaleLuminanceSource.

Enhanced QZXing, in case of decode failure, it now reties with "tryHarder" added decode hint.
These changes have the following increment on success rates when decoding (numbers generated by test application):
CODE_128: was 44/48, is 47/48
EAN_8: was 7/8, is 8/8
EAN_13: was 101/157, is 119/157
ITF: was 18/27, is 22/27
QR_CODE: was 135/178, is 137/178
UPC_A: was 80/167, is 99/167
UPC_E: was 40/55, is 47/55
This commit is contained in:
favoritas37 2016-02-21 03:41:45 +02:00
parent 5de6bf853f
commit 41ebf93087
3 changed files with 156 additions and 82 deletions

View File

@ -10,11 +10,14 @@ CameraImageWrapper::CameraImageWrapper() : LuminanceSource(0,0), image(NULL)
CameraImageWrapper::CameraImageWrapper(const QImage &sourceImage) : LuminanceSource(sourceImage.width(), sourceImage.height())
{
image = grayScaleImage( &sourceImage );
delegate = Ref<GreyscaleLuminanceSource>(
new GreyscaleLuminanceSource(getMatrixP(),image->width(), image->height(),0, 0, image->width(), image->height()));
}
CameraImageWrapper::CameraImageWrapper(CameraImageWrapper& otherInstance) : LuminanceSource(otherInstance.getWidth(), otherInstance.getHeight())
{
image = new QImage(otherInstance.getOriginalImage());
delegate = otherInstance.getDelegate();
}
CameraImageWrapper::~CameraImageWrapper()
@ -25,7 +28,7 @@ CameraImageWrapper::~CameraImageWrapper()
CameraImageWrapper *CameraImageWrapper::Factory(const QImage &sourceImage, int maxWidth, int maxHeight, bool smoothTransformation)
{
if((maxWidth != 1 || maxHeight != 1) && (sourceImage.width() > maxWidth || sourceImage.height() > maxHeight))
if((maxWidth != 1 && sourceImage.width() > maxWidth) || (maxHeight != 1 && sourceImage.height() > maxHeight))
{
QImage image;
image = sourceImage.scaled(
@ -39,33 +42,6 @@ CameraImageWrapper *CameraImageWrapper::Factory(const QImage &sourceImage, int m
return new CameraImageWrapper(sourceImage);
}
int CameraImageWrapper::getWidth() const
{
return image->width();
}
int CameraImageWrapper::getHeight() const
{
return image->height();
}
unsigned char CameraImageWrapper::getPixel(int x, int y) const
{
return image->pixel(x,y);
}
unsigned char* CameraImageWrapper::copyMatrix() const
{
unsigned char* newMatrix = (unsigned char*)malloc(image->width() * image->height() * sizeof(unsigned char));
int cnt = 0;
for(int i=0; i<image->width(); i++)
for(int j=0; j<image->height(); j++)
newMatrix[cnt++] = getPixel(i,j);
return newMatrix;
}
QImage* CameraImageWrapper::grayScaleImage(const QImage *origin)
{
QImage *tmp = new QImage(origin->width(), origin->height(), QImage::Format_Grayscale8);
@ -89,6 +65,62 @@ QImage CameraImageWrapper::getOriginalImage()
}
ArrayRef<char> CameraImageWrapper::getRow(int y, ArrayRef<char> row) const
{
if(delegate)
return delegate->getRow(y, row);
else
return getRowP(y, row);
}
ArrayRef<char> CameraImageWrapper::getMatrix() const
{
if(delegate)
return delegate->getMatrix();
else
return getMatrixP();
}
bool CameraImageWrapper::isCropSupported() const
{
if(delegate)
return delegate->isCropSupported();
else
return LuminanceSource::isCropSupported();
}
Ref<LuminanceSource> CameraImageWrapper::crop(int left, int top, int width, int height) const
{
if(delegate)
return delegate->crop(left, top, width, height);
else
return LuminanceSource::crop(left, top, width, height);
}
bool CameraImageWrapper::isRotateSupported() const
{
if(delegate)
return delegate->isRotateSupported();
else
return LuminanceSource::isRotateSupported();
}
Ref<LuminanceSource> CameraImageWrapper::invert() const
{
if(delegate)
return delegate->invert();
else
return LuminanceSource::invert();
}
Ref<LuminanceSource> CameraImageWrapper::rotateCounterClockwise() const
{
if(delegate)
return delegate->rotateCounterClockwise();
else
return LuminanceSource::rotateCounterClockwise();
}
ArrayRef<char> CameraImageWrapper::getRowP(int y, ArrayRef<char> row) const
{
int width = getWidth();
@ -96,12 +128,12 @@ ArrayRef<char> CameraImageWrapper::getRow(int y, ArrayRef<char> row) const
row.reset(ArrayRef<char>(width));
for (int x = 0; x < width; x++)
row[x] = getPixel(x,y);
row[x] = image->pixel(x,y);
return row;
}
ArrayRef<char> CameraImageWrapper::getMatrix() const
ArrayRef<char> CameraImageWrapper::getMatrixP() const
{
int width = getWidth();
int height = getHeight();
@ -113,7 +145,7 @@ ArrayRef<char> CameraImageWrapper::getMatrix() const
for(int y=0; y<height; y++)
{
tmpRow = getRow(y, tmpRow);
tmpRow = getRowP(y, tmpRow);
#if __cplusplus > 199711L
memcpy(m, tmpRow->values().data(), width);
#else
@ -125,6 +157,31 @@ ArrayRef<char> CameraImageWrapper::getMatrix() const
return arr;
}
//bool CameraImageWrapper::isCropSupported() const
//{
// return true;
//}
//Ref<LuminanceSource> CameraImageWrapper::crop(int left, int top, int width, int height) const
//{
//}
//bool CameraImageWrapper::isRotateSupported() const
//{
// return true;
//}
//Ref<LuminanceSource> CameraImageWrapper::invert() const
//{
//}
//Ref<LuminanceSource> CameraImageWrapper::rotateCounterClockwise() const
//{
//}
QImage *CameraImageWrapper::sharpen(const QImage *origin)
{
QImage * newImage = new QImage(* origin);

View File

@ -3,7 +3,7 @@
#include <QImage>
#include <QString>
#include <zxing/zxing/LuminanceSource.h>
#include <zxing/zxing/common/GreyscaleLuminanceSource.h>
using namespace zxing;
@ -17,23 +17,27 @@ public:
static CameraImageWrapper* Factory(const QImage& image, int maxWidth=-1, int maxHeight=-1, bool smoothTransformation=false);
int getWidth() const;
int getHeight() const;
unsigned char getPixel(int x, int y) const;
unsigned char* copyMatrix() const;
QImage* grayScaleImage(const QImage *origin);
QImage getOriginalImage();
Ref<GreyscaleLuminanceSource> getDelegate() { return delegate; }
// Callers take ownership of the returned memory and must call delete [] on it themselves.
ArrayRef<char> getRow(int y, ArrayRef<char> row) const;
ArrayRef<char> getMatrix() const;
bool isCropSupported() const;
Ref<LuminanceSource> crop(int left, int top, int width, int height) const;
bool isRotateSupported() const;
Ref<LuminanceSource> invert() const;
Ref<LuminanceSource> rotateCounterClockwise() const;
private:
ArrayRef<char> getRowP(int y, ArrayRef<char> row) const;
ArrayRef<char> getMatrixP() const;
QImage* grayScaleImage(const QImage *origin);
QImage* sharpen(const QImage *origin);
QImage* image;
Ref<GreyscaleLuminanceSource> delegate;
};
#endif //CAMERAIMAGE_H

View File

@ -51,56 +51,56 @@ QZXing::QZXing(QZXing::DecoderFormat decodeHints, QObject *parent) : QObject(par
QString QZXing::decoderFormatToString(int fmt)
{
switch (fmt) {
case DecoderFormat_Aztec:
return "AZTEC";
case DecoderFormat_Aztec:
return "AZTEC";
case DecoderFormat_CODABAR:
return "CODABAR";
case DecoderFormat_CODABAR:
return "CODABAR";
case DecoderFormat_CODE_39:
return "CODE_39";
case DecoderFormat_CODE_39:
return "CODE_39";
case DecoderFormat_CODE_93:
return "CODE_93";
case DecoderFormat_CODE_93:
return "CODE_93";
case DecoderFormat_CODE_128:
return "CODE_128";
case DecoderFormat_CODE_128:
return "CODE_128";
case DecoderFormat_DATA_MATRIX:
return "DATA_MATRIX";
case DecoderFormat_DATA_MATRIX:
return "DATA_MATRIX";
case DecoderFormat_EAN_8:
return "EAN_8";
case DecoderFormat_EAN_8:
return "EAN_8";
case DecoderFormat_EAN_13:
return "EAN_13";
case DecoderFormat_EAN_13:
return "EAN_13";
case DecoderFormat_ITF:
return "ITF";
case DecoderFormat_ITF:
return "ITF";
case DecoderFormat_MAXICODE:
return "MAXICODE";
case DecoderFormat_MAXICODE:
return "MAXICODE";
case DecoderFormat_PDF_417:
return "PDF_417";
case DecoderFormat_PDF_417:
return "PDF_417";
case DecoderFormat_QR_CODE:
return "QR_CODE";
case DecoderFormat_QR_CODE:
return "QR_CODE";
case DecoderFormat_RSS_14:
return "RSS_14";
case DecoderFormat_RSS_14:
return "RSS_14";
case DecoderFormat_RSS_EXPANDED:
return "RSS_EXPANDED";
case DecoderFormat_RSS_EXPANDED:
return "RSS_EXPANDED";
case DecoderFormat_UPC_A:
return "UPC_A";
case DecoderFormat_UPC_A:
return "UPC_A";
case DecoderFormat_UPC_E:
return "UPC_E";
case DecoderFormat_UPC_E:
return "UPC_E";
case DecoderFormat_UPC_EAN_EXTENSION:
return "UPC_EAN_EXTENSION";
case DecoderFormat_UPC_EAN_EXTENSION:
return "UPC_EAN_EXTENSION";
} // switch
return QString();
}
@ -190,12 +190,13 @@ QString QZXing::decodeImage(const QImage &image, int maxWidth, int maxHeight, bo
}
CameraImageWrapper *ciw = NULL;
try {
if ((maxWidth > 0) || (maxHeight > 0))
ciw = CameraImageWrapper::Factory(image, maxWidth, maxHeight, smoothTransformation);
else
ciw = CameraImageWrapper::Factory(image, 999, 999, true);
if ((maxWidth > 0) || (maxHeight > 0))
ciw = CameraImageWrapper::Factory(image, maxWidth, maxHeight, smoothTransformation);
else
ciw = CameraImageWrapper::Factory(image, 999, 999, true);
try {
Ref<LuminanceSource> imageRef(ciw);
GlobalHistogramBinarizer *binz = new GlobalHistogramBinarizer(imageRef);
@ -204,7 +205,19 @@ QString QZXing::decodeImage(const QImage &image, int maxWidth, int maxHeight, bo
Ref<BinaryBitmap> ref(bb);
res = decoder->decode(ref, DecodeHints((int)enabledDecoders));
DecodeHints hints((int)enabledDecoders);
bool hasSucceded = false;
try {
res = decoder->decode(ref, hints);
hasSucceded = true;
}catch(zxing::Exception &e){}
if(!hasSucceded)
{
hints.setTryHarder(true);
res = decoder->decode(ref, hints);
}
QString string = QString(res->getText()->getText().c_str());
if (!string.isEmpty() && (string.length() > 0)) {
@ -298,8 +311,8 @@ QImage QZXing::encodeData(const QString& data)
for(int i=0; i<bytesRef->getWidth(); i++)
for(int j=0; j<bytesRef->getHeight(); j++)
image.setPixel(i, j, bytes[i][j] ?
qRgb(0,0,0) :
qRgb(255,255,255));
qRgb(0,0,0) :
qRgb(255,255,255));
image = image.scaled(240, 240);
bool success = image.save("tmp.bmp","BMP");