美人鱼图像双目配准-Mermaid

news2024/9/23 20:11:46

前言:

我在进行一项双目测距的项目,已经通过matlab 进行了相机标定,如果手动选择左右图像里的相同物体,是可以给出可接受距离的。

但是现在我希望能够让左视图的坐标点和右视图的坐标点进行匹配(如下图)

于是,我分别使用了ORB 关键点匹配进行投射变换、美人鱼图像配准得到变换矩阵

ORB 关键点匹配

思路:

先进行关键点匹配,由于双目图像已经是标定后的,所以一般来说可以认为图像是水平的。

那么可以过滤一下匹配点,把斜率超过0.1的全部筛掉,只保留水平匹配线。

效果:

不是那么理想,进行变换后,发现由于物体的远近,导致配准时候只保留了最前端物体的匹配。所有只有部分数据是可以进行距离测量的。

代码:

'''
-*- coding: utf-8 -*-
@File  : match.py
@Author: Shanmh
@Time  : 2024/03/22 上午9:50
@Function: 关键点匹配进行投射变换
'''

import cv2
import imutils
import numpy as np
import math
import time
import os


def align_images(image, template, maxFeatures=100000, keepPercent=1,
                 debug=False):
    # use the homography matrix to align the images
    (h, w) = template.shape[:2]
    print(image.shape)
    print(template.shape)


    # convert both the input image and template to grayscale
    imageGray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    templateGray = cv2.cvtColor(template, cv2.COLOR_BGR2GRAY)

    # use ORB to detect keypoints and extract (binary) local
    # invariant features
    orb = cv2.ORB_create(nfeatures = maxFeatures,
             scaleFactor = 1.2,
             nlevels = 32,
             edgeThreshold = 16,
             firstLevel = 2,
             WTA_K = 4,
             scoreType = 1,
             patchSize = 8,
             fastThreshold = 20)


    (kpsA, descsA) = orb.detectAndCompute(imageGray, None)
    (kpsB, descsB) = orb.detectAndCompute(templateGray, None)

    method = cv2.DESCRIPTOR_MATCHER_BRUTEFORCE_HAMMING
    matcher = cv2.DescriptorMatcher_create(method)
    matches = matcher.match(descsA, descsB, None)

    # sort the matches by their distance (the smaller the distance,

    matchesall = sorted(matches, key=lambda x: x.distance)

    keep = int(len(matchesall) * 0.5)
    matches=matchesall[:keep]

    new_match=[]
    image_show=np.concatenate((image,template),axis=1)
    # 匹配角度过滤
    for match in matches:
        query_idx = match.queryIdx
        train_idx = match.trainIdx
        distance = match.distance
        pt1=(int(kpsA[query_idx].pt[0]),int(kpsA[query_idx].pt[1]))
        pt2=int(kpsB[train_idx].pt[0]+w),int(kpsB[train_idx].pt[1])
        dw=abs(pt1[0]-pt2[0])
        dh=abs(pt1[1]-pt2[1])

        if dh/dw<0.1  :
            if debug:
                # cv2.line(image_show,pt1,pt2,(0,0,255), thickness=1)
                cv2.circle(image_show, pt1, 2, (0, 255, 0), -1)
                cv2.circle(image_show, pt2, 2, (0, 255, 0), -1)
            new_match.append(match)


    if debug:
        cv2.imshow("show",image_show)
    matches=new_match


    # check to see if we should visualize the matched keypoints
    if debug:
        matchedVis = cv2.drawMatches(image, kpsA, template, kpsB,
                                     matches, None)
        matchedVis = imutils.resize(matchedVis, width=1000)
        cv2.imshow("Matched Keypoints", matchedVis)
        cv2.waitKey(0)

    ptsA = np.zeros((len(matches), 2), dtype="float")
    ptsB = np.zeros((len(matches), 2), dtype="float")
    for (i, m) in enumerate(matches):
        ptsA[i] = kpsA[m.queryIdx].pt
        ptsB[i] = kpsB[m.trainIdx].pt

    (H, mask) = cv2.findHomography(ptsA, ptsB, method=cv2.RANSAC)
    (h, w) = template.shape[:2]
    print(template.shape)
    # aligned2 = cv2.warpPerspective(image, H, (w, h))
    return H



