opencv 图像的旋转

图像的旋转

  • 1 单点旋转
  • 2. 图片旋转(cv2.getRotationMatrix2D)
  • 3. 插值方法
    • 3.1 最近邻插值(cv2.INTER_NEAREST)
    • 3.2 双线性插值(cv2.INTER_LINEAR)
    • 3.3 像素区域插值(cv2.INTER_AREA)
    • 3.4 双三次插值(cv2.INTER_CUBIC)
    • 3.5 Lanczos插值(cv2.INTER_LANCZOS4)
    • 3.6 小结
  • 4. 边缘填充方式(cv2.warpAffine的属性borderMode)
    • 4.1 边界复制(BODER_REPLICATE)
      • 4.2 边界反射(BORDER_REFLECT)
    • 4.3 边界反射101(BORDER_REFLECT_101)
    • 4.4 边界常数(BORDER_CONSTANT)
      • 4.5 边界包裹(BORDER_WRAP)

图像旋转是指图像以某一点为旋转中心,将图像中的所有像素点都围绕该点旋转一定的角度,并且旋转后的像素点组成的图像与原图像相同。

1 单点旋转

首先我们以最简单的一个点的旋转为例子,且以最简单的情况举例,令旋转中心为坐标系中心O(0,0),假设有一点 P 0 ( x 0 , y 0 ) P_{0}(x_{0},y_{0}) P0(x0,y0) P 0 P_{0} P0离旋转中心O的距离为r, O P 0 OP_{0} OP0与坐标轴x轴的夹角为 α \alpha α P 0 P_{0} P0绕O顺时针旋转 θ \theta θ角后对应的点为 P ( x , y ) P(x,y) P(x,y),如下图所示:

在这里插入图片描述
单点旋转的原理

2. 图片旋转(cv2.getRotationMatrix2D)

明白了单个点的旋转过程之后,其实图像旋转也很好理解,就是将图像里的每个像素点都带入仿射变换矩阵里,从而得到旋转后的新坐标。在OpenCV中,要得到仿射变换矩阵可以使用cv2.getRotationMatrix2D(),通过这个函数即可直接获取到上面的旋转矩阵,
格式如下:

cv2.RotationMatrix2D(Center,Angle,Scale)

该函数需要接收的参数为:

  • Center:表示旋转的中心点,是一个二维的坐标点(x,y)
  • Angle:表示旋转的角度
  • Scale:表示缩放比例,可以通过该参数调整图像相对于原始图像的大小变化

因此,在本实验中只需要在组件中填好图片要旋转的角度与缩放的比例即可。
在这里插入图片描述
代码如下:

 '''图片的旋转'''img=cv2.imread(r"../15day4.10/src/1.jpg")# 求出图片的高宽和颜色h,w,c=img.shape# 给出一个旋转角度angle=45# 给出缩放倍数sacle=1# 以图片的中心作为旋转中心的仿射变换矩阵m=cv2.getRotationMatrix2D((h/2,w/2),angle=angle,scale=sacle)img_rotate=cv2.warpAffine(img,m,(w,h))cv2.imshow("img",img)cv2.imshow("img_rotate",img_rotate)cv2.waitKey(0)

在这里插入图片描述

但是这里会有一个问题:

  • 由于三角函数的值是小数,那么其乘积也会是小数,虽然OpenCV中会对其进行取整操作,但是像素点旋转之后的取整结果也有可能重合,这样就会导致可能会在旋转的过程中丢失一部分原始的像素信息。
  • 并且如果使用了scale参数进行图像的缩放的话,当图像放大时,比如一个10*10的图像放大成20*20,图像由100个像素点变成400个像素点,那么多余的300个像素点是怎么来的?而当图像缩小时,比如一个20*20的图像缩小为10*10的图像,需要丢掉300个像素点,那到底要怎么丢才能保证图像还能是一个正常的图像?
  • 因此我们需要一种方法来帮我们计算旋转后的图像中每一个像素点所对应的像素值,从而保证图像的完整性,这种方法就叫做插值法。

3. 插值方法

