【python】OpenCV—Augmented Reality Using Aruco Markers

news2024/9/20 15:04:03

在这里插入图片描述

文章目录

  • 1、任务描述
  • 2、Aruco Markers
  • 3、代码实现
  • 4、更多例子展示
  • 5、涉及到的库
    • cv2.findHomography
  • 6、参考

1、任务描述

借助 Aruco Markers,替换墙面上画面中的内容

在这里插入图片描述

在这里插入图片描述

2、Aruco Markers

OpenCV 中的 aruco 模块共有 25 个预定义的标记字典。字典中的所有标记包含相同数量的块或位(4×4、5×5、6×6 或 7×7),每个字典包含固定数量的标记(50、100、250 或 1000)

上面的 drawMarker 函数让我们从 250 个标记的集合中选择具有给定 id(第二个参数 - 66)的标记,这些标记的 id 从 0 到 249。

drawMarker 函数的第三个参数决定生成的标记的大小。在上面的例子中,它会生成一个 200×200 像素的图像。

第四个参数表示将存储生成的标记的对象(上面的markerImage)。

最后,第五个参数是厚度参数,它决定了应该添加多少块作为生成的二进制模式的边界。

在上面的示例中,将在 6×6 生成的模式周围添加 1 位边界,以在 200×200 像素图像中生成具有 7×7 位的图像。

下面我们来生成一些 markers

import cv2 as cv
import numpy as np

size = 200
padding = 1

# Load the predefined dictionary
dictionary = cv.aruco.Dictionary_get(cv.aruco.DICT_6X6_250)

# Generate the marker
markerImage = np.zeros((size, size), dtype=np.uint8)

for id in range(0, 250):
    markerImage = cv.aruco.drawMarker(dictionary, id, size, markerImage, padding)
    cv.imwrite(f"./images/marker{id}.png", markerImage)

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

3、代码实现

# This code is written by Sunita Nayak at BigVision LLC. It is based on the OpenCV project. It is subject to the license terms in the LICENSE file found in this distribution and at http://opencv.org/license.html

# Usage example:   python3 augmented_reality_with_aruco.py --image=test.jpg
#                  python3 augmented_reality_with_aruco.py --video=test.mp4

import cv2 as cv
#from cv2 import aruco
import argparse
import sys
import os.path
import numpy as np

parser = argparse.ArgumentParser(description='Augmented Reality using Aruco markers in OpenCV')
parser.add_argument('--image', help='Path to image file.')
parser.add_argument('--video', help='Path to video file.')
args = parser.parse_args()

im_src = cv.imread("1.jpg") # 选择插入的图片

outputFile = "ar_out_py.avi"
if (args.image):
    # Open the image file
    if not os.path.isfile(args.image):
        print("Input image file ", args.image, " doesn't exist")
        sys.exit(1)
    cap = cv.VideoCapture(args.image)
    outputFile = args.image[:-4]+'_ar_out_py.jpg'
elif (args.video):
    # Open the video file
    if not os.path.isfile(args.video):
        print("Input video file ", args.video, " doesn't exist")
        sys.exit(1)
    cap = cv.VideoCapture(args.video)
    outputFile = args.video[:-4]+'_ar_out_py.avi'
    print("Storing it as :", outputFile)
else:
    # Webcam input
    cap = cv.VideoCapture(0)

# Get the video writer initialized to save the output video
if (not args.image):
    vid_writer = cv.VideoWriter(outputFile, cv.VideoWriter_fourcc('M','J','P','G'), 28,
                                (round(2*cap.get(cv.CAP_PROP_FRAME_WIDTH)),
                                 round(cap.get(cv.CAP_PROP_FRAME_HEIGHT))))

winName = "Augmented Reality using Aruco markers in OpenCV"

