在现在这个互联网发展的时代二维码在生活中无处不在,手机扫码以成习以为常,但其中相机对二维码的识别却很复杂,本文主要介绍如何使用Opencv通过透视变换来实现二维码的畸变矫正也是其中的一部分。

以倾斜二维码为例这是原图片:

 这是根据原二维码处理后的图片:

 介绍及注意事项:

 1.主要功能:
     检测图像中的二维码
     提取二维码的四个角点
     计算透视变换矩阵
     应用透视变换矫正畸变
     保存和显示结果

2. 关键步骤:
     使用`cv2.QRCodeDetector()`检测二维码
     order_points()`函数确保四个角点按正确顺序排列
     使用`cv2.getPerspectiveTransform()`计算变换矩阵
     使用`cv2.warpPerspective()`应用变换

3.  使用方法:
     替换`input_image`为你的畸变二维码图像路径
     运行代码后,会显示原始图像(带二维码轮廓)和矫正后的图像
     矫正后的图像会保存到`output_image`指定的路径

注意事项:

  1. 确保安装了正确版本的OpenCV一般用pip:

pip install opencv-python opencv-contrib-python

  2. 如果二维码检测失败,可以尝试:
     调整图像对比度
     确保二维码在图像中足够大且清晰
     尝试不同的预处理方法(如阈值化)

  3. 对于严重畸变的二维码,可能需要手动指定角点位置。

接下来进入主题:

1.载入opencv和库:

import cv2
import numpy as np

 2.检测图像中的二维码并进行畸变矫正:

        image_path: 输入图像路径

        output_path: 矫正后图像保存路径(可选)

参数 类型 是否必需 说明
image_path string 输入图像的路径(需畸变矫正的二维码图像)
output_path string 输出图像保存路径。若为 None,则函数可能直接返回矫正后的图像对象
 核心目的:

      用于 矫正含有二维码(QR Code)的图像畸变,提高二维码识别的准确率。主要解决因镜头畸变、拍摄角度倾斜或透视变形导致的二维码扭曲问题

 技术实现:

    畸变矫正:利用相机的内参矩阵(camera matrix)和畸变系数(distortion coefficients),通过 OpenCV 的 undistort() 或 remap() 函数消除径向/切向畸变。

透视校正:通过霍夫变换或特征点检测定位二维码边界,再使用透视变换(warpPerspective)将倾斜的二维码拉正。

def correct_qr_distortion(image_path, output_path=None):
 (1)使用cv2.QRCodeDetector()检测二维码:
# 读取图像
    image = cv2.imread(image_path)
    if image is None:
        raise ValueError("无法加载图像,请检查路径是否正确")
    
    # 转换为灰度图
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    
    # 初始化二维码检测器
    qr_detector = cv2.QRCodeDetector()
    
    # 检测二维码
    retval, points, straight_qrcode = qr_detector.detectAndDecode(gray)
 (2) order_points()函数确保四个角点按正确顺序排列:
if not retval:
        print("未检测到二维码")
        return None
    
    # 将点转换为整数坐标
    points = points.astype(int)
    
    # 在原始图像上绘制二维码轮廓
    cv2.polylines(image, [points], isClosed=True, color=(0, 255, 0), thickness=2)
    
   
 (3)使用cv2.getPerspectiveTransform()计算变换矩阵:
# 获取二维码的四个角点
    # 注意:points的顺序可能不一致,我们需要按左上、右上、右下、左下的顺序排列
    rect = order_points(points.reshape(4, 2))
    
    # 计算二维码的宽度和高度
    (tl, tr, br, bl) = rect
    
    # 计算新二维码的宽度
    widthA = np.linalg.norm(br - bl)
    widthB = np.linalg.norm(tr - tl)
    maxWidth = max(int(widthA), int(widthB))
    
    # 计算新二维码的高度
    heightA = np.linalg.norm(tr - br)
    heightB = np.linalg.norm(tl - bl)
    maxHeight = max(int(heightA), int(heightB))
    
    # 定义目标点
    dst = np.array([
        [0, 0],
        [maxWidth - 1, 0],
        [maxWidth - 1, maxHeight - 1],
        [0, maxHeight - 1]], dtype="float32")
    
    # 计算透视变换矩阵
    M = cv2.getPerspectiveTransform(rect, dst)
(4) 使用`cv2.warpPerspective()`应用变换:
# 应用透视变换
    warped = cv2.warpPerspective(image, M, (maxWidth, maxHeight))

 3.保存矩阵变换后的结果:

# 如果提供了输出路径,则保存结果
    if output_path is not None:
        cv2.imwrite(output_path, warped)
    
    # 显示结果
    cv2.imshow("Original with QR Code Outline", image)
    cv2.imshow("Corrected QR Code", warped)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    
    return warped

4.  把保存好的结果按四个点按左上、右上、右下、左下的顺序排列:

def order_points(pts):
    """
    将四个点按左上、右上、右下、左下的顺序排列
    
    参数:
        pts: 包含四个点坐标的数组
    
    返回:
        排序后的点坐标
    """
    # 初始化一个坐标数组,并将四个点相加求和
    rect = np.zeros((4, 2), dtype="float32")
    s = pts.sum(axis=1)
    
    # 左上角的点坐标和最小
    rect[0] = pts[np.argmin(s)]
    # 右下角的点坐标和最大
    rect[2] = pts[np.argmax(s)]
    
    # 计算点之间的差值
    diff = np.diff(pts, axis=1)
    # 右上角的点差值最小
    rect[1] = pts[np.argmin(diff)]
    # 左下角的点差值最大
    rect[3] = pts[np.argmax(diff)]
    
    return rect

5 .替换和保存:

     为了使用方便,这里可以替换使用图片将 input_image = "cs3.jpg"  替换为input_image =(你的图像路径)。

# 使用示例
if __name__ == "__main__":
    input_image = "cs3.jpg"  # 替换为你的图像路径
    output_image = "corrected_qr_code.jpg"  # 输出图像路径
     
    corrected = correct_qr_distortion(input_image, output_image)
    
    if corrected is not None:
        print("二维码矫正完成并已保存!")

      本文用的是vscode配置python开发环境编写opencv。利用cv2.QRCodeDetector()检测二维码,
order_points()函数确保四个角点按正确顺序排列,使用cv2.getPerspectiveTransform()计算变换矩阵,使用cv2.warpPerspective()应用变换,最后达到对二维码进行矫正的效果。

这是本文完整代码:

import cv2
import numpy as np

def correct_qr_distortion(image_path, output_path=None):
    """
    检测图像中的二维码并进行畸变矫正
    
    参数:
        image_path: 输入图像路径
        output_path: 矫正后图像保存路径(可选)
    
    返回:
        矫正后的图像

        核心目的
           用于 矫正含有二维码(QR Code)的图像畸变,提高二维码识别的准确率。主要解决因镜头畸变、拍摄角度倾斜或透视变形导致的二维码扭曲问题
        技术实现
畸变矫正:利用相机的内参矩阵(camera matrix)和畸变系数(distortion coefficients),通过 OpenCV 的 undistort() 或 remap() 函数消除径向/切向畸变。
透视校正:通过霍夫变换或特征点检测定位二维码边界,再使用透视变换(warpPerspective)将倾斜的二维码拉正。
    """
     # 读取图像
    image = cv2.imread(image_path)
    if image is None:
        raise ValueError("无法加载图像,请检查路径是否正确")
    
    # 转换为灰度图
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    
    # 初始化二维码检测器
    qr_detector = cv2.QRCodeDetector()
    
    # 检测二维码
    retval, points, straight_qrcode = qr_detector.detectAndDecode(gray)
    
    if not retval:
        print("未检测到二维码")
        return None
    
    # 将点转换为整数坐标
    points = points.astype(int)
    
    # 在原始图像上绘制二维码轮廓
    cv2.polylines(image, [points], isClosed=True, color=(0, 255, 0), thickness=2)
    
    # 获取二维码的四个角点
    # 注意:points的顺序可能不一致,我们需要按左上、右上、右下、左下的顺序排列
    rect = order_points(points.reshape(4, 2))
    
    # 计算二维码的宽度和高度
    (tl, tr, br, bl) = rect
    
    # 计算新二维码的宽度
    widthA = np.linalg.norm(br - bl)
    widthB = np.linalg.norm(tr - tl)
    maxWidth = max(int(widthA), int(widthB))
    
    # 计算新二维码的高度
    heightA = np.linalg.norm(tr - br)
    heightB = np.linalg.norm(tl - bl)
    maxHeight = max(int(heightA), int(heightB))
    
    # 定义目标点
    dst = np.array([
        [0, 0],
        [maxWidth - 1, 0],
        [maxWidth - 1, maxHeight - 1],
        [0, maxHeight - 1]], dtype="float32")
    
    # 计算透视变换矩阵
    M = cv2.getPerspectiveTransform(rect, dst)
    
    # 应用透视变换
    warped = cv2.warpPerspective(image, M, (maxWidth, maxHeight))
    
    # 如果提供了输出路径,则保存结果
    if output_path is not None:
        cv2.imwrite(output_path, warped)
    
    # 显示结果
    cv2.imshow("Original with QR Code Outline", image)
    cv2.imshow("Corrected QR Code", warped)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    
    return warped

def order_points(pts):
    """
    将四个点按左上、右上、右下、左下的顺序排列
    
    参数:
        pts: 包含四个点坐标的数组
    
    返回:
        排序后的点坐标
    """
    # 初始化一个坐标数组,并将四个点相加求和
    rect = np.zeros((4, 2), dtype="float32")
    s = pts.sum(axis=1)
    
    # 左上角的点坐标和最小
    rect[0] = pts[np.argmin(s)]
    # 右下角的点坐标和最大
    rect[2] = pts[np.argmax(s)]
    
    # 计算点之间的差值
    diff = np.diff(pts, axis=1)
    # 右上角的点差值最小
    rect[1] = pts[np.argmin(diff)]
    # 左下角的点差值最大
    rect[3] = pts[np.argmax(diff)]
    
    return rect

# 使用示例
if __name__ == "__main__":
    input_image = "cs3.jpg"  # 替换为你的图像路径
    output_image = "corrected_qr_code.jpg"  # 输出图像路径
     
    corrected = correct_qr_distortion(input_image, output_image)
    
    if corrected is not None:
        print("二维码矫正完成并已保存!")

      谢谢观看!! 

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