不同相机之间图片像素对应关系求解(单应性矩阵求解)

news2024/9/23 13:27:23

一、场景

        相机1和相机2相对位置不变,相机拍摄图片有重叠,求他们交叠部分的一一对应关系。数学语言描述为已知相机1图片中P点像素(u1, v1),相机1中P点在相机2图片中像素值为(u2, v2),它们存在某种变换,求变换矩阵。

        因为涉及的场景比较简单,目前没有涉及深度,同时采集的目标近似平面,所以可以简化场景,采用单应性矩阵求解。所以上述所涉及的变换矩阵假设为单应性矩阵H(3*3矩阵),它们满足如下关系。

         这样的话,简单很多(如果场景复杂,涉及了深度或者采集对象不是平面,可以使用本质矩阵/基础矩阵的方法获取这个变换矩阵),只需借助标准标定板计算得到H。

二、单应性矩阵

        定义:用 [理想成像] 的相机从不同位置拍摄 [同一平面物体] 的图像之间存在单应性,可以用 [透视变换] 表示 。有以下公式:

         接下来就是求解H矩阵,上述公式展开如下:

         由平面坐标与齐次坐标对应关系,上式可以表示为:

         进一步,

        写成AX=0形式,如下。这种形式求解方式很多,前面的博客也有所涉及。不过需要特别指出的是,虽然H矩阵有9个未知数,但是只有8个自由度(平面关系),其中h33=1。所以求解方程只需要4个不共线点即可求解。

 

三、实际效果

3.1 全部代码

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import cv2
import numpy as np


def OnMouseAction(event, x, y, flags, param):
    """
    鼠标的回调函数,处理鼠标事件
    :param event:
    :param x:
    :param y:
    :param flags:
    :param param:
    :return:
    """
    if event == cv2.EVENT_LBUTTONDOWN:
        global gimg_x, gimg_y, gis_ok
        gimg_x = x
        gimg_y = y
        gis_ok = True
    elif event == cv2.EVENT_RBUTTONDOWN:
        print("右键点击")
    elif flags == cv2.EVENT_FLAG_LBUTTON:
        print("左鍵拖曳")
    elif event == cv2.EVENT_MBUTTONDOWN:
        print("中键点击")


def verification(img1, img2, H):
    def nothing(x):
        pass

    cv2.namedWindow('image1')
    cv2.setMouseCallback('image1', OnMouseAction)
    # create trackbars for color change
    cv2.createTrackbar('thr', 'image1', 121, 255, nothing)
    cv2.createTrackbar('Shading', 'image1', 255, 255, nothing)
    count = 0
    while True:
        cv2.imshow("image1", img1)
        cv2.imshow("image2", img2)

        k = cv2.waitKey(1) & 0xFF
        # 通过关闭窗口的右上角关闭
        if cv2.getWindowProperty('image1', cv2.WND_PROP_AUTOSIZE) < 1:
            break
        # 通过按键盘的ESC退出
        if k == 27:
            break
        global gimg_x, gimg_y, gis_ok
        if gis_ok:
            count += 1
            cv2.circle(img1, (gimg_x, gimg_y), 3, (0, 0, 255), -1)
            cv2.putText(img1, str(count), (gimg_x, gimg_y), 2, 1, (0, 0, 255))
            gis_ok = False

            (x, y, z) = np.matmul(H, np.array([gimg_x, gimg_y, 1]).T)

            cv2.circle(img2, (int(x / z), int(y / z)), 2, (0, 0, 255), -1)
            cv2.putText(img2, str(count), (int(x / z), int(y / z)), 2, 1, (0, 0, 255))


def getHomography(img1, img2):
    gray1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
    gray2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)
    criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)

    ret, corners1_1 = cv2.findChessboardCorners(gray1, (gcols, grows), None)
    if not ret:
        return ret, None
    # sub-pixel corner detection
    corners1_2 = cv2.cornerSubPix(gray1, corners1_1, (11, 11), (-1, -1), criteria)

    ret, corners2_1 = cv2.findChessboardCorners(gray2, (gcols, grows), None)
    if not ret:
        return ret, None
    # sub-pixel corner detection
    corners2_2 = cv2.cornerSubPix(gray2, corners2_1, (11, 11), (-1, -1), criteria)

    H, mask = cv2.findHomography(corners1_2, corners2_2, cv2.RANSAC)

    return True, H