while cv.waitKey(1) < 0:
    try:
        # get frame from the video
        hasFrame, frame = cap.read()
        
        # Stop the program if reached end of video
        if not hasFrame:
            print("Done processing !!!")
            print("Output file is stored as ", outputFile)
            cv.waitKey(3000)
            break

        #Load the dictionary that was used to generate the markers.
        dictionary = cv.aruco.Dictionary_get(cv.aruco.DICT_6X6_250)
        
        # Initialize the detector parameters using default values
        parameters = cv.aruco.DetectorParameters_create()
        
        # Detect the markers in the image
        markerCorners, markerIds, rejectedCandidates = cv.aruco.detectMarkers(frame, dictionary, parameters=parameters)

        if True:
            if len(markerCorners) > 0:
                # Flatten the ArUCo IDs list
                ids = markerIds.flatten()
                image = frame.copy()
                # Loop over the detected ArUCo corners
                for (markerCorner, markerID) in zip(markerCorners, markerIds):
                    # Extract the markers corners which are always returned in the following order:
                    # TOP-LEFT, TOP-RIGHT, BOTTOM-RIGHT, BOTTOM-LEFT
                    corners = markerCorner.reshape((4, 2))
                    (topLeft, topRight, bottomRight, bottomLeft) = corners
                    # Convert each of the (x, y)-coordinate pairs to integers
                    topRight = (int(topRight[0]), int(topRight[1]))
                    bottomRight = (int(bottomRight[0]), int(bottomRight[1]))
                    bottomLeft = (int(bottomLeft[0]), int(bottomLeft[1]))
                    topLeft = (int(topLeft[0]), int(topLeft[1]))
                    # Draw the bounding box of the ArUCo detection
                    cv.line(image, topLeft, topRight, (0, 255, 0), 2)
                    cv.line(image, topRight, bottomRight, (0, 255, 0), 2)
                    cv.line(image, bottomRight, bottomLeft, (0, 255, 0), 2)
                    cv.line(image, bottomLeft, topLeft, (0, 255, 0), 2)
                    # Compute and draw the center (x, y) coordinates of the ArUCo marker
                    cX = int((topLeft[0] + bottomRight[0]) / 2.0)
                    cY = int((topLeft[1] + bottomRight[1]) / 2.0)
                    cv.circle(image, (cX, cY), 4, (0, 0, 255), -1)
                    # Draw the ArUco marker ID on the image
                    cv.putText(image, str(markerID), (topLeft[0], topLeft[1] - 15), cv.FONT_HERSHEY_SIMPLEX,
                                0.5, (0, 255, 0), 2)
                    print("[INFO] ArUco marker ID: {}".format(markerID))
                    # write the output image
                    # cv.imwrite("{}_{}.jpg".format(args["type"], markerID), image)
                    # Show the output image
                    cv.imshow("Image", image)
                    cv.waitKey(0)

        index = np.squeeze(np.where(markerIds == 25))  # id 25 左上角
        refPt1 = np.squeeze(markerCorners[index[0]])[1]
        
        index = np.squeeze(np.where(markerIds == 33))  # id 33 右上角
        refPt2 = np.squeeze(markerCorners[index[0]])[2]

        distance = np.linalg.norm(refPt1-refPt2)  # 左上右上的欧氏距离
        
        scalingFac = 0.02
        pts_dst = [[refPt1[0] - round(scalingFac*distance),
                    refPt1[1] - round(scalingFac*distance)]]  # 边界外扩

        pts_dst = pts_dst + [[refPt2[0] + round(scalingFac*distance),
                              refPt2[1] - round(scalingFac*distance)]]  # 边界外扩
        
        index = np.squeeze(np.where(markerIds == 30))  # id 30 右下
        refPt3 = np.squeeze(markerCorners[index[0]])[0]
        pts_dst = pts_dst + [[refPt3[0] + round(scalingFac*distance),
                              refPt3[1] + round(scalingFac*distance)]]  # 边界外扩

        index = np.squeeze(np.where(markerIds == 23))  # id 30 左下
        refPt4 = np.squeeze(markerCorners[index[0]])[0]
        pts_dst = pts_dst + [[refPt4[0] - round(scalingFac*distance),
                              refPt4[1] + round(scalingFac*distance)]]  # 边界外扩
        # [[519.0, 184.0], [968.0, 142.0], [978.0, 654.0], [509.0, 640.0]]

        pts_src = [[0,0], [im_src.shape[1], 0], [im_src.shape[1], im_src.shape[0]], [0, im_src.shape[0]]]
        # [[0, 0], [1707, 0], [1707, 1280], [0, 1280]]
        
        pts_src_m = np.asarray(pts_src)
        pts_dst_m = np.asarray(pts_dst)

        # Calculate Homography
        h, status = cv.findHomography(pts_src_m, pts_dst_m)
        """
        h
            array([[ 2.01635985e-01, -2.38521041e-02,  5.19000000e+02],
                   [-3.36113857e-02,  3.36082325e-01,  1.84000000e+02],
                   [-6.34282837e-05, -3.15119923e-05,  1.00000000e+00]])
               
        status
            array([[1],
                   [1],
                   [1],
                   [1]], dtype=uint8)
        """
        
        # Warp source image to destination based on homography
        warped_image = cv.warpPerspective(im_src, h, (frame.shape[1],frame.shape[0]))
        
        # Prepare a mask representing region to copy from the warped image into the original frame.
        mask = np.zeros([frame.shape[0], frame.shape[1]], dtype=np.uint8)
        cv.fillConvexPoly(mask, np.int32([pts_dst_m]), (255, 255, 255), cv.LINE_AA)

        # Erode the mask to not copy the boundary effects from the warping
        element = cv.getStructuringElement(cv.MORPH_RECT, (3,3))
        mask = cv.erode(mask, element, iterations=3)

        # Copy the mask into 3 channels.
        warped_image = warped_image.astype(float)
        mask3 = np.zeros_like(warped_image)
        for i in range(0, 3):
            mask3[:,:,i] = mask/255

        # Copy the warped image into the original frame in the mask region.
        warped_image_masked = cv.multiply(warped_image, mask3)
        frame_masked = cv.multiply(frame.astype(float), 1-mask3)
        im_out = cv.add(warped_image_masked, frame_masked)
        
        # Showing the original image and the new output image side by side
        concatenatedOutput = cv.hconcat([frame.astype(float), im_out])
        cv.imshow("AR using Aruco markers", concatenatedOutput.astype(np.uint8))
        
        # Write the frame with the detection boxes
        if (args.image):
            cv.imwrite(outputFile, concatenatedOutput.astype(np.uint8))
        else:
            vid_writer.write(concatenatedOutput.astype(np.uint8))


    except Exception as inst:
        print(inst)

