Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
O
opencv
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
opencv
Commits
53ec8f28
Commit
53ec8f28
authored
Aug 17, 2018
by
Alexander Nesterov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Added QR code decoding.
parent
50beef60
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
2174 additions
and
21 deletions
+2174
-21
CMakeLists.txt
3rdparty/quirc/CMakeLists.txt
+30
-0
LICENSE
3rdparty/quirc/LICENSE
+16
-0
quirc.h
3rdparty/quirc/include/quirc.h
+173
-0
quirc_internal.h
3rdparty/quirc/include/quirc_internal.h
+115
-0
decode.c
3rdparty/quirc/src/decode.c
+919
-0
quirc.c
3rdparty/quirc/src/quirc.c
+138
-0
version_db.c
3rdparty/quirc/src/version_db.c
+430
-0
CMakeLists.txt
CMakeLists.txt
+5
-0
cvconfig.h.in
cmake/templates/cvconfig.h.in
+2
-0
CMakeLists.txt
modules/objdetect/CMakeLists.txt
+7
-1
objdetect.hpp
modules/objdetect/include/opencv2/objdetect.hpp
+7
-0
qrcode.cpp
modules/objdetect/src/qrcode.cpp
+282
-3
test_qrcode.cpp
modules/objdetect/test/test_qrcode.cpp
+31
-14
live_detect_qrcode.cpp
samples/cpp/live_detect_qrcode.cpp
+19
-3
No files found.
3rdparty/quirc/CMakeLists.txt
0 → 100644
View file @
53ec8f28
project
(
quirc
)
set
(
CURR_INCLUDE_DIR
"
${
CMAKE_CURRENT_LIST_DIR
}
/include"
)
set_property
(
GLOBAL PROPERTY QUIRC_INCLUDE_DIR
${
CURR_INCLUDE_DIR
}
)
ocv_include_directories
(
${
CURR_INCLUDE_DIR
}
)
file
(
GLOB_RECURSE quirc_headers RELATIVE
"
${
CMAKE_CURRENT_LIST_DIR
}
"
"include/*.h"
)
file
(
GLOB_RECURSE quirc_sources RELATIVE
"
${
CMAKE_CURRENT_LIST_DIR
}
"
"src/*.c"
)
add_library
(
${
PROJECT_NAME
}
STATIC
${
quirc_headers
}
${
quirc_sources
}
)
ocv_warnings_disable
(
CMAKE_C_FLAGS -Wunused-variable -Wshadow
)
set_target_properties
(
${
PROJECT_NAME
}
PROPERTIES OUTPUT_NAME
${
PROJECT_NAME
}
DEBUG_POSTFIX
"
${
OPENCV_DEBUG_POSTFIX
}
"
COMPILE_PDB_NAME
${
PROJECT_NAME
}
COMPILE_PDB_NAME_DEBUG
"
${
PROJECT_NAME
}${
OPENCV_DEBUG_POSTFIX
}
"
ARCHIVE_OUTPUT_DIRECTORY
${
3P_LIBRARY_OUTPUT_PATH
}
)
if
(
ENABLE_SOLUTION_FOLDERS
)
set_target_properties
(
${
PROJECT_NAME
}
PROPERTIES FOLDER
"3rdparty"
)
endif
()
if
(
NOT BUILD_SHARED_LIBS
)
ocv_install_target
(
${
PROJECT_NAME
}
EXPORT OpenCVModules ARCHIVE DESTINATION
${
OPENCV_3P_LIB_INSTALL_PATH
}
COMPONENT dev
)
endif
()
ocv_install_3rdparty_licenses
(
${
PROJECT_NAME
}
LICENSE
)
3rdparty/quirc/LICENSE
0 → 100644
View file @
53ec8f28
quirc -- QR-code recognition library
Copyright (C) 2010-2012 Daniel Beer <dlbeer@gmail.com>
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.
3rdparty/quirc/include/quirc.h
0 → 100644
View file @
53ec8f28
/* quirc -- QR-code recognition library
* Copyright (C) 2010-2012 Daniel Beer <dlbeer@gmail.com>
*
* 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.
*/
#ifndef QUIRC_H_
#define QUIRC_H_
#include <stdint.h>
#ifdef __cplusplus
extern
"C"
{
#endif
struct
quirc
;
/* Obtain the library version string. */
const
char
*
quirc_version
(
void
);
/* Construct a new QR-code recognizer. This function will return NULL
* if sufficient memory could not be allocated.
*/
struct
quirc
*
quirc_new
(
void
);
/* Destroy a QR-code recognizer. */
void
quirc_destroy
(
struct
quirc
*
q
);
/* Resize the QR-code recognizer. The size of an image must be
* specified before codes can be analyzed.
*
* This function returns 0 on success, or -1 if sufficient memory could
* not be allocated.
*/
int
quirc_resize
(
struct
quirc
*
q
,
int
w
,
int
h
);
/* These functions are used to process images for QR-code recognition.
* quirc_begin() must first be called to obtain access to a buffer into
* which the input image should be placed. Optionally, the current
* width and height may be returned.
*
* After filling the buffer, quirc_end() should be called to process
* the image for QR-code recognition. The locations and content of each
* code may be obtained using accessor functions described below.
*/
uint8_t
*
quirc_begin
(
struct
quirc
*
q
,
int
*
w
,
int
*
h
);
void
quirc_end
(
struct
quirc
*
q
);
/* This structure describes a location in the input image buffer. */
struct
quirc_point
{
int
x
;
int
y
;
};
/* This enum describes the various decoder errors which may occur. */
typedef
enum
{
QUIRC_SUCCESS
=
0
,
QUIRC_ERROR_INVALID_GRID_SIZE
,
QUIRC_ERROR_INVALID_VERSION
,
QUIRC_ERROR_FORMAT_ECC
,
QUIRC_ERROR_DATA_ECC
,
QUIRC_ERROR_UNKNOWN_DATA_TYPE
,
QUIRC_ERROR_DATA_OVERFLOW
,
QUIRC_ERROR_DATA_UNDERFLOW
}
quirc_decode_error_t
;
/* Return a string error message for an error code. */
const
char
*
quirc_strerror
(
quirc_decode_error_t
err
);
/* Limits on the maximum size of QR-codes and their content. */
#define QUIRC_MAX_BITMAP 3917
#define QUIRC_MAX_PAYLOAD 8896
/* QR-code ECC types. */
#define QUIRC_ECC_LEVEL_M 0
#define QUIRC_ECC_LEVEL_L 1
#define QUIRC_ECC_LEVEL_H 2
#define QUIRC_ECC_LEVEL_Q 3
/* QR-code data types. */
#define QUIRC_DATA_TYPE_NUMERIC 1
#define QUIRC_DATA_TYPE_ALPHA 2
#define QUIRC_DATA_TYPE_BYTE 4
#define QUIRC_DATA_TYPE_KANJI 8
/* Common character encodings */
#define QUIRC_ECI_ISO_8859_1 1
#define QUIRC_ECI_IBM437 2
#define QUIRC_ECI_ISO_8859_2 4
#define QUIRC_ECI_ISO_8859_3 5
#define QUIRC_ECI_ISO_8859_4 6
#define QUIRC_ECI_ISO_8859_5 7
#define QUIRC_ECI_ISO_8859_6 8
#define QUIRC_ECI_ISO_8859_7 9
#define QUIRC_ECI_ISO_8859_8 10
#define QUIRC_ECI_ISO_8859_9 11
#define QUIRC_ECI_WINDOWS_874 13
#define QUIRC_ECI_ISO_8859_13 15
#define QUIRC_ECI_ISO_8859_15 17
#define QUIRC_ECI_SHIFT_JIS 20
#define QUIRC_ECI_UTF_8 26
/* This structure is used to return information about detected QR codes
* in the input image.
*/
struct
quirc_code
{
/* The four corners of the QR-code, from top left, clockwise */
struct
quirc_point
corners
[
4
];
/* The number of cells across in the QR-code. The cell bitmap
* is a bitmask giving the actual values of cells. If the cell
* at (x, y) is black, then the following bit is set:
*
* cell_bitmap[i >> 3] & (1 << (i & 7))
*
* where i = (y * size) + x.
*/
int
size
;
uint8_t
cell_bitmap
[
QUIRC_MAX_BITMAP
];
};
/* This structure holds the decoded QR-code data */
struct
quirc_data
{
/* Various parameters of the QR-code. These can mostly be
* ignored if you only care about the data.
*/
int
version
;
int
ecc_level
;
int
mask
;
/* This field is the highest-valued data type found in the QR
* code.
*/
int
data_type
;
/* Data payload. For the Kanji datatype, payload is encoded as
* Shift-JIS. For all other datatypes, payload is ASCII text.
*/
uint8_t
payload
[
QUIRC_MAX_PAYLOAD
];
int
payload_len
;
/* ECI assignment number */
uint32_t
eci
;
};
/* Return the number of QR-codes identified in the last processed
* image.
*/
int
quirc_count
(
const
struct
quirc
*
q
);
/* Extract the QR-code specified by the given index. */
void
quirc_extract
(
const
struct
quirc
*
q
,
int
index
,
struct
quirc_code
*
code
);
/* Decode a QR-code, returning the payload data. */
quirc_decode_error_t
quirc_decode
(
const
struct
quirc_code
*
code
,
struct
quirc_data
*
data
);
#ifdef __cplusplus
}
#endif
#endif
3rdparty/quirc/include/quirc_internal.h
0 → 100644
View file @
53ec8f28
/* quirc -- QR-code recognition library
* Copyright (C) 2010-2012 Daniel Beer <dlbeer@gmail.com>
*
* 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.
*/
#ifndef QUIRC_INTERNAL_H_
#define QUIRC_INTERNAL_H_
#include <quirc.h>
#define QUIRC_PIXEL_WHITE 0
#define QUIRC_PIXEL_BLACK 1
#define QUIRC_PIXEL_REGION 2
#ifndef QUIRC_MAX_REGIONS
#define QUIRC_MAX_REGIONS 254
#endif
#define QUIRC_MAX_CAPSTONES 32
#define QUIRC_MAX_GRIDS 8
#define QUIRC_PERSPECTIVE_PARAMS 8
#if QUIRC_MAX_REGIONS < UINT8_MAX
typedef
uint8_t
quirc_pixel_t
;
#elif QUIRC_MAX_REGIONS < UINT16_MAX
typedef
uint16_t
quirc_pixel_t
;
#else
#error "QUIRC_MAX_REGIONS > 65534 is not supported"
#endif
struct
quirc_region
{
struct
quirc_point
seed
;
int
count
;
int
capstone
;
};
struct
quirc_capstone
{
int
ring
;
int
stone
;
struct
quirc_point
corners
[
4
];
struct
quirc_point
center
;
double
c
[
QUIRC_PERSPECTIVE_PARAMS
];
int
qr_grid
;
};
struct
quirc_grid
{
/* Capstone indices */
int
caps
[
3
];
/* Alignment pattern region and corner */
int
align_region
;
struct
quirc_point
align
;
/* Timing pattern endpoints */
struct
quirc_point
tpep
[
3
];
int
hscan
;
int
vscan
;
/* Grid size and perspective transform */
int
grid_size
;
double
c
[
QUIRC_PERSPECTIVE_PARAMS
];
};
struct
quirc
{
uint8_t
*
image
;
quirc_pixel_t
*
pixels
;
int
*
row_average
;
/* used by threshold() */
int
w
;
int
h
;
int
num_regions
;
struct
quirc_region
regions
[
QUIRC_MAX_REGIONS
];
int
num_capstones
;
struct
quirc_capstone
capstones
[
QUIRC_MAX_CAPSTONES
];
int
num_grids
;
struct
quirc_grid
grids
[
QUIRC_MAX_GRIDS
];
};
/************************************************************************
* QR-code version information database
*/
#define QUIRC_MAX_VERSION 40
#define QUIRC_MAX_ALIGNMENT 7
struct
quirc_rs_params
{
int
bs
;
/* Small block size */
int
dw
;
/* Small data words */
int
ns
;
/* Number of small blocks */
};
struct
quirc_version_info
{
int
data_bytes
;
int
apat
[
QUIRC_MAX_ALIGNMENT
];
struct
quirc_rs_params
ecc
[
4
];
};
extern
const
struct
quirc_version_info
quirc_version_db
[
QUIRC_MAX_VERSION
+
1
];
#endif
3rdparty/quirc/src/decode.c
0 → 100644
View file @
53ec8f28
/* quirc -- QR-code recognition library
* Copyright (C) 2010-2012 Daniel Beer <dlbeer@gmail.com>
*
* 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 <quirc_internal.h>
#include <string.h>
#include <stdlib.h>
#define MAX_POLY 64
/************************************************************************
* Galois fields
*/
struct
galois_field
{
int
p
;
const
uint8_t
*
log
;
const
uint8_t
*
exp
;
};
static
const
uint8_t
gf16_exp
[
16
]
=
{
0x01
,
0x02
,
0x04
,
0x08
,
0x03
,
0x06
,
0x0c
,
0x0b
,
0x05
,
0x0a
,
0x07
,
0x0e
,
0x0f
,
0x0d
,
0x09
,
0x01
};
static
const
uint8_t
gf16_log
[
16
]
=
{
0x00
,
0x0f
,
0x01
,
0x04
,
0x02
,
0x08
,
0x05
,
0x0a
,
0x03
,
0x0e
,
0x09
,
0x07
,
0x06
,
0x0d
,
0x0b
,
0x0c
};
static
const
struct
galois_field
gf16
=
{
.
p
=
15
,
.
log
=
gf16_log
,
.
exp
=
gf16_exp
};
static
const
uint8_t
gf256_exp
[
256
]
=
{
0x01
,
0x02
,
0x04
,
0x08
,
0x10
,
0x20
,
0x40
,
0x80
,
0x1d
,
0x3a
,
0x74
,
0xe8
,
0xcd
,
0x87
,
0x13
,
0x26
,
0x4c
,
0x98
,
0x2d
,
0x5a
,
0xb4
,
0x75
,
0xea
,
0xc9
,
0x8f
,
0x03
,
0x06
,
0x0c
,
0x18
,
0x30
,
0x60
,
0xc0
,
0x9d
,
0x27
,
0x4e
,
0x9c
,
0x25
,
0x4a
,
0x94
,
0x35
,
0x6a
,
0xd4
,
0xb5
,
0x77
,
0xee
,
0xc1
,
0x9f
,
0x23
,
0x46
,
0x8c
,
0x05
,
0x0a
,
0x14
,
0x28
,
0x50
,
0xa0
,
0x5d
,
0xba
,
0x69
,
0xd2
,
0xb9
,
0x6f
,
0xde
,
0xa1
,
0x5f
,
0xbe
,
0x61
,
0xc2
,
0x99
,
0x2f
,
0x5e
,
0xbc
,
0x65
,
0xca
,
0x89
,
0x0f
,
0x1e
,
0x3c
,
0x78
,
0xf0
,
0xfd
,
0xe7
,
0xd3
,
0xbb
,
0x6b
,
0xd6
,
0xb1
,
0x7f
,
0xfe
,
0xe1
,
0xdf
,
0xa3
,
0x5b
,
0xb6
,
0x71
,
0xe2
,
0xd9
,
0xaf
,
0x43
,
0x86
,
0x11
,
0x22
,
0x44
,
0x88
,
0x0d
,
0x1a
,
0x34
,
0x68
,
0xd0
,
0xbd
,
0x67
,
0xce
,
0x81
,
0x1f
,
0x3e
,
0x7c
,
0xf8
,
0xed
,
0xc7
,
0x93
,
0x3b
,
0x76
,
0xec
,
0xc5
,
0x97
,
0x33
,
0x66
,
0xcc
,
0x85
,
0x17
,
0x2e
,
0x5c
,
0xb8
,
0x6d
,
0xda
,
0xa9
,
0x4f
,
0x9e
,
0x21
,
0x42
,
0x84
,
0x15
,
0x2a
,
0x54
,
0xa8
,
0x4d
,
0x9a
,
0x29
,
0x52
,
0xa4
,
0x55
,
0xaa
,
0x49
,
0x92
,
0x39
,
0x72
,
0xe4
,
0xd5
,
0xb7
,
0x73
,
0xe6
,
0xd1
,
0xbf
,
0x63
,
0xc6
,
0x91
,
0x3f
,
0x7e
,
0xfc
,
0xe5
,
0xd7
,
0xb3
,
0x7b
,
0xf6
,
0xf1
,
0xff
,
0xe3
,
0xdb
,
0xab
,
0x4b
,
0x96
,
0x31
,
0x62
,
0xc4
,
0x95
,
0x37
,
0x6e
,
0xdc
,
0xa5
,
0x57
,
0xae
,
0x41
,
0x82
,
0x19
,
0x32
,
0x64
,
0xc8
,
0x8d
,
0x07
,
0x0e
,
0x1c
,
0x38
,
0x70
,
0xe0
,
0xdd
,
0xa7
,
0x53
,
0xa6
,
0x51
,
0xa2
,
0x59
,
0xb2
,
0x79
,
0xf2
,
0xf9
,
0xef
,
0xc3
,
0x9b
,
0x2b
,
0x56
,
0xac
,
0x45
,
0x8a
,
0x09
,
0x12
,
0x24
,
0x48
,
0x90
,
0x3d
,
0x7a
,
0xf4
,
0xf5
,
0xf7
,
0xf3
,
0xfb
,
0xeb
,
0xcb
,
0x8b
,
0x0b
,
0x16
,
0x2c
,
0x58
,
0xb0
,
0x7d
,
0xfa
,
0xe9
,
0xcf
,
0x83
,
0x1b
,
0x36
,
0x6c
,
0xd8
,
0xad
,
0x47
,
0x8e
,
0x01
};
static
const
uint8_t
gf256_log
[
256
]
=
{
0x00
,
0xff
,
0x01
,
0x19
,
0x02
,
0x32
,
0x1a
,
0xc6
,
0x03
,
0xdf
,
0x33
,
0xee
,
0x1b
,
0x68
,
0xc7
,
0x4b
,
0x04
,
0x64
,
0xe0
,
0x0e
,
0x34
,
0x8d
,
0xef
,
0x81
,
0x1c
,
0xc1
,
0x69
,
0xf8
,
0xc8
,
0x08
,
0x4c
,
0x71
,
0x05
,
0x8a
,
0x65
,
0x2f
,
0xe1
,
0x24
,
0x0f
,
0x21
,
0x35
,
0x93
,
0x8e
,
0xda
,
0xf0
,
0x12
,
0x82
,
0x45
,
0x1d
,
0xb5
,
0xc2
,
0x7d
,
0x6a
,
0x27
,
0xf9
,
0xb9
,
0xc9
,
0x9a
,
0x09
,
0x78
,
0x4d
,
0xe4
,
0x72
,
0xa6
,
0x06
,
0xbf
,
0x8b
,
0x62
,
0x66
,
0xdd
,
0x30
,
0xfd
,
0xe2
,
0x98
,
0x25
,
0xb3
,
0x10
,
0x91
,
0x22
,
0x88
,
0x36
,
0xd0
,
0x94
,
0xce
,
0x8f
,
0x96
,
0xdb
,
0xbd
,
0xf1
,
0xd2
,
0x13
,
0x5c
,
0x83
,
0x38
,
0x46
,
0x40
,
0x1e
,
0x42
,
0xb6
,
0xa3
,
0xc3
,
0x48
,
0x7e
,
0x6e
,
0x6b
,
0x3a
,
0x28
,
0x54
,
0xfa
,
0x85
,
0xba
,
0x3d
,
0xca
,
0x5e
,
0x9b
,
0x9f
,
0x0a
,
0x15
,
0x79
,
0x2b
,
0x4e
,
0xd4
,
0xe5
,
0xac
,
0x73
,
0xf3
,
0xa7
,
0x57
,
0x07
,
0x70
,
0xc0
,
0xf7
,
0x8c
,
0x80
,
0x63
,
0x0d
,
0x67
,
0x4a
,
0xde
,
0xed
,
0x31
,
0xc5
,
0xfe
,
0x18
,
0xe3
,
0xa5
,
0x99
,
0x77
,
0x26
,
0xb8
,
0xb4
,
0x7c
,
0x11
,
0x44
,
0x92
,
0xd9
,
0x23
,
0x20
,
0x89
,
0x2e
,
0x37
,
0x3f
,
0xd1
,
0x5b
,
0x95
,
0xbc
,
0xcf
,
0xcd
,
0x90
,
0x87
,
0x97
,
0xb2
,
0xdc
,
0xfc
,
0xbe
,
0x61
,
0xf2
,
0x56
,
0xd3
,
0xab
,
0x14
,
0x2a
,
0x5d
,
0x9e
,
0x84
,
0x3c
,
0x39
,
0x53
,
0x47
,
0x6d
,
0x41
,
0xa2
,
0x1f
,
0x2d
,
0x43
,
0xd8
,
0xb7
,
0x7b
,
0xa4
,
0x76
,
0xc4
,
0x17
,
0x49
,
0xec
,
0x7f
,
0x0c
,
0x6f
,
0xf6
,
0x6c
,
0xa1
,
0x3b
,
0x52
,
0x29
,
0x9d
,
0x55
,
0xaa
,
0xfb
,
0x60
,
0x86
,
0xb1
,
0xbb
,
0xcc
,
0x3e
,
0x5a
,
0xcb
,
0x59
,
0x5f
,
0xb0
,
0x9c
,
0xa9
,
0xa0
,
0x51
,
0x0b
,
0xf5
,
0x16
,
0xeb
,
0x7a
,
0x75
,
0x2c
,
0xd7
,
0x4f
,
0xae
,
0xd5
,
0xe9
,
0xe6
,
0xe7
,
0xad
,
0xe8
,
0x74
,
0xd6
,
0xf4
,
0xea
,
0xa8
,
0x50
,
0x58
,
0xaf
};
static
const
struct
galois_field
gf256
=
{
.
p
=
255
,
.
log
=
gf256_log
,
.
exp
=
gf256_exp
};
/************************************************************************
* Polynomial operations
*/
static
void
poly_add
(
uint8_t
*
dst
,
const
uint8_t
*
src
,
uint8_t
c
,
int
shift
,
const
struct
galois_field
*
gf
)
{
int
i
;
int
log_c
=
gf
->
log
[
c
];
if
(
!
c
)
return
;
for
(
i
=
0
;
i
<
MAX_POLY
;
i
++
)
{
int
p
=
i
+
shift
;
uint8_t
v
=
src
[
i
];
if
(
p
<
0
||
p
>=
MAX_POLY
)
continue
;
if
(
!
v
)
continue
;
dst
[
p
]
^=
gf
->
exp
[(
gf
->
log
[
v
]
+
log_c
)
%
gf
->
p
];
}
}
static
uint8_t
poly_eval
(
const
uint8_t
*
s
,
uint8_t
x
,
const
struct
galois_field
*
gf
)
{
int
i
;
uint8_t
sum
=
0
;
uint8_t
log_x
=
gf
->
log
[
x
];
if
(
!
x
)
return
s
[
0
];
for
(
i
=
0
;
i
<
MAX_POLY
;
i
++
)
{
uint8_t
c
=
s
[
i
];
if
(
!
c
)
continue
;
sum
^=
gf
->
exp
[(
gf
->
log
[
c
]
+
log_x
*
i
)
%
gf
->
p
];
}
return
sum
;
}
/************************************************************************
* Berlekamp-Massey algorithm for finding error locator polynomials.
*/
static
void
berlekamp_massey
(
const
uint8_t
*
s
,
int
N
,
const
struct
galois_field
*
gf
,
uint8_t
*
sigma
)
{
uint8_t
C
[
MAX_POLY
];
uint8_t
B
[
MAX_POLY
];
int
L
=
0
;
int
m
=
1
;
uint8_t
b
=
1
;
int
n
;
memset
(
B
,
0
,
sizeof
(
B
));
memset
(
C
,
0
,
sizeof
(
C
));
B
[
0
]
=
1
;
C
[
0
]
=
1
;
for
(
n
=
0
;
n
<
N
;
n
++
)
{
uint8_t
d
=
s
[
n
];
uint8_t
mult
;
int
i
;
for
(
i
=
1
;
i
<=
L
;
i
++
)
{
if
(
!
(
C
[
i
]
&&
s
[
n
-
i
]))
continue
;
d
^=
gf
->
exp
[(
gf
->
log
[
C
[
i
]]
+
gf
->
log
[
s
[
n
-
i
]])
%
gf
->
p
];
}
mult
=
gf
->
exp
[(
gf
->
p
-
gf
->
log
[
b
]
+
gf
->
log
[
d
])
%
gf
->
p
];
if
(
!
d
)
{
m
++
;
}
else
if
(
L
*
2
<=
n
)
{
uint8_t
T
[
MAX_POLY
];
memcpy
(
T
,
C
,
sizeof
(
T
));
poly_add
(
C
,
B
,
mult
,
m
,
gf
);
memcpy
(
B
,
T
,
sizeof
(
B
));
L
=
n
+
1
-
L
;
b
=
d
;
m
=
1
;
}
else
{
poly_add
(
C
,
B
,
mult
,
m
,
gf
);
m
++
;
}
}
memcpy
(
sigma
,
C
,
MAX_POLY
);
}
/************************************************************************
* Code stream error correction
*
* Generator polynomial for GF(2^8) is x^8 + x^4 + x^3 + x^2 + 1
*/
static
int
block_syndromes
(
const
uint8_t
*
data
,
int
bs
,
int
npar
,
uint8_t
*
s
)
{
int
nonzero
=
0
;
int
i
;
memset
(
s
,
0
,
MAX_POLY
);
for
(
i
=
0
;
i
<
npar
;
i
++
)
{
int
j
;
for
(
j
=
0
;
j
<
bs
;
j
++
)
{
uint8_t
c
=
data
[
bs
-
j
-
1
];
if
(
!
c
)
continue
;
s
[
i
]
^=
gf256_exp
[((
int
)
gf256_log
[
c
]
+
i
*
j
)
%
255
];
}
if
(
s
[
i
])
nonzero
=
1
;
}
return
nonzero
;
}
static
void
eloc_poly
(
uint8_t
*
omega
,
const
uint8_t
*
s
,
const
uint8_t
*
sigma
,
int
npar
)
{
int
i
;
memset
(
omega
,
0
,
MAX_POLY
);
for
(
i
=
0
;
i
<
npar
;
i
++
)
{
const
uint8_t
a
=
sigma
[
i
];
const
uint8_t
log_a
=
gf256_log
[
a
];
int
j
;
if
(
!
a
)
continue
;
for
(
j
=
0
;
j
+
1
<
MAX_POLY
;
j
++
)
{
const
uint8_t
b
=
s
[
j
+
1
];
if
(
i
+
j
>=
npar
)
break
;
if
(
!
b
)
continue
;
omega
[
i
+
j
]
^=
gf256_exp
[(
log_a
+
gf256_log
[
b
])
%
255
];
}
}
}
static
quirc_decode_error_t
correct_block
(
uint8_t
*
data
,
const
struct
quirc_rs_params
*
ecc
)
{
int
npar
=
ecc
->
bs
-
ecc
->
dw
;
uint8_t
s
[
MAX_POLY
];
uint8_t
sigma
[
MAX_POLY
];
uint8_t
sigma_deriv
[
MAX_POLY
];
uint8_t
omega
[
MAX_POLY
];
int
i
;
/* Compute syndrome vector */
if
(
!
block_syndromes
(
data
,
ecc
->
bs
,
npar
,
s
))
return
QUIRC_SUCCESS
;
berlekamp_massey
(
s
,
npar
,
&
gf256
,
sigma
);
/* Compute derivative of sigma */
memset
(
sigma_deriv
,
0
,
MAX_POLY
);
for
(
i
=
0
;
i
+
1
<
MAX_POLY
;
i
+=
2
)
sigma_deriv
[
i
]
=
sigma
[
i
+
1
];
/* Compute error evaluator polynomial */
eloc_poly
(
omega
,
s
,
sigma
,
npar
-
1
);
/* Find error locations and magnitudes */
for
(
i
=
0
;
i
<
ecc
->
bs
;
i
++
)
{
uint8_t
xinv
=
gf256_exp
[
255
-
i
];
if
(
!
poly_eval
(
sigma
,
xinv
,
&
gf256
))
{
uint8_t
sd_x
=
poly_eval
(
sigma_deriv
,
xinv
,
&
gf256
);
uint8_t
omega_x
=
poly_eval
(
omega
,
xinv
,
&
gf256
);
uint8_t
error
=
gf256_exp
[(
255
-
gf256_log
[
sd_x
]
+
gf256_log
[
omega_x
])
%
255
];
data
[
ecc
->
bs
-
i
-
1
]
^=
error
;
}
}
if
(
block_syndromes
(
data
,
ecc
->
bs
,
npar
,
s
))
return
QUIRC_ERROR_DATA_ECC
;
return
QUIRC_SUCCESS
;
}
/************************************************************************
* Format value error correction
*
* Generator polynomial for GF(2^4) is x^4 + x + 1
*/
#define FORMAT_MAX_ERROR 3
#define FORMAT_SYNDROMES (FORMAT_MAX_ERROR * 2)
#define FORMAT_BITS 15
static
int
format_syndromes
(
uint16_t
u
,
uint8_t
*
s
)
{
int
i
;
int
nonzero
=
0
;
memset
(
s
,
0
,
MAX_POLY
);
for
(
i
=
0
;
i
<
FORMAT_SYNDROMES
;
i
++
)
{
int
j
;
s
[
i
]
=
0
;
for
(
j
=
0
;
j
<
FORMAT_BITS
;
j
++
)
if
(
u
&
(
1
<<
j
))
s
[
i
]
^=
gf16_exp
[((
i
+
1
)
*
j
)
%
15
];
if
(
s
[
i
])
nonzero
=
1
;
}
return
nonzero
;
}
static
quirc_decode_error_t
correct_format
(
uint16_t
*
f_ret
)
{
uint16_t
u
=
*
f_ret
;
int
i
;
uint8_t
s
[
MAX_POLY
];
uint8_t
sigma
[
MAX_POLY
];
/* Evaluate U (received codeword) at each of alpha_1 .. alpha_6
* to get S_1 .. S_6 (but we index them from 0).
*/
if
(
!
format_syndromes
(
u
,
s
))
return
QUIRC_SUCCESS
;
berlekamp_massey
(
s
,
FORMAT_SYNDROMES
,
&
gf16
,
sigma
);
/* Now, find the roots of the polynomial */
for
(
i
=
0
;
i
<
15
;
i
++
)
if
(
!
poly_eval
(
sigma
,
gf16_exp
[
15
-
i
],
&
gf16
))
u
^=
(
1
<<
i
);
if
(
format_syndromes
(
u
,
s
))
return
QUIRC_ERROR_FORMAT_ECC
;
*
f_ret
=
u
;
return
QUIRC_SUCCESS
;
}
/************************************************************************
* Decoder algorithm
*/
struct
datastream
{
uint8_t
raw
[
QUIRC_MAX_PAYLOAD
];
int
data_bits
;
int
ptr
;
uint8_t
data
[
QUIRC_MAX_PAYLOAD
];
};
static
inline
int
grid_bit
(
const
struct
quirc_code
*
code
,
int
x
,
int
y
)
{
int
p
=
y
*
code
->
size
+
x
;
return
(
code
->
cell_bitmap
[
p
>>
3
]
>>
(
p
&
7
))
&
1
;
}
static
quirc_decode_error_t
read_format
(
const
struct
quirc_code
*
code
,
struct
quirc_data
*
data
,
int
which
)
{
int
i
;
uint16_t
format
=
0
;
uint16_t
fdata
;
quirc_decode_error_t
err
;
if
(
which
)
{
for
(
i
=
0
;
i
<
7
;
i
++
)
format
=
(
format
<<
1
)
|
grid_bit
(
code
,
8
,
code
->
size
-
1
-
i
);
for
(
i
=
0
;
i
<
8
;
i
++
)
format
=
(
format
<<
1
)
|
grid_bit
(
code
,
code
->
size
-
8
+
i
,
8
);
}
else
{
static
const
int
xs
[
15
]
=
{
8
,
8
,
8
,
8
,
8
,
8
,
8
,
8
,
7
,
5
,
4
,
3
,
2
,
1
,
0
};
static
const
int
ys
[
15
]
=
{
0
,
1
,
2
,
3
,
4
,
5
,
7
,
8
,
8
,
8
,
8
,
8
,
8
,
8
,
8
};
for
(
i
=
14
;
i
>=
0
;
i
--
)
format
=
(
format
<<
1
)
|
grid_bit
(
code
,
xs
[
i
],
ys
[
i
]);
}
format
^=
0x5412
;
err
=
correct_format
(
&
format
);
if
(
err
)
return
err
;
fdata
=
format
>>
10
;
data
->
ecc_level
=
fdata
>>
3
;
data
->
mask
=
fdata
&
7
;
return
QUIRC_SUCCESS
;
}
static
int
mask_bit
(
int
mask
,
int
i
,
int
j
)
{
switch
(
mask
)
{
case
0
:
return
!
((
i
+
j
)
%
2
);
case
1
:
return
!
(
i
%
2
);
case
2
:
return
!
(
j
%
3
);
case
3
:
return
!
((
i
+
j
)
%
3
);
case
4
:
return
!
(((
i
/
2
)
+
(
j
/
3
))
%
2
);
case
5
:
return
!
((
i
*
j
)
%
2
+
(
i
*
j
)
%
3
);
case
6
:
return
!
(((
i
*
j
)
%
2
+
(
i
*
j
)
%
3
)
%
2
);
case
7
:
return
!
(((
i
*
j
)
%
3
+
(
i
+
j
)
%
2
)
%
2
);
}
return
0
;
}
static
int
reserved_cell
(
int
version
,
int
i
,
int
j
)
{
const
struct
quirc_version_info
*
ver
=
&
quirc_version_db
[
version
];
int
size
=
version
*
4
+
17
;
int
ai
=
-
1
,
aj
=
-
1
,
a
;
/* Finder + format: top left */
if
(
i
<
9
&&
j
<
9
)
return
1
;
/* Finder + format: bottom left */
if
(
i
+
8
>=
size
&&
j
<
9
)
return
1
;
/* Finder + format: top right */
if
(
i
<
9
&&
j
+
8
>=
size
)
return
1
;
/* Exclude timing patterns */
if
(
i
==
6
||
j
==
6
)
return
1
;
/* Exclude version info, if it exists. Version info sits adjacent to
* the top-right and bottom-left finders in three rows, bounded by
* the timing pattern.
*/
if
(
version
>=
7
)
{
if
(
i
<
6
&&
j
+
11
>=
size
)
return
1
;
if
(
i
+
11
>=
size
&&
j
<
6
)
return
1
;
}
/* Exclude alignment patterns */
for
(
a
=
0
;
a
<
QUIRC_MAX_ALIGNMENT
&&
ver
->
apat
[
a
];
a
++
)
{
int
p
=
ver
->
apat
[
a
];
if
(
abs
(
p
-
i
)
<
3
)
ai
=
a
;
if
(
abs
(
p
-
j
)
<
3
)
aj
=
a
;
}
if
(
ai
>=
0
&&
aj
>=
0
)
{
a
--
;
if
(
ai
>
0
&&
ai
<
a
)
return
1
;
if
(
aj
>
0
&&
aj
<
a
)
return
1
;
if
(
aj
==
a
&&
ai
==
a
)
return
1
;
}
return
0
;
}
static
void
read_bit
(
const
struct
quirc_code
*
code
,
struct
quirc_data
*
data
,
struct
datastream
*
ds
,
int
i
,
int
j
)
{
int
bitpos
=
ds
->
data_bits
&
7
;
int
bytepos
=
ds
->
data_bits
>>
3
;
int
v
=
grid_bit
(
code
,
j
,
i
);
if
(
mask_bit
(
data
->
mask
,
i
,
j
))
v
^=
1
;
if
(
v
)
ds
->
raw
[
bytepos
]
|=
(
0x80
>>
bitpos
);
ds
->
data_bits
++
;
}
static
void
read_data
(
const
struct
quirc_code
*
code
,
struct
quirc_data
*
data
,
struct
datastream
*
ds
)
{
int
y
=
code
->
size
-
1
;
int
x
=
code
->
size
-
1
;
int
dir
=
-
1
;
while
(
x
>
0
)
{
if
(
x
==
6
)
x
--
;
if
(
!
reserved_cell
(
data
->
version
,
y
,
x
))
read_bit
(
code
,
data
,
ds
,
y
,
x
);
if
(
!
reserved_cell
(
data
->
version
,
y
,
x
-
1
))
read_bit
(
code
,
data
,
ds
,
y
,
x
-
1
);
y
+=
dir
;
if
(
y
<
0
||
y
>=
code
->
size
)
{
dir
=
-
dir
;
x
-=
2
;
y
+=
dir
;
}
}
}
static
quirc_decode_error_t
codestream_ecc
(
struct
quirc_data
*
data
,
struct
datastream
*
ds
)
{
const
struct
quirc_version_info
*
ver
=
&
quirc_version_db
[
data
->
version
];
const
struct
quirc_rs_params
*
sb_ecc
=
&
ver
->
ecc
[
data
->
ecc_level
];
struct
quirc_rs_params
lb_ecc
;
const
int
lb_count
=
(
ver
->
data_bytes
-
sb_ecc
->
bs
*
sb_ecc
->
ns
)
/
(
sb_ecc
->
bs
+
1
);
const
int
bc
=
lb_count
+
sb_ecc
->
ns
;
const
int
ecc_offset
=
sb_ecc
->
dw
*
bc
+
lb_count
;
int
dst_offset
=
0
;
int
i
;
memcpy
(
&
lb_ecc
,
sb_ecc
,
sizeof
(
lb_ecc
));
lb_ecc
.
dw
++
;
lb_ecc
.
bs
++
;
for
(
i
=
0
;
i
<
bc
;
i
++
)
{
uint8_t
*
dst
=
ds
->
data
+
dst_offset
;
const
struct
quirc_rs_params
*
ecc
=
(
i
<
sb_ecc
->
ns
)
?
sb_ecc
:
&
lb_ecc
;
const
int
num_ec
=
ecc
->
bs
-
ecc
->
dw
;
quirc_decode_error_t
err
;
int
j
;
for
(
j
=
0
;
j
<
ecc
->
dw
;
j
++
)
dst
[
j
]
=
ds
->
raw
[
j
*
bc
+
i
];
for
(
j
=
0
;
j
<
num_ec
;
j
++
)
dst
[
ecc
->
dw
+
j
]
=
ds
->
raw
[
ecc_offset
+
j
*
bc
+
i
];
err
=
correct_block
(
dst
,
ecc
);
if
(
err
)
return
err
;
dst_offset
+=
ecc
->
dw
;
}
ds
->
data_bits
=
dst_offset
*
8
;
return
QUIRC_SUCCESS
;
}
static
inline
int
bits_remaining
(
const
struct
datastream
*
ds
)
{
return
ds
->
data_bits
-
ds
->
ptr
;
}
static
int
take_bits
(
struct
datastream
*
ds
,
int
len
)
{
int
ret
=
0
;
while
(
len
&&
(
ds
->
ptr
<
ds
->
data_bits
))
{
uint8_t
b
=
ds
->
data
[
ds
->
ptr
>>
3
];
int
bitpos
=
ds
->
ptr
&
7
;
ret
<<=
1
;
if
((
b
<<
bitpos
)
&
0x80
)
ret
|=
1
;
ds
->
ptr
++
;
len
--
;
}
return
ret
;
}
static
int
numeric_tuple
(
struct
quirc_data
*
data
,
struct
datastream
*
ds
,
int
bits
,
int
digits
)
{
int
tuple
;
int
i
;
if
(
bits_remaining
(
ds
)
<
bits
)
return
-
1
;
tuple
=
take_bits
(
ds
,
bits
);
for
(
i
=
digits
-
1
;
i
>=
0
;
i
--
)
{
data
->
payload
[
data
->
payload_len
+
i
]
=
tuple
%
10
+
'0'
;
tuple
/=
10
;
}
data
->
payload_len
+=
digits
;
return
0
;
}
static
quirc_decode_error_t
decode_numeric
(
struct
quirc_data
*
data
,
struct
datastream
*
ds
)
{
int
bits
=
14
;
int
count
;
if
(
data
->
version
<
10
)
bits
=
10
;
else
if
(
data
->
version
<
27
)
bits
=
12
;
count
=
take_bits
(
ds
,
bits
);
if
(
data
->
payload_len
+
count
+
1
>
QUIRC_MAX_PAYLOAD
)
return
QUIRC_ERROR_DATA_OVERFLOW
;
while
(
count
>=
3
)
{
if
(
numeric_tuple
(
data
,
ds
,
10
,
3
)
<
0
)
return
QUIRC_ERROR_DATA_UNDERFLOW
;
count
-=
3
;
}
if
(
count
>=
2
)
{
if
(
numeric_tuple
(
data
,
ds
,
7
,
2
)
<
0
)
return
QUIRC_ERROR_DATA_UNDERFLOW
;
count
-=
2
;
}
if
(
count
)
{
if
(
numeric_tuple
(
data
,
ds
,
4
,
1
)
<
0
)
return
QUIRC_ERROR_DATA_UNDERFLOW
;
count
--
;
}
return
QUIRC_SUCCESS
;
}
static
int
alpha_tuple
(
struct
quirc_data
*
data
,
struct
datastream
*
ds
,
int
bits
,
int
digits
)
{
int
tuple
;
int
i
;
if
(
bits_remaining
(
ds
)
<
bits
)
return
-
1
;
tuple
=
take_bits
(
ds
,
bits
);
for
(
i
=
0
;
i
<
digits
;
i
++
)
{
static
const
char
*
alpha_map
=
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:"
;
data
->
payload
[
data
->
payload_len
+
digits
-
i
-
1
]
=
alpha_map
[
tuple
%
45
];
tuple
/=
45
;
}
data
->
payload_len
+=
digits
;
return
0
;
}
static
quirc_decode_error_t
decode_alpha
(
struct
quirc_data
*
data
,
struct
datastream
*
ds
)
{
int
bits
=
13
;
int
count
;
if
(
data
->
version
<
10
)
bits
=
9
;
else
if
(
data
->
version
<
27
)
bits
=
11
;
count
=
take_bits
(
ds
,
bits
);
if
(
data
->
payload_len
+
count
+
1
>
QUIRC_MAX_PAYLOAD
)
return
QUIRC_ERROR_DATA_OVERFLOW
;
while
(
count
>=
2
)
{
if
(
alpha_tuple
(
data
,
ds
,
11
,
2
)
<
0
)
return
QUIRC_ERROR_DATA_UNDERFLOW
;
count
-=
2
;
}
if
(
count
)
{
if
(
alpha_tuple
(
data
,
ds
,
6
,
1
)
<
0
)
return
QUIRC_ERROR_DATA_UNDERFLOW
;
count
--
;
}
return
QUIRC_SUCCESS
;
}
static
quirc_decode_error_t
decode_byte
(
struct
quirc_data
*
data
,
struct
datastream
*
ds
)
{
int
bits
=
16
;
int
count
;
int
i
;
if
(
data
->
version
<
10
)
bits
=
8
;
count
=
take_bits
(
ds
,
bits
);
if
(
data
->
payload_len
+
count
+
1
>
QUIRC_MAX_PAYLOAD
)
return
QUIRC_ERROR_DATA_OVERFLOW
;
if
(
bits_remaining
(
ds
)
<
count
*
8
)
return
QUIRC_ERROR_DATA_UNDERFLOW
;
for
(
i
=
0
;
i
<
count
;
i
++
)
data
->
payload
[
data
->
payload_len
++
]
=
take_bits
(
ds
,
8
);
return
QUIRC_SUCCESS
;
}
static
quirc_decode_error_t
decode_kanji
(
struct
quirc_data
*
data
,
struct
datastream
*
ds
)
{
int
bits
=
12
;
int
count
;
int
i
;
if
(
data
->
version
<
10
)
bits
=
8
;
else
if
(
data
->
version
<
27
)
bits
=
10
;
count
=
take_bits
(
ds
,
bits
);
if
(
data
->
payload_len
+
count
*
2
+
1
>
QUIRC_MAX_PAYLOAD
)
return
QUIRC_ERROR_DATA_OVERFLOW
;
if
(
bits_remaining
(
ds
)
<
count
*
13
)
return
QUIRC_ERROR_DATA_UNDERFLOW
;
for
(
i
=
0
;
i
<
count
;
i
++
)
{
int
d
=
take_bits
(
ds
,
13
);
int
msB
=
d
/
0xc0
;
int
lsB
=
d
%
0xc0
;
int
intermediate
=
(
msB
<<
8
)
|
lsB
;
uint16_t
sjw
;
if
(
intermediate
+
0x8140
<=
0x9ffc
)
{
/* bytes are in the range 0x8140 to 0x9FFC */
sjw
=
intermediate
+
0x8140
;
}
else
{
/* bytes are in the range 0xE040 to 0xEBBF */
sjw
=
intermediate
+
0xc140
;
}
data
->
payload
[
data
->
payload_len
++
]
=
sjw
>>
8
;
data
->
payload
[
data
->
payload_len
++
]
=
sjw
&
0xff
;
}
return
QUIRC_SUCCESS
;
}
static
quirc_decode_error_t
decode_eci
(
struct
quirc_data
*
data
,
struct
datastream
*
ds
)
{
if
(
bits_remaining
(
ds
)
<
8
)
return
QUIRC_ERROR_DATA_UNDERFLOW
;
data
->
eci
=
take_bits
(
ds
,
8
);
if
((
data
->
eci
&
0xc0
)
==
0x80
)
{
if
(
bits_remaining
(
ds
)
<
8
)
return
QUIRC_ERROR_DATA_UNDERFLOW
;
data
->
eci
=
(
data
->
eci
<<
8
)
|
take_bits
(
ds
,
8
);
}
else
if
((
data
->
eci
&
0xe0
)
==
0xc0
)
{
if
(
bits_remaining
(
ds
)
<
16
)
return
QUIRC_ERROR_DATA_UNDERFLOW
;
data
->
eci
=
(
data
->
eci
<<
16
)
|
take_bits
(
ds
,
16
);
}
return
QUIRC_SUCCESS
;
}
static
quirc_decode_error_t
decode_payload
(
struct
quirc_data
*
data
,
struct
datastream
*
ds
)
{
while
(
bits_remaining
(
ds
)
>=
4
)
{
quirc_decode_error_t
err
=
QUIRC_SUCCESS
;
int
type
=
take_bits
(
ds
,
4
);
switch
(
type
)
{
case
QUIRC_DATA_TYPE_NUMERIC
:
err
=
decode_numeric
(
data
,
ds
);
break
;
case
QUIRC_DATA_TYPE_ALPHA
:
err
=
decode_alpha
(
data
,
ds
);
break
;
case
QUIRC_DATA_TYPE_BYTE
:
err
=
decode_byte
(
data
,
ds
);
break
;
case
QUIRC_DATA_TYPE_KANJI
:
err
=
decode_kanji
(
data
,
ds
);
break
;
case
7
:
err
=
decode_eci
(
data
,
ds
);
break
;
default:
goto
done
;
}
if
(
err
)
return
err
;
if
(
!
(
type
&
(
type
-
1
))
&&
(
type
>
data
->
data_type
))
data
->
data_type
=
type
;
}
done:
/* Add nul terminator to all payloads */
if
((
unsigned
)
data
->
payload_len
>=
sizeof
(
data
->
payload
))
data
->
payload_len
--
;
data
->
payload
[
data
->
payload_len
]
=
0
;
return
QUIRC_SUCCESS
;
}
quirc_decode_error_t
quirc_decode
(
const
struct
quirc_code
*
code
,
struct
quirc_data
*
data
)
{
quirc_decode_error_t
err
;
struct
datastream
ds
;
if
((
code
->
size
-
17
)
%
4
)
return
QUIRC_ERROR_INVALID_GRID_SIZE
;
memset
(
data
,
0
,
sizeof
(
*
data
));
memset
(
&
ds
,
0
,
sizeof
(
ds
));
data
->
version
=
(
code
->
size
-
17
)
/
4
;
if
(
data
->
version
<
1
||
data
->
version
>
QUIRC_MAX_VERSION
)
return
QUIRC_ERROR_INVALID_VERSION
;
/* Read format information -- try both locations */
err
=
read_format
(
code
,
data
,
0
);
if
(
err
)
err
=
read_format
(
code
,
data
,
1
);
if
(
err
)
return
err
;
read_data
(
code
,
data
,
&
ds
);
err
=
codestream_ecc
(
data
,
&
ds
);
if
(
err
)
return
err
;
err
=
decode_payload
(
data
,
&
ds
);
if
(
err
)
return
err
;
return
QUIRC_SUCCESS
;
}
3rdparty/quirc/src/quirc.c
0 → 100644
View file @
53ec8f28
/* quirc -- QR-code recognition library
* Copyright (C) 2010-2012 Daniel Beer <dlbeer@gmail.com>
*
* 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 <stdlib.h>
#include <string.h>
#include <quirc_internal.h>
const
char
*
quirc_version
(
void
)
{
return
"1.0"
;
}
struct
quirc
*
quirc_new
(
void
)
{
struct
quirc
*
q
=
malloc
(
sizeof
(
*
q
));
if
(
!
q
)
return
NULL
;
memset
(
q
,
0
,
sizeof
(
*
q
));
return
q
;
}
void
quirc_destroy
(
struct
quirc
*
q
)
{
free
(
q
->
image
);
/* q->pixels may alias q->image when their type representation is of the
same size, so we need to be careful here to avoid a double free */
if
(
sizeof
(
*
q
->
image
)
!=
sizeof
(
*
q
->
pixels
))
free
(
q
->
pixels
);
free
(
q
->
row_average
);
free
(
q
);
}
int
quirc_resize
(
struct
quirc
*
q
,
int
w
,
int
h
)
{
uint8_t
*
image
=
NULL
;
quirc_pixel_t
*
pixels
=
NULL
;
int
*
row_average
=
NULL
;
/*
* XXX: w and h should be size_t (or at least unsigned) as negatives
* values would not make much sense. The downside is that it would break
* both the API and ABI. Thus, at the moment, let's just do a sanity
* check.
*/
if
(
w
<
0
||
h
<
0
)
goto
fail
;
/*
* alloc a new buffer for q->image. We avoid realloc(3) because we want
* on failure to be leave `q` in a consistant, unmodified state.
*/
image
=
calloc
(
w
,
h
);
if
(
!
image
)
goto
fail
;
/* compute the "old" (i.e. currently allocated) and the "new"
(i.e. requested) image dimensions */
size_t
olddim
=
q
->
w
*
q
->
h
;
size_t
newdim
=
w
*
h
;
size_t
min
=
(
olddim
<
newdim
?
olddim
:
newdim
);
/*
* copy the data into the new buffer, avoiding (a) to read beyond the
* old buffer when the new size is greater and (b) to write beyond the
* new buffer when the new size is smaller, hence the min computation.
*/
(
void
)
memcpy
(
image
,
q
->
image
,
min
);
/* alloc a new buffer for q->pixels if needed */
if
(
sizeof
(
*
q
->
image
)
!=
sizeof
(
*
q
->
pixels
))
{
pixels
=
calloc
(
newdim
,
sizeof
(
quirc_pixel_t
));
if
(
!
pixels
)
goto
fail
;
}
/* alloc a new buffer for q->row_average */
row_average
=
calloc
(
w
,
sizeof
(
int
));
if
(
!
row_average
)
goto
fail
;
/* alloc succeeded, update `q` with the new size and buffers */
q
->
w
=
w
;
q
->
h
=
h
;
free
(
q
->
image
);
q
->
image
=
image
;
if
(
sizeof
(
*
q
->
image
)
!=
sizeof
(
*
q
->
pixels
))
{
free
(
q
->
pixels
);
q
->
pixels
=
pixels
;
}
free
(
q
->
row_average
);
q
->
row_average
=
row_average
;
return
0
;
/* NOTREACHED */
fail:
free
(
image
);
free
(
pixels
);
free
(
row_average
);
return
-
1
;
}
int
quirc_count
(
const
struct
quirc
*
q
)
{
return
q
->
num_grids
;
}
static
const
char
*
const
error_table
[]
=
{
[
QUIRC_SUCCESS
]
=
"Success"
,
[
QUIRC_ERROR_INVALID_GRID_SIZE
]
=
"Invalid grid size"
,
[
QUIRC_ERROR_INVALID_VERSION
]
=
"Invalid version"
,
[
QUIRC_ERROR_FORMAT_ECC
]
=
"Format data ECC failure"
,
[
QUIRC_ERROR_DATA_ECC
]
=
"ECC failure"
,
[
QUIRC_ERROR_UNKNOWN_DATA_TYPE
]
=
"Unknown data type"
,
[
QUIRC_ERROR_DATA_OVERFLOW
]
=
"Data overflow"
,
[
QUIRC_ERROR_DATA_UNDERFLOW
]
=
"Data underflow"
};
const
char
*
quirc_strerror
(
quirc_decode_error_t
err
)
{
if
((
int
)
err
<
8
)
{
return
error_table
[
err
];
}
else
{
return
"Unknown error"
;
}
}
3rdparty/quirc/src/version_db.c
0 → 100644
View file @
53ec8f28
/* quirc -- QR-code recognition library
* Copyright (C) 2010-2012 Daniel Beer <dlbeer@gmail.com>
*
* 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 <quirc_internal.h>
const
struct
quirc_version_info
quirc_version_db
[
QUIRC_MAX_VERSION
+
1
]
=
{
{
/* 0 */
.
data_bytes
=
0
,
.
apat
=
{
0
},
.
ecc
=
{
{.
bs
=
0
,
.
dw
=
0
,
.
ns
=
0
},
{.
bs
=
0
,
.
dw
=
0
,
.
ns
=
0
},
{.
bs
=
0
,
.
dw
=
0
,
.
ns
=
0
},
{.
bs
=
0
,
.
dw
=
0
,
.
ns
=
0
}
}
},
{
/* Version 1 */
.
data_bytes
=
26
,
.
apat
=
{
0
},
.
ecc
=
{
{.
bs
=
26
,
.
dw
=
16
,
.
ns
=
1
},
{.
bs
=
26
,
.
dw
=
19
,
.
ns
=
1
},
{.
bs
=
26
,
.
dw
=
9
,
.
ns
=
1
},
{.
bs
=
26
,
.
dw
=
13
,
.
ns
=
1
}
}
},
{
/* Version 2 */
.
data_bytes
=
44
,
.
apat
=
{
6
,
18
,
0
},
.
ecc
=
{
{.
bs
=
44
,
.
dw
=
28
,
.
ns
=
1
},
{.
bs
=
44
,
.
dw
=
34
,
.
ns
=
1
},
{.
bs
=
44
,
.
dw
=
16
,
.
ns
=
1
},
{.
bs
=
44
,
.
dw
=
22
,
.
ns
=
1
}
}
},
{
/* Version 3 */
.
data_bytes
=
70
,
.
apat
=
{
6
,
22
,
0
},
.
ecc
=
{
{.
bs
=
70
,
.
dw
=
44
,
.
ns
=
1
},
{.
bs
=
70
,
.
dw
=
55
,
.
ns
=
1
},
{.
bs
=
35
,
.
dw
=
13
,
.
ns
=
2
},
{.
bs
=
35
,
.
dw
=
17
,
.
ns
=
2
}
}
},
{
/* Version 4 */
.
data_bytes
=
100
,
.
apat
=
{
6
,
26
,
0
},
.
ecc
=
{
{.
bs
=
50
,
.
dw
=
32
,
.
ns
=
2
},
{.
bs
=
100
,
.
dw
=
80
,
.
ns
=
1
},
{.
bs
=
25
,
.
dw
=
9
,
.
ns
=
4
},
{.
bs
=
50
,
.
dw
=
24
,
.
ns
=
2
}
}
},
{
/* Version 5 */
.
data_bytes
=
134
,
.
apat
=
{
6
,
30
,
0
},
.
ecc
=
{
{.
bs
=
67
,
.
dw
=
43
,
.
ns
=
2
},
{.
bs
=
134
,
.
dw
=
108
,
.
ns
=
1
},
{.
bs
=
33
,
.
dw
=
11
,
.
ns
=
2
},
{.
bs
=
33
,
.
dw
=
15
,
.
ns
=
2
}
}
},
{
/* Version 6 */
.
data_bytes
=
172
,
.
apat
=
{
6
,
34
,
0
},
.
ecc
=
{
{.
bs
=
43
,
.
dw
=
27
,
.
ns
=
4
},
{.
bs
=
86
,
.
dw
=
68
,
.
ns
=
2
},
{.
bs
=
43
,
.
dw
=
15
,
.
ns
=
4
},
{.
bs
=
43
,
.
dw
=
19
,
.
ns
=
4
}
}
},
{
/* Version 7 */
.
data_bytes
=
196
,
.
apat
=
{
6
,
22
,
38
,
0
},
.
ecc
=
{
{.
bs
=
49
,
.
dw
=
31
,
.
ns
=
4
},
{.
bs
=
98
,
.
dw
=
78
,
.
ns
=
2
},
{.
bs
=
39
,
.
dw
=
13
,
.
ns
=
4
},
{.
bs
=
32
,
.
dw
=
14
,
.
ns
=
2
}
}
},
{
/* Version 8 */
.
data_bytes
=
242
,
.
apat
=
{
6
,
24
,
42
,
0
},
.
ecc
=
{
{.
bs
=
60
,
.
dw
=
38
,
.
ns
=
2
},
{.
bs
=
121
,
.
dw
=
97
,
.
ns
=
2
},
{.
bs
=
40
,
.
dw
=
14
,
.
ns
=
4
},
{.
bs
=
40
,
.
dw
=
18
,
.
ns
=
4
}
}
},
{
/* Version 9 */
.
data_bytes
=
292
,
.
apat
=
{
6
,
26
,
46
,
0
},
.
ecc
=
{
{.
bs
=
58
,
.
dw
=
36
,
.
ns
=
3
},
{.
bs
=
146
,
.
dw
=
116
,
.
ns
=
2
},
{.
bs
=
36
,
.
dw
=
12
,
.
ns
=
4
},
{.
bs
=
36
,
.
dw
=
16
,
.
ns
=
4
}
}
},
{
/* Version 10 */
.
data_bytes
=
346
,
.
apat
=
{
6
,
28
,
50
,
0
},
.
ecc
=
{
{.
bs
=
69
,
.
dw
=
43
,
.
ns
=
4
},
{.
bs
=
86
,
.
dw
=
68
,
.
ns
=
2
},
{.
bs
=
43
,
.
dw
=
15
,
.
ns
=
6
},
{.
bs
=
43
,
.
dw
=
19
,
.
ns
=
6
}
}
},
{
/* Version 11 */
.
data_bytes
=
404
,
.
apat
=
{
6
,
30
,
54
,
0
},
.
ecc
=
{
{.
bs
=
80
,
.
dw
=
50
,
.
ns
=
1
},
{.
bs
=
101
,
.
dw
=
81
,
.
ns
=
4
},
{.
bs
=
36
,
.
dw
=
12
,
.
ns
=
3
},
{.
bs
=
50
,
.
dw
=
22
,
.
ns
=
4
}
}
},
{
/* Version 12 */
.
data_bytes
=
466
,
.
apat
=
{
6
,
32
,
58
,
0
},
.
ecc
=
{
{.
bs
=
58
,
.
dw
=
36
,
.
ns
=
6
},
{.
bs
=
116
,
.
dw
=
92
,
.
ns
=
2
},
{.
bs
=
42
,
.
dw
=
14
,
.
ns
=
7
},
{.
bs
=
46
,
.
dw
=
20
,
.
ns
=
4
}
}
},
{
/* Version 13 */
.
data_bytes
=
532
,
.
apat
=
{
6
,
34
,
62
,
0
},
.
ecc
=
{
{.
bs
=
59
,
.
dw
=
37
,
.
ns
=
8
},
{.
bs
=
133
,
.
dw
=
107
,
.
ns
=
4
},
{.
bs
=
33
,
.
dw
=
11
,
.
ns
=
12
},
{.
bs
=
44
,
.
dw
=
20
,
.
ns
=
8
}
}
},
{
/* Version 14 */
.
data_bytes
=
581
,
.
apat
=
{
6
,
26
,
46
,
66
,
0
},
.
ecc
=
{
{.
bs
=
64
,
.
dw
=
40
,
.
ns
=
4
},
{.
bs
=
145
,
.
dw
=
115
,
.
ns
=
3
},
{.
bs
=
36
,
.
dw
=
12
,
.
ns
=
11
},
{.
bs
=
36
,
.
dw
=
16
,
.
ns
=
11
}
}
},
{
/* Version 15 */
.
data_bytes
=
655
,
.
apat
=
{
6
,
26
,
48
,
70
,
0
},
.
ecc
=
{
{.
bs
=
65
,
.
dw
=
41
,
.
ns
=
5
},
{.
bs
=
109
,
.
dw
=
87
,
.
ns
=
5
},
{.
bs
=
36
,
.
dw
=
12
,
.
ns
=
11
},
{.
bs
=
54
,
.
dw
=
24
,
.
ns
=
5
}
}
},
{
/* Version 16 */
.
data_bytes
=
733
,
.
apat
=
{
6
,
26
,
50
,
74
,
0
},
.
ecc
=
{
{.
bs
=
73
,
.
dw
=
45
,
.
ns
=
7
},
{.
bs
=
122
,
.
dw
=
98
,
.
ns
=
5
},
{.
bs
=
45
,
.
dw
=
15
,
.
ns
=
3
},
{.
bs
=
43
,
.
dw
=
19
,
.
ns
=
15
}
}
},
{
/* Version 17 */
.
data_bytes
=
815
,
.
apat
=
{
6
,
30
,
54
,
78
,
0
},
.
ecc
=
{
{.
bs
=
74
,
.
dw
=
46
,
.
ns
=
10
},
{.
bs
=
135
,
.
dw
=
107
,
.
ns
=
1
},
{.
bs
=
42
,
.
dw
=
14
,
.
ns
=
2
},
{.
bs
=
50
,
.
dw
=
22
,
.
ns
=
1
}
}
},
{
/* Version 18 */
.
data_bytes
=
901
,
.
apat
=
{
6
,
30
,
56
,
82
,
0
},
.
ecc
=
{
{.
bs
=
69
,
.
dw
=
43
,
.
ns
=
9
},
{.
bs
=
150
,
.
dw
=
120
,
.
ns
=
5
},
{.
bs
=
42
,
.
dw
=
14
,
.
ns
=
2
},
{.
bs
=
50
,
.
dw
=
22
,
.
ns
=
17
}
}
},
{
/* Version 19 */
.
data_bytes
=
991
,
.
apat
=
{
6
,
30
,
58
,
86
,
0
},
.
ecc
=
{
{.
bs
=
70
,
.
dw
=
44
,
.
ns
=
3
},
{.
bs
=
141
,
.
dw
=
113
,
.
ns
=
3
},
{.
bs
=
39
,
.
dw
=
13
,
.
ns
=
9
},
{.
bs
=
47
,
.
dw
=
21
,
.
ns
=
17
}
}
},
{
/* Version 20 */
.
data_bytes
=
1085
,
.
apat
=
{
6
,
34
,
62
,
90
,
0
},
.
ecc
=
{
{.
bs
=
67
,
.
dw
=
41
,
.
ns
=
3
},
{.
bs
=
135
,
.
dw
=
107
,
.
ns
=
3
},
{.
bs
=
43
,
.
dw
=
15
,
.
ns
=
15
},
{.
bs
=
54
,
.
dw
=
24
,
.
ns
=
15
}
}
},
{
/* Version 21 */
.
data_bytes
=
1156
,
.
apat
=
{
6
,
28
,
50
,
72
,
92
,
0
},
.
ecc
=
{
{.
bs
=
68
,
.
dw
=
42
,
.
ns
=
17
},
{.
bs
=
144
,
.
dw
=
116
,
.
ns
=
4
},
{.
bs
=
46
,
.
dw
=
16
,
.
ns
=
19
},
{.
bs
=
50
,
.
dw
=
22
,
.
ns
=
17
}
}
},
{
/* Version 22 */
.
data_bytes
=
1258
,
.
apat
=
{
6
,
26
,
50
,
74
,
98
,
0
},
.
ecc
=
{
{.
bs
=
74
,
.
dw
=
46
,
.
ns
=
17
},
{.
bs
=
139
,
.
dw
=
111
,
.
ns
=
2
},
{.
bs
=
37
,
.
dw
=
13
,
.
ns
=
34
},
{.
bs
=
54
,
.
dw
=
24
,
.
ns
=
7
}
}
},
{
/* Version 23 */
.
data_bytes
=
1364
,
.
apat
=
{
6
,
30
,
54
,
78
,
102
,
0
},
.
ecc
=
{
{.
bs
=
75
,
.
dw
=
47
,
.
ns
=
4
},
{.
bs
=
151
,
.
dw
=
121
,
.
ns
=
4
},
{.
bs
=
45
,
.
dw
=
15
,
.
ns
=
16
},
{.
bs
=
54
,
.
dw
=
24
,
.
ns
=
11
}
}
},
{
/* Version 24 */
.
data_bytes
=
1474
,
.
apat
=
{
6
,
28
,
54
,
80
,
106
,
0
},
.
ecc
=
{
{.
bs
=
73
,
.
dw
=
45
,
.
ns
=
6
},
{.
bs
=
147
,
.
dw
=
117
,
.
ns
=
6
},
{.
bs
=
46
,
.
dw
=
16
,
.
ns
=
30
},
{.
bs
=
54
,
.
dw
=
24
,
.
ns
=
11
}
}
},
{
/* Version 25 */
.
data_bytes
=
1588
,
.
apat
=
{
6
,
32
,
58
,
84
,
110
,
0
},
.
ecc
=
{
{.
bs
=
75
,
.
dw
=
47
,
.
ns
=
8
},
{.
bs
=
132
,
.
dw
=
106
,
.
ns
=
8
},
{.
bs
=
45
,
.
dw
=
15
,
.
ns
=
22
},
{.
bs
=
54
,
.
dw
=
24
,
.
ns
=
7
}
}
},
{
/* Version 26 */
.
data_bytes
=
1706
,
.
apat
=
{
6
,
30
,
58
,
86
,
114
,
0
},
.
ecc
=
{
{.
bs
=
74
,
.
dw
=
46
,
.
ns
=
19
},
{.
bs
=
142
,
.
dw
=
114
,
.
ns
=
10
},
{.
bs
=
46
,
.
dw
=
16
,
.
ns
=
33
},
{.
bs
=
50
,
.
dw
=
22
,
.
ns
=
28
}
}
},
{
/* Version 27 */
.
data_bytes
=
1828
,
.
apat
=
{
6
,
34
,
62
,
90
,
118
,
0
},
.
ecc
=
{
{.
bs
=
73
,
.
dw
=
45
,
.
ns
=
22
},
{.
bs
=
152
,
.
dw
=
122
,
.
ns
=
8
},
{.
bs
=
45
,
.
dw
=
15
,
.
ns
=
12
},
{.
bs
=
53
,
.
dw
=
23
,
.
ns
=
8
}
}
},
{
/* Version 28 */
.
data_bytes
=
1921
,
.
apat
=
{
6
,
26
,
50
,
74
,
98
,
122
,
0
},
.
ecc
=
{
{.
bs
=
73
,
.
dw
=
45
,
.
ns
=
3
},
{.
bs
=
147
,
.
dw
=
117
,
.
ns
=
3
},
{.
bs
=
45
,
.
dw
=
15
,
.
ns
=
11
},
{.
bs
=
54
,
.
dw
=
24
,
.
ns
=
4
}
}
},
{
/* Version 29 */
.
data_bytes
=
2051
,
.
apat
=
{
6
,
30
,
54
,
78
,
102
,
126
,
0
},
.
ecc
=
{
{.
bs
=
73
,
.
dw
=
45
,
.
ns
=
21
},
{.
bs
=
146
,
.
dw
=
116
,
.
ns
=
7
},
{.
bs
=
45
,
.
dw
=
15
,
.
ns
=
19
},
{.
bs
=
53
,
.
dw
=
23
,
.
ns
=
1
}
}
},
{
/* Version 30 */
.
data_bytes
=
2185
,
.
apat
=
{
6
,
26
,
52
,
78
,
104
,
130
,
0
},
.
ecc
=
{
{.
bs
=
75
,
.
dw
=
47
,
.
ns
=
19
},
{.
bs
=
145
,
.
dw
=
115
,
.
ns
=
5
},
{.
bs
=
45
,
.
dw
=
15
,
.
ns
=
23
},
{.
bs
=
54
,
.
dw
=
24
,
.
ns
=
15
}
}
},
{
/* Version 31 */
.
data_bytes
=
2323
,
.
apat
=
{
6
,
30
,
56
,
82
,
108
,
134
,
0
},
.
ecc
=
{
{.
bs
=
74
,
.
dw
=
46
,
.
ns
=
2
},
{.
bs
=
145
,
.
dw
=
115
,
.
ns
=
13
},
{.
bs
=
45
,
.
dw
=
15
,
.
ns
=
23
},
{.
bs
=
54
,
.
dw
=
24
,
.
ns
=
42
}
}
},
{
/* Version 32 */
.
data_bytes
=
2465
,
.
apat
=
{
6
,
34
,
60
,
86
,
112
,
138
,
0
},
.
ecc
=
{
{.
bs
=
74
,
.
dw
=
46
,
.
ns
=
10
},
{.
bs
=
145
,
.
dw
=
115
,
.
ns
=
17
},
{.
bs
=
45
,
.
dw
=
15
,
.
ns
=
19
},
{.
bs
=
54
,
.
dw
=
24
,
.
ns
=
10
}
}
},
{
/* Version 33 */
.
data_bytes
=
2611
,
.
apat
=
{
6
,
30
,
58
,
86
,
114
,
142
,
0
},
.
ecc
=
{
{.
bs
=
74
,
.
dw
=
46
,
.
ns
=
14
},
{.
bs
=
145
,
.
dw
=
115
,
.
ns
=
17
},
{.
bs
=
45
,
.
dw
=
15
,
.
ns
=
11
},
{.
bs
=
54
,
.
dw
=
24
,
.
ns
=
29
}
}
},
{
/* Version 34 */
.
data_bytes
=
2761
,
.
apat
=
{
6
,
34
,
62
,
90
,
118
,
146
,
0
},
.
ecc
=
{
{.
bs
=
74
,
.
dw
=
46
,
.
ns
=
14
},
{.
bs
=
145
,
.
dw
=
115
,
.
ns
=
13
},
{.
bs
=
46
,
.
dw
=
16
,
.
ns
=
59
},
{.
bs
=
54
,
.
dw
=
24
,
.
ns
=
44
}
}
},
{
/* Version 35 */
.
data_bytes
=
2876
,
.
apat
=
{
6
,
30
,
54
,
78
,
102
,
126
,
150
},
.
ecc
=
{
{.
bs
=
75
,
.
dw
=
47
,
.
ns
=
12
},
{.
bs
=
151
,
.
dw
=
121
,
.
ns
=
12
},
{.
bs
=
45
,
.
dw
=
15
,
.
ns
=
22
},
{.
bs
=
54
,
.
dw
=
24
,
.
ns
=
39
}
}
},
{
/* Version 36 */
.
data_bytes
=
3034
,
.
apat
=
{
6
,
24
,
50
,
76
,
102
,
128
,
154
},
.
ecc
=
{
{.
bs
=
75
,
.
dw
=
47
,
.
ns
=
6
},
{.
bs
=
151
,
.
dw
=
121
,
.
ns
=
6
},
{.
bs
=
45
,
.
dw
=
15
,
.
ns
=
2
},
{.
bs
=
54
,
.
dw
=
24
,
.
ns
=
46
}
}
},
{
/* Version 37 */
.
data_bytes
=
3196
,
.
apat
=
{
6
,
28
,
54
,
80
,
106
,
132
,
158
},
.
ecc
=
{
{.
bs
=
74
,
.
dw
=
46
,
.
ns
=
29
},
{.
bs
=
152
,
.
dw
=
122
,
.
ns
=
17
},
{.
bs
=
45
,
.
dw
=
15
,
.
ns
=
24
},
{.
bs
=
54
,
.
dw
=
24
,
.
ns
=
49
}
}
},
{
/* Version 38 */
.
data_bytes
=
3362
,
.
apat
=
{
6
,
32
,
58
,
84
,
110
,
136
,
162
},
.
ecc
=
{
{.
bs
=
74
,
.
dw
=
46
,
.
ns
=
13
},
{.
bs
=
152
,
.
dw
=
122
,
.
ns
=
4
},
{.
bs
=
45
,
.
dw
=
15
,
.
ns
=
42
},
{.
bs
=
54
,
.
dw
=
24
,
.
ns
=
48
}
}
},
{
/* Version 39 */
.
data_bytes
=
3532
,
.
apat
=
{
6
,
26
,
54
,
82
,
110
,
138
,
166
},
.
ecc
=
{
{.
bs
=
75
,
.
dw
=
47
,
.
ns
=
40
},
{.
bs
=
147
,
.
dw
=
117
,
.
ns
=
20
},
{.
bs
=
45
,
.
dw
=
15
,
.
ns
=
10
},
{.
bs
=
54
,
.
dw
=
24
,
.
ns
=
43
}
}
},
{
/* Version 40 */
.
data_bytes
=
3706
,
.
apat
=
{
6
,
30
,
58
,
86
,
114
,
142
,
170
},
.
ecc
=
{
{.
bs
=
75
,
.
dw
=
47
,
.
ns
=
18
},
{.
bs
=
148
,
.
dw
=
118
,
.
ns
=
19
},
{.
bs
=
45
,
.
dw
=
15
,
.
ns
=
20
},
{.
bs
=
54
,
.
dw
=
24
,
.
ns
=
34
}
}
}
};
CMakeLists.txt
View file @
53ec8f28
...
...
@@ -282,6 +282,7 @@ OCV_OPTION(WITH_PROTOBUF "Enable libprotobuf" ON
OCV_OPTION
(
WITH_IMGCODEC_HDR
"Include HDR support"
ON
)
OCV_OPTION
(
WITH_IMGCODEC_SUNRASTER
"Include SUNRASTER support"
ON
)
OCV_OPTION
(
WITH_IMGCODEC_PXM
"Include PNM (PBM,PGM,PPM) and PAM formats support"
ON
)
OCV_OPTION
(
WITH_QUIRC
"Include library QR-code decoding"
ON
)
# OpenCV build components
# ===================================================
...
...
@@ -700,6 +701,10 @@ if(WITH_OPENVX)
include
(
cmake/FindOpenVX.cmake
)
endif
()
if
(
WITH_QUIRC
)
add_subdirectory
(
3rdparty/quirc
)
set
(
HAVE_QUIRC TRUE
)
endif
()
# ----------------------------------------------------------------------------
# OpenCV HAL
# ----------------------------------------------------------------------------
...
...
cmake/templates/cvconfig.h.in
View file @
53ec8f28
...
...
@@ -241,5 +241,7 @@
/* OpenCV trace utilities */
#cmakedefine OPENCV_TRACE
/* Library QR-code decoding */
#cmakedefine HAVE_QUIRC
#endif // OPENCV_CVCONFIG_H_INCLUDED
modules/objdetect/CMakeLists.txt
View file @
53ec8f28
set
(
the_description
"Object Detection"
)
ocv_define_module
(
objdetect opencv_core opencv_imgproc WRAP java python js
)
ocv_define_module
(
objdetect opencv_core opencv_imgproc opencv_calib3d WRAP java python js
)
if
(
HAVE_QUIRC
)
get_property
(
QUIRC_INCLUDE GLOBAL PROPERTY QUIRC_INCLUDE_DIR
)
ocv_include_directories
(
${
QUIRC_INCLUDE
}
)
ocv_target_link_libraries
(
${
PROJECT_NAME
}
quirc
)
endif
()
modules/objdetect/include/opencv2/objdetect.hpp
View file @
53ec8f28
...
...
@@ -693,6 +693,13 @@ protected:
*/
CV_EXPORTS
bool
detectQRCode
(
InputArray
in
,
std
::
vector
<
Point
>
&
points
,
double
eps_x
=
0.2
,
double
eps_y
=
0.1
);
/** @brief Decode QR code in image and return text that is encrypted in QR code.
@param in Matrix of the type CV_8UC1 containing an image where QR code are detected.
@param points Input vector of vertices of a quadrangle of minimal area that describes QR code.
@param decoded_info String information that is encrypted in QR code.
@param straight_qrcode Matrix of the type CV_8UC1 containing an binary straight QR code.
*/
CV_EXPORTS
bool
decodeQRCode
(
InputArray
in
,
InputArray
points
,
std
::
string
&
decoded_info
,
OutputArray
straight_qrcode
=
noArray
());
//! @} objdetect
}
...
...
modules/objdetect/src/qrcode.cpp
View file @
53ec8f28
...
...
@@ -7,10 +7,16 @@
#include "precomp.hpp"
#include "opencv2/objdetect.hpp"
#include "opencv2/calib3d.hpp"
#ifdef HAVE_QUIRC
#include "quirc.h"
#endif
#include <limits>
#include <cmath>
#include <iostream>
#include <queue>
namespace
cv
{
...
...
@@ -25,11 +31,11 @@ public:
Mat
getBinBarcode
()
{
return
bin_barcode
;
}
Mat
getStraightBarcode
()
{
return
straight_barcode
;
}
vector
<
Point2f
>
getTransformationPoints
()
{
return
transformation_points
;
}
static
Point2f
intersectionLines
(
Point2f
a1
,
Point2f
a2
,
Point2f
b1
,
Point2f
b2
);
protected
:
vector
<
Vec3d
>
searchHorizontalLines
();
vector
<
Point2f
>
separateVerticalLines
(
const
vector
<
Vec3d
>
&
list_lines
);
void
fixationPoints
(
vector
<
Point2f
>
&
local_point
);
Point2f
intersectionLines
(
Point2f
a1
,
Point2f
a2
,
Point2f
b1
,
Point2f
b2
);
vector
<
Point2f
>
getQuadrilateral
(
vector
<
Point2f
>
angle_list
);
bool
testBypassRoute
(
vector
<
Point2f
>
hull
,
int
start
,
int
finish
);
inline
double
getCosVectors
(
Point2f
a
,
Point2f
b
,
Point2f
c
);
...
...
@@ -61,6 +67,7 @@ void QRDetect::init(const Mat& src, double eps_vertical_, double eps_horizontal_
eps_vertical
=
eps_vertical_
;
eps_horizontal
=
eps_horizontal_
;
adaptiveThreshold
(
barcode
,
bin_barcode
,
255
,
ADAPTIVE_THRESH_GAUSSIAN_C
,
THRESH_BINARY
,
83
,
2
);
}
vector
<
Vec3d
>
QRDetect
::
searchHorizontalLines
()
...
...
@@ -538,7 +545,7 @@ vector<Point2f> QRDetect::getQuadrilateral(vector<Point2f> angle_list)
vector
<
Point
>
locations
;
Mat
mask_roi
=
mask
(
Range
(
1
,
bin_barcode
.
rows
-
1
),
Range
(
1
,
bin_barcode
.
cols
-
1
));
cv
::
findNonZero
(
mask_roi
,
locations
);
findNonZero
(
mask_roi
,
locations
);
for
(
size_t
i
=
0
;
i
<
angle_list
.
size
();
i
++
)
{
...
...
@@ -783,7 +790,7 @@ bool QRCodeDetector::detect(InputArray in, OutputArray points) const
return
true
;
}
CV_EXPORTS
bool
detectQRCode
(
InputArray
in
,
std
::
vector
<
Point
>
&
points
,
double
eps_x
,
double
eps_y
)
CV_EXPORTS
bool
detectQRCode
(
InputArray
in
,
vector
<
Point
>
&
points
,
double
eps_x
,
double
eps_y
)
{
QRCodeDetector
qrdetector
;
qrdetector
.
setEpsX
(
eps_x
);
...
...
@@ -792,4 +799,276 @@ CV_EXPORTS bool detectQRCode(InputArray in, std::vector<Point> &points, double e
return
qrdetector
.
detect
(
in
,
points
);
}
class
QRDecode
{
public
:
void
init
(
const
Mat
&
src
,
const
vector
<
Point2f
>
&
points
);
Mat
getIntermediateBarcode
()
{
return
intermediate
;
}
Mat
getStraightBarcode
()
{
return
straight
;
}
size_t
getVersion
()
{
return
version
;
}
std
::
string
getDecodeInformation
()
{
return
result_info
;
}
bool
fullDecodingProcess
();
protected
:
bool
updatePerspective
();
bool
versionDefinition
();
bool
samplingForVersion
();
bool
decodingProcess
();
Mat
original
,
no_border_intermediate
,
intermediate
,
straight
;
vector
<
Point2f
>
original_points
;
std
::
string
result_info
;
uint8_t
version
,
version_size
;
float
test_perspective_size
;
};
void
QRDecode
::
init
(
const
Mat
&
src
,
const
vector
<
Point2f
>
&
points
)
{
original
=
src
.
clone
();
intermediate
=
Mat
::
zeros
(
src
.
size
(),
CV_8UC1
);
original_points
=
points
;
version
=
0
;
version_size
=
0
;
test_perspective_size
=
251
;
result_info
=
""
;
}
bool
QRDecode
::
updatePerspective
()
{
const
Size
temporary_size
(
cvRound
(
test_perspective_size
),
cvRound
(
test_perspective_size
));
vector
<
Point2f
>
perspective_points
;
perspective_points
.
push_back
(
Point2f
(
0.
f
,
0.
f
));
perspective_points
.
push_back
(
Point2f
(
test_perspective_size
,
0.
f
));
perspective_points
.
push_back
(
Point2f
(
static_cast
<
float
>
(
test_perspective_size
*
0.5
),
static_cast
<
float
>
(
test_perspective_size
*
0.5
)));
original_points
.
insert
(
original_points
.
begin
()
+
2
,
QRDetect
::
intersectionLines
(
original_points
[
0
],
original_points
[
2
],
original_points
[
1
],
original_points
[
3
]));
perspective_points
.
push_back
(
Point2f
(
test_perspective_size
,
test_perspective_size
));
perspective_points
.
push_back
(
Point2f
(
0.
f
,
test_perspective_size
));
Mat
H
=
findHomography
(
original_points
,
perspective_points
);
Mat
bin_original
=
Mat
::
zeros
(
original
.
size
(),
CV_8UC1
);
adaptiveThreshold
(
original
,
bin_original
,
255
,
ADAPTIVE_THRESH_GAUSSIAN_C
,
THRESH_BINARY
,
83
,
2
);
Mat
temp_intermediate
=
Mat
::
zeros
(
temporary_size
,
CV_8UC1
);
warpPerspective
(
bin_original
,
temp_intermediate
,
H
,
temporary_size
,
INTER_NEAREST
);
no_border_intermediate
=
temp_intermediate
(
Range
(
1
,
temp_intermediate
.
rows
),
Range
(
1
,
temp_intermediate
.
cols
));
const
int
border
=
cvRound
(
0.1
*
test_perspective_size
);
const
int
borderType
=
BORDER_CONSTANT
;
copyMakeBorder
(
no_border_intermediate
,
intermediate
,
border
,
border
,
border
,
border
,
borderType
,
Scalar
(
255
));
return
true
;
}
bool
QRDecode
::
versionDefinition
()
{
LineIterator
line_iter
(
intermediate
,
Point2f
(
0
,
0
),
Point2f
(
test_perspective_size
,
test_perspective_size
));
Point
black_point
=
Point
(
0
,
0
);
for
(
int
j
=
0
;
j
<
line_iter
.
count
;
j
++
,
++
line_iter
)
{
const
uint8_t
value
=
intermediate
.
at
<
uint8_t
>
(
line_iter
.
pos
());
if
(
value
==
0
)
{
black_point
=
line_iter
.
pos
();
break
;
}
}
Mat
mask
=
Mat
::
zeros
(
intermediate
.
rows
+
2
,
intermediate
.
cols
+
2
,
CV_8UC1
);
floodFill
(
intermediate
,
mask
,
black_point
,
255
,
0
,
Scalar
(),
Scalar
(),
FLOODFILL_MASK_ONLY
);
vector
<
Point
>
locations
,
non_zero_elem
;
Mat
mask_roi
=
mask
(
Range
(
1
,
intermediate
.
rows
-
1
),
Range
(
1
,
intermediate
.
cols
-
1
));
findNonZero
(
mask_roi
,
non_zero_elem
);
convexHull
(
Mat
(
non_zero_elem
),
locations
);
Point
temp_remote
=
locations
[
0
],
remote_point
;
const
Point
delta_diff
=
Point
(
4
,
4
);
for
(
size_t
i
=
0
;
i
<
locations
.
size
();
i
++
)
{
if
(
norm
(
black_point
-
temp_remote
)
<
norm
(
black_point
-
locations
[
i
]))
{
const
uint8_t
value
=
intermediate
.
at
<
uint8_t
>
(
temp_remote
-
delta_diff
);
if
(
value
==
0
)
{
remote_point
=
temp_remote
-
delta_diff
;
}
else
{
remote_point
=
temp_remote
;
}
temp_remote
=
locations
[
i
];
}
}
size_t
transition_x
=
0
,
transition_y
=
0
;
uint8_t
future_pixel
=
255
;
const
uint8_t
*
intermediate_row
=
intermediate
.
ptr
<
uint8_t
>
(
remote_point
.
y
);
for
(
int
i
=
remote_point
.
x
;
i
<
intermediate
.
cols
;
i
++
)
{
if
(
intermediate_row
[
i
]
==
future_pixel
)
{
future_pixel
=
255
-
future_pixel
;
transition_x
++
;
}
}
future_pixel
=
255
;
for
(
int
j
=
remote_point
.
y
;
j
<
intermediate
.
rows
;
j
++
)
{
const
uint8_t
value
=
intermediate
.
at
<
uint8_t
>
(
Point
(
j
,
remote_point
.
x
));
if
(
value
==
future_pixel
)
{
future_pixel
=
255
-
future_pixel
;
transition_y
++
;
}
}
version
=
saturate_cast
<
uint8_t
>
((
std
::
min
(
transition_x
,
transition_y
)
-
1
)
*
0.25
-
1
);
if
(
!
(
0
<
version
&&
version
<=
40
)
)
{
return
false
;
}
version_size
=
21
+
(
version
-
1
)
*
4
;
return
true
;
}
bool
QRDecode
::
samplingForVersion
()
{
const
double
multiplyingFactor
=
(
version
<
3
)
?
1
:
(
version
==
3
)
?
1.5
:
version
*
(
5
+
version
-
4
);
const
Size
newFactorSize
(
cvRound
(
no_border_intermediate
.
size
().
width
*
multiplyingFactor
),
cvRound
(
no_border_intermediate
.
size
().
height
*
multiplyingFactor
));
Mat
postIntermediate
(
newFactorSize
,
CV_8UC1
);
resize
(
no_border_intermediate
,
postIntermediate
,
newFactorSize
,
0
,
0
,
INTER_AREA
);
const
int
no_inter_rows
=
postIntermediate
.
rows
;
const
int
no_inter_cols
=
postIntermediate
.
cols
;
const
int
delta_rows
=
cvRound
((
no_inter_rows
*
1.0
)
/
version_size
);
const
int
delta_cols
=
cvRound
((
no_inter_cols
*
1.0
)
/
version_size
);
vector
<
double
>
listFrequencyElem
;
for
(
int
r
=
0
;
r
<
no_inter_rows
;
r
+=
delta_rows
)
{
for
(
int
c
=
0
;
c
<
no_inter_cols
;
c
+=
delta_cols
)
{
Mat
tile
=
postIntermediate
(
Range
(
r
,
min
(
r
+
delta_rows
,
no_inter_rows
)),
Range
(
c
,
min
(
c
+
delta_cols
,
no_inter_cols
)));
const
double
frequencyElem
=
(
countNonZero
(
tile
)
*
1.0
)
/
tile
.
total
();
listFrequencyElem
.
push_back
(
frequencyElem
);
}
}
double
dispersionEFE
=
std
::
numeric_limits
<
double
>::
max
();
double
experimentalFrequencyElem
=
0
;
for
(
double
expVal
=
0
;
expVal
<
1
;
expVal
+=
0.001
)
{
double
testDispersionEFE
=
0.0
;
for
(
size_t
i
=
0
;
i
<
listFrequencyElem
.
size
();
i
++
)
{
testDispersionEFE
+=
(
listFrequencyElem
[
i
]
-
expVal
)
*
(
listFrequencyElem
[
i
]
-
expVal
);
}
testDispersionEFE
/=
(
listFrequencyElem
.
size
()
-
1
);
if
(
dispersionEFE
>
testDispersionEFE
)
{
dispersionEFE
=
testDispersionEFE
;
experimentalFrequencyElem
=
expVal
;
}
}
straight
=
Mat
(
Size
(
version_size
,
version_size
),
CV_8UC1
,
Scalar
(
0
));
size_t
k
=
0
;
for
(
int
r
=
0
;
r
<
no_inter_rows
&&
k
<
listFrequencyElem
.
size
()
&&
floor
((
r
*
1.0
)
/
delta_rows
)
<
version_size
;
r
+=
delta_rows
)
{
for
(
int
c
=
0
;
c
<
no_inter_cols
&&
k
<
listFrequencyElem
.
size
()
&&
floor
((
c
*
1.0
)
/
delta_cols
)
<
version_size
;
c
+=
delta_cols
,
k
++
)
{
Mat
tile
=
postIntermediate
(
Range
(
r
,
min
(
r
+
delta_rows
,
no_inter_rows
)),
Range
(
c
,
min
(
c
+
delta_cols
,
no_inter_cols
)));
if
(
listFrequencyElem
[
k
]
<
experimentalFrequencyElem
)
{
tile
.
setTo
(
0
);
}
else
{
tile
.
setTo
(
255
);
straight
.
at
<
uint8_t
>
(
cvRound
(
floor
((
r
*
1.0
)
/
delta_rows
)),
cvRound
(
floor
((
c
*
1.0
)
/
delta_cols
)))
=
255
;
}
}
}
return
true
;
}
bool
QRDecode
::
decodingProcess
()
{
#ifdef HAVE_QUIRC
if
(
straight
.
empty
())
{
return
false
;
}
quirc_code
qr_code
;
memset
(
&
qr_code
,
0
,
sizeof
(
qr_code
));
qr_code
.
size
=
straight
.
size
().
width
;
for
(
int
x
=
0
;
x
<
qr_code
.
size
;
x
++
)
{
for
(
int
y
=
0
;
y
<
qr_code
.
size
;
y
++
)
{
int
position
=
y
*
qr_code
.
size
+
x
;
qr_code
.
cell_bitmap
[
position
>>
3
]
|=
straight
.
at
<
uint8_t
>
(
y
,
x
)
?
0
:
(
1
<<
(
position
&
7
));
}
}
quirc_data
qr_code_data
;
quirc_decode_error_t
errorCode
=
quirc_decode
(
&
qr_code
,
&
qr_code_data
);
if
(
errorCode
!=
0
)
{
return
false
;
}
for
(
int
i
=
0
;
i
<
qr_code_data
.
payload_len
;
i
++
)
{
result_info
+=
qr_code_data
.
payload
[
i
];
}
return
true
;
#else
return
false
;
#endif
}
bool
QRDecode
::
fullDecodingProcess
()
{
#ifdef HAVE_QUIRC
if
(
!
updatePerspective
())
{
return
false
;
}
if
(
!
versionDefinition
())
{
return
false
;
}
if
(
!
samplingForVersion
())
{
return
false
;
}
if
(
!
decodingProcess
())
{
return
false
;
}
return
true
;
#else
std
::
cout
<<
"Library QUIRC is not linked. No decoding is performed. Take it to the OpenCV repository."
<<
std
::
endl
;
return
false
;
#endif
}
CV_EXPORTS
bool
decodeQRCode
(
InputArray
in
,
InputArray
points
,
std
::
string
&
decoded_info
,
OutputArray
straight_qrcode
)
{
Mat
inarr
=
in
.
getMat
();
CV_Assert
(
!
inarr
.
empty
());
inarr
.
convertTo
(
inarr
,
CV_8UC1
);
CV_Assert
(
points
.
isVector
());
vector
<
Point2f
>
src_points
;
points
.
copyTo
(
src_points
);
CV_Assert
(
src_points
.
size
()
==
4
);
QRDecode
qrdec
;
qrdec
.
init
(
inarr
,
src_points
);
bool
exit_flag
=
qrdec
.
fullDecodingProcess
();
decoded_info
=
qrdec
.
getDecodeInformation
();
if
(
straight_qrcode
.
needed
())
{
qrdec
.
getStraightBarcode
().
convertTo
(
straight_qrcode
,
straight_qrcode
.
fixedType
()
?
straight_qrcode
.
type
()
:
CV_32FC2
);
}
return
exit_flag
;
}
}
modules/objdetect/test/test_qrcode.cpp
View file @
53ec8f28
...
...
@@ -4,19 +4,15 @@
#include "test_precomp.hpp"
namespace
opencv_test
{
namespace
{
std
::
string
qrcode_images_name
[]
=
{
// "20110817_030.jpg",
"20110817_048.jpg"
,
"img_20120226_161648.jpg"
,
"img_2714.jpg"
,
"img_2716.jpg"
,
"img_3011.jpg"
,
"img_3029.jpg"
,
"img_3070.jpg"
,
"qr_test_030.jpg"
"version_1_down.jpg"
,
"version_1_left.jpg"
,
"version_1_right.jpg"
,
"version_1_up.jpg"
,
"version_1_top.jpg"
,
"version_2_down.jpg"
,
"version_2_left.jpg"
,
"version_2_right.jpg"
,
"version_2_up.jpg"
,
"version_2_top.jpg"
,
"version_3_down.jpg"
,
"version_3_left.jpg"
,
"version_3_right.jpg"
,
"version_3_up.jpg"
,
"version_3_top.jpg"
,
"version_4_down.jpg"
,
"version_4_left.jpg"
,
"version_4_right.jpg"
,
"version_4_up.jpg"
,
"version_4_top.jpg"
,
"version_5_down.jpg"
,
"version_5_left.jpg"
,
"version_5_right.jpg"
,
"version_5_up.jpg"
,
"version_5_top.jpg"
,
"russian.jpg"
,
"kanji.jpg"
,
"link_github_ocv.jpg"
,
"link_ocv.jpg"
,
"link_wiki_cv.jpg"
};
// #define UPDATE_QRCODE_TEST_DATA
...
...
@@ -35,15 +31,21 @@ TEST(Objdetect_QRCode, generate_test_data)
file_config
<<
"{:"
<<
"image_name"
<<
qrcode_images_name
[
i
];
std
::
string
image_path
=
findDataFile
(
root
+
qrcode_images_name
[
i
]);
std
::
vector
<
Point
>
corners
;
Mat
src
=
imread
(
image_path
,
IMREAD_GRAYSCALE
);
Mat
src
=
imread
(
image_path
,
IMREAD_GRAYSCALE
),
straight_barcode
;
std
::
string
decoded_info
;
ASSERT_FALSE
(
src
.
empty
())
<<
"Can't read image: "
<<
image_path
;
EXPECT_TRUE
(
detectQRCode
(
src
,
corners
));
#ifdef HAVE_QUIRC
EXPECT_TRUE
(
decodeQRCode
(
src
,
corners
,
decoded_info
,
straight_barcode
));
#endif
file_config
<<
"x"
<<
"[:"
;
for
(
size_t
j
=
0
;
j
<
corners
.
size
();
j
++
)
{
file_config
<<
corners
[
j
].
x
;
}
file_config
<<
"]"
;
file_config
<<
"y"
<<
"[:"
;
for
(
size_t
j
=
0
;
j
<
corners
.
size
();
j
++
)
{
file_config
<<
corners
[
j
].
y
;
}
file_config
<<
"]"
<<
"}"
;
file_config
<<
"]"
;
file_config
<<
"info"
<<
decoded_info
;
file_config
<<
"}"
;
}
file_config
<<
"]"
;
file_config
.
release
();
...
...
@@ -59,11 +61,15 @@ TEST_P(Objdetect_QRCode, regression)
const
int
pixels_error
=
3
;
std
::
string
image_path
=
findDataFile
(
root
+
name_current_image
);
Mat
src
=
imread
(
image_path
,
IMREAD_GRAYSCALE
);
Mat
src
=
imread
(
image_path
,
IMREAD_GRAYSCALE
)
,
straight_barcode
;
ASSERT_FALSE
(
src
.
empty
())
<<
"Can't read image: "
<<
image_path
;
std
::
vector
<
Point
>
corners
;
std
::
string
decoded_info
;
ASSERT_TRUE
(
detectQRCode
(
src
,
corners
));
#ifdef HAVE_QUIRC
ASSERT_TRUE
(
decodeQRCode
(
src
,
corners
,
decoded_info
,
straight_barcode
));
#endif
const
std
::
string
dataset_config
=
findDataFile
(
root
+
"dataset_config.json"
,
false
);
FileStorage
file_config
(
dataset_config
,
FileStorage
::
READ
);
...
...
@@ -86,6 +92,12 @@ TEST_P(Objdetect_QRCode, regression)
EXPECT_NEAR
(
x
,
corners
[
i
].
x
,
pixels_error
);
EXPECT_NEAR
(
y
,
corners
[
i
].
y
,
pixels_error
);
}
#ifdef HAVE_QUIRC
std
::
string
original_info
=
config
[
"info"
];
EXPECT_EQ
(
decoded_info
,
original_info
);
#endif
return
;
// done
}
}
...
...
@@ -103,9 +115,14 @@ INSTANTIATE_TEST_CASE_P(/**/, Objdetect_QRCode, testing::ValuesIn(qrcode_images_
TEST
(
Objdetect_QRCode_basic
,
not_found_qrcode
)
{
std
::
vector
<
Point
>
corners
;
std
::
vector
<
Point
>
corners
,
straight_barcode
;
std
::
string
decoded_info
;
Mat
zero_image
=
Mat
::
zeros
(
256
,
256
,
CV_8UC1
);
EXPECT_FALSE
(
detectQRCode
(
zero_image
,
corners
));
#ifdef HAVE_QUIRC
corners
=
std
::
vector
<
Point
>
(
4
);
EXPECT_FALSE
(
decodeQRCode
(
zero_image
,
corners
,
decoded_info
,
straight_barcode
));
#endif
}
...
...
samples/cpp/live_detect_qrcode.cpp
View file @
53ec8f28
...
...
@@ -89,7 +89,8 @@ int liveQRCodeDetect()
TickMeter
total
;
for
(;;)
{
Mat
frame
,
src
;
Mat
frame
,
src
,
straight_barcode
;
string
decode_info
;
vector
<
Point
>
transform
;
cap
>>
frame
;
if
(
frame
.
empty
())
{
break
;
}
...
...
@@ -97,6 +98,11 @@ int liveQRCodeDetect()
total
.
start
();
bool
result_detection
=
detectQRCode
(
src
,
transform
);
if
(
result_detection
)
{
bool
result_decode
=
decodeQRCode
(
src
,
transform
,
decode_info
,
straight_barcode
);
if
(
result_decode
)
{
cout
<<
decode_info
<<
'\n'
;
}
}
total
.
stop
();
double
fps
=
1
/
total
.
getTimeSec
();
total
.
reset
();
...
...
@@ -112,11 +118,12 @@ int liveQRCodeDetect()
int
showImageQRCodeDetect
(
string
in
,
string
out
)
{
Mat
src
=
imread
(
in
,
IMREAD_GRAYSCALE
);
Mat
src
=
imread
(
in
,
IMREAD_GRAYSCALE
),
straight_barcode
;
string
decode_info
;
vector
<
Point
>
transform
;
const
int
count_experiments
=
10
;
double
transform_time
=
0.0
;
bool
result_detection
=
false
;
bool
result_detection
=
false
,
result_decode
=
false
;
TickMeter
total
;
for
(
size_t
i
=
0
;
i
<
count_experiments
;
i
++
)
{
...
...
@@ -125,12 +132,20 @@ int showImageQRCodeDetect(string in, string out)
result_detection
=
detectQRCode
(
src
,
transform
);
total
.
stop
();
transform_time
+=
total
.
getTimeSec
();
total
.
reset
();
if
(
!
result_detection
)
{
break
;
}
total
.
start
();
result_decode
=
decodeQRCode
(
src
,
transform
,
decode_info
,
straight_barcode
);
total
.
stop
();
transform_time
+=
total
.
getTimeSec
();
total
.
reset
();
if
(
!
result_decode
)
{
break
;
}
}
double
fps
=
count_experiments
/
transform_time
;
if
(
!
result_detection
)
{
cout
<<
"Not find QR-code."
<<
'\n'
;
return
-
2
;
}
if
(
!
result_decode
)
{
cout
<<
"Not decode QR-code."
<<
'\n'
;
return
-
3
;
}
Mat
color_src
=
imread
(
in
);
getMatWithQRCodeContour
(
color_src
,
transform
);
...
...
@@ -151,6 +166,7 @@ int showImageQRCodeDetect(string in, string out)
cout
<<
"Output image file path: "
<<
out
<<
'\n'
;
cout
<<
"Size: "
<<
color_src
.
size
()
<<
'\n'
;
cout
<<
"FPS: "
<<
fps
<<
'\n'
;
cout
<<
"Decode info: "
<<
decode_info
<<
'\n'
;
vector
<
int
>
compression_params
;
compression_params
.
push_back
(
IMWRITE_PNG_COMPRESSION
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment