Python计算机视觉 第3章-图像到图像的映射

Python计算机视觉 第3章-图像到图像的映射

3.1 单应性变换

单应性变换(Homography)是计算机视觉中非常重要的一种几何变换,它用于将一个平面内的点映射到另一个平面内。具体来说,单应性变换可以描述一个图像在摄像机视角变化、平面移动或旋转时,如何从一个视角变换到另一个视角。

这种变换在多个应用场景中非常有用,比如:

  1. 图像配准:将不同视角或不同时间拍摄的图像对齐,找到它们之间的对应关系。
  2. 图像校正:修正由于摄像机角度或透视导致的图像扭曲,使图像看起来更平整。
  3. 纹理扭曲:将一个平面的纹理准确地映射到另一个平面上。
  4. 全景图像创建:将多个图像拼接成一个大的全景图像。

单应性变换的频繁使用,尤其是在涉及多个视角或需要精确对齐图像的情况下,能够显著提升算法的鲁棒性和精度。在项目中,理解和正确应用单应性变换是处理图像和三维几何信息的关键技能。

单应性变换(Homography)将二维平面上的点映射到另一个平面上的点,在齐次坐标(homogeneous coordinates)下,这种映射可以通过以下方程来表示:

( x ′ y ′ w ′ ) H ⋅ ( x y w ) \begin{pmatrix} x' \\ y' \\ w' \ \end{pmatrix} \mathbf{H} \cdot \begin{pmatrix} x \\ y \\ w \end{pmatrix} xyw  H xyw

其中,单应性矩阵 H \mathbf{H} H 为:

H = ( h 11 h 12 h 13 h 21 h 22 h 23 h 31 h 32 h 33 ) \mathbf{H} = \begin{pmatrix} h_{11} & h_{12} & h_{13} \\ h_{21} & h_{22} & h_{23} \\ h_{31} & h_{32} & h_{33} \end{pmatrix} H= h11h21h31h12h22h32h13h23h33

经过单应性变换后的目标点的常规二维坐标 ( x ′ , y ′ ) (x', y') (x,y) 为:

x ′ = h 11 x + h 12 y + h 13 h 31 x + h 32 y + h 33 x' = \frac{h_{11}x + h_{12}y + h_{13}}{h_{31}x + h_{32}y + h_{33}} x=h31x+h32y+h33h11x+h12y+h13

y ′ = h 21 x + h 22 y + h 23 h 31 x + h 32 y + h 33 y' = \frac{h_{21}x + h_{22}y + h_{23}}{h_{31}x + h_{32}y + h_{33}} y=h31x+h32y+h33h21x+h22y+h23

通过这些公式,你可以描述平面间的各种变换,比如旋转、缩放、平移、透视变换等。

3.1.1 直接线性变换算法

单应性矩阵可以由两幅图像(或者平面)中对应点对计算出来。前面已经提到过,一个完全射影变换具有8个自由度。根据对应点约束,每个对应点对可以写出两个方程,分别对应于x和y坐标。因此,计算单应性矩阵H需要4个对应点对。

DLT(Direct Linear Transformation,直接线性变换)是给定4个或者更多对应点对矩阵,来计算单应性矩阵H的算法。将单应性矩阵H作用在对应点对上,重新写出该方程,我们可以得到下面的方程:

[ − x 1 − y 1 − 1 0 0 0 x 1 x 1 ′ y 1 x 1 ′ x 1 ′ 0 0 0 − x 1 − y 1 − 1 x 1 y 1 ′ y 1 y 1 ′ y 1 ′ − x 2 − y 2 − 1 0 0 0 x 2 x 2 ′ y 2 x 2 ′ x 2 ′ 0 0 0 − x 2 − y 2 − 1 x 2 y 2 ′ y 2 y 2 ′ y 2 ′ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ ] [ h 1 h 2 h 3 h 4 h 5 h 6 h 7 h 8 h 9 ] = 0 \begin{bmatrix}-x_1&-y_1&-1&0&0&0&x_1x_1^{\prime}&y_1x_1^{\prime}&x_1^{\prime}\\0&0&0&-x_1&-y_1&-1&x_1y_1^{\prime}&y_1y_1^{\prime}&y_1^{\prime}\\-x_2&-y_2&-1&0&0&0&x_2x_2^{\prime}&y_2x_2^{\prime}&x_2^{\prime}\\0&0&0&-x_2&-y_2&-1&x_2y_2^{\prime}&y_2y_2^{\prime}&y_2^{\prime}\\&\vdots&&\vdots&\vdots&\vdots&\vdots&\vdots\end{bmatrix}\begin{bmatrix}h_1\\h_2\\h_3\\h_4\\h_5\\h_6\\h_7\\h_8\\h_9\end{bmatrix}=\mathbf{0} x10x20y10y2010100x10x20y10y20101x1x1x1y1x2x2x2y2y1x1y1y1y2x2y2y2x1y1x2y2 h1h2h3h4h5h6h7h8h9 =0

或者Ah=0,其中A是一个具有对应点对二倍数量行数的矩阵。将这些对应点对方程的系数堆叠到一个矩阵中,我们可以使用SVD(Singular Value Decomposition,奇异值分解)算法找到H的最小二乘解。

下面是该算法的代码:

def H_from_points(fp, tp):"""使用线性DLT方法,计算单应性矩阵H,使fp映射到tp。点自动进行归一化"""if fp.shape != tp.shape:raise RuntimeError('number of points do not match')# 对点进行归一化(对数值计算很重要)# ---映射起始点---m = mean(fp[:2], axis=1)maxstd = max(std(fp[:2], axis=1)) + 1e-9C1 = diag([1/maxstd, 1/maxstd, 1])C1[0][2] = -m[0]/maxstdC1[1][2] = -m[1]/maxstdfp = dot(C1, fp)# ---映射对应点---m = mean(tp[:2], axis=1)maxstd = max(std(tp[:2], axis=1)) + 1e-9C2 = diag([1/maxstd, 1/maxstd, 1])C2[0][2] = -m[0]/maxstdC2[1][2] = -m[1]/maxstdtp = dot(C2, tp)# 创建用于线性方法的矩阵,对于每个对应对,在矩阵中会出现两行数值nbr_correspondences = fp.shape[1]A = zeros((2*nbr_correspondences, 9))for i in range(nbr_correspondences):A[2*i] = [-fp[0][i], -fp[1][i], -1, 0, 0, 0,tp[0][i]*fp[0][i], tp[0][i]*fp[1][i], tp[0][i]]A[2*i+1] = [0, 0, 0, -fp[0][i], -fp[1][i], -1,tp[1][i]*fp[0][i], tp[1][i]*fp[1][i], tp[1][i]]U, S, V = linalg.svd(A)H = V[8].reshape((3, 3))# 反归一化H = dot(linalg.inv(C2), dot(H, C1))# 归一化,然后返回return H / H[2, 2]

上面函数的第一步操作是检查点对的两个数组中点的数目是否相同。如果不相同,函数将会抛出异常信息。这对于写出稳健的代码来说非常有用。但是,为了使得代码例子更简单、更容易理解,我们在本书中仅在很少的例子中使用异常处理技巧。

3.1.2 仿射变换

由于仿射变换具有6个自由度,因此我们需要三个对应点对来估计矩阵H。通过将最后两个元素设置为0,即 h 7 = h 8 = 0 h_7 =h_8=0 h7=h8=0,仿射变换可以用上面的DLT算法估计得出。
下面是算法的关键代码部分:

def Haffine_from_points(fp, tp):"""计算 H,仿射变换,使得 tp 是 fp 经过仿射变换 H 得到的"""if fp.shape != tp.shape:raise RuntimeError('number of points do not match')# 对点进行归一化# --- 映射起始点 ---m = mean(fp[:2], axis=1)maxstd = max(std(fp[:2], axis=1)) + 1e-9C1 = diag([1/maxstd, 1/maxstd, 1])C1[0][2] = -m[0]/maxstdC1[1][2] = -m[1]/maxstdfp_cond = dot(C1, fp)# --- 映射对应点 ---m = mean(tp[:2], axis=1)C2 = C1.copy()  # 两个点集,必须都进行相同的缩放C2[0][2] = -m[0]/maxstdC2[1][2] = -m[1]/maxstdtp_cond = dot(C2, tp)# 因为归一化后点的均值为0,所以平移量为0A = concatenate((fp_cond[:2], tp_cond[:2]), axis=0)U, S, V = linalg.svd(A.T)# 如 Hartley 和 Zisserman 著的 Multiple View Geometry in Computer, Second Edition 所示,# 创建矩阵 B 和 Ctmp = V[:2].TB = tmp[:2]C = tmp[2:4]# 反归一化tmp2 = concatenate((dot(C, linalg.pinv(B)), zeros((2, 1))), axis=1)H = vstack((tmp2, [0, 0, 1]))H = dot(linalg.inv(C2), dot(H, C1))return H / H[2, 2]

同样地,类似于DLT算法,这些点需要经过预处理和去处理化操作。

3.2 图像扭曲

对图像块应用仿射变换,我们将其称为图像扭曲(或者仿射扭曲)。该操作不仅经常应用在计算机图形学中,而且经常出现在计算机视觉算法中。扭曲操作可以使用SciPy工具包中的ndimage包来简单完成。

以下为实验代码:

import numpy as np
from scipy import ndimage
import matplotlib.pyplot as plt
from skimage import data, color# 读取示例图像
image = color.rgb2gray(data.astronaut())# 定义仿射变换矩阵
# 例如,这里是一个旋转矩阵和一个平移矩阵的组合
affine_matrix = np.array([[1.2, 0.2, -30],  # x轴的缩放和旋转,以及平移[0.1, 1.2, 20],   # y轴的缩放和旋转,以及平移[0, 0, 1]         # 齐次坐标的归一化因子
])# 对图像应用仿射变换
transformed_image = ndimage.affine_transform(image,affine_matrix[:2, :2],  # 2x2 仿射矩阵offset=affine_matrix[:2, 2],  # 平移偏移mode='reflect'  # 边界处理模式
)# 显示原始和变换后的图像
plt.figure(figsize=(10, 5))plt.subplot(1, 2, 1)
plt.title('Original Image')
plt.imshow(image, cmap='gray')
plt.axis('off')plt.subplot(1, 2, 2)
plt.title('Transformed Image')
plt.imshow(transformed_image, cmap='gray')
plt.axis('off')plt.show()

在这里插入图片描述

实验图1 图像扭曲处理结果

3.2.1 图像中的图像

仿射扭曲的一个简单例子是,将图像或者图像的一部分放置在另一幅图像中,使得它们能够和指定的区域或者标记物对齐。

import numpy as np
from scipy import ndimage
import matplotlib.pyplot as plt
from skimage import io, colordef image_in_image(background, overlay, position):"""将图像 overlay 放置到图像 background 中的指定位置。:param background: 背景图像:param overlay: 要放置的图像:param position: 放置 overlay 的坐标 (x, y) 元组:return: 带有 overlay 的背景图像"""# 确保 overlay 图像的尺寸h, w = overlay.shape[:2]# 生成仿射变换矩阵,将 overlay 图像的四个角点对齐到背景图像中的指定区域src_points = np.array([[0, 0],  # overlay 的左上角[w, 0],  # overlay 的右上角[w, h],  # overlay 的右下角[0, h]  # overlay 的左下角])dst_points = np.array([[position[0], position[1]],  # 背景图像中放置位置的左上角[position[0] + w, position[1]],  # 背景图像中放置位置的右上角[position[0] + w, position[1] + h],  # 背景图像中放置位置的右下角[position[0], position[1] + h]  # 背景图像中放置位置的左下角])# 构建矩阵 A 和向量 b 以求解仿射变换矩阵A = []b = []for i in range(4):A.append([src_points[i][0], src_points[i][1], 1, 0, 0, 0, -dst_points[i][0] * src_points[i][0],-dst_points[i][0] * src_points[i][1]])A.append([0, 0, 0, src_points[i][0], src_points[i][1], 1, -dst_points[i][1] * src_points[i][0],-dst_points[i][1] * src_points[i][1]])b.append(dst_points[i][0])b.append(dst_points[i][1])A = np.array(A)b = np.array(b)# 通过最小二乘法求解仿射变换矩阵h = np.linalg.lstsq(A, b, rcond=None)[0]H = np.append(h, [1]).reshape(3, 3)# 将 overlay 图像进行仿射变换transformed_overlay = ndimage.affine_transform(overlay,H[:2, :2],offset=H[:2, 2],output_shape=background.shape,mode='constant',cval=0)# 合并图像mask = (transformed_overlay > 0).astype(float)result = background.copy()result = result * (1 - mask) + transformed_overlay * maskreturn result# 示例使用
if __name__ == "__main__":# 读取内置示例图像background = color.rgb2gray(io.imread('img.png'))  # 背景图像overlay = color.rgb2gray(io.imread('python.png'))  # 要放置的图像position = (100, 100)  # 放置位置(x, y)# 应用函数result_image = image_in_image(background, overlay, position)# 显示结果plt.figure(figsize=(10, 5))plt.subplot(1, 3, 1)plt.title('Background Image')plt.imshow(background, cmap='gray')plt.axis('off')plt.subplot(1, 3, 2)plt.title('Overlay Image')plt.imshow(overlay, cmap='gray')plt.axis('off')plt.subplot(1, 3, 3)plt.title('Result Image')plt.imshow(result_image, cmap='gray')plt.axis('off')plt.show()

