第四章:照相机模型与增强现实

news/2024/9/18 14:57:43/ 标签: ar
<article class="baidu_pl">
article_content" class="article_content clearfix">

目录

argin-left:80px;">1 针孔照相机模型

argin-left:120px;">1.1 照相机矩阵

argin-left:120px;">1.2 三维点的投影

argin-left:120px;">1.3 照相机矩阵的分解

argin-left:120px;">1.4 计算照相机中心

argin-left:80px;">2 照相机标定

argin-left:80px;">3 以平面和标记物进行姿态估计

argin-left:80px;">4 增强现实

argin-left:120px;">4.1 PyGame和PyOpenGL

argin-left:120px;">4.2 从照相机矩阵到OpenGL格式

argin-left:120px;">4.3 在图像中放置物体


arent;">1 针孔照相机模型

针孔照相机模型是计算机视觉中广泛使用的照相机模型。该相机从一个小孔采集射到暗箱内部的光线。在真空照相机模型中,在光线投射到图像平面之前,从唯一一个点经过。

在图中示出了与针孔相机映射有关的几何形状。该图包含以下基本对象:

  • 一个原点在O点的三维正交坐标系,这也是相机光圈的位置。坐标系的三个轴被称为X1、X2、X3。X3轴指向相机的观察方向,称为光轴、主轴或主射线。由轴X1和X2张成的平面是相机的正面,或称主平面。
  • 一个像平面,其中三维世界通过相机光圈进行投影。像平面平行于轴X1和X2,并且在X3轴的负方向上与原点O距离为f,其中f是针孔相机的焦距。针孔相机的实际实现意味着像平面的位置应使与X3轴在坐标-f处相交,其中f>0。
  • 在光轴和像平面相交处的点R,该点称为主点或图像中心。
  • 真实世界中的某一点P,有相对于轴X1、X2、X3的坐标(x1,x2,x3)。点P在相机中的投影线。也就是图中穿过点P和点O的绿线。点P在像平面上的投影,记作点Q。这个点由投影线(绿色)与像平面的交点表示。在任何实际情况下,我们可以假设x3>0,这意味着交点是定义良好的。
  • 在像平面上也有一个二维坐标系:原点在R,轴Y1和Y2分别平行于X1和X2。点Q相对于这个坐标系的坐标是(y1,y2)。
1.1 照相机矩阵

照相机矩阵可以分解为:

P=K[R|t]

其中,R是描述照相机方向的旋转矩阵,t是描述照相机中心位置的三维平移向量,内标定矩阵K描述照相机的投影性质。标定矩阵仅和照相机自身的情况相关,通常情况下可以写成:

K=\begin{bmatrix} f &0 & c_x\\ 0& f &c_y \\ 0& 0&1 \end{bmatrix}

图像平面和照相机中心的距离称为焦距f。当像素数组在传感器上偏斜的时候,需要用到倾斜参数s。在大多数情况下s可以设置为0。

纵横比例α是在像素元素非正方形的情况下使用的,通常情况下可以默认设置α=1。

除焦距之外,标定矩阵中剩余的唯一参数为光心,即主点,也就是光线坐标轴和图像平面的交点。因为光心通常在图像的中心,并且图像的坐标是从左上角开始计算的,所以光心的坐标常接近于图像高度和宽度的一半。

1.2 三维点的投影

创建一个照相机类,用来处理对照相机和投影建模所需要的全部操作

from scipy.import linalgclass Camera(object):def _init_(self, p):self.p = pself.K = Noneself.R = Noneself.t = Noneself.c = Nonedef project(self, x):x = dot(self.P, X)for i in range(3):x[i] /= x[2]return x

下边的例子将三维中的点投影到图像视图中:

from pylab import *
import camerapoints=loadtxt('house.p3d').T
points=vstack((points,ones(points.shape[1])))P=hstack((eye(3),array([[0],[0],[-10]])))
cam = camera.Camera(P)
x=cam.project(points)figure()
subplot(121)
axis('off')
plot(x[0],x[1],'k.')
subplot(122)
axis('off')
r=0.05*random.rand(3)
rot=camera.rotation_matrix(r)
for t in range(20):cam.P=dot(cam.P,rot)x=cam.project(points)plot(x[0],x[1],'k.')show()