在图像处理和计算机图形学中,插值(Interpolation)是一种通过已知数据点之间的推断或估计来获取新数据点的方法。它在图像处理中常用于处理图像的放大、缩小、旋转、变形等操作,以及处理图像中的像素值。

图像插值算法是为了解决图像缩放或者旋转等操作时,由于像素之间的间隔不一致而导致的信息丢失和图像质量下降的问题。当我们对图像进行缩放或旋转等操作时,需要在新的像素位置上计算出对应的像素值,而插值算法的作用就是根据已知的像素值来推测未知位置的像素值。本实验提供了五种常见的插值算法,下面一一介绍。

3.1 最近邻插值(cv2.INTER_NEAREST)

最近邻插值的原理
代码如下:

'''最近邻插值法'''img=cv2.imread(r"../15day4.10/src/1.jpg")# 求出图片的高宽和颜色h,w,c=img.shape# 给出一个旋转角度angle=45# 给出缩放倍数sacle=1.5#给出缩放后的图像的窗口大小frame=(2*w,2*h)# 以图片的中心作为旋转中心的仿射变换矩阵m=cv2.getRotationMatrix2D((h/2,w/2),0,sacle)img_rotate=cv2.warpAffine(img,m,frame,flags=cv2.INTER_NEAREST)cv2.imshow("img",img)cv2.imshow("img_rotate",img_rotate)cv2.waitKey(0)

在这里插入图片描述

3.2 双线性插值(cv2.INTER_LINEAR)

双线性插值的原理
代码如下:

 '''双线性插值'''img=cv2.imread(r"../15day4.10/src/1.jpg")# 求出图片的高宽和颜色h,w,c=img.shape# 给出一个旋转角度angle=45# 给出缩放倍数sacle=1.5#给出缩放后的图像的窗口大小frame=(2*w,2*h)# 以图片的中心作为旋转中心的仿射变换矩阵m=cv2.getRotationMatrix2D((h/2,w/2),0,sacle)img_rotate=cv2.warpAffine(img,m,frame,flags=cv2.INTER_LINEAR)cv2.imshow("img",img)cv2.imshow("img_rotate",img_rotate)cv2.waitKey(0)

在这里插入图片描述
注意:

  • 双线性插值和最近邻插值的区别就,当放大倍数为小数时,最近邻插值(cv2.INTER_NEAREST)是对结果下取整,而双线性插值(cv2.INTER_LINEAR)根据距离哪个像素点近就将取大的权值
  • 在这里插入图片描述

3.3 像素区域插值(cv2.INTER_AREA)

像素区域插值主要分两种情况,缩小图像和放大图像的工作原理并不相同。

当使用像素区域插值方法进行缩小图像时,它就会变成一个均值滤波器(滤波器其实就是一个核,这里只做简单了解,后面实验中会介绍),其工作原理可以理解为对一个区域内(均值滤波器/核)的像素值取平均值。

当使用像素区域插值方法进行放大图像时,如果图像放大的比例是整数倍,那么其工作原理与最近邻插值类似;如果放大的比例不是整数倍,那么就会调用双线性插值进行放大。

其中目标像素点与原图像的像素点的对应公式如下所示:
s r c X = d s t X ∗ s r c W i d t h d s t W i d t h s r c X=d s t X*{\frac{s r c W i d t h}{d s t W i d t h}} srcX=dstXdstWidthsrcWidth

s r c Y = d s t Y ∗ s r c H e i g h t d s t H e i g h t s r c Y=d s t Y*{\frac{s r c H e i g h t}{d s t H e i g h t}} srcY=dstYdstHeightsrcHeight
代码如下:

 '''像素区域插值'''img=cv2.imread(r"../15day4.10/src/1.jpg")# 求出图片的高宽和颜色h,w,c=img.shape# 给出一个旋转角度angle=45# 给出缩放倍数sacle=1.5#给出缩放后的图像的窗口大小frame=(2*w,2*h)# 以图片的中心作为旋转中心的仿射变换矩阵m=cv2.getRotationMatrix2D((h/2,w/2),0,sacle)img_rotate=cv2.warpAffine(img,m,frame,flags=cv2.INTER_AREA)cv2.imshow("img",img)cv2.imshow("img_rotate",img_rotate)cv2.waitKey(0)      