cv.destroyAllWindows()
if 'vid_writer' in locals():
    vid_writer.release()
    print('Video writer released..')

aruco markers 检测结果

在这里插入图片描述

根据原壁画中左上右上的距离,使壁画向边缘都快扩了一些些 scalingFace = 0.02,这样方便新壁画覆盖原始壁画的时候,可以覆盖完全,不会露出来原始的画

id 25 左上角边界点(壁画的左上角)向左向上移动

id 33 右上角边界点(壁画的右上角)向右向下移动

id 30 右下角边界点(壁画的右下角)向右向下移动

id 23 左下角边界点(壁画的左下角)向左向下移动

应用单应性矩阵变化后得到的 warped_image

在这里插入图片描述

mask 和 mask-erode 的区别,可以看出边缘是做了一些处理,使得融合后更加自然

在这里插入图片描述

warped_image 和 warped_image_masked 的区别

在这里插入图片描述

最终结果展示

在这里插入图片描述

在这里插入图片描述

4、更多例子展示

在这里插入图片描述

在这里插入图片描述

test_ar_out_py

5、涉及到的库

cv2.findHomography

cv2.findHomography 是 OpenCV 库中的一个函数,用于计算两个平面之间的单应性矩阵(Homography Matrix)。单应性矩阵是一个 3x3 的矩阵,它可以用来将一个平面上的点映射到另一个平面上的对应点,常用于图像校正、图像拼接、视角变换等场景。

一、函数原型

H, status = cv2.findHomography(srcPoints, dstPoints, method=0, ransacReprojThresh=5.0, mask=None[, maxIters=2000[, confidence=0.995]])

二、参数说明

  • srcPoints: 源图像中的点集,通常是 numpy 数组,形状为 (N, 1, 2) 或 (N, 2),其中 N 是点的数量,每个点由 (x, y) 坐标表示。
  • dstPoints: 目标图像中对应点的点集,与 srcPoints 有相同的形状和数量。
  • method: 计算单应性矩阵的方法。常用值为 0(默认)、cv2.RANSAC、cv2.LMEDS、cv2.RHO。cv2.RANSAC 是最常用的,因为它对噪声和异常值具有很好的鲁棒性。
  • ransacReprojThresh: 仅当 method 为 cv2.RANSAC 或 cv2.LMEDS 时使用。它指定了最大重投影误差,以决定哪些点是内点。
  • mask: 可选参数,输出掩码,表示哪些点是内点(值为 1)或外点(值为 0)。
  • maxIters: cv2.RANSAC 方法中的最大迭代次数,默认为 2000。
  • confidence: cv2.RANSAC 方法的置信度,即内点在所有点中所占的比例,默认为 0.995。

返回值

  • retval: 计算得到的单应性矩阵 3x3 。
  • status: 如果提供了该参数,函数会填充这个数组,表示每个点是否为内点。

三、使用示例

假设你有两张图片,并已经找到了一些对应的特征点,你可以使用这些点来计算单应性矩阵,然后使用这个矩阵进行图像变换。

import cv2  
import numpy as np  
  
# 假设 src_pts 和 dst_pts 是你已经找到的对应点  
src_pts = np.float32([[56, 65], [128, 159], [23, 145], [100, 100]])  
dst_pts = np.float32([[10, 50], [200, 200], [100, 100], [150, 150]])  
  
