diff --git a/Makefile b/Makefile index 2fc4a14..dbe6269 100644 --- a/Makefile +++ b/Makefile @@ -47,6 +47,9 @@ qrtest: tests/dbgutil.o tests/qrtest.o libquirc.a inspect: tests/dbgutil.o tests/inspect.o libquirc.a $(CC) -o $@ tests/dbgutil.o tests/inspect.o libquirc.a $(LDFLAGS) -lm -ljpeg -lpng $(SDL_LIBS) -lSDL_gfx +inspect-opencv: tests/dbgutil.o tests/inspect_opencv.o libquirc.a + $(CXX) -o $@ tests/dbgutil.o tests/inspect_opencv.o libquirc.a $(LDFLAGS) -lm -ljpeg -lpng $(OPENCV_LIBS) + quirc-demo: $(DEMO_OBJ) $(DEMO_UTIL_OBJ) demo/demo.o libquirc.a $(CC) -o $@ $(DEMO_OBJ) $(DEMO_UTIL_OBJ) demo/demo.o libquirc.a $(LDFLAGS) -lm -ljpeg $(SDL_LIBS) -lSDL_gfx @@ -98,6 +101,7 @@ clean: rm -f libquirc.so.$(LIB_VERSION) rm -f qrtest rm -f inspect + rm -f inspect-opencv rm -f quirc-demo rm -f quirc-demo-opencv rm -f quirc-scanner diff --git a/README.md b/README.md index c965561..5efc0a5 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,13 @@ additional information on stdout. This requires: libjpeg, libpng, SDL +### inspect-opencv + +A test similar to `inspect`. +But this version uses OpenCV instead of other libraries. + +This requires: libjpeg, libpng, OpenCV + Build-time requirements ----------------------- @@ -109,6 +116,7 @@ are unable to build everything: * libquirc.so * qrtest * inspect +* inspect-opencv * quirc-scanner * quirc-demo * quirc-demo-opencv diff --git a/tests/dbgutil.h b/tests/dbgutil.h index 7a5cc6a..8e2f655 100644 --- a/tests/dbgutil.h +++ b/tests/dbgutil.h @@ -19,6 +19,10 @@ #include "quirc.h" +#ifdef __cplusplus +extern "C" { +#endif + /* Dump decoded information on stdout. */ void dump_data(const struct quirc_data *data); @@ -45,4 +49,8 @@ int check_if_png(const char *filename); */ int load_png(struct quirc *q, const char *filename); +#ifdef __cplusplus +} +#endif + #endif diff --git a/tests/inspect_opencv.cxx b/tests/inspect_opencv.cxx new file mode 100644 index 0000000..800c0f6 --- /dev/null +++ b/tests/inspect_opencv.cxx @@ -0,0 +1,279 @@ +/* quirc -- QR-code recognition library + * Copyright (C) 2010-2012 Daniel Beer + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include + +#include +#include +#include + +using namespace cv; + +#include "quirc_internal.h" +#include "dbgutil.h" + +/* + * Macros to conver a color from the SDL_gfxprimitive style format. + * bpp=4, little-endian. + */ + +#define R(c) ((c) & 0xff) +#define G(c) ((c >> 8) & 0xff) +#define B(c) ((c >> 16) & 0xff) +#define COLOR(c) Scalar(B(c), G(c), R(c)) + +static void stringColor(Mat &screen, int x, int y, const char *text, + uint32_t color) +{ + static const int font = FONT_HERSHEY_PLAIN; + static const int thickness = 4; + static const double font_scale = 4.0; + + putText(screen, text, Point(x, y), font, font_scale, COLOR(color), + thickness); +} + +static void pixelColor(Mat &screen, int x, int y, uint32_t color) +{ + if (x < 0 || y < 0 || x >= screen.cols || y >= screen.rows) { + return; + } + + Vec3b &screen_pixel = screen.at(y, x); + screen_pixel[0] = B(color); + screen_pixel[1] = G(color); + screen_pixel[2] = R(color); +} + +static void lineColor(Mat &screen, int x1, int y1, int x2, int y2, + uint32_t color) +{ + line(screen, Point(x1, y1), Point(x2, y2), COLOR(color), 8); +} + +static void dump_info(struct quirc *q) +{ + int count = quirc_count(q); + int i; + + printf("%d QR-codes found:\n\n", count); + for (i = 0; i < count; i++) { + struct quirc_code code; + struct quirc_data data; + quirc_decode_error_t err; + + quirc_extract(q, i, &code); + err = quirc_decode(&code, &data); + if (err == QUIRC_ERROR_DATA_ECC) { + quirc_flip(&code); + err = quirc_decode(&code, &data); + } + + dump_cells(&code); + printf("\n"); + + if (err) { + printf(" Decoding FAILED: %s\n", quirc_strerror(err)); + } else { + printf(" Decoding successful:\n"); + dump_data(&data); + } + + printf("\n"); + } +} + +static void draw_frame(Mat &screen, struct quirc *q) +{ + uint8_t *raw = q->image; + int x, y; + + for (y = 0; y < q->h; y++) { + for (x = 0; x < q->w; x++) { + uint8_t v = *(raw++); + uint32_t color = (v << 16) | (v << 8) | v; + struct quirc_region *reg = &q->regions[v]; + + switch (v) { + case QUIRC_PIXEL_WHITE: + color = 0x00ffffff; + break; + + case QUIRC_PIXEL_BLACK: + color = 0x00000000; + break; + + default: + if (reg->capstone >= 0) + color = 0x00008000; + else + color = 0x00808080; + break; + } + + pixelColor(screen, x, y, color); + } + } +} + +static void draw_blob(Mat &screen, int x, int y) +{ + int i, j; + + for (i = -2; i <= 2; i++) + for (j = -2; j <= 2; j++) + pixelColor(screen, x + i, y + j, 0x0000ffff); +} + +static void draw_mark(Mat &screen, int x, int y) +{ + pixelColor(screen, x, y, 0xff0000ff); + pixelColor(screen, x + 1, y, 0xff0000ff); + pixelColor(screen, x - 1, y, 0xff0000ff); + pixelColor(screen, x, y + 1, 0xff0000ff); + pixelColor(screen, x, y - 1, 0xff0000ff); +} + +static void draw_capstone(Mat &screen, struct quirc *q, int index) +{ + struct quirc_capstone *cap = &q->capstones[index]; + int j; + char buf[8]; + + for (j = 0; j < 4; j++) { + struct quirc_point *p0 = &cap->corners[j]; + struct quirc_point *p1 = &cap->corners[(j + 1) % 4]; + + lineColor(screen, p0->x, p0->y, p1->x, p1->y, + 0x800080ff); + } + + draw_blob(screen, cap->corners[0].x, cap->corners[0].y); + + if (cap->qr_grid < 0) { + snprintf(buf, sizeof(buf), "?%d", index); + stringColor(screen, cap->center.x, cap->center.y, buf, + 0x000000ff); + } +} + +static void perspective_map(const double *c, + double u, double v, struct quirc_point *ret) +{ + double den = c[6]*u + c[7]*v + 1.0; + double x = (c[0]*u + c[1]*v + c[2]) / den; + double y = (c[3]*u + c[4]*v + c[5]) / den; + + ret->x = rint(x); + ret->y = rint(y); +} + +static void draw_grid(Mat &screen, struct quirc *q, int index) +{ + struct quirc_grid *qr = &q->grids[index]; + int x, y; + int i; + + for (i = 0; i < 3; i++) { + struct quirc_capstone *cap = &q->capstones[qr->caps[i]]; + char buf[16]; + + snprintf(buf, sizeof(buf), "%d.%c", index, "ABC"[i]); + stringColor(screen, cap->center.x, cap->center.y, buf, + 0x000000ff); + } + + lineColor(screen, qr->tpep[0].x, qr->tpep[0].y, + qr->tpep[1].x, qr->tpep[1].y, 0xff00ffff); + lineColor(screen, qr->tpep[1].x, qr->tpep[1].y, + qr->tpep[2].x, qr->tpep[2].y, 0xff00ffff); + + if (qr->align_region >= 0) + draw_blob(screen, qr->align.x, qr->align.y); + + for (y = 0; y < qr->grid_size; y++) { + for (x = 0; x < qr->grid_size; x++) { + double u = x + 0.5; + double v = y + 0.5; + struct quirc_point p; + + perspective_map(qr->c, u, v, &p); + draw_mark(screen, p.x, p.y); + } + } +} + +static int opencv_examine(struct quirc *q) +{ + static const char *win = "inspect-opencv"; + Mat frame(q->h, q->w, CV_8UC3); + int i; + + draw_frame(frame, q); + for (i = 0; i < q->num_capstones; i++) + draw_capstone(frame, q, i); + for (i = 0; i < q->num_grids; i++) + draw_grid(frame, q, i); + + imshow(win, frame); + waitKey(0); + + return 0; +} + +int main(int argc, char **argv) +{ + struct quirc *q; + + printf("quirc inspection program\n"); + printf("Copyright (C) 2010-2012 Daniel Beer \n"); + printf("Library version: %s\n", quirc_version()); + printf("\n"); + + if (argc < 2) { + fprintf(stderr, "Usage: %s \n", argv[0]); + return -1; + } + + q = quirc_new(); + if (!q) { + perror("can't create quirc object"); + return -1; + } + + int status = -1; + if (check_if_png(argv[1])) { + status = load_png(q, argv[1]); + } else { + status = load_jpeg(q, argv[1]); + } + if (status < 0) { + quirc_destroy(q); + return -1; + } + + quirc_end(q); + dump_info(q); + + if (opencv_examine(q) < 0) { + quirc_destroy(q); + return -1; + } + + quirc_destroy(q); + return 0; +}