在这里插入图片描述

实验图2 处理结果

3.2.2 分段仿射扭曲

对应点对集合之间最常用的扭曲方式:分段仿射扭曲。给定任意图像的标记点,通过将这些点进行三角剖分,然后使用仿射扭曲来扭曲每个三角形,我们可以将图像和另一幅图像的对应标记点扭曲对应。对于任何图形和图像处理库来说,这些都是最基本的操作。
为了三角化这些点,我们经常使用狄洛克三角剖分方法。在Matplotlib(但是不在PyLab 库中)中有狄洛克三角剖分,我们可以用下面的方式使用它:

以下是实验代码:

import matplotlib.pyplot as plt
import numpy as np
from scipy import ndimage
from scipy.spatial import Delaunayx,y = np.array(np.random.standard_normal((2,100)))
tri = Delaunay(np.c_[x, y]).simplices
plt.figure() 
for t in tri:t_ext = [t[0], t[1], t[2], t[0]] # 将第一个点加入到最后plt.plot(x[t_ext],y[t_ext],'r')
plt.plot(x,y,'*')
plt.axis('off')
plt.show()

在这里插入图片描述

实验图3 处理结果

3.2.3 图像配准

图像配准是对图像进行变换,使变换后的图像能够在常见的坐标系中对齐。配准可以是严格配准,也可以是非严格配准。为了能够进行图像对比和更精细的图像分析,图像配准是一步非常重要的操作。

3.3 创建全景图

在同一位置(即图像的照相机位置相同)拍摄的两幅或者多幅图像是单应性相关的(如图3-9所示)。我们经常使用该约束将很多图像缝补起来,拼成一个大的图像来创建全景图像。
在这里插入图片描述

图3-9 瑞典隆德主要大学建筑的5幅图像。这些图像都是从同一个视点拍摄的

3.3.1 RANSAC

RANSAC是“RANdom SAmple Consensus”(随机一致性采样)的缩写。该方法是用来找到正确模型来拟合带有噪声数据的迭代方法。给定一个模型,例如点集之间的单应性矩阵,RANSAC基本的思想是,数据中包含正确的点和噪声点,合理的模型应该能够在描述正确数据点的同时摒弃噪声点。

RANSAC的标准例子:用一条直线拟合带有噪声数据的点集。简单的最小二乘在该例子中可能会失效,但是RANSAC能够挑选出正确的点,然后获取能够正确拟合的直线。

在这里插入图片描述

图3-10 使用RANSAC算法用一条直线来拟合包含噪声数据点集

3.3.2 拼接图像

估计出图像间的单应性矩阵(使用RANSAC算法),现在我们需要将所有的图像扭曲到一个公共的图像平面上。通常,这里的公共平面为中心图像平面(否则,需要进行大量变形)。一种方法是创建一个很大的图像,比如图像中全部填充0,使其和中心图像平行,然后将所有的图像扭曲到上面。由于我们所有的图像是由照相机水平旋转拍摄的,因此我们可以使用一个较简单的步骤:将中心图像左边或者右边的区域填充0,以便为扭曲的图像腾出空间。以下为示例代码:

def panorama(H, fromim, toim, padding=2400, delta=2400):""" 使用单应性矩阵 H(使用 RANSAC 健壮性估计得出),协调两幅图像,创建水平全景图像。结果为一幅和 toim 具有相同高度的图像。padding 指定填充像素的数目,delta 指定额外的平移量。 """# 检查图像是灰度图像,还是彩色图像is_color = len(fromim.shape) == 3# 用于 geometric_transform() 的单应性变换def transf(p):p2 = np.dot(H, [p[0], p[1], 1])return (p2[0] / p2[2], p2[1] / p2[2])if H[1, 2] < 0:  # fromim 在右边print('warp - right')# 变换 fromimif is_color:# 在目标图像的右边填充 0toim_t = np.hstack((toim, np.zeros((toim.shape[0], padding, 3))))fromim_t = np.zeros((toim.shape[0], toim.shape[1] + padding, toim.shape[2]))for col in range(3):fromim_t[:, :, col] = ndimage.geometric_transform(fromim[:, :, col], transf, (toim.shape[0], toim.shape[1] + padding))else:# 在目标图像的右边填充 0toim_t = np.hstack((toim, np.zeros((toim.shape[0], padding))))fromim_t = ndimage.geometric_transform(fromim, transf, (toim.shape[0], toim.shape[1] + padding))else:  # fromim 在左边print('warp - left')# 为了补偿填充效果,在左边加入平移量H_delta = np.array([[1, 0, 0], [0, 1, -delta], [0, 0, 1]])H = np.dot(H, H_delta)# 变换 fromimif is_color:# 在目标图像的左边填充 0toim_t = np.hstack((np.zeros((toim.shape[0], padding, 3)), toim))fromim_t = np.zeros((toim.shape[0], toim.shape[1] + padding, toim.shape[2]))for col in range(3):fromim_t[:, :, col] = ndimage.geometric_transform(fromim[:, :, col], transf, (toim.shape[0], toim.shape[1] + padding))else:# 在目标图像的左边填充 0toim_t = np.hstack((np.zeros((toim.shape[0], padding)), toim))fromim_t = ndimage.geometric_transform(fromim, transf, (toim.shape[0], toim.shape[1] + padding))# 协调后返回(将 fromim 放置在 toim 上)if is_color:# 所有非黑色像素alpha = ((fromim_t[:, :, 0] > 0) | (fromim_t[:, :, 1] > 0) | (fromim_t[:, :, 2] > 0))for col in range(3):toim_t[:, :, col] = fromim_t[:, :, col] * alpha + toim_t[:, :, col] * ~alphaelse:alpha = (fromim_t > 0)toim_t = fromim_t * alpha + toim_t * ~alphareturn toim_t

对于通用的geometric_transform() 函数,我们需要指定能够描述像素到像素间映射的函数。在这个例子中,transf()函数就是该指定的函数。该函数通过将像素和H相乘,然后对齐次坐标进行归一化来实现像素间的映射。通过查看H中的平移量,我们可以决定应该将该图像填补到左边还是右边。当该图像填补到左边时,由于目标图像中点的坐标也变化了,所以在“左边”情况中,需要在单应性矩阵中加入平移。简单起见,我们同样使用0像素的技巧来寻找alpha图。现在在图像中使用该操作,函数如下所示:

# 扭曲图像
delta = 2000  # 用于填充和平移# 读取图像
im1 = np.array(Image.open(imname[1]))
im2 = np.array(Image.open(imname[2]))# 图像拼接
im_12 = warp.panorama(H_12, im1, im2, delta, delta)im1 = np.array(Image.open(imname[0]))
im_02 = warp.panorama(np.dot(H_12, H_01), im1, im_12, delta, delta)im1 = np.array(Image.open(imname[3]))
im_32 = warp.panorama(H_32, im1, im_02, delta, delta)im1 = np.array(Image.open(imname[j + 1]))  # 确保 imname[j + 1] 是一个有效的索引
im_42 = warp.panorama(np.dot(H_32, H_43), im1, im_32, delta, 2 * delta)

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

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

相关文章

vue3+vite+axios+mock从接口获取模拟数据实战

