Detect and read QR codes with OpenCV in Python
This article describes how to detect and read QR codes with OpenCV in Python.
cv2.QRCodeDetector
- Detect and read QR codes from an image
- Detect and read QR codes from camera video
See the following article on how to create a QR code.
See the following article on how to detect and read barcodes instead of QR codes.
You can also use ZBar (pyzbar). Although not thoroughly verified, ZBar seems to have better detection accuracy.
The version of OpenCV used in the sample code is 4.6.0
.
import cv2
print(cv2.__version__)
# 4.6.0
cv2.QRCodeDetector
The cv2.QRCodeDetector
class is used to detect and read QR codes.
In version 4.3
, detectAndDecodeMulti()
was added to detect and decode multiple QR codes at once.
Although detect()
to only detect and decode()
to decode based on the detected coordinates are also provided, they are not mentioned here.
Detect and read QR codes from an image
The following image is used as an example.
The text stored in each QR Code is, from left to right, QR Code One
, QR Code Two
, and QR Code Three
. The rightmost QR Code is masked with a white square in the center to make it difficult to read.
img = cv2.imread('data/src/qrcode.png')
Create an instance of cv2.QRCodeDetector
and execute detectAndDecodeMulti()
. Note that the result may differ depending on the version and environment.
qcd = cv2.QRCodeDetector()
retval, decoded_info, points, straight_qrcode = qcd.detectAndDecodeMulti(img)
retval
is True
if a QR code is detected and False
if none is detected.
print(retval)
# True
decoded_info
is a tuple whose elements are strings stored in QR codes. If it can be detected but not decoded, it is an empty string ''
.
print(decoded_info)
# ('QR Code Two', '', 'QR Code One')
points
is a numpy.ndarray
representing the coordinates of the four corners of the detected QR Code.
print(type(points))
# <class 'numpy.ndarray'>
print(points)
# [[[290.9108 106.20954 ]
# [472.8162 0.8958926]
# [578.5836 184.1002 ]
# [396.0495 287.81277 ]]
#
# [[620. 40. ]
# [829. 40. ]
# [829. 249. ]
# [620. 249. ]]
#
# [[ 40. 40. ]
# [249. 40. ]
# [249. 249. ]
# [ 40. 249. ]]]
print(points.shape)
# (3, 4, 2)
straight_qrcode
is a tuple whose elements are numpy.ndarray
. The numpy.ndarray
is a binary value of 0
and 255
representing the black and white of each cell of the QR code.
print(points.shape)
# (3, 4, 2)
print(type(straight_qrcode))
# <class 'tuple'>
print(type(straight_qrcode[0]))
# <class 'numpy.ndarray'>
print(straight_qrcode[0].shape)
# (21, 21)
Draw frames for the detected QR code and superimpose the decoded text.
img = cv2.polylines(img, points.astype(int), True, (0, 255, 0), 3)
for s, p in zip(decoded_info, points):
img = cv2.putText(img, s, p[0].astype(int),
cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2, cv2.LINE_AA)
cv2.imwrite('data/dst/qrcode_opencv.jpg', img)
Detect and read QR codes from camera video
The following is a sample code that detects and reads barcodes from real-time camera video.
See the following article for more information on the handling of videos in OpenCV.
Press q
on the keyboard to exit.
import cv2
camera_id = 0
delay = 1
window_name = 'OpenCV QR Code'
qcd = cv2.QRCodeDetector()
cap = cv2.VideoCapture(camera_id)
while True:
ret, frame = cap.read()
if ret:
ret_qr, decoded_info, points, _ = qcd.detectAndDecodeMulti(frame)
if ret_qr:
for s, p in zip(decoded_info, points):
if s:
print(s)
color = (0, 255, 0)
else:
color = (0, 0, 255)
frame = cv2.polylines(frame, [p.astype(int)], True, color, 8)
cv2.imshow(window_name, frame)
if cv2.waitKey(delay) & 0xFF == ord('q'):
break
cv2.destroyWindow(window_name)
If a QR code can be detected but not decoded, a red frame is displayed; if it can be decoded, a green frame is displayed. If you want to display the decoded string, please refer to the still image example above.
In an actual application, the while
loop would be terminated by break
when the decoded_info
string is obtained, and the application would move on to operation using the string.