像素区域插值(cv2.INTER_AREA)就是最近邻插值和双线性插值的结合

3.4 双三次插值(cv2.INTER_CUBIC)

与双线性插值法相同,该方法也是通过映射,在映射点的邻域内通过加权来得到放大图像中的像素值。不同的是,双三次插值法需要原图像中近邻的16个点来加权。

目标像素点与原图像的像素点的对应公式如下所示:
s r c X = d s t X ∗ s r c W i d t h d s t W i d t h s r c X=d s t X*{\frac{s r c W i d t h}{d s t W i d t h}} srcX=dstXdstWidthsrcWidth

s r c Y = d s t Y ∗ s r c H e i g h t d s t H e i g h t s r c Y=d s t Y*{\frac{s r c H e i g h t}{d s t H e i g h t}} srcY=dstYdstHeightsrcHeight

下面我们举例说明,假设原图像A大小为m*n,缩放后的目标图像B的大小为M*N。其中A的每一个像素点是已知的,B是未知的,我们想要求出目标图像B中每一个像素点(X,Y)的值,必须先找出像素(X,Y)在原图像A中对应的像素(x,y),再根据原图像A距离像素(x,y)最近的16个像素点作为计算目标图像B(X,Y)处像素值的参数,利用BiCubic基函数求出16个像素点的权重,图B像素(x,y)的值就等于16个像素点的加权叠加。

假如下图中的P点就是目标图像B在(X,Y)处根据上述公式计算出的对应于原图像A中的位置,P的坐标位置会出现小数部分,所以我们假设P点的坐标为(x+u,y+v),其中x、y表示整数部分,u、v表示小数部分,那么我们就可以得到其周围的最近的16个像素的位置,我们用a(i,j)(i,j=0,1,2,3)来表示,如下图所示。

在这里插入图片描述

然后给出BiCubic函数:
JYBx-1745050039632)

其中,a一般取-0.5或-0.75。

我们要做的就是将上面的16个点的坐标带入函数中,获取16像素所对应的权重 W ( x ) W(x) W(x)。然而BiCubic函数是一维的,所以我们需要将像素点的行与列分开计算,比如a00这个点,我们需要将x=0带入BiCubic函数中,计算a00点对于P点的x方向的权重,然后将y=0带入BiCubic函数中,计算a00点对于P点的y方向的权重,其他像素点也是这样的计算过程,最终我们就可以得到P所对应的目标图像B在(X,Y)处的像素值为:
B ( X , Y ) = ∑ i = 0 3 ∑ j = 0 3 a i j × W ( i ) × W ( j ) B(X,Y)=\sum_{i=0}^{3}\sum_{j=0}^{3}a_{i j}\times W_{(i)}\times W_{(j)} B(X,Y)=i=03j=03aij×W(i)×W(j)
依此办法我们就可以得到目标图像中所有的像素点的像素值。

代码如下:

'''双三次插值'''img=cv2.imread(r"../15day4.10/src/1.jpg")# 求出图片的高宽和颜色h,w,c=img.shape# 给出一个旋转角度angle=45# 给出缩放倍数sacle=1.5#给出缩放后的图像的窗口大小frame=(2*w,2*h)# 以图片的中心作为旋转中心的仿射变换矩阵m=cv2.getRotationMatrix2D((h/2,w/2),0,sacle)img_rotate=cv2.warpAffine(img,m,frame,flags=cv2.INTER_CUBIC)cv2.imshow("img",img)cv2.imshow("img_rotate",img_rotate)cv2.waitKey(0)      

在这里插入图片描述
双三次插值(cv2.INTER_CUBIC)比双线性插值(cv2.INTER_LINEAR)对图片处理更精细,但是执行效率比较低

3.5 Lanczos插值(cv2.INTER_LANCZOS4)

Lanczos插值方法与双三次插值的思想是一样的,不同的就是其需要的原图像周围的像素点的范围变成了8*8,并且不再使用BiCubic函数来计算权重,而是换了一个公式计算权重。