if __name__ == '__main__':
    pass
    imgl=cv2.imread("../test240421/llll.jpg")[100:-100,:,:]
    imgl=cv2.imread("/home/hxzh/PycharmProjects/StereoVision/im1E.png")
    imgl=cv2.resize(imgl,(900,720))
    imgr=cv2.imread("../test240421/rrrr.jpg")[100:-100,:,:]
    imgr=cv2.imread("/home/hxzh/PycharmProjects/StereoVision/im1L.png")
    imgr=cv2.resize(imgr,(900,720))

    homography=align_images(imgl,imgr,debug=True)
    image_con = np.concatenate((imgl, imgr), axis=1)
    # 定义imgl上的点
    pointl=[607,425]
    srcPoint = np.array([[pointl]], dtype=np.float32)
    # 进行坐标变换
    dstPoint = cv2.perspectiveTransform(srcPoint, homography)[0][0]
    print(dstPoint)
    cv2.line(image_con, pointl, [int(dstPoint[0]+imgr.shape[1]),int(dstPoint[1])], (0, 0, 255), thickness=1)

    cv2.imshow("aaaaaaaa",image_con)


    align = cv2.warpPerspective(imgl, homography, imgr.shape[:2][::-1])
    cv2.imshow("imgl",imgl)
    cv2.imshow("imgr",imgr)
    cv2.imshow("align",align)

    cv2.imwrite("testimg.jpg",align)
    cv2.imwrite("imgr.jpg",imgr)
    cv2.imwrite("imgl.jpg",imgl)

    print(align.shape)
    cv2.waitKey(0)


美人鱼配准

github:GitHub - uncbiag/mermaid: Image registration using pytorch

doc:mermaid: iMagE Registration via autoMAtIc Differentiation — mermaid 0.1 documentation

思路:

使用美人鱼进行迭代配准,得到转换矩阵,计算对应坐标

效果:

可以看到红色栅格线,已经进行了流变换,保证了左右视图物体对应。对于这种背景单一,只有一个物体的效果还是不错的。但是这种对左右视图要求比较高,左右视图对应物体最好不要超过一个网格的距离。

代码:

需要先参考doc配置好环境,然后再jupyter运行,迭代到 relF 为0 就差不多了

'''

pip install -U numpy==1.22.4

'''



import time
import cv2
import numpy as np
import matplotlib.pyplot as plt
import mermaid.module_parameters as pars
import mermaid.example_generation as EG

time.sleep(10)
def show_warped_with_grid(I, phi, title):
    plt.imshow(I[0,0,:,:] ,cmap='gray')
    plt.contour(phi[0, 0, :, :],
            np.linspace(-1, 1, 20),
            colors='r',
            linestyles='solid',
            linewidths=0.5)
    plt.contour(phi[0, 1, :, :],
            np.linspace(-1, 1, 20),
            colors='r',
            linestyles='solid',
            linewidths=0.5)
def show_image(I, title):
    plt.imshow(I[0,0,:,:], cmap='gray')
    plt.axis('off')
    plt.title(title)

#创建大小黑格
params = pars.ParameterDict()
use_synthetic_test_case = True
add_noise_to_bg = True
dim = 2
sz = 64
szEx = np.tile(sz, dim)
I0_syn, I1_syn, spacing_syn = EG.CreateSquares(dim, add_noise_to_bg).create_image_pair(szEx, params)
print("I0_syn",I0_syn.dtype,I0_syn)
print("I1_syn",I1_syn.dtype,I1_syn)
print("spacing_syn",spacing_syn.dtype ,spacing_syn)

