视频二维码检测

任务三

使用计算机读取视频或者摄像头,实时检测图像中的二维码(可用手机屏幕显示二维码),并将二维码的四角位置实时叠加在显示画面中,控制台打印输出二维码内容。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
import cv2
from PIL import Image, ImageDraw, ImageFont
import numpy as np

# 定义 draw_text 函数
def draw_text(img, text, pos, font, color):
img_pil = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
draw = ImageDraw.Draw(img_pil)
draw.text(pos, text, font=font, fill=color)
return cv2.cvtColor(np.array(img_pil), cv2.COLOR_RGB2BGR)

# 初始化摄像头
cap = cv2.VideoCapture(0)

# 创建二维码检测器
qr_code_detector = cv2.QRCodeDetector()

# 加载中文字体
font_path = "simhei.ttf" # 请确保路径正确,simhei.ttf 是黑体字体文件
font = ImageFont.truetype(font_path, 24)

while True:
# 读取摄像头帧
ret, frame = cap.read()
if not ret:
break

# 检测二维码
retval, decoded_info, points, straight_qrcode = qr_code_detector.detectAndDecodeMulti(frame)

if retval:
# 打印二维码内容
for info in decoded_info:
print("QR Code Content:", info)

# 绘制二维码的四角位置
if points is not None:
points = points.astype(int)
for i in range(len(points)):
for j in range(4):
cv2.line(frame, tuple(points[i][j]), tuple(points[i][(j + 1) % 4]), (0, 255, 0), 3)
# 在屏幕左上角显示四角的位置坐标
text = f"{points[i]}"
frame = draw_text(frame, text, (10, 30 + i * 30), font, (0, 255, 0))
else:
# 在屏幕左上角显示“未检测到二维码”
frame = draw_text(frame, "未检测到二维码", (10, 30), font, (255, 0, 0))

# 显示帧
cv2.imshow("QR Code Detection", frame)

# 按下 'q' 键退出
if cv2.waitKey(1) & 0xFF == ord('q'):
break

# 释放摄像头并关闭窗口
cap.release()
cv2.destroyAllWindows()

代码思路

先将需要的资源进行初始化,初始化摄像头资源,二维码检测器,并预先写好字体显示函数,要注意PIL库和openCV库的色彩顺序分别为RGB和BGR。然后在循环内持续读取视频帧实现连续播放,退出循环后的release()和destroyAllWindows()函数释放资源。循环内部先读取视频帧,然后对视频帧使用detectAndDecodeMulti()函数进行检测读取内容。使用line()函数依次连接判断出的二维码四角。。

代码解释

1
def draw_text(img, text, pos, font, color):

定义一个函数draw_text,用于在图像上绘制文本。

  1. img: 输入的 OpenCV 图像(NumPy 数组格式)。
  2. text: 要绘制的文本内容。
  3. pos: 文本绘制的起始位置(左上角坐标)。
  4. font: 使用的字体对象。
  5. color: 文本颜色(BGR 格式)。
1
img_pil = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))

将 OpenCV 图像(BGR 格式)转换为 RGB 格式,并使用 Image.fromarray 将其转换为 PIL 图像对象

1
draw = ImageDraw.Draw(img_pil)

创建一个 ImageDraw 对象,用于在 PIL 图像上绘制图形或文字。

1
draw.text(pos, text, font=font, fill=color)

在 PIL 图像上绘制文本。

  1. pos: 文本绘制的起始位置。
  2. text: 要绘制的文本内容。
  3. font: 使用的字体对象。
  4. fill: 文本的颜色
1
return cv2.cvtColor(np.array(img_pil), cv2.COLOR_RGB2BGR)

将 PIL 图像转换回 NumPy 数组,并将其从 RGB 格式转换回 BGR 格式,以便与 OpenCV 兼容

1
cap = cv2.VideoCapture(0)

初始化摄像头,0 表示默认摄像头。

1
qr_code_detector = cv2.QRCodeDetector()

创建二维码检测器对象qr_code_detector,用于检测和解码二维码。

1
font_path = "simhei.ttf"

设置字体,simhei.ttf 是黑体字体文件,用于支持中文显示。

1
font = ImageFont.truetype(font_path, 24)

加载指定路径的字体文件,并设置字体大小为 24。

1
while True:

摄像头传输数据连续,读取摄像头数据时需要一个无限循环保证连续读取视频帧

1
ret, frame = cap.read()

读取摄像头的一帧图像,返回值分别赋给retframe

  1. ret: 布尔值,表示是否成功读取帧。
  2. frame: 读取到的图像帧(NumPy 数组格式)。
1
2
if not ret:
break

如果未能成功读取帧ret为0,退出循环,结束运行。

1
retval, decoded_info, points, straight_qrcode = qr_code_detector.detectAndDecodeMulti(frame)

使用二维码检测器检测并解码图像中的二维码。

  1. retval: 布尔值,表示是否成功检测到二维码。
  2. decoded_info: 解码后的二维码内容列表。
  3. points: 检测到的二维码的四角坐标列表。
  4. straight_qrcode: 矫正后的二维码图像
1
2
3
if retval:
for info in decoded_info:
print("QR Code Content:", info)

如果成功检测到二维码,将解码后的二维码内容输出。
使用for循环是因为detectAndDecodeMulti()的返回值为列表,可能有多个元素。

1
2
if points is not None:
points = points.astype(int)

如果二维码的四角坐标不为空,将坐标数据类型转换为整数。
为什么要转化为整数?
OpenCV 的绘图函数(后面用到了cv2.line()函数)要求坐标点的值必须是整数
points 是通过二维码检测器返回的坐标数组,可能包含浮点数。如果直接使用返回的坐标,函数会报错。

1
2
3
for i in range(len(points)):
for j in range(4):
cv2.line(frame, tuple(points[i][j]), tuple(points[i][(j + 1) % 4]), (0, 255, 0), 3)

遍历每个二维码的四角坐标,并绘制绿色线条连接四个角点,形成矩形框。
(0, 255, 0) 表示绿色,3 表示线条宽度。

1
2
text = f"{points[i]}"
frame = draw_text(frame, text, (10, 30 + i * 30), font, (0, 255, 0))

将二维码的四角坐标转换为字符串,并调用 draw_text 函数在图像左上角显示坐标信息。

1
2
else:
frame = draw_text(frame, "未检测到二维码", (10, 30), font, (255, 0, 0))

如果未检测到二维码,在图像左上角显示“未检测到二维码”文本,颜色为红色。

1
cv2.imshow("QR Code Detection", frame)

使用 OpenCV 显示处理后的图像帧,在循环之中连续播放的帧成为的实时的视频画面,窗口标题为“QR Code Detection”。

1
2
if cv2.waitKey(1) & 0xFF == ord('q'):
break

检查用户是否按下键盘上的 ‘q’ 键,如果按下,则退出循环。如果不是视频不能这样写。

1
cap.release()

释放摄像头资源。

1
cv2.destroyAllWindows()

关闭所有 OpenCV 窗口。

运行结果

opencv #二维码 #QR #二维码识别


视频二维码检测
https://pattianfang.github.io/2025/04/01/视频二维码检测/
作者
Pat Tian Fang
发布于
2025年4月1日
更新于
2025年5月3日
许可协议