首先还是目标像素点与原图像的像素点的对应公式如下所示:
s r c X = d s t X ∗ s r c W i d t h d s t W i d t h s r c X=d s t X*{\frac{s r c W i d t h}{d s t W i d t h}} srcX=dstXdstWidthsrcWidth

s r c Y = d s t Y ∗ s r c H e i g h t d s t H e i g h t s r c Y=d s t Y*{\frac{s r c H e i g h t}{d s t H e i g h t}} srcY=dstYdstHeightsrcHeight

下面我们举例说明,假设原图像A大小为m*n,缩放后的目标图像B的大小为M*N。其中A的每一个像素点是已知的,B是未知的,我们想要求出目标图像B中每一个像素点(X,Y)的值,必须先找出像素(X,Y)在原图像A中对应的像素(x,y),再根据原图像A距离像素(x,y)最近的64个像素点作为计算目标图像B(X,Y)处像素值的参数,利用权重函数求出64个像素点的权重,图B像素(x,y)的值就等于64个像素点的加权叠加。

假如下图中的P点就是目标图像B在(X,Y)处根据上述公式计算出的对应于原图像A中的位置,P的坐标位置会出现小数部分,所以我们假设P点的坐标为(x+u,y+v),其中x、y表示整数部分,u、v表示小数部分,那么我们就可以得到其周围的最近的64个像素的位置,我们用a(i,j)(i,j=0,1,2,3,4,5,6,7)来表示,如下图所示。

在这里插入图片描述

然后给出权重公式:
在这里插入图片描述

其中a通常取2或者3,当a=2时,该算法适用于图像缩小。a=3时,该算法适用于图像放大。

与双三次插值一样,这里也需要将像素点分行和列分别带入计算权重值,其他像素点也是这样的计算过程,最终我们就可以得到P所对应的目标图像B在(X,Y)处的像素值为:
S ( x , y ) = ∑ i = [ x ] − a + 1 [ x ] + a ∑ j = [ y ] − a + 1 [ y ] + a s i j L ( x − i ) L ( y − j ) S(x,y)=\sum_{i=[x]-a+1}^{[x]+a}\sum_{j=[y]-a+1}^{[y]+a}s_{i j}L(x-i)L(y-j) S(x,y)=i=[x]a+1[x]+aj=[y]a+1[y]+asijL(xi)L(yj)
其中 [ x ] [x] [x] [ y ] [y] [y]表示对坐标值向下取整,通过该方法就可以计算出新的图像中所有的像素点的像素值。
代码如下:

 '''lanczos'''img=cv2.imread(r"../15day4.10/src/1.jpg")# 求出图片的高宽和颜色h,w,c=img.shape# 给出一个旋转角度angle=45# 给出缩放倍数sacle=1.5#给出缩放后的图像的窗口大小frame=(2*w,2*h)# 以图片的中心作为旋转中心的仿射变换矩阵m=cv2.getRotationMatrix2D((h/2,w/2),0,sacle)img_rotate=cv2.warpAffine(img,m,frame,flags=cv2.INTER_LANCZOS4)cv2.imshow("img",img)cv2.imshow("img_rotate",img_rotate)cv2.waitKey(0)      

在这里插入图片描述

3.6 小结

最近邻插值的计算速度最快,但是可能会导致图像出现锯齿状边缘和失真,效果较差。双线性插值的计算速度慢一点,但效果有了大幅度的提高,适用于大多数场景。双三次插值、Lanczos插值的计算速度都很慢,但是效果都很好。

在OpenCV中,关于插值方法默认选择的都是双线性插值,且一般情况下双线性插值已经能满足大部分需求。

4. 边缘填充方式(cv2.warpAffine的属性borderMode)

在这里插入图片描述

可以看到,左图在逆时针旋转45度之后原图的四个顶点在右图中已经看不到了,同时,右图的四个顶点区域其实是什么都没有的,因此我们需要对空出来的区域进行一个填充。右图就是对空出来的区域进行了像素值为(0,0,0)的填充,也就是黑色像素值的填充。除此之外,后续的一些图像处理方式也会用到边缘填充,这里介绍五个常用的边缘填充方法。

4.1 边界复制(BODER_REPLICATE)

