ImageMagic+zbar 二维码识别分析-zbarimg

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

------------------------------------------------------仅此记录------------------------------------------------------------

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值