文章目录 一、安装相关组件二、在vite.config.js中配置vite-plugin-mock插件三、实现mock服务四、调用api接口请求mock数据方法一、直接使用axios 请求mock 数据方法二、对axios进行封装统一请求mock数据 五、实际运行效果 在用Vue.js开发前端应用时通常要与后端服务进行交互&a…

白酒与家庭聚会:温馨与和谐的时光

在繁忙的都市生活中&#xff0c;家庭聚会是每个人心中那份较温暖的港湾。每当夜幕降临&#xff0c;灯火通明&#xff0c;家人们围坐在一起&#xff0c;谈笑风生&#xff0c;那份温馨与和谐仿佛能够驱散一切疲惫。而在这个温馨的时刻&#xff0c;白酒——豪迈白酒&#xff08;HO…

Python 爬虫入门(十二):正则表达式「详细介绍」

Python 爬虫入门&#xff08;十二&#xff09;&#xff1a;正则表达式 前言一、正则表达式的用途二、正则表达式的基本组成元素2.1 特殊字符2.2 量词2.3 位置锚点2.4 断言2.5 字符集2.6 字符类2.6.1 基本字符类2.6.2 常见字符类简写2.6.3 POSIX字符类2.6.4 组合使用 三、 正则表…

如何使用ssm实现亿互游在线平台设计与开发+vue

TOC ssm118亿互游在线平台设计与开发vue 绪论 1.1研究背景 时代的发展&#xff0c;我们迎来了数字化信息时代&#xff0c;它正在渐渐的改变着人们的工作、学习以及娱乐方式。计算机网络&#xff0c;Internet扮演着越来越重要的角色&#xff0c;人们已经离不开网络了&#x…

2024世界机器人大会盛大开幕,卓翼飞思携无人智能领域产品集中亮相 !

开放创新 聚享未来&#xff01;万众瞩目的2024世界机器人大会暨博览会于8月21日在北京亦创国际会展中心盛大开幕。大会聚焦机器人技术与产业前沿趋势&#xff0c;展示机器人创新应用赋能千行百业的多元场景&#xff0c;全球顶尖的机器人科学家、行业领袖、创新精英汇聚一堂&…

使用HAL库实现按键控制LED和蜂鸣器

下载STM32CubeMX实现项目的初始配置&#xff08;寄存器操作)&#xff0c;下载keil对程序进行编译烧写 在STM32CubeMX中将PB0/PB1设置为输入引脚作为按键&#xff0c;PA6/PA4设置为输出引脚作为led和Beep&#xff0c;将按键引脚设置为上拉输入&#xff1a; 创建项目完成后在kei…

C语言 | Leetcode C语言题解之第365题水壶问题

题目&#xff1a; 题解&#xff1a; bool canMeasureWater(int jug1Capacity, int jug2Capacity, int targetCapacity) {int j1 jug1Capacity < jug2Capacity ? jug1Capacity : jug2Capacity, j2 jug1Capacity > jug2Capacity ? jug1Capacity : jug2Capacity;if (ta…

Umi-OCR 文字识别工具

免费开源的离线orc识别功能 git地址 感谢大佬的贡献 Umi-OCR 文字识别工具 使用说明 • 下载地址 • 更新日志 • 提交Bug 免费&#xff0c;开源&#xff0c;可批量的离线OCR软件 适用于 Windows7 x64 、Linux x64 免费&#xff1a;本项目所有代码开源&#x…

Verilog刷题笔记59

题目: Exams/m2014 q6c 解题&#xff1a; module top_module (input [6:1] y,input w,output Y2,output Y4);assign Y2y[1]&w0;assign Y4(y[2]&w1)|(y[3]&w1)|(y[5]&w1)|(y[6]&w1);endmodule结果正确: 注意点: 起初&#xff0c;我的代码有错误,代码如下…

9 正则表达式:Java爬虫和正则表达式、String中的正则表达式方法(基本语法7)