边界复制会将边界处的像素值进行复制,然后作为边界填充的像素值,如下图所示,可以看到四周的像素值都一样。
在这里插入图片描述
代码如下:

 '''边界复制'''img=cv2.imread(r"../15day4.10/src/face.png")# 求出图片的高宽和颜色h,w,c=img.shape# 给出一个旋转角度angle=45# 给出缩放倍数sacle=1#给出缩放后的图像的窗口大小frame=(2*w,2*h)# 以图片的中心作为旋转中心的仿射变换矩阵m=cv2.getRotationMatrix2D((h/2,w/2),angle,sacle)img_rotate=cv2.warpAffine(img,m,frame,borderMode=cv2.BORDER_REPLICATE)cv2.imshow("img",img)cv2.imshow("img_rotate",img_rotate)cv2.waitKey(0)      

在这里插入图片描述

4.2 边界反射(BORDER_REFLECT)

如下图所示,会根据原图的边缘进行反射。
在这里插入图片描述

代码如下:

 '''边界反射'''img=cv2.imread(r"../15day4.10/src/face.png")# 求出图片的高宽和颜色h,w,c=img.shape# 给出一个旋转角度angle=45# 给出缩放倍数sacle=1#给出缩放后的图像的窗口大小frame=(2*w,2*h)# 以图片的中心作为旋转中心的仿射变换矩阵m=cv2.getRotationMatrix2D((h/2,w/2),angle,sacle)img_rotate=cv2.warpAffine(img,m,frame,borderMode=cv2.BORDER_REFLECT)cv2.imshow("img",img)cv2.imshow("img_rotate",img_rotate)cv2.waitKey(0)    

在这里插入图片描述
边界反射是将原图沿着原图的边界镜像复制填充整个边框

4.3 边界反射101(BORDER_REFLECT_101)

与边界反射不同的是,不再反射边缘的像素点,如下图所示。
在这里插入图片描述
代码如下:

 '''边界反射_101'''img=cv2.imread(r"../15day4.10/src/face.png")# 求出图片的高宽和颜色h,w,c=img.shape# 给出一个旋转角度angle=45# 给出缩放倍数sacle=1#给出缩放后的图像的窗口大小frame=(2*w,2*h)# 以图片的中心作为旋转中心的仿射变换矩阵m=cv2.getRotationMatrix2D((h/2,w/2),angle,sacle)img_rotate=cv2.warpAffine(img,m,frame,borderMode=cv2.BORDER_REFLECT_101)cv2.imshow("img",img)cv2.imshow("img_rotate",img_rotate)cv2.waitKey(0)

在这里插入图片描述
边界反射101是将原图以原图的边界为轴镜像复制填充整个边框

4.4 边界常数(BORDER_CONSTANT)

当选择边界常数时,还要指定常数值是多少,默认的填充常数值为0,如下图所示。

img2=cv2.warpAffine(img,M,(shape[1],shape[0]),flags=cv2.INTER_LINEAR,borderMode=cv2.BORDER_CONSTANT,borderValue=100)


代码如下:

'''边界常数'''img=cv2.imread(r"../15day4.10/src/face.png")# 求出图片的高宽和颜色h,w,c=img.shape# 给出一个旋转角度angle=45# 给出缩放倍数sacle=1#给出缩放后的图像的窗口大小frame=(2*w,2*h)# 以图片的中心作为旋转中心的仿射变换矩阵m=cv2.getRotationMatrix2D((h/2,w/2),angle,sacle)#边界常数(borderMode=cv2.BORDER_CONSTANT)的边界值(borderVlue)为0则是黑色,如果就是一个值的话是将bgr这三个值都赋值为这个值img_rotate=cv2.warpAffine(img,m,frame,borderMode=cv2.BORDER_CONSTANT,borderValue=(0,0,255))cv2.imshow("img",img)cv2.imshow("img_rotate",img_rotate)cv2.waitKey(0)

在这里插入图片描述
边界常数(borderMode=cv2.BORDER_CONSTANT)的边界值(borderVlue)为0则是黑色,如果就是一个值的话是将bgr这三个值都赋值为这个值