print('Size I0:', I0_syn.shape)
print('Size I1:', I1_syn.shape)
plt.figure(figsize=(10,4))
plt.subplot(121)
plt.imshow(I0_syn[0,0,:,:],cmap='gray')
plt.title('Source')
plt.axis('off');
plt.subplot(122)
plt.imshow(I1_syn[0,0,:,:],cmap='gray')
plt.title('Target')
plt.axis('off');

img=cv2.imread("/home/hxzh/PycharmProjects/StereoVision/im1E.png",0)
targetimg=cv2.imread("/home/hxzh/PycharmProjects/StereoVision/im1L.png",0)

img=cv2.resize(img,(640,640))/255.
targetimg=cv2.resize(targetimg,(640,640))/255.

print(img.shape)
print(targetimg.shape)

I0_syn = img.reshape([1, 1] + list(img.shape)).astype(np.float32)
I1_syn = (targetimg.reshape([1, 1] + list(targetimg.shape))).astype(np.float32)
spacing_syn=spacing = 1. / (np.array(I0_syn.shape)[2::] - 1)   
        

print("I0_syn",I0_syn.dtype,I0_syn)
print("I1_syn",I1_syn.dtype,I1_syn)
print("spacing_syn",spacing_syn.dtype ,spacing_syn)

print('Size I0:', I0_syn.shape)
print('Size I1:', I1_syn.shape)
plt.figure(figsize=(10,4))
plt.subplot(121)
plt.imshow(I0_syn[0,0,:,:],cmap='gray')
plt.title('Source')
plt.axis('off');
plt.subplot(122)
plt.imshow(I1_syn[0,0,:,:],cmap='gray')
plt.title('Target')
plt.axis('off');
import time

#LDDDM (shooting, scalar momentum)
import torch
import mermaid.utils as utils
import mermaid.visualize_registration_results as vizreg
from __future__ import print_function
import numpy as np
import matplotlib.pyplot as plt

import mermaid.simple_interface as SI


import cv2



si = SI.RegisterImagePair()
si.print_available_models()

I_0 = torch.from_numpy(I0_syn)
I_1 = torch.from_numpy(I1_syn)
phi = si.get_map()
# I_W = utils.compute_warped_image_multiNC(I_0,
#                                          phi,
#                                          spacing_syn,
#                                          spline_order=1)
# vizreg.show_current_images(len(si.get_history()['energy']),
#                            I_0,
#                            I_1,
#                            I_W,
#                            phiWarped=phi)



si.register_images(I0_syn, I1_syn, spacing_syn, model_name='lddmm_shooting_scalar_momentum_image',
                   nr_of_iterations=100,
                   use_multi_scale=True,
                   visualize_step=True,
                   optimizer_name='sgd',
                   learning_rate=0.5,
                   rel_ftol=1e-7,
                   json_config_out_filename=('test2d_tst.json', 'test2d_tst_with_comments.json'),
                   params='./mermaid_demos/2d_example_synth/lddmm_setting.json',
#                    params="test/json/test_lddmm_shooting_scalar_momentum_image_multi_scale_config.json",
                   recording_step=1)

参考:

给几个双目相机标定的参考文章:

双目摄像头Matlab参数定标_matlab双目相机标定参数-CSDN博客

YOLO v5与双目测距结合,实现目标的识别和定位测距_yolo双目测距-CSDN博客

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

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

相关文章

Windows 安装 Java JDK 17 (源码方式安装)【图文详细教程】

这里我选择安装的 Java JDK 的版本为 17 Java JDK 下载 这里选择下载压缩包形式的 Java JDK&#xff0c;下载完成后&#xff0c;我们只需要对压缩包进行解压&#xff0c;然后再配置系统环境变量就可以了下载网址&#xff1a;https://www.oracle.com/cn/java/technologies/down…