首先使用齐次坐标表示这些点,然后使用一个投影矩阵来创建Camera对象将这些三维点投影到图像平面并执行绘制操作,上边的代码围绕这个随机的三维变量进行增量旋转的投影,使用rotation_matrix()函数创建了一个进行三维旋转的旋转矩阵,可以运行代码进行随机旋转并观察结果。得到的结果如下图所示:

1.3 照相机矩阵的分解

如果给定一个照相机矩阵P,需要恢复内参数K以及照相机的位置t和姿势R,这种矩阵分块操作称为因子分解。

下面的代码使用RQ因子分解的方法。但这种分解方法的结果并不是唯一的,分解的结果存在二义性。由于需要限制旋转矩阵R为正定的,所以如果需要可以在求解的结果中加入变换T来改变符号。

def factor(self):K, R = li.rq(self.P[:, :3])T = diag(sign(diag(K)))if li.det(T) < 0:T[1, 1] *= -1self.K = dot(K, T)self.R = dot(T, R)self.t = dot(li.inv(self.K), self.P[:, 3])return self.K, self.R, self.t

运行下面的代码,观察矩阵分解的结果:

K=array([[1000,0,500],[0,1000,300],[0,0,1]])
tmp=camera.rotation_matrix([0,0,1])[:3,:3]
Rt=hstack((tmp,array([[50],[40],[30]])))
cam=camera.Camera(dot(K,Rt))print(K,Rt)
print(cam.factor())

 运行结果:

1.4 计算照相机中心

给定照相机投影矩阵P,可以计算出空间上照相机的所在位置。照相机中心为C,是一个三维点,满足约束条件PC=0。对于投影矩阵为P=K[R|t]照相机可以通过下述式子计算C:

在这里插入图片描述

下面的代码可以按照上述公式返回机选照相机的中心:

def center(self):if self.c is not None:return self.celse:self.factor()self.c = -dot(self.R.T, self.t)return self.c

arent;">2 照相机标定

标定照相机是指计算出该照相机的内参数。

具体步骤如下:

  • 测量你选定矩形标定物体的变长dX和dY;
  • 将照相机和标定物体放置在平面上,使得照相机的背面和标定物体平行,同时物体位于照相机图像视图的中心;
  • 测量标定物体到照相机的距离dZ;
  • 拍摄一幅图像来检验该设置是否正确,即标定物体的边要和图像的行和列对齐;
  • 使用像素数来测量标定物体图像的宽度和高度。

测量到的数据写入一个辅助函数:

def my_calibration(sz):row,col= szfx=2555*col/2592fy=2586*row/1936K=diag([fx,fy,1])K[0,2]=0.5*colK[1,2]=0.5*rowreturn K

该函数的输入参数为表示图像大小的元组,返回参数为标定矩阵。

3 以平面和标记物进行姿态估计

使用下面的代码提取两幅图像的SIFT特征,然后使用RANSAC算法稳健地估计单应性矩阵:

sift1.process_image('qinghai1.jpg', 'im0.sift')
l0, d0 = sift.read_features_from_file('im0.sift')sift1.process_image('qinghai2.jpg', 'im1.sift')
l1, d1 = sift.read_features_from_file('im1.sift')matches = sift.match_twosided(d0, d1)
ndx = matches.nonzero()[0]
fp = homography.make_homog(l0[ndx, :2].T)
ndx2 = [int(matches[i]) for i in ndx]
tp = homography.make_homog(l1[ndx, :2].T)model = homography.RansacModel()
H = homography.H_from_ransac(fp, tp, model)

该单应性矩阵将一幅图像中标记物上的点映射到另一幅图像中的对应点。定义相应的三维坐标系,使标记物在X-Y平面上,原点在标记物的某位置上。