4.5 边界包裹(BORDER_WRAP)

如下图所示。
在这里插入图片描述
代码如下:

'''边界包裹'''img=cv2.imread(r"../15day4.10/src/face.png")# 求出图片的高宽和颜色h,w,c=img.shape# 给出一个旋转角度angle=45# 给出缩放倍数sacle=1#给出缩放后的图像的窗口大小frame=(2*w,2*h)# 以图片的中心作为旋转中心的仿射变换矩阵m=cv2.getRotationMatrix2D((h/2,w/2),angle,sacle)img_rotate=cv2.warpAffine(img,m,frame,borderMode=cv2.BORDER_WRAP)cv2.imshow("img",img)cv2.imshow("img_rotate",img_rotate)cv2.waitKey(0)

在这里插入图片描述
边界包裹(cv2.BORDER_WRAP)的含义就是将图片平铺填充窗口

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

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

相关文章

如何在 Odoo 18 中配置自动化动作

如何在 Odoo 18 中配置自动化动作 Odoo是一款多功能的业务管理平台,旨在帮助各种规模的企业更高效地处理日常运营。凭借其涵盖销售、库存、客户关系管理(CRM)、会计和人力资源等领域的多样化模块,Odoo 简化了业务流程&#xff0c…

每日两道leetcode

345. 反转字符串中的元音字母 - 力扣(LeetCode) 题目 给你一个字符串 s ,仅反转字符串中的所有元音字母,并返回结果字符串。 元音字母包括 a、e、i、o、u,且可能以大小写两种形式出现不止一次。 示例 1:…

【SQL 基础入门 1. -- SQL 基本语法详解及举例】

文章目录 SQL 数据库创建及使用删除数据库SQL 查看数据空中有哪些表格SQL 创建表格SQL 修改表格列数据格式SQL 表格插入数据SQL 查看表格类型组成SQL 查看表格中的内容 SQL 查询语句SQL 查看指定列SQL 选择指定列SQL 按指定列进行升序排序SQL 平均值/求和/最大值/最小值 SQL 数…

PostgreSQL 分区表——范围分区SQL实践

PostgreSQL 分区表——范围分区SQL实践 1、环境准备1-1、新增原始表1-2、执行脚本新增2400w行1-3、创建pg分区表-分区键为创建时间1-4、创建24年所有分区1-5、设置默认分区(兜底用)1-6、迁移数据1-7、创建分区表索引 2、SQL增删改查测试2-1、查询速度对比…

Apache Flink 深度解析:流处理引擎的核心原理与生产实践指南

Apache Flink 深度解析:流处理引擎的核心原理与生产实践指南 引言:实时计算的范式革命 2023年双十一期间,某头部电商平台基于Flink构建的实时风控系统成功拦截了每秒超过120万次的异常交易请求。这背后是Apache Flink作为第四代计算引擎的强…

【Java学习笔记】选择结构

选择结构 内容结构 一、顺序结构 二、分支控制 (1)单分支 (2)双分支 (3)多分支 (4)嵌套分支 (5)switch 分支结构 三、switch和if的比较 一、顺序结构…

03_JavaScript

文章目录 一、概述1.1、JavaScript简介1.2、JavaScript组成部分1.3、为什么要学习JavaScript1.4、学习的目的1.5、JavaScript与Java的关系 二、使用位置及运行说明2.1、使用位置2.2、如何运行 三、JavaScript基础语法3.1、变量3.2、运算符3.3、控制流程3.3.1、分支结构3.3.2、循…

PySide6 GUI 学习笔记——常用类及控件使用方法(常用类矩阵QRect)

文章目录 一、构造与初始化方法二、坐标与尺寸获取三、坐标与尺寸设置四、几何运算方法五、移动与调整方法六、状态判断方法七、类型转换方法八、操作符重载九、静态方法十、特殊方法附录方法速查表注意的问题交集和并集图解 📘 PySide6.QtCore.QRect 使用整数精度定…

AI 开发入门之 RAG 技术

目录 一、从一个简单的问题开始二、语言模型“闭卷考试”的困境三、RAG 是什么—LLM 的现实世界“外挂”四、RAG 的七步流程第一步:加载数据(Load)第二步:切分文本(Chunking)第三步:向量化&…