【C语言】linux内核pci_enable_device函数和_PCI_NOP宏

pci_enable_device 一、注释 static int pci_enable_device_flags(struct pci_dev *dev, unsigned long flags) {struct pci_dev *bridge;int err;int i, bars 0;/** 此时电源状态可能是未知的&#xff0c;可能是由于新启动或者设备移除调用。* 因此获取当前的电源状态&…

电脑总是自动删除下载或解压后的文件

电脑总是自动删除下载或解压后的文件 前言&#xff1a; 最近navicat15 破解时候&#xff0c;下载安装包和破解包&#xff0c;破解包在解压后自动删除&#xff0c;要不然就是文件包含病毒电脑自动关闭打开功能。 解决方案&#xff1a; 注意&#xff1a;注意电脑重启或者重新打…

springboot 大文件分片上传

springboot 大文件分片上传 constantentityvocontrollerutils大文件分片上传是一种将大文件分割成多个小文件片段,然后分别上传这些小文件片段的方法。这种方法的好处包括: 减少重新上传开销:如果网络传输中断,只需重传未上传的部分,而不是整个文件。 提高灵活性:分片大小…

【ZZULI数据结构实验一】多项式的三则运算

【ZZULI数据结构实验一】多项式的四则运算 ♋ 结构设计♋ 方法声明♋ 方法实现&#x1f407; 定义一个多项式类型并初始化---CreateDataList&#x1f407; 增加节点---Getnewnode&#x1f407; 打印多项式类型的数据-- PrintPoly&#x1f407; 单链表的尾插--Listpush_back&…

Bert基础(七)--Bert实战之理解Bert模型结构

在篇我们将详细学习如何使用预训练的BERT模型。首先&#xff0c;我们将了解谷歌对外公开的预训练的BERT模型的不同配置。然后&#xff0c;我们将学习如何使用预训练的BERT模型作为特征提取器。此外&#xff0c;我们还将探究Hugging Face的Transformers库&#xff0c;学习如何使…

【机器学习】引领未来的力量:技术革新与应用探索

&#x1f9d1; 作者简介&#xff1a;阿里巴巴嵌入式技术专家&#xff0c;深耕嵌入式人工智能领域&#xff0c;具备多年的嵌入式硬件产品研发管理经验。 &#x1f4d2; 博客介绍&#xff1a;分享嵌入式开发领域的相关知识、经验、思考和感悟。提供嵌入式方向的学习指导、简历面…

nodejs中使用@maxmind/geoip2-node 查询地理位置信息

介绍 maxmind/geoip2-node 是一个Node.js模块&#xff0c;用于与MaxMind的GeoIP2数据库进行交互&#xff0c;从而获取IP地址的地理位置信息。MaxMind的GeoIP2数据库包含了全球范围内的IP地址和对应的地理位置信息&#xff0c;如国家、城市、经纬度等。使用maxmind/geoip2-node…

利用sin/cos原理驱动步进电机

利用sin/cos原理控制步进电机转动 前言什么是步进电机驱动器细分控制电机内部结构图片步进电机驱动原理&#xff08;重要&#xff09;步进电机参数&#xff11;、步距角&#xff1a;收到一个脉冲转动的角度&#xff12;、细分数 &#xff1a;&#xff11;&#xff0f;&#xf…

M1 mac安装 Parallels Desktop 18 激活

M1 mac安装 Parallels Desktop 18 激活 下载安装Parallels Desktop 18.1.1 (53328) 激活1. 拷贝prl_disp_service2. 在终端打开Crack所在位置3. 输入命令&#xff0c;激活成功 下载 安装包和激活文件下载地址 链接: https://pan.baidu.com/s/1EjT7xeEDcntIIoOvvhBDfg?pwd9pue …

Kubernetes Pod深度解析:构建可靠微服务的秘密武器(上)

&#x1f407;明明跟你说过&#xff1a;个人主页 &#x1f3c5;个人专栏&#xff1a;《Kubernetes航线图&#xff1a;从船长到K8s掌舵者》 &#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目录 一、引言 1、Kubernetes概述 2、Pod概述 二、Po…

AI老人跌倒监测报警摄像机

AI老人跌倒监测报警摄像机是一种基于人工智能技术的智能监控设备&#xff0c;专门用于监测老年人的跌倒情况并提供实时报警功能&#xff0c;以及时处理紧急情况&#xff0c;保障老人安全。这种摄像机利用先进的AI算法和深度学习技术&#xff0c;能够实时监测老人的行为&#xf…

时序信号高低频分析——经验模态分解EMD

时序信号高低频分析——经验模态分解EMD 介绍 经验模态分解&#xff08;Empirical Mode Decomposition&#xff0c;EMD&#xff09;是一种用于时序信号分解的自适应方法&#xff0c;旨在将原始信号分解为多个固有模态函数&#xff08;Intrinsic Mode Functions&#xff0c;IM…

【c++】类和对象(二)this指针

&#x1f525;个人主页&#xff1a;Quitecoder &#x1f525;专栏&#xff1a;c笔记仓 朋友们大家好&#xff0c;本节内容来到类和对象第二篇&#xff0c;本篇文章会带领大家了解this指针 目录 1.this指针1.1this指针的引出1.2this指针的特性1.3思考题1.4C语言和C实现Stack的对…

RWTH-PHOENIX Weather数据集模型说明和下载

RWTH-PHOENIX Weather 2014 T数据集说明: 德国公共电视台PHOENIX在三年内(2009 年至 2011 年) 录制了配有手语翻译的每日新闻和天气预报节目,并使用注释符号转录了 386 个版本的天气预报。 此外,我们使用自动语音识别和手动清理来转录原始德语语音。因此,该语料库允许训练…

近线数仓优化改造

近线数仓优化改造 1. 背景2. 优化3. 改造3.1. 重构3.2. 优化 1. 背景 大概就是有那么一个数仓&#xff0c;然后简略结构如下&#xff1a; #mermaid-svg-PVoUzuQhj2BK7Qge {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid…

【C语言】动态内存管理及其常见错误

文章目录 1、前言&#xff1a;为什么要有动态内存分布2、三种动态内存的创建方式及其释放2.1 malloc2.2 calloc2.3 ralloc2.4 free 3、常⻅的动态内存的错误3.1 对NULL指针的解引用操作3.2 对动态开辟空间的越界访问3.3 对非动态开辟内存使用free释放3.4 使⽤free释放⼀块动态开…

C++动态内存管理:new/delete与malloc/free的对比

在C中&#xff0c;动态内存管理是一个至关重要的概念。它允许我们在程序运行时根据需要动态地分配和释放内存&#xff0c;为对象创建和销毁提供了灵活性。在C中&#xff0c;我们通常会用到两对工具&#xff1a;new/delete 和 malloc/free。虽然它们都能够完成类似的任务&#x…

2月线上速溶咖啡行业数据分析:“减肥咖啡”引领电商新潮流

随着生活节奏的加快&#xff0c;速溶咖啡因其便捷性受到广大消费者的青睐。不过&#xff0c;在如今世界咖啡市场激烈竞争的情况下&#xff0c;中国速溶咖啡市场也受到影响&#xff0c;增速有所放缓。 根据鲸参谋电商数据平台显示&#xff0c;2月线上综合电商&#xff08;京东天…

003_vector_conventions_in_MATLA中的向量约定

MATLAB中的向量约定 1. 前言 MATLAB是一种用于数值计算和数据可视化的高级编程语言。以前&#xff0c;都不好意思说它是编程语言&#xff0c;它实际上只是一个脚本工具&#xff0c;配套了一堆工具箱。比如Simulink&#xff0c;可以开展非常复杂的仿真&#xff0c;还能编译到实…