为了检验单应性矩阵结果的正确性,需要将一些简单的三维物体放置在标记物上,下边的函数用来产生立方体上的点:

def cube_points(c, wid):p = []p.append([c[0] - wid, c[1] - wid, c[2] - wid])p.append([c[0] - wid, c[1] + wid, c[2] - wid])p.append([c[0] + wid, c[1] + wid, c[2] - wid])p.append([c[0] + wid, c[1] - wid, c[2] - wid])p.append([c[0] - wid, c[1] - wid, c[2] - wid])p.append([c[0] - wid, c[1] - wid, c[2] + wid])p.append([c[0] - wid, c[1] + wid, c[2] + wid])p.append([c[0] + wid, c[1] + wid, c[2] + wid])p.append([c[0] + wid, c[1] - wid, c[2] + wid])p.append([c[0] - wid, c[1] - wid, c[2] + wid])p.append([c[0] - wid, c[1] - wid, c[2] + wid])p.append([c[0] - wid, c[1] + wid, c[2] + wid])p.append([c[0] - wid, c[1] + wid, c[2] - wid])p.append([c[0] + wid, c[1] + wid, c[2] - wid])p.append([c[0] + wid, c[1] + wid, c[2] + wid])p.append([c[0] + wid, c[1] - wid, c[2] + wid])p.append([c[0] + wid, c[1] - wid, c[2] - wid])return array(p).T

接下来可以实现两个视图间的相对变换:

K = my_calibration((747, 1000))box = cube_points([0, 0, 0.1], 0.1)cam1 = camera.Camera(hstack((K, dot(K, array([[0], [0], [-1]])))))box_cam1 = cam1.project(homography.make_homog(box[:, :5]))box_trans = homography.normalize(dot(H,box_cam1))cam2 = camera.Camera(dot(H, cam1.P))
A = dot(linalg.inv(K), cam2.P[:, :3])
A = array([A[:, 0], A[:, 1], cross(A[:, 0], A[:, 1])]).T
cam2.P[:, :3] = dot(K, A)box_cam2 = cam2.project(homography.make_homog(box))

第一个产生的标定矩阵就是在该图像分辨率大小下的标定矩阵,cube_points()函数产生的前五个点对应与立方体底部的点。

使用下边的代码来可视化这些投影后的点:

im0 = array(Image.open('1.jpg'))
im1 = array(Image.open('2.jpg'))figure()
imshow(im0)
plot(box_cam1[0, :], box_cam1[1, :], linewidth=3)
title('2D projection of bottom square')
axis('off')figure()
imshow(im1)
plot(box_trans[0, :], box_trans[1, :], linewidth=3)
title('2D projection transfered with H')
axis('off')figure()
imshow(im1)
plot(box_cam2[0, :], box_cam2[1, :], linewidth=3)
title('3D points projected in second image')
axis('off')show()

 为了能够之后再次使用,可以使用Pickle将这些照相机矩阵保存起来:

import picklewith open('ar_camera.pkl', 'w') as f:pickle.dump(K, f)pickle.dump(dot(linalg.inv(K), cam2.P), f)

4 增强现实

增强现实(Augmented Reality,简称 AR),是一种实时地计算摄影机影像的位置及角度并加上相应图像的技术。它把原本在现实世界的一定时间空间范围内很难体验到的实体信息(视觉信息,声音,味道,触觉等),通过科学技术模拟仿真后再叠加到现实世界被人类感官所感知,从而达到超越现实的感官体验。

4.1 PyGame和PyOpenGL

PyGame是非常流行的游戏开发工具包,它可以简单的处理现实窗口、输入设备、事件,以及其他内容。
PyOpenGL是OpenGL图形编程的Python绑定接口。OpenGL可以安装在几乎所有的系统上,并且具有很好的图形性能。OpenGL具有跨平台性,能够在不同的操作系统之间工作。

4.2 从照相机矩阵到OpenGL格式

