zbar 源码中已经列出了 二维码、条形码图片识别程序,zbarimg
这里加入了一些说明,并单独进行编译测试
zbarimg.c
#include <config.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifdef HAVE_SYS_TIMES_H
# include <sys/times.h>
#endif
#ifdef _WIN32
# include <io.h>
# include <fcntl.h>
#endif
#include <assert.h>
#include <zbar.h>
#include <wand/MagickWand.h>
/* in 6.4.5.4 MagickGetImagePixels changed to MagickExportImagePixels.
* (still not sure this check is quite right...
* how does MagickGetAuthenticImagePixels fit in?)
* ref http://bugs.gentoo.org/247292
*/
#if MagickLibVersion < 0x645
# define MagickExportImagePixels MagickGetImagePixels
#endif
static const char *note_usage =
"usage: zbarimg [options] <image>...\n"
"\n"
"scan and decode bar codes from one or more image files\n"
"\n"
"options:\n"
" -h, --help display this help text\n"
" --version display version information and exit\n"
" -q, --quiet minimal output, only print decoded symbol data\n"
" -v, --verbose increase debug output level\n"
" --verbose=N set specific debug output level\n"
" -d, --display enable display of following images to the screen\n"
" -D, --nodisplay disable display of following images (default)\n"
" --xml, --noxml enable/disable XML output format\n"
" --raw output decoded symbol data without symbology prefix\n"
" -S<CONFIG>[=<VALUE>], --set <CONFIG>[=<VALUE>]\n"
" set decoder/scanner <CONFIG> to <VALUE> (or 1)\n"
// FIXME overlay level
"\n"
;
static const char *warning_not_found =
"\n"
"WARNING: barcode data was not detected in some image(s)\n"
" things to check:\n"
" - is the barcode type supported?"
" currently supported symbologies are:\n"
" EAN/UPC (EAN-13, EAN-8, UPC-A, UPC-E, ISBN-10, ISBN-13),\n"
" Code 128, Code 39 and Interleaved 2 of 5\n"
" - is the barcode large enough in the image?\n"
" - is the barcode mostly in focus?\n"
" - is there sufficient contrast/illumination?\n"
"\n";
static const char *xml_head =
"<barcodes xmlns='http://zbar.sourceforge.net/2008/barcode'>\n";
static const char *xml_foot =
"</barcodes>\n";
static int notfound = 0, exit_code = 0;
static int num_images = 0, num_symbols = 0;
static int xmllvl = 0;
char *xmlbuf = NULL;
unsigned xmlbuflen = 0;
static zbar_processor_t *processor = NULL;
static inline int dump_error(MagickWand *wand)
{
char *desc;
ExceptionType severity;
desc = MagickGetException(wand, &severity);
if(severity >= FatalErrorException)
exit_code = 2;
else if(severity >= ErrorException)
exit_code = 1;
else
exit_code = 0;
static const char *sevdesc[] = { "WARNING", "ERROR", "FATAL" };
fprintf(stderr, "%s: %s\n", sevdesc[exit_code], desc);
MagickRelinquishMemory(desc);
return(exit_code);
}
static int scan_image (const char *filename)
{
if(exit_code == 3)
return(-1);
printf("file:%s\n",filename);
int found = 0;
// 新建并读取图像数据,和DestroyMagickWand()对应
MagickWand *images = NewMagickWand();
if(!MagickReadImage(images, filename) && dump_error(images))
return(-1);
// 获取此images 中包含的图像个数,,(images可以是一组图像序列)
unsigned seq, n = MagickGetNumberImages(images);
printf("n=%d\n",n);
for(seq = 0; seq < n; seq++) {
if(exit_code == 3)
return(-1);
// 设置当前图片序列
if(!MagickSetIteratorIndex(images, seq) && dump_error(images))
return(-1);
// 新建zbar图像数据,和zbar_image_destroy()对应,并设定格式“Y800”,图像原始数据格式
zbar_image_t *zimage = zbar_image_create();
assert(zimage);
zbar_image_set_format(zimage, *(unsigned long*)"Y800");
// 获取图片尺寸
int width = MagickGetImageWidth(images);
int height = MagickGetImageHeight(images);
zbar_image_set_size(zimage, width, height);
printf("image size=%d*%d\n",width,height);
// 制定图像数据
// extract grayscale image pixels
// FIXME color!! ...preserve most color w/422P
// (but only if it's a color image)
size_t bloblen = width * height;
unsigned char *blob = malloc(bloblen);
zbar_image_set_data(zimage, blob, bloblen, zbar_image_free_data);
// 从图像中提取像素数据,“I”灰度数据,CharPixel像素数据类型:单字节
if(!MagickExportImagePixels(images, 0, 0, width, height,
"I", CharPixel, blob))
return(-1);
// 直观打印二维码图形(二进制图形灰度数据,就是二维码图片的直观体现)
// for (size_t i = 0; i < height*width; i++)
// {
// if (i%width == 0)
// printf("\n");
// printf("%c",blob[i]?' ':'#');
// }
// printf("\n");
if(xmllvl == 1) {
xmllvl++;
printf("<source href='%s'>\n", filename);
}
// 解码图像数据,返回<0,则解码失败,返回>0,解码成功
int ret = zbar_process_image(processor, zimage);
printf("ret=%d\n");
// output result data 返回图像的第一个解码符号结果
const zbar_symbol_t *sym = zbar_image_first_symbol(zimage);
for(; sym; sym = zbar_symbol_next(sym)) {
zbar_symbol_type_t typ = zbar_symbol_get_type(sym);
if(typ == ZBAR_PARTIAL)
continue;
else if(!xmllvl)
{
printf("decoder-->\n");
printf("[type]%s%s\n[data]:%s\n",
zbar_get_symbol_name(typ),
zbar_get_addon_name(typ),
zbar_symbol_get_data(sym));
}
else if(xmllvl < 0)
printf("%s\n", zbar_symbol_get_data(sym));
else {
if(xmllvl < 3) {
xmllvl++;
printf("<index num='%u'>\n", seq);
}
zbar_symbol_xml(sym, &xmlbuf, &xmlbuflen);
printf("%s\n", xmlbuf);
}
found++;
num_symbols++;
}
if(xmllvl > 2) {
xmllvl--;
printf("</index>\n");
}
fflush(stdout);
zbar_image_destroy(zimage);
num_images++;
if(zbar_processor_is_visible(processor)) {
int rc = zbar_processor_user_wait(processor, -1);
if(rc < 0 || rc == 'q' || rc == 'Q')
exit_code = 3;
}
}
if(xmllvl > 1) {
xmllvl--;
printf("</source>\n");
}
if(!found)
notfound++;
DestroyMagickWand(images);
return(0);
}
int usage (int rc,
const char *msg,
const char *arg)
{
FILE *out = (rc) ? stderr : stdout;
if(msg) {
fprintf(out, "%s", msg);
if(arg)
fprintf(out, "%s", arg);
fprintf(out, "\n\n");
}
fprintf(out, "%s", note_usage);
return(rc);
}
static inline int parse_config (const char *cfgstr, const char *arg)
{
if(!cfgstr || !cfgstr[0])
return(usage(1, "ERROR: need argument for option: ", arg));
if(zbar_processor_parse_config(processor, cfgstr))
return(usage(1, "ERROR: invalid configuration setting: ", cfgstr));
return(0);
}
int main (int argc, const char *argv[])
{
// option pre-scan
int quiet = 0;
int display = 0;
int i, j;
for(i = 1; i < argc; i++) {
const char *arg = argv[i];
if(arg[0] != '-')
// first pass, skip images
num_images++;
else if(arg[1] != '-')
for(j = 1; arg[j]; j++) {
if(arg[j] == 'S') {
if(!arg[++j] && ++i >= argc)
/* FIXME parse check */
return(parse_config("", "-S"));
break;
}
switch(arg[j]) {
case 'h': return(usage(0, NULL, NULL));
case 'q': quiet = 1; break;
case 'v': zbar_increase_verbosity(); break;
case 'd': display = 1; break;
case 'D': break;
default:
return(usage(1, "ERROR: unknown bundled option: -",
arg + j));
}
}
else if(!strcmp(arg, "--help"))
return(usage(0, NULL, NULL));
else if(!strcmp(arg, "--version")) {
printf("%s\n", PACKAGE_VERSION);
return(0);
}
else if(!strcmp(arg, "--quiet")) {
quiet = 1;
argv[i] = NULL;
}
else if(!strcmp(arg, "--verbose"))
zbar_increase_verbosity();
else if(!strncmp(arg, "--verbose=", 10))
zbar_set_verbosity(strtol(argv[i] + 10, NULL, 0));
else if(!strcmp(arg, "--display"))
display++;
else if(!strcmp(arg, "--nodisplay") ||
!strcmp(arg, "--set") ||
!strcmp(arg, "--xml") ||
!strcmp(arg, "--noxml") ||
!strcmp(arg, "--raw") ||
!strncmp(arg, "--set=", 6))
continue;
else if(!strcmp(arg, "--")) {
num_images += argc - i - 1;
break;
}
else
return(usage(1, "ERROR: unknown option: ", arg));
}
if(!num_images)
return(usage(1, "ERROR: specify image file(s) to scan", NULL));
num_images = 0;
// initializes the MagickWand environment.
MagickWandGenesis();
printf("1.creat!\n");
// zbar线程创建
processor = zbar_processor_create(0);
assert(processor);
printf("2.init!\n");
if(zbar_processor_init(processor, NULL, display)) {
zbar_processor_error_spew(processor, 0);
return(1);
}
printf("3.scan!\n");
for(i = 1; i < argc; i++) {
const char *arg = argv[i];
if(!arg)
continue;
if(arg[0] != '-') {
if(scan_image(arg))
return(exit_code);
}
else if(arg[1] != '-')
for(j = 1; arg[j]; j++) {
if(arg[j] == 'S') {
if((arg[++j])
? parse_config(arg + j, "-S")
: parse_config(argv[++i], "-S"))
return(1);
break;
}
switch(arg[j]) {
case 'd': zbar_processor_set_visible(processor, 1); break;
case 'D': zbar_processor_set_visible(processor, 0); break;
}
}
else if(!strcmp(arg, "--display"))
zbar_processor_set_visible(processor, 1);
else if(!strcmp(arg, "--nodisplay"))
zbar_processor_set_visible(processor, 0);
else if(!strcmp(arg, "--xml")) {
if(xmllvl < 1) {
xmllvl = 1;
#ifdef _WIN32
fflush(stdout);
_setmode(_fileno(stdout), _O_BINARY);
#endif
printf("%s", xml_head);
}
}
else if(!strcmp(arg, "--noxml") || !strcmp(arg, "--raw")) {
if(xmllvl > 0) {
xmllvl = 0;
printf("%s", xml_foot);
fflush(stdout);
#ifdef _WIN32
_setmode(_fileno(stdout), _O_TEXT);
#endif
}
if(!strcmp(arg, "--raw")) {
xmllvl = -1;
#ifdef _WIN32
fflush(stdout);
_setmode(_fileno(stdout), _O_BINARY);
#endif
}
}
else if(!strcmp(arg, "--set")) {
if(parse_config(argv[++i], "--set"))
return(1);
}
else if(!strncmp(arg, "--set=", 6)) {
if(parse_config(arg + 6, "--set="))
return(1);
}
else if(!strcmp(arg, "--"))
break;
}
// 扫描更多文件
for(i++; i < argc; i++)
if(scan_image(argv[i]))
return(exit_code);
/* ignore quit during last image */
if(exit_code == 3)
exit_code = 0;
if(xmllvl > 0) {
xmllvl = -1;
printf("%s", xml_foot);
fflush(stdout);
}
if(xmlbuf)
free(xmlbuf);
if(num_images && !quiet && xmllvl <= 0) {
fprintf(stderr, "scanned %d barcode symbols from %d images",
num_symbols, num_images);
#ifdef HAVE_SYS_TIMES_H
#ifdef HAVE_UNISTD_H
long clk_tck = sysconf(_SC_CLK_TCK);
struct tms tms;
if(clk_tck > 0 && times(&tms) >= 0) {
double secs = tms.tms_utime + tms.tms_stime;
secs /= clk_tck;
fprintf(stderr, " in %.2g seconds\n", secs);
}
#endif
#endif
fprintf(stderr, "\n");
if(notfound)
fprintf(stderr, "%s", warning_not_found);
}
if(num_images && notfound && !exit_code)
exit_code = 4;
zbar_processor_destroy(processor);
MagickWandTerminus();
return(exit_code);
}
Makefile
######################################
#
######################################
#source file
SOURCE := $(wildcard *.c ./ringBuffer/*.c) $(wildcard *.cpp) # a.c /sub/b.c /sub/c.c
NODIR := $(notdir $(SOURCE)) # a.c b.c c.c
OBJS := $(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(SOURCE)))
#target you can change test to what you want
TARGET := zbarimg
#compile and lib parameter
CC := gcc
LIBS := /usr/local/lib/libzbar.a /usr/lib/x86_64-linux-gnu/libjpeg.so /usr/lib/x86_64-linux-gnu/libX11.so -lMagickWand-7.Q16HDRI -lMagickCore-7.Q16HDRI #$(wildcard ./libmbedtls/*.a) #libmbedtls.a libmbedx509.a libmbedcrypto.a
LDFLAGS := -lpthread -lm #-lm 这将告诉gcc链接您的代码与数学库。只要确保把标志放在你想链接的对象后面
DEFINES :=
INCLUDE := -I. -I./json/ -I./ringBuffer/ -I/usr/local/include/ImageMagick-7
CFLAGS := -g -Wall -O3 $(DEFINES) $(INCLUDE)
CXXFLAGS:= $(CFLAGS) -DHAVE_CONFIG_H $(MAGICK_CFLAGS)
.PHONY : everything objs clean veryclean rebuild
everything : $(TARGET)
all : $(TARGET)
objs : $(OBJS)
rebuild: veryclean everything
clean :
rm -fr ./ringBuffer/*.o
rm -fr *.so
rm -fr *.o
rm -rf $(TARGET)
veryclean : clean
rm -fr $(TARGET)
$(TARGET) : $(OBJS)
$(CC) $(CXXFLAGS) -o $@ $(OBJS) $(LDFLAGS) $(LIBS)
注意,相关库要加进去
/usr/local/lib/libzbar.a /usr/lib/x86_64-linux-gnu/libjpeg.so /usr/lib/x86_64-linux-gnu/libX11.so -lMagickWand-7.Q16HDRI -lMagickCore-7.Q16HDRI
zbar识别流程分析:
1、创建zbar处理线程,zbar_processor_create(0);
2、透过ImageMaigc(或者OpenCV)读取图片,并转换成zbar可以处理的像素数据(二进制灰度数据 raw)
3、创建zbar图像,zbar_image_create
4、设置zbar图像,格式,尺寸,填充数据等,zbar_image_set_format,zbar_image_set_data
5、启动zbar处理线程,zbar_process_image
6、读取解析到的二维码格式以及内容,zbar_symbol_get_type,zbar_symbol_get_data
------------------------------------------------------仅此记录------------------------------------------------------------