gimg1Root = "./image_homography/1080p_1.png"
gimg2Root = "./image_homography/1080p_2.png"
gimg3Root = "./image_homography/720p_3.png"
(grows, gcols) = (8, 11)
def main():
    img1 = cv2.imread(gimg1Root)
    img2 = cv2.imread(gimg3Root)
    is_ok, H = getHomography(img1, img2)
    print(H)

    verification(img1, img2, H)


global gimg_x, gimg_y, gis_ok
gimg_x = 0
gimg_y = 0
gis_ok = False
if __name__ == "__main__":
    main()

3.2 实际效果

 

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

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

相关文章

计算机存储数字的本质,正码,反码,补码

计算机-原码 就是二进制定点表示法&#xff0c;即最高位为符号位&#xff1a;“0”表示正&#xff0c;“1”表示负&#xff0c;其余位表示数值的大小。 该数字不进行其他操作时数字最原始的二进制表示&#xff0c; 对于原码来说&#xff0c;绝对值相等的正数和负数只有符号位不…

高通平台开发系列讲解(USB篇)libuvc详解

文章目录 一、什么是UVC二、UVC拓扑结构三、libuvc的预览时序图沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇文章将介绍libuvc。 一、什么是UVC UVC,全称为:USB video(device) class。 UVC是微软与另外几家设备厂商联合推出的为USB视频捕获设备定义的协议标…

缓存雪崩 缓存击穿-总结

目录 缓存雪崩 缓存击穿-总结 缓存雪崩 出现场景&#xff1a; 解决方案&#xff1a; 缓存击穿 出现场景&#xff1a; 举例如图&#xff1a; 缓存击穿的三个前提&#xff1a; 解决方案&#xff1a; 缓存雪崩 缓存击穿-总结 缓存雪崩 出现场景&#xff1a; (1) 对于R…

用于隔离PWM的光耦合器选择和使用

光耦合器&#xff08;或光隔离器&#xff09;是一种将电路电隔离的器件&#xff0c;不仅在隔离方面非常出色&#xff0c;而且允许您连接到具有不同接地层或在不同电压电平下工作的电路。光耦合器具有“故障安全”功能&#xff0c;因为如果受到高于最大额定值的电压&#xff0c;…

3.1 OSPF引入路由

实验目的掌握OSPF引入静态路由的办法掌握OSPF引入直连路由的办法实验拓扑OSPF引入路由实验拓扑如图3-1所示: 图3-1:OSPF引入路由 实验步骤配置IP地址R1的配置 <Huawei>system-view [Huawei]undo info-center enabl

软件测试面试题中的sql题目你会做吗?

目录 1.学生表 2.一道SQL语句面试题&#xff0c;关于group by表内容&#xff1a; 3.表中有A B C三列,用SQL语句实现&#xff1a;当A列大于B列时选择A列否则选择B列&#xff0c;当B列大于C列时选择B列否则选择C列 4. 5.姓名&#xff1a;name 课程&#xff1a;subject 分数&…

node-sass按照失败

一、描述 从网上下载的一个Vue模板项目&#xff0c;导入VsCode&#xff0c;执行npm install命令后&#xff0c;报错了&#xff0c;报错的信息是node-sass安装失败&#xff0c;同时提示需要python环境的错误信息&#xff0c;这是因为安装node-sass失败了&#xff0c;而node-sas…

开源实时监控系统 HertzBeat 对 Linux 操作系统的监控告警实践

使用开源实时监控系统 HertzBeat 对 Linux 操作系统的监控告警实践&#xff0c;5分钟搞定&#xff01; HertzBeat 介绍 HertzBeat 是一款开源&#xff0c;易用友好的实时监控系统&#xff0c;无需Agent&#xff0c;拥有强大自定义监控能力。 集监控-告警-通知为一体&#xff0…

Spring入门案例三:注解进行引用类型的自动装配

本系列文章将会带领大家进行Spring的全面学习&#xff0c;持续关注我&#xff0c;不断更新中… 一.案例分级 简单解析:配置类替代以前的配置文件&#xff0c;实体类提供对象&#xff0c;业务类中有实体类的引用对象&#xff0c;在业务层中实现引用类的自动装配。 二.各层代码…

Java基础 -- 泛型