# 计算单应性矩阵  
H, status = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0)  
  
# 使用单应性矩阵进行图像变换(此处略去)

注意,在实际应用中,特征点通常是通过特征检测算法(如 SIFT、SURF、ORB 等)自动找到的。

6、参考

  • AttributeError: module ‘cv2.aruco’ has no attribute ‘Dictionary_get’

    在这里插入图片描述
    在这里插入图片描述
    opencv-python 也用的是 4.6.0.66 版本

  • OpenCV进阶(10)在 OpenCV 中使用 ArUco 标记的增强现实

  • 代码出处
    链接:https://pan.baidu.com/s/10OERAD4NQlg83eTuxj_LkQ
    提取码:123a

  • https://learnopencv.com/augmented-reality-using-aruco-markers-in-opencv-c-python/

  • 【python】OpenCV—Aruco

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2130104.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

新代机床采集数据

新代集團1995年成立於台灣新竹,事業版圖遍布全球,以台灣為中心向外發展,據點橫跨歐洲、美洲、亞洲三大洲。新代長期深耕於機床控制器的軟體及硬體技術研發,專注於運動控制領域,目前已成為亞太市場中深具影響力的控制器領導品牌之一。主營產品包括:機床數控系統、伺服驅動…

Java虚拟机 - 高级篇

一、GraalVM 1. 什么是GraalVM 2. GraalVM的两种运行模式 &#xff08;1&#xff09;JIT即时编译模式 &#xff08;2&#xff09;AOT提前编译模式 3. 应用场景 4. 参数优化和故障诊断 二、新一代的GC 1. 垃圾回收器的技术演进 2. Shenandoah GC 测试代码&#xff1a; /** C…

Ubuntu 20.04/22.04无法连接网络(网络图标丢失、找不到网卡)的解决方案

问题复述&#xff1a; Ubuntu 20.04无法连接到网络&#xff0c;网络连接图标丢失&#xff0c;网络设置中无网络设置选项。 解决方案 对于Ubuntu 20.04而言&#xff1a;逐条执行 sudo service network-manager stopsudo rm /var/lib/NetworkManager/NetworkManager.statesudo…

《深度学习》OpenCV轮廓检测 模版匹配 解析及实现

目录 一、模型匹配 1、什么是模型匹配 2、步骤 1&#xff09;提取模型的特征 2&#xff09;在图像中查找特征点 3&#xff09;进行特征匹配 4&#xff09;模型匹配 3、参数及用法 1、用法 2、参数 1&#xff09;image&#xff1a;待搜索对象 2&#xff09;templ&am…

利用AI驱动智能BI数据可视化-深度评测Amazon Quicksight(四)

简介 随着生成式人工智能的兴起&#xff0c;传统的 BI 报表功能已经无法满足用户对于自动化和智能化的需求&#xff0c;今天我们将介绍亚马逊云科技平台上的AI驱动数据可视化神器 – Quicksight&#xff0c;利用生成式AI的能力来加速业务决策&#xff0c;从而提高业务生产力。…

科技之光,照亮未来之路“2024南京国际人工智能展会”

全球科技产业的版图正以前所未有的速度重构&#xff0c;而位于中国东部沿海经济带的江浙沪地区&#xff0c;作为科技创新与产业升级的高地&#xff0c;始终站在这一浪潮的最前沿。2024年&#xff0c;这一区域的科技盛宴——“2024南京人工智能展会”即将在南京国际博览中心盛大…

基础的八股

JS this 全局&#xff1a;this指向window 函数&#xff1a;this指向window 对象&#xff1a;this指向调用它的 get、post的区别 1、写的地方不同&#xff1a;get在地址栏里 地址栏有多长就只能写多少、post在请求体里 没有上限 2、关于回退和刷新&#xff1a;get回退和刷新没问…

TCP、UDP、HTTPS、HTTP

前言 OSI七层网络 名称解释协议应用层定义了各种应用协议的数据规范 HTTP、HTTPS、SSL FTP、DNS TFTP、SMTP 表示层不同系统之间通信会话层断点续传传输层 一个电脑有许多端口&#xff0c;根据端口找到发送方与接收方 确保数据包完整性 TCP、UDP网络层 ARP协议&#xff1a;通过…

shopify主题布局layout

一、基本概念 Layout是Shopify主题中的基础结构&#xff0c;它决定了页面的整体框架和布局方式。通过Layout&#xff0c;可以统一管理和控制页面上的公共元素&#xff0c;如页眉&#xff08;Header&#xff09;、页脚&#xff08;Footer&#xff09;等&#xff0c;确保这些元素…