OpenGL 使用4×4 的矩阵来表示变换(包括三维变换和投影)。这和我们使用 的 3×4 照相机矩阵略有差别。但是,照相机与场景的变换分成了两个矩阵,GL_PROJECTION 矩阵和GL_MODELVIEW 矩阵GL_PROJECTION 矩阵处理图像成像的性质,等价于我们的内标定矩阵 K。GL_MODELVIEW 矩阵处理物体和照 相机之间的三维变换关系,对应于我们照相机矩阵中的R 和 t 部分。一个不同之处是,假设照相机为坐标系的中心,GL_MODELVIEW 矩阵实际上包含了将物体放置 在照相机前面的变换。

假设我们已经获得了标定好的照相机,即已知标定矩阵 K,下面的函数可以将照相机参数转换为 OpenGL 中的投影矩阵:

def set_projection_from_camera(K):"""从照相机标定矩阵中获得视图"""glMatrixMode(GL_PROJECTION)glLoadIdentity()fx = K[0,0]fy = K[1,1]fovy = 2 * arctan(0.5*height / fy) * 180 / piaspect = (width*fy) / (height * fx)# 定义近的和圆的裁剪平面near = 0.1       far = 100.0gluPerspective(fovy, aspect, near, far)glViewport(0, 0, width, height)
4.3 在图像中放置物体
import pickle
from pylab import *
from OpenGL.GL import * 
from OpenGL.GLU import * 
from OpenGL.GLUT import * 
import pygame, pygame.image 
from pygame.locals import *
from PCV.geometry import homography, camera
from PCV.localdescriptors import sift
import cv2
#绘制立方体
def cube_points(c, wid):p = []# bottomp.append([c[0]-wid, c[1]-wid, c[2]-wid])p.append([c[0]-wid, c[1]+wid, c[2]-wid])p.append([c[0]+wid, c[1]+wid, c[2]-wid])p.append([c[0]+wid, c[1]-wid, c[2]-wid])p.append([c[0]-wid, c[1]-wid, c[2]-wid]) #same as first to close plot   # topp.append([c[0]-wid, c[1]-wid, c[2]+wid])p.append([c[0]-wid, c[1]+wid, c[2]+wid])p.append([c[0]+wid, c[1]+wid, c[2]+wid])p.append([c[0]+wid, c[1]-wid, c[2]+wid])p.append([c[0]-wid, c[1]-wid, c[2]+wid]) #same as first to close plot    # vertical sidesp.append([c[0]-wid, c[1]-wid, c[2]+wid])p.append([c[0]-wid, c[1]+wid, c[2]+wid])p.append([c[0]-wid, c[1]+wid, c[2]-wid])p.append([c[0]+wid, c[1]+wid, c[2]-wid])p.append([c[0]+wid, c[1]+wid, c[2]+wid])p.append([c[0]+wid, c[1]-wid, c[2]+wid])p.append([c[0]+wid, c[1]-wid, c[2]-wid])return array(p).T 
def my_calibration(sz):row, col = szfx = 758*col/640fy = 752*row/480K = diag([fx, fy, 1])K[0, 2] = 0.5*colK[1, 2] = 0.5*rowreturn K
def set_projection_from_camera(K): glMatrixMode(GL_PROJECTION) glLoadIdentity()fx = K[0,0] fy = K[1,1] fovy = 2*math.atan(0.5*height/fy)*180/math.pi aspect = (width*fy)/(height*fx)near = 0.1 far = 100.0gluPerspective(fovy,aspect,near,far) glViewport(0,0,width,height)
def set_modelview_from_camera(Rt): glMatrixMode(GL_MODELVIEW) glLoadIdentity()Rx = np.array([[1,0,0],[0,0,-1],[0,1,0]])R = Rt[:,:3] U,S,V = np.linalg.svd(R) R = np.dot(U,V) R[0,:] = -R[0,:]t = Rt[:,3]M = np.eye(4) M[:3,:3] = np.dot(R,Rx) M[:3,3] = tM = M.Tm = M.flatten()glLoadMatrixf(m)
def draw_background(imname):bg_image = pygame.image.load(imname).convert() bg_data = pygame.image.tostring(bg_image,"RGBX",1)glMatrixMode(GL_MODELVIEW) glLoadIdentity()glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)glEnable(GL_TEXTURE_2D) glBindTexture(GL_TEXTURE_2D,glGenTextures(1)) glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,width,height,0,GL_RGBA,GL_UNSIGNED_BYTE,bg_data) glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST)glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST)glBegin(GL_QUADS) glTexCoord2f(0.0,0.0); glVertex3f(-1.0,-1.0,-1.0) glTexCoord2f(1.0,0.0); glVertex3f( 1.0,-1.0,-1.0) glTexCoord2f(1.0,1.0); glVertex3f( 1.0, 1.0,-1.0) glTexCoord2f(0.0,1.0); glVertex3f(-1.0, 1.0,-1.0) glEnd()glDeleteTextures(1)
def draw_teapot(size):glEnable(GL_LIGHTING) glEnable(GL_LIGHT0) glEnable(GL_DEPTH_TEST) glClear(GL_DEPTH_BUFFER_BIT)glMaterialfv(GL_FRONT,GL_AMBIENT,[0,0,0,0]) glMaterialfv(GL_FRONT,GL_DIFFUSE,[0.5,0.0,0.0,0.0]) glMaterialfv(GL_FRONT,GL_SPECULAR,[0.7,0.6,0.6,0.0]) glMaterialf(GL_FRONT,GL_SHININESS,0.25*128.0) glutSolidTeapot(size)
def drawFunc(size):  # 白色茶壶glRotatef(0.5, 5, 5, 0)  # (角度,x,y,z)glutWireTeapot(size)# 刷新显示glFlush()
width, height = 1000, 747
def setup():  # 设置窗口和pygame环境pygame.init()pygame.display.set_mode((width, height), OPENGL | DOUBLEBUF)pygame.display.set_caption("OpenGL AR demo")
sift.process_image('D:\\123\图像处理\Image Processing\Image Processing\Chapter 4\\book_frontal.JPG', 'im0.sift')
l0, d0 = sift.read_features_from_file('im0.sift')
sift.process_image('D:\\123\图像处理\Image Processing\Image Processing\Chapter 4\\book_perspective.JPG','im1.sift')
l1, d1 = sift.read_features_from_file('im1.sift') 
matches = sift.match_twosided(d0, d1)
ndx = matches.nonzero()[0]
fp = homography.make_homog(l0[ndx, :2].T)
ndx2 = [int(matches[i]) for i in ndx]
tp = homography.make_homog(l1[ndx2, :2].T)
model = homography.RansacModel()
H, inliers = homography.H_from_ransac(fp, tp, model)
K = my_calibration((747, 1000))
box = cube_points([0, 0, 0.1], 0.1)
cam1 = camera.Camera(hstack((K, dot(K, array([[0], [0], [-1]]))))) 
box_cam1 = cam1.project(homography.make_homog(box[:, :5]))
box_trans = homography.normalize(dot(H, box_cam1))
cam2 = camera.Camera(dot(H, cam1.P))
A = dot(linalg.inv(K), cam2.P[:, :3])
A = array([A[:, 0], A[:, 1], cross(A[:, 0], A[:, 1])]).T
cam2.P[:, :3] = dot(K, A)
#使用第二个照相机矩阵投影
box_cam2 = cam2.project(homography.make_homog(box))
Rt = dot(linalg.inv(K), cam2.P)
setup()
draw_background("D:\\123\图像处理\Image Processing\Image Processing\Chapter 4\\book_perspective.bmp")
set_projection_from_camera(K)
set_modelview_from_camera(Rt)
draw_teapot(0.05)  # 显示红色茶壶
#drawFunc(0.05)  # 显示白色空心茶壶
pygame.display.flip()
while True:for event in pygame.event.get():if event.type == pygame.QUIT:sys.exit()

 


