利用 libdmtx 解码 DataMatrix
Posted liyuanbhu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了利用 libdmtx 解码 DataMatrix相关的知识,希望对你有一定的参考价值。
上面两篇博客简单的介绍了如何编译 libdmtx 和如何利用 libdmtx 生成 Data matrix 码。这篇博客讲讲如何解码。程序同样还是用到了Qt。图像都是先加载到 QImage 中,然后传给 libdmtx 来解码。
libdmtx 功能挺好,性能也还不错,但是文档有点差。网上也很少有对它的 API 的详细介绍。这些 API 的用法基本是靠 阅读 dmtx-utils 中的 dmtxread.c 来学习的。
解码功能封装到了一个类中:DataMatrixDecoder
这个类的声明如下:
class DataMatrixDecoder
public:
struct UserOptions
int edgeMin; /* -e, --minimum-edge, pixel length of smallest expected edge in image */
int edgeMax; /* -E, --maximum-edge, pixel length of largest expected edge in image */
int scanGap; /* -g, --gap */
int timeoutMS; /* -m, --milliseconds, 每幅画的解码时间,超过时间就直接退出 */
int squareDevn; /* -q, --square-deviation, allow non-squareness of corners in degrees (0-90) */
int sizeIdxExpected; /* -s, --symbol-size,DmtxSymbolShapeAuto, DmtxSymbolSquareAuto, DmtxSymbolRectAuto */
int edgeThresh; /* -t, --threshold,ignore weak edges below threshold N (1-100) */
int xMin; /* -x, --x-range-min 舍弃前面 xMin 列不处理 */
int xMax; /* -X, --x-range-max 舍弃 xMax 后的列不处理 */
int yMin; /* -y, --y-range-min 舍弃前面 yMin 行不处理 */
int yMax; /* -Y, --y-range-max 舍弃 yMax 后的列不处理 */
int correctionsMax; /* -C, --corrections-max ,correct at most N errors (0 = correction disabled)*/
int mosaic; /* -M, --mosaic , DmtxTrue, DmtxFalse*/
int stopAfter; /* -N, --stop-after, 获得 N 个码后退出 */
int shrinkMin; /* -S, --shrink (if range specified), internally shrink image by a factor of N */
int gs1; /* -G, --gs1 ,0-255 中间的一个字符,用来作为 FNC1 */
;
DataMatrixDecoder();
QStringList decodeMulti(QImage &image);
QString decode(QImage &image);
static void restoreDefaultOption(UserOptions &opt);
void setOptions(UserOptions &opt);
UserOptions options() const;
private:
DmtxPassFail setDecodeOptions(DmtxDecode *dec, UserOptions &opt);
DmtxDecode *m_dec = nullptr;
DmtxImage *m_img = nullptr;
UserOptions m_opt;
;
其中 UserOptions 用来控制解码时的各种参数,多数情况我们都用默认值就行了。
真正用来解码的有两个函数:
QStringList decodeMulti(QImage &image);
QString decode(QImage &image);
这里的 image 可以是8bit灰度图像,也可以是 RGB888 或者 RGB32 图像。
实现代码如下:
#include <string>
#include <cassert>
#include <QDebug>
#include "DataMatrixDecoder.h"
static DmtxImage* createDmtxImageFormQImage(QImage &image)
DmtxImage* img = nullptr;
switch (image.format())
case QImage::Format_RGB32:
case QImage::Format_ARGB32:
case QImage::Format_ARGB32_Premultiplied:
img = dmtxImageCreate(image.bits(), image.width(), image.height(), DmtxPack32bppXRGB);
img->rowSizeBytes = image.bytesPerLine();
break;
case QImage::Format_RGB888:
img = dmtxImageCreate(image.bits(), image.width(), image.height(), DmtxPack24bppRGB);
img->rowSizeBytes = image.bytesPerLine();
break;
case QImage::Format_Grayscale8:
img = dmtxImageCreate(image.bits(), image.width(), image.height(), DmtxPack8bppK);
img->rowSizeBytes = image.bytesPerLine();
break;
default:
break;
return img;
QString DataMatrixDecoder::decode(QImage &image)
QString str;
DmtxImage* img = createDmtxImageFormQImage(image);
DmtxDecode* dec = dmtxDecodeCreate(img, 1);
DmtxRegion* reg = dmtxRegionFindNext(dec, NULL);
if (reg != NULL)
DmtxMessage* msg = dmtxDecodeMatrixRegion(dec, reg, m_opt.correctionsMax);
if (msg != NULL)
str = QString::fromLatin1((const char *)msg->output);
dmtxMessageDestroy(&msg);
else
qDebug() << "Not valid data type.";
dmtxRegionDestroy(®);
return str;
QStringList DataMatrixDecoder::decodeMulti(QImage &image)
QStringList list;
DmtxTime timeout;
/* Reset timeout for each new page */
if(m_opt.timeoutMS != DmtxUndefined)
timeout = dmtxTimeAdd(dmtxTimeNow(), m_opt.timeoutMS);
/* Initialize libdmtx image */
DmtxImage* img = createDmtxImageFormQImage(image);
if(img == nullptr)
qFatal("dmtxImageCreate() error");
dmtxImageSetProp(img, DmtxPropImageFlip, DmtxFlipNone);
/* Initialize scan */
DmtxDecode* dec = dmtxDecodeCreate(img, m_opt.shrinkMin);
if(dec == nullptr)
qFatal("dmtxDecodeCreate() error");
DmtxPassFail err = setDecodeOptions(dec, m_opt);
if(err != DmtxPass)
qFatal("decode option error");
int imgScanCount = 0;
for(;;)
DmtxRegion* reg = nullptr;
/* Find next barcode region within image, but do not decode yet */
if(m_opt.timeoutMS == DmtxUndefined)
reg = dmtxRegionFindNext(dec, nullptr);
else
reg = dmtxRegionFindNext(dec, &timeout);
/* Finished file or ran out of time before finding another region */
if(reg == nullptr)
break;
/* Decode region based on requested barcode mode */
DmtxMessage* msg = nullptr;
if(m_opt.mosaic == DmtxTrue)
msg = dmtxDecodeMosaicRegion(dec, reg, m_opt.correctionsMax);
else
msg = dmtxDecodeMatrixRegion(dec, reg, m_opt.correctionsMax);
if(msg != nullptr)
list << QString::fromLatin1((const char *)msg->output);
imgScanCount++;
dmtxMessageDestroy(&msg);
dmtxRegionDestroy(®);
if(m_opt.stopAfter != DmtxUndefined && imgScanCount >= m_opt.stopAfter)
break;
dmtxDecodeDestroy(&dec);
dmtxImageDestroy(&img);
return list;
void DataMatrixDecoder::setOptions(UserOptions &opt)
m_opt = opt;
DataMatrixDecoder::UserOptions DataMatrixDecoder::options() const
return m_opt;
DmtxPassFail DataMatrixDecoder::setDecodeOptions(DmtxDecode *dec, UserOptions &opt)
int err;
#define RETURN_IF_FAILED(e) if(e != DmtxPass) return DmtxFail;
err = dmtxDecodeSetProp(dec, DmtxPropScanGap, opt.scanGap);
RETURN_IF_FAILED(err)
if(opt.gs1 != DmtxUndefined)
err = dmtxDecodeSetProp(dec, DmtxPropFnc1, opt.gs1);
RETURN_IF_FAILED(err)
if(opt.edgeMin != DmtxUndefined)
err = dmtxDecodeSetProp(dec, DmtxPropEdgeMin, opt.edgeMin);
RETURN_IF_FAILED(err)
if(opt.edgeMax != DmtxUndefined)
err = dmtxDecodeSetProp(dec, DmtxPropEdgeMax, opt.edgeMax);
RETURN_IF_FAILED(err)
if(opt.squareDevn != DmtxUndefined)
err = dmtxDecodeSetProp(dec, DmtxPropSquareDevn, opt.squareDevn);
RETURN_IF_FAILED(err)
err = dmtxDecodeSetProp(dec, DmtxPropSymbolSize, opt.sizeIdxExpected);
RETURN_IF_FAILED(err)
err = dmtxDecodeSetProp(dec, DmtxPropEdgeThresh, opt.edgeThresh);
RETURN_IF_FAILED(err)
if(opt.xMin)
err = dmtxDecodeSetProp(dec, DmtxPropXmin, opt.xMin);
RETURN_IF_FAILED(err)
if(opt.xMax)
err = dmtxDecodeSetProp(dec, DmtxPropXmax, opt.xMax);
RETURN_IF_FAILED(err)
if(opt.yMin)
err = dmtxDecodeSetProp(dec, DmtxPropYmin, opt.yMin);
RETURN_IF_FAILED(err)
if(opt.yMax)
err = dmtxDecodeSetProp(dec, DmtxPropYmax, opt.yMax);
RETURN_IF_FAILED(err)
#undef RETURN_IF_FAILED
return DmtxPass;
void DataMatrixDecoder::restoreDefaultOption(UserOptions &opt)
memset(&opt, 0x00, sizeof(UserOptions));
/* Default options */
opt.edgeMin = DmtxUndefined;
opt.edgeMax = DmtxUndefined;
opt.scanGap = 2;
opt.timeoutMS = DmtxUndefined;
opt.squareDevn = DmtxUndefined;
opt.sizeIdxExpected = DmtxSymbolShapeAuto;
opt.edgeThresh = 5;
opt.xMin = 0;
opt.xMax = 0;
opt.yMin = 0;
opt.yMax = 0;
opt.correctionsMax = DmtxUndefined;
opt.mosaic = DmtxFalse;
opt.stopAfter = DmtxUndefined;
opt.shrinkMin = 1;
opt.gs1 = DmtxUndefined;
DataMatrixDecoder::DataMatrixDecoder()
restoreDefaultOption(m_opt);
代码基本就这样。还有些需要进一步完善的地方。比如除了解码的字符串之外,还应该获得DM 码所在的位置。这一块用什么样的数据结构来返回还没想好。等后面有空了再完善一下。
以上是关于利用 libdmtx 解码 DataMatrix的主要内容,如果未能解决你的问题,请参考以下文章
Data Matrix 二维码解码库 libdmtx 编译方法
Data Matrix 二维码解码库 libdmtx 编译方法