闯关leetcode——20. Valid Parentheses

大纲 题目地址内容 解题代码地址 题目 地址 https://leetcode.com/problems/valid-parentheses/description/ 内容 Given a string s containing just the characters ‘(’, ‘)’, ‘{’, ‘}’, ‘[’ and ‘]’, determine if the input string is valid. An input st…

批量采集电商商品详情数据接口(上货and数据分析价格库存监控等)

——在成长的路上&#xff0c;我们都是同行者。这篇关于电商API接口的文章&#xff0c;希望能帮助到您。期待与您继续分享更多API接口的知识&#xff0c;请记得关注Anzexi58哦&#xff01; 批量采集电商商品详情数据涉及到多个方面&#xff0c;包括商品的上货、价格监控、库存监…

机器学习--神经网络

神经网络 计算 神经网络非常简单&#xff0c;举个例子就理解了&#xff08;最后一层的那个写错了&#xff0c;应该是 a 1 ( 3 ) a^{(3)}_1 a1(3)​&#xff09;&#xff1a; n o t a t i o n notation notation&#xff1a; a j ( i ) a^{(i)}_j aj(i)​ 表示第 i i i 层的…

SprinBoot+Vue财务管理系统的设计与实现

目录 1 项目介绍2 项目截图3 核心代码3.1 Controller3.2 Service3.3 Dao3.4 application.yml3.5 SpringbootApplication3.5 Vue 4 数据库表设计5 文档参考6 计算机毕设选题推荐7 源码获取 1 项目介绍 博主个人介绍&#xff1a;CSDN认证博客专家&#xff0c;CSDN平台Java领域优质…

使用opencv优化图片(画面变清晰)

文章目录 需求影响照片清晰度的因素 实现降噪测试代码 锐化空间锐化Unsharp Masking频率域锐化对比测试 对比度增强常用算法对比测试 需求 对图像进行优化&#xff0c;使其看起来更清晰&#xff0c;同时保持尺寸不变&#xff0c;通常涉及到图像处理技术如锐化、降噪、对比度增强…

百度地图SDK Android版开发 11 覆盖物示例 4 线

百度地图SDK Android版开发 11 覆盖物示例 4 线 前言界面布局MapPolyline类常量成员变量初始值创建覆盖物移除覆盖物设置属性加载地图和释放地图 MapPolylineActivity类控件响应事件 运行效果图 前言 文本通过创建多个不同线宽的折线和大地曲线&#xff0c;介绍Polyline的使用…

numpy中的比较运算

目录 比较运算符 比较运算符 有两种情况会普遍使用比较运算符&#xff0c;一个是从数组中查询满足条件的元素&#xff0c;另一个是根据判断的结果执行不同的操作。 示例入下&#xff1a; import numpy as np arr7 np.array([[1,2,10],[10,8,3],[7,6,5]]) arr8 np.array([[2,…

整流器制造5G智能工厂物联数字孪生平台,推进制造业数字化转型

整流器制造行业作为制造业的重要组成部分&#xff0c;也在积极探索数字化转型的新路径。整流器&#xff0c;作为电力电子领域的关键元件&#xff0c;广泛应用于通信、工业控制、新能源等多个领域&#xff0c;其制造过程的智能化升级不仅关乎产品性能的提升&#xff0c;更是推动…

opencv使用videocapture打开视频时,依赖opencv_ffmpeg***.dll,默认必须放到执行目录,自定义目录需要重新编译opencv库

1. 找到modules下opencv_highgui模块的cap_ffmpeg.cpp 2. 找到加载opencv_ffmpeg的接口, 修改接口内opencv_ffmpeg的路径即可.

YOLOv10优改系列一:YOLOv10融合C2f_Ghost网络,让YoloV10实现性能的均衡

&#x1f4a5; &#x1f4a5;&#x1f4a5; &#x1f4a5;&#x1f4a5; &#x1f4a5;&#x1f4a5; &#x1f4a5;&#x1f4a5;神经网络专栏改进完整目录&#xff1a;点击 &#x1f497; 只需订阅一个专栏即可享用所有网络改进内容&#xff0c;每周定时更新 文章内容&#x…

基于JavaWeb开发的javaSpringboot+mybatis+layui的装修验收管理系统设计和实现

基于JavaWeb开发的javaSpringbootmybatislayui的装修验收管理系统设计和实现 &#x1f345; 作者主页 网顺技术团队 &#x1f345; 欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; &#x1f345; 文末获取源码联系方式 &#x1f4dd; &#x1f345; 查看下方微信号获取联系…