文章目录 前言一、正则表达式1 [ ] 语法(1)[ABC] 和 [^ABC](2)[A-Z]和[a-zA-Z]小总结2 特殊字符语法(\w 这些)3 数量符4 \ 、()、 |5 锚点 ^ 和 $,\b,\B6 (?i) : 忽略其后面的大小写 ---- 这个Java是可以的,其他语言我不知道(正则表达式虽然大多通用,但也有部分是…

视频检索技术为电子商务直播领域带来了前所未有的革新

视频检测在这个场景中指的是通过视频流实时识别和检索直播中销售人员展示的商品。这涉及到从连续的视频帧中分析和识别商品的视觉内容&#xff0c;通常与语音和文本数据结合&#xff0c;以提高识别准确性。 技术原理 文本引导的注意机制&#xff1a;这一机制通过直播中销售人员…

Prometheus学习

监控架构介绍&#xff1a; 基本架构&#xff1a; Prometheus 和 Zabbix 的对比&#xff1a; 安装和使用&#xff1a; Prometheus 采集、存储数据Grafana 用于图表展示alertmanager 用于接收 Prometheus 发送的警告信息node-exporter 用于收集操作系统和硬件信息的 metrics …

猫头虎 分享:Python库 Matplotlib 的简介、安装、用法详解入门教程

&#x1f42f; 猫头虎 分享&#xff1a;Python库 Matplotlib 的简介、安装、用法详解入门教程 今天猫头虎 带大家一起探索一个非常重要的 Python 库——Matplotlib。这是一个强大的工具&#xff0c;广泛应用于数据科学、人工智能和机器学习等领域&#xff0c;用于创建静态、动…

3、springboot时代背景

一、微服务 二、分布式 三、云原生 原生应用如何上云。 Cloud Native 上云的困难 服务自愈弹性伸缩服务隔离自动化部署灰度发布流量治理...... 上云的解决

怎样更改电脑的MAC地址?

怎样更改电脑的MAC地址&#xff1f; 电脑的机器码是可以修改的。 操作步骤&#xff1a; 1、通过按WINR键&#xff0c;调来电脑的接运行窗口&#xff0c;打开CMD命令来查看机器码。 2、命令提示符窗口里输入ipconfig /all&#xff0c;回车&#xff0c;即可显示出当前电脑的网…

调试理解 NodeJS 模块机制

前言 通过断点调试理解 NodeJS & CommonJS 的模块机制&#xff0c;先说结论&#xff1a; NodeJS 中每个文件视作一个模块&#xff0c;每个模块默认可以访问 module、exports、require、__filename、__dirname 变量NodeJS 中通过将模块源码包裹在 Wrapper 函数中&#xff…

【每日一题】【素数筛板子题】又是一年毕业季 牛客小白月赛99 D题 C++

牛客小白月赛99 D题 又是一年毕业季 题目背景 牛客小白月赛99 题目描述 样例 #1 样例输入 #1 3 4 2 4 6 5 5 6 2 5 3 2333333 8 11 4 5 14 19 19 8 10样例输出 #1 3 7 2做题思路 首先观察到 即需要保证拍照的时刻 大于等于 2 那么就从2开始往上走&#xff0c;如果有人…

红黑树、B+Tree、B—Tree

红黑树 B-Tree 这三个通常都是把内存全部加载到内存里&#xff0c;然后再内存中进行处理的&#xff0c;数据量通常不会很大。 内存一般容量都在GB级别&#xff0c;比如说现在常见的4G、8G或者16G。 如果要处理的数据规模非常大&#xff0c;大到内存根本存不下的时候。这个时候…

Spring Boot 集成 swagger 3.0 指南

Spring Boot 集成 swagger 3.0 指南 一、Swagger介绍1.springfox-swagger 22.SpringFox 3.0.0 发布 二、Spring Boot 集成 swagger 3.01. 添加Maven依赖2. 创建配置类配置Swagger2.1 创建SwaggerConfig 配置类2.1 创建TestInfoConfig信息配置类 3. 在你的Controller上添加swagg…

【思源笔记】思源笔记配置S3同步

本文首发于 ❄️慕雪的寒舍 文章目录 1. 写在前面2. 什么是思源笔记的S3/WEBDAV同步&#xff1f;2.1. 说明2.2. 思源的同步配置和工作空间2.3. 什么是S3协议&#xff1f; 3. 配置思源S3同步3.1. 初始化数据仓库密钥3.2. 思源S3同步界面3.3. 配置七牛云KODO3.4. 如何将同步配置导…