首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >A judgment method by feature matching through the positioning area of the QRCode

A judgment method by feature matching through the positioning area of the QRCode

原创
作者头像
Swing Dunn
发布2025-10-23 17:50:17
发布2025-10-23 17:50:17
620
举报
文章被收录于专栏:Some studies in imgsSome studies in imgs

By using the "回" shape feature of the three positioning points of the QR code, and through template matching, the positioning area of the QR code is identified, thereby determining whether a QR code exists here.

The idea is as follows:

The main method is to locate the area by using the template image, and it is in the form of a square.

Because there are no other similar "loop"-shaped areas in my image that could interfere, we can assume that once the positioning area is found, it indicates that a QR code exists here.

Source code:

代码语言:txt
复制
import cv2
import os
from pyzbar.pyzbar import decode
import numpy as np

# 读取目标图像和模板图像
def show_image(img):
    cv2.namedWindow("1",cv2.WINDOW_AUTOSIZE )
    cv2.imshow("1",img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

# 1. 生成标准回字形模板(7x7)
def create_qrcode_template(size=7):
    """创建二维码定位点的回字形模板(黑=0,白=255)"""
    template = np.ones((size, size), dtype=np.uint8) * 255  # 初始全白
    # 外层黑框(第0行、第6行,第0列、第6列)
    template[0, :] = 0
    template[-1, :] = 0
    template[:, 0] = 0
    template[:, -1] = 0
    # 内层黑方块(第2-4行,第2-4列)
    template[2:5, 2:5] = 0

    return template

def exist_rect(candidates,score_x,score_y,score_w):
    for (x, y, w, h, score) in candidates:
        if abs(score_x -x )< 10 and abs(score_y - y) < 10 and 0.8 <= score_w / w <= 1.2:
            return True
         
    return False

# 2. 多尺度模板匹配
def match_template_multi_scale(img_gray, template, min_scale=3, max_scale=7.0, step=0.1):
    """在多个尺度下进行模板匹配,返回高相似度区域"""
    h, w = template.shape[:2]
    candidates = []
    
    # 遍历不同尺度
    scale = min_scale
    while scale <= max_scale:
        # 缩放模板
        scaled_h = int(h * scale)
        scaled_w = int(w * scale)
        if scaled_h < 7 or scaled_w < 7:  # 最小不小于原始模板尺寸(避免信息丢失)
            scale += step
            continue
        scaled_template = cv2.resize(template, (scaled_w, scaled_h))
        #show_image(scaled_template)
        
        # 模板匹配(TM_CCOEFF_NORMED 输出归一化相关系数,值越接近1越匹配)
        result = cv2.matchTemplate(img_gray, scaled_template, cv2.TM_CCOEFF_NORMED)
        
        # 筛选匹配得分高于阈值的区域(阈值可根据图像质量调整)
        threshold = 0.7
        locations = np.where(result >= threshold)
        for pt in zip(*locations[::-1]):  # (x, y) 坐标
            # 记录匹配区域(左上角坐标、宽高、得分)
            score = result[pt[1], pt[0]]
            if not exist_rect(candidates,pt[0], pt[1], scaled_w):
                candidates.append((pt[0], pt[1], scaled_w, scaled_h, score))
        scale += step
    
    # 按得分排序,保留前N个高得分区域(去重)
    candidates.sort(key=lambda x: x[4], reverse=True)
    return candidates[:10] # 取前10个候选

# 3. 验证候选区域是否为正方形(定位点应为正方形)
def is_square(candidate, ratio_threshold=0.1):
    x, y, w, h, _ = candidate
    aspect_ratio = w / h
    return 1 - ratio_threshold <= aspect_ratio <= 1 + ratio_threshold

# 4. 主函数:定位二维码的三个定位点
def find_qrcode_position_points(img):
    img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    #增强图像对比度 
    clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
    gray_c = clahe.apply(img_gray)

    #高斯滤波
    gray_c = cv2.GaussianBlur(gray_c, (3, 3), 0)    # 二值化(增强黑白对比)
    _, img_bin = cv2.threshold(gray_c, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)

    
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
    img_bin = cv2.morphologyEx(img_bin, cv2.MORPH_CLOSE, kernel)

    #show_image(img_bin)
    # 创建模板
    template = create_qrcode_template()
    
    # 多尺度匹配
    candidates = match_template_multi_scale(img_bin, template)
    
    # 筛选正方形候选区域
    valid_candidates = [c for c in candidates if is_square(c)]

    # 绘制结果
    result_img = img.copy()
    for (x, y, w, h, score) in valid_candidates[:3]:  # 取前3个最可能的定位点
        cv2.rectangle(result_img, (x, y), (x + w, y + h), (0, 255, 0), 2)
        cv2.putText(result_img, f"{score:.2f}", (x, y - 10), 
                    cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 1)
        # range_img = result_img[y:  y +h, x : x+w]
        # show_image(range_img)
    
    return result_img, valid_candidates[:3]

# 测试
def main():
    folder_path = './imgs9'
    #模板定位点信息
   #bar_range = (1377, 138, 1536, 293)
    bar_range = (152, 192, 352, 350)
    paper_num = 0
    error_paper_num = 0
    less_than_3 = 0

    # 递归遍历文件夹
    for root, dirs, files in os.walk(folder_path): 
        for filename in files:
            if filename.lower().endswith('.jpg'):
                paper_num += 1

                file_path = os.path.join(root, filename)
                ori_img = cv2.imread(file_path, cv2.IMREAD_ANYCOLOR)  # 目标图像
                if len(ori_img.shape) == 3 and ori_img.shape[2] == 3:
                    gray_img = cv2.cvtColor(ori_img, cv2.COLOR_BGR2GRAY)
                elif len(ori_img.shape) == 2:
                    gray_img = ori_img.copy()
                else:
                    print('error: bad image')
                    return
     
                ori_bar_area = ori_img[bar_range[1]:bar_range[3], bar_range[0]:bar_range[2]]

                # height, width = ori_bar_area.shape[:2]
                # if height > 300 or width > 300:
                #     # 缩小图像:用INTER_AREA
                #     resized = cv2.resize(ori_bar_area, (300, 300), interpolation=cv2.INTER_AREA)
                # else:
                #     # 放大图像:用INTER_CUBIC(更清晰)
                #     resized = cv2.resize(ori_bar_area, (300, 300), interpolation=cv2.INTER_CUBIC)
                
                result_img, points = find_qrcode_position_points(ori_bar_area)

                if len(points) > 0:
                    print('识别到特征点个数:' , len(points))
                    if(len(points)) < 2:
                        less_than_3 += 1
                        show_image(result_img)
                    #show_image(result_img)
                    pass
                else:
                    error_paper_num += 1
                    # show_image(result_img)
                    # show_image(ori_img)


                print('识别总份数: ', paper_num)
                print('特征点低于3的份数 ', less_than_3)
                print('未识别到二维码份数: ', error_paper_num)
                print('二维码识别率: ', str(1 - error_paper_num / paper_num))
                print()   

                # cv2.imshow("QR Code Position Points", result_img)
                # cv2.waitKey(0)
                # cv2.destroyAllWindows()

if __name__ == "__main__":
    main()

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档