import cv2
import numpy as np
from pyzbar.pyzbar import decode
import sys
def is_overlap(rect1, rect2):
"""
判断两个矩形区域是否重叠
:param rect1: 第一个矩形区域,格式为 (x1, y1, x2, y2)
:param rect2: 第二个矩形区域,格式为 (x1, y1, x2, y2)
:return: 如果重叠返回 True,否则返回 False
"""
x1_1, y1_1, x2_1, y2_1 = rect1
x1_2, y1_2, x2_2, y2_2 = rect2
return not (x2_1 < x1_2 or x2_2 < x1_1 or y2_1 < y1_2 or y2_2 < y1_1)
def remove_overlaps(rectangles):
"""
去除重叠的矩形区域
:param rectangles: 矩形区域列表,每个元素格式为 (x1, y1, x2, y2)
:return: 去除重叠后的矩形区域列表
"""
non_overlapping = []
for rect in rectangles:
is_valid = True
for existing_rect in non_overlapping:
if is_overlap(rect, existing_rect):
is_valid = False
break
if is_valid:
non_overlapping.append(rect)
return non_overlapping
def find_qr_codes(image_path):
# 尝试使用 pyzbar 识别二维码
image = cv2.imread(image_path)
if image is None:
print(f"无法打开或读取文件: {image_path},请检查文件路径和文件完整性。")
return []
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
decoded_objects = decode(gray)
qr_coordinates = []
for obj in decoded_objects:
if obj.type == 'QRCODE':
points = obj.polygon
if len(points) == 4:
x_coords = [point.x for point in points]
y_coords = [point.y for point in points]
x_min = min(x_coords)
x_max = max(x_coords)
y_min = min(y_coords)
y_max = max(y_coords)
qr_coordinates.append((x_min, y_min, x_max, y_max))
# 将识别到的区域设为白色(遮挡)
gray[y_min:y_max, x_min:x_max] = 255
templates = [
'/www/pythoncmd/qrcode/template_dy.png',
'/www/pythoncmd/qrcode/template_wx.png'
]
for template_path in templates:
template = cv2.imread(template_path, 0)
if template is None:
print(f"无法打开或读取模板文件: {template_path},请检查文件路径和文件完整性。")
continue
# 创建 SIFT 对象
sift = cv2.SIFT_create()
# 检测关键点和描述符
kp1, des1 = sift.detectAndCompute(template, None)
kp2, des2 = sift.detectAndCompute(gray, None)
# 使用 FLANN 进行特征匹配
FLANN_INDEX_KDTREE = 1
index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5)
search_params = dict(checks=50)
flann = cv2.FlannBasedMatcher(index_params, search_params)
matches = flann.knnMatch(des1, des2, k=2)
# 筛选好的匹配点
good_matches = []
for m, n in matches:
if m.distance < 0.7 * n.distance:
good_matches.append(m)
if len(good_matches) > 10:
src_pts = np.float32([kp1[m.queryIdx].pt for m in good_matches]).reshape(-1, 1, 2)
dst_pts = np.float32([kp2[m.trainIdx].pt for m in good_matches]).reshape(-1, 1, 2)
M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0)
if M is not None: # 检查 M 是否有效
h, w = template.shape
pts = np.float32([[0, 0], [0, h - 1], [w - 1, h - 1], [w - 1, 0]]).reshape(-1, 1, 2)
dst = cv2.perspectiveTransform(pts, M)
x_coords = [point[0][0] for point in dst]
y_coords = [point[0][1] for point in dst]
x_min = int(min(x_coords))
x_max = int(max(x_coords))
y_min = int(min(y_coords))
y_max = int(max(y_coords))
# 获取图像的宽度和高度
height, width = image.shape[:2]
if (x_max < width and y_max < height and x_max - x_min > 100 and y_max - y_min > 100):
qr_coordinates.append((x_min, y_min, x_max, y_max))
gray[y_min:y_max, x_min:x_max] = 255
# else:
# print("单应性矩阵 M 无效,跳过当前模板匹配")
# 去除重叠区域
qr_coordinates = remove_overlaps(qr_coordinates)
return qr_coordinates
if __name__ == "__main__":
if len(sys.argv) != 2:
print("用法: python detect_qrcodes.py <图片路径>")
print(len(sys.argv))
sys.exit(1)
image_path = sys.argv[1]
coordinates = find_qr_codes(image_path)
print(coordinates)