解决yarn install 报错 error \node_modules\electron: Command failed.

在电脑重装系统后,重新安装项目依赖,遇到这一报错 完整报错信息如下: error D:\xxxxx\xxxxxx\node_modules\electron: Command failed. Exit code: 1 Command: node install.js Arguments: Directory: D:\xxxxx\xxxxx\node_modules\electron Output: HTTPError: Response cod…

2025年3月电子学会青少年机器人技术(五级)等级考试试卷-理论综合

青少年机器人技术等级考试理论综合试卷(五级) 分数:100 题数:30 一、单选题(共20题,共80分) 1. 2025年初,中国科技初创公司深度求索在大模型领域迅速崛起,其开源的大模型成为全球AI领域的焦…

23种设计模式-行为型模式之模版方法模式(Java版本)

Java 模板方法模式(Template Method Pattern)详解 🧠 什么是模板方法模式? 模板方法模式是一种行为型设计模式,在一个方法中定义一个操作中的算法骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在…

长城杯铁人三项初赛-REVERSE复现

前言 记录记录 1.LoginToMe int __fastcall main(int argc, const char **argv, const char **envp) {unsigned int v3; // eaxchar s[96]; // [rsp10h] [rbp-70h] BYREFint v6; // [rsp70h] [rbp-10h]int v7; // [rsp78h] [rbp-8h]int i; // [rsp7Ch] [rbp-4h]memset(s, 0, s…

DNS实验

DNS原理 客户端发起请求:客户端向本地 DNS 服务器发送域名解析请求,这是流程的起始点。本地 DNS 服务器查询根域名服务器:若本地 DNS 服务器缓存中无对应记录,它向根域名服务器发起查询,根域名服务器是 DNS 系统顶层&a…

SQLMesh 通知系统深度解析:构建自动化监控体系

SQLMesh 是一款强大的数据编排工具,其内置的灵活通知系统可显著提升团队协作效率。本文将系统解读 SQLMesh 的通知机制,涵盖配置方法、事件触发逻辑及高级定制技巧。 一、通知系统的核心架构 1. 通知目标(Notification Targets) …

精益数据分析(20/126):解析经典数据分析框架,助力创业增长

精益数据分析(20/126):解析经典数据分析框架,助力创业增长 在创业和数据分析的学习道路上,每一次深入探索都可能为我们带来新的启发。今天,依旧带着和大家共同进步的想法,我们一起深入研读《精…

【OSG学习笔记】Day 8: 纹理贴图——赋予模型细节

在 OSG(Open Scene Graph)中,纹理贴图是为模型添加细节的关键技术,主要涉及纹理加载、UV 映射和多重纹理叠加三部分。 基础理论 纹理加载 纹理的作用,就是将2D图像映射到3D模型表面,增强视觉细节。 纹理类型与格式支持: OSG 支持多种图像格式,包括常见的 .jpg/.jpe…

基于事件驱动的云原生后端架构设计:从理念到落地

📝个人主页🌹:慌ZHANG-CSDN博客 🌹🌹期待您的关注 🌹🌹 一、引言:微服务之后,事件驱动正在成为新范式 随着业务复杂度的提升,传统同步式微服务调用模式逐渐暴露出瓶颈:服务间耦合度高、并发能力有限、出错链路复杂。而在互联网业务、金融交易、物联网等场景中…

vue3:十一、主页面布局(修改顶部导航栏样式-右侧:用户信息+退出登录+全屏显示)

一、效果 完成效果,增加顶部导航栏,右侧用户信息(其中个人中心需要后续进行页面开发,这里只写了退出登录功能),以及全屏功能 二、搭建并引入右侧组件 将右侧内容封装到单独的组件,直接引入(像左侧导航条等内容也是可以做成这种形式) 1、新建右侧组件的页面 在layout中…

沁恒CHV203中断嵌套导致修改线程栈-韦东山

调试专题bug实例 2025年01月09日20点场 处理办法1:就是关闭中断嵌套 处理办法2: 使用原来的栈