http://www.ppmy.cn/news/1517067.html

相关文章

MYSQL集群技术

---------------第一部分---------------------- 一.mysql源码部署 环境&#xff1a;rhel7.9 1.1.下载安装包 官网&#xff1a;http://www.mysql.com 1.2.在linux下部署mysql 1.创建登录用户和数据目录&#xff0c;并给数据目录赋权&#xff0c;因为配置文件读取需要权限&…

WPF中如何根据数据类型使用不同的数据模板

我们在将一个数据集合绑定到列表控件时&#xff0c;有时候想根据不同的数据类型&#xff0c;显示为不同的效果。 例如将一个文件夹集合绑定到ListBox时&#xff0c;系统文件夹和普通文件夹分别显示为不同的效果&#xff0c;就可以使用模板选择器功能。 WPF提供了一个模板选择…

机器学习-训练集、验证集、测试集(附:分割方法+交叉验证)【随记】

训练集、验证集、测试集&#xff08;附&#xff1a;分割方法交叉验证&#xff09; 1. 训练集&#xff08;Training Set&#xff09; 2. 验证集&#xff08;Validation Set&#xff09; 3. 测试集&#xff08;Test Set&#xff09; 4. 数据集的分割方法 5. 交叉验证&#x…

2024.8.15(python管理mysql、Mycat实现读写分离)