Java基础 -- 泛型1. Introduction1.1 好处1.2 常用泛型2. User Guide2.1 泛型类2.2 泛型方法2.3 泛型接口3. 限定泛型范围4. Awakening1. Introduction 1.1 好处 代码复用&#xff0c;多种数据类型执行相同的代码在编译期间可以检查类型是否安全&#xff0c;报警ClassCastExce…

什么是webpack

目录 1、什么是webpack&#xff08;必会&#xff09; 2、Webpack的优点是什么&#xff1f;&#xff08;必会&#xff09; 3、webpack的构建流程是什么?从读取配置到输出文件这个过程尽量说全&#xff08;必会&#xff09; 4、说一下 Webpack 的热更新原理(必会) 5、webpa…

为什么说接口幂等性很重要

先讲个故事大概三年前&#xff0c;外卖平台 Uber Eats 在印度发生了一次重大事故&#xff0c;使得用户可以免费获得食品。一天早上&#xff0c;有人试图通过印度的 Uber Eats 订购食物&#xff0c;并使用印度的支付平台 Paytm 付款。但是&#xff0c;他的账户里面没有足够的余额…

蓝牙耳机哪款性价比高音质好?2023公认音质最好的蓝牙耳机

如今音乐成了当下解压的方式之一&#xff0c;甚至是集中注意力的法器。耳机作为传播音乐的媒介&#xff0c;每个人对自己的专属耳机总有那么点小追求&#xff0c;高质量的耳机不仅保护双耳&#xff0c;带来的音质能让你的耳朵分分钟怀孕&#xff0c;下面分享几款2023年音质高的…

Cain执行中间人攻击

实验目的&#xff1a;通过构建虚拟场景&#xff0c;了解中间人攻击和钓鱼网站攻击的执行流程&#xff0c;熟练使用Cain & Abel工具实现攻击&#xff0c;并掌握识别和防御此类攻击的技术原理和方法。 一、场景简介 甄某为犯罪嫌疑人&#xff0c;警察想获得甄某在其单位网站…

IB学科学习方法分享,看看不同学科怎么学习?(一)

在这个部分&#xff0c;我们邀请到了在各个学科中突出的同学们&#xff0c;让他们介绍自己的学习方法。同辈的经验总是我们能够获取的珍贵的宝藏&#xff01; 分享人&#xff1a;吴 分享学科&#xff1a;VA HL &#xff08;个人选课&#xff1a;HL&#xff1a;VA 中文 经济…

同行不同命:极兔喜、韵达愁?

配图来自Canva可画 年前买坚果、牛奶、灯笼、对联等年货&#xff0c;年后寄香肠、腊肉、泡菜、水果等特产&#xff0c;春节前后是快递业迎来收发货小高峰&#xff0c;三通一达&#xff0c;顺丰、京东、极兔相继宣布“春节不打烊”消息&#xff0c;全力保障快递运力。 春节快递…

力扣-组合两个表

大家好&#xff0c;我是空空star&#xff0c;本篇带你了解一道简单的力扣sql练习题。 文章目录前言一、题目&#xff1a;175. 组合两个表二、解题1.left join提交SQL运行结果2.right join提交SQL运行结果总结前言 一、题目&#xff1a;175. 组合两个表 表: Person ----------…

Bernstein-Vazirani算法

B-V算法 (1) 问题描述 给定布尔函数f:{0,1}n→0,1f:{\left\{ {0,1} \right\}^n} \to{0,1}f:{0,1}n→0,1, 函数fff的值是由输入比特串xxx和确定的比特串sss做模2意义下的内积&#xff1a;f(x)x⋅s(mod2),f\left( x \right) x \cdot s\left( {\bmod 2} \right),f(x)x⋅s(mod2),…

【Node.js】 npm与包

npm与包什么是包包的来源为什么需要包从哪里下载包怎么下载包初体验在项目中安装包的命令npm的注意点包的语义化版本规范包管理配置文件&#xff08;package.json&#xff09;当第三方包的体积过大时快速创建package.jsondependencies节点devDependencies节点卸载包解决下载包速…

H.264视频隐写中可用于隐藏的场地(变换过程)

与静止图像中的信息隐藏类似&#xff0c;通过位平面替换的方式&#xff0c;亮度DCT系数通常被用于信息隐藏。 Ma等[77]提出将信息嵌入在I-frame中量化的DCT系数中(亮度)。在分析DCT系数与像素值产生的失真之间的关系的基础上&#xff0c;对几个系数进行配对&#xff0c;以达到数…