一、python管理mysql 1、搭建主mysql [rootmysql57 ~]# tar -xf mysql-5.7.44-linux-glibc2.12-x86_64.tar.gz [rootmysql57 ~]# cp -r mysql-5.7.44-linux-glibc2.12-x86_64 /usr/local/mysql [rootmysql57 ~]# rm -rf /etc/my.cnf [rootmysql57 ~]# mkdir /usr/local/mysql…

pdf与canvas结合使用的场景1——为pdf增加水印

title: pdf与canvas结合使用的场景 date: 2024-08-28 10:03:45 tags: javascript 场景1:生成新的pdf水印 添加水印场景分析 这种情况下&#xff0c;不用再次封装好的一些水印工具的话&#xff0c;纯vue3前端的话就是使用pdfjscanvas来生成。 思路&#xff1a;1.上传并读取p…

《第二十八章:性能优化 - 电量优化》

一、引言 在 Android 应用开发中&#xff0c;电量优化是提升用户体验、延长设备续航的重要环节。一个电量消耗过高的应用可能会导致用户不满&#xff0c;甚至卸载。在这一章中&#xff0c;我们将重点探讨如何通过合理使用传感器和优化网络请求来降低应用的电量消耗。 二、合理使…

Tower for Mac Git客户端管理软件

Mac分享吧 文章目录 效果一、下载软件二、开始安装1、双击运行软件&#xff0c;将其从左侧拖入右侧文件夹中&#xff0c;等待安装完毕2、应用程序显示软件图标&#xff0c;表示安装成功 三、运行测试1、打开软件&#xff0c;测试2、克隆项目&#xff0c;测试 安装完成&#xf…

java-Mybatis框架02

1.#{} 和${}区别 #{} 是占位符&#xff0c;是采用编译方式向sql中传值&#xff0c;可以防止sql注入&#xff0c;如果往sql中传值&#xff0c;使用#{}${} 是将内容直接拼接到sql语句中&#xff0c;一般不用于向sql中传值&#xff0c;一般用于向sql中动态传递列名。区别&#xff…

代理IP的来源、工作原理与应用

在数字化时代&#xff0c;代理IP已经成为网络活动中不可或缺的一部分&#xff0c;尤其在跨境电商、网络营销、网络爬虫等领域&#xff0c;代理IP发挥着至关重要的作用。本文将深入探讨代理IP的来源、工作原理、应用以及潜在风险&#xff0c;帮助读者更好地理解并合理利用这一网…

Git下载安装配置

Git的下载与安装 Git是一种分布式版本控制系统&#xff0c;用于跟踪文件和文件夹的变化。它最初由Linus Torvalds开发&#xff0c;用于管理Linux内核的源代码。Git的设计目标是&#xff1a;速度快、开发效率高、数据完整性和可靠性强。 Git通过创建一个存储库&#xff08;rep…

(一) 初入MySQL 【认识和部署】

前置资源 一、数据库概述 1.1、数据库基本概念 数据(Data) 描述事物的符号记录称为数据。数字、文字、图形、图像、声音、档案记录等都是数据。数据是以“记录”的形式按照统一的格式进行存储的&#xff0c;而不是杂乱无章的。 相同格式和类型的数据统一存放在一起&#xff0…

Python实现RSA加解密算法

目录 深入了解RSA加密算法一、RSA算法概述1.1 关键步骤1.2 安全性分析 二、RSA算法的Python实现2.1 辅助函数2.2 密钥生成2.3 加密与解密2.4 使用示例 三、总结 深入了解RSA加密算法 RSA&#xff08;Rivest-Shamir-Adleman&#xff09;是一种非对称加密算法&#xff0c;由Ron …

如何快速熟悉一个软件

当入职一家新公司时&#xff0c;必然要熟悉一些新的软件项目&#xff0c;这个时候&#xff0c;如何才能快速熟悉软件项目&#xff0c;以达到快速上手的目的。 1大忌 还记得自己刚毕业的第一份工作&#xff0c;一上来就去看代码&#xff0c;看代码的细节。在看代码的时候&…

[C++]set和map的介绍及使用

关于set和map的接口函数部分&#xff0c;只重点介绍一些相较于别的容器有特殊地方的接口&#xff0c;set和map的接口可以触类旁通。 一、概念 &#xff08;一&#xff09;、关联式容器 关联式容器存储的元素是一个个的键值对<key,value>。通过键&#xff08;key&#x…

MATLAB 生成指定范围、角度、厚度的含噪平面点云(77)

模拟生成点云并可视化显示,可以验证算法有效性,尤其是针对验证算法的某方面 MATLAB 生成指定范围、角度、厚度的含噪平面点云(77) 一、算法介绍二、使用步骤1.代码2.效果一、算法介绍 如题,模拟生成一组平面点云,含有噪声点,确定算法稳定性,可以指定生成平面的范围,厚…

Java集合—Map系列集合(习题一)

文章目录 Java集合—Map集合&#xff08;习题&#xff09;1.使用泛型修改根据学员姓名找学员对象2.运用Map的三种遍历方式进行遍历迭代器遍历键值对遍历增强遍历 综合要求 Java集合—Map集合&#xff08;习题&#xff09; 1.使用泛型修改根据学员姓名找学员对象 2.运用Map的三…

【JAVA]DAY 2在网页中输出日期和时间,实时还是静止?

一、如何输出日期文本 使用document.write(Date()); 会在网页中输出当前的日期和时间。在 2024 年 8 月 28 日星期三执行这段代码&#xff0c;可能会输出类似 “Wed Aug 28 2024 [具体时间]” 这样的内容。 Date()是 JavaScript 中的一个内置对象&#xff0c;用于处理日期和…

UE5 多个类选择界面生成

在Unreal Engine 5 (UE5) 中&#xff0c;如果你想要创建一个可以选择多个类的界面&#xff0c;你可以使用SClassPicker小部件。以下是一个简单的例子&#xff0c;展示如何在UE5的编辑器模块中创建一个自定义的编辑器工具栏按钮&#xff0c;并打开一个类选择器。 #include &quo…

论文写作遇到的问题——个人记录用

1.实验结果图绘制 python画图字体设置 Science Plots使用中中文配置的问题 11种 Matplotlib 科研论文图表教程 2.论文写作格式 word公式居中、编号右对齐、自动编号、交叉引用 mathtype操作合集&#xff0c;使用大全 arxiv.org的文章引用格式 LaTex的下载与安装&#x…

[CLIP-VIT-L + Qwen] 多模态大模型源码阅读 - DataSet篇

[CLIP-VIT-L Qwen] 多模态大模型源码阅读 - DataSet篇 前情提要源码解读完整代码逐行解读导包readjson函数data_collate函数ImageCaptionDataset类&#xff08;init函数&#xff09;ImageCaptionDataset类&#xff08;readImage函数&#xff09; 参考repo:WatchTower-Liu/VLM-…