opencv学习笔记(十):图像缩放、平移、旋转变换理论推导及应用

本文主要是介绍opencv学习笔记(十):图像缩放、平移、旋转变换理论推导及应用,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

opencv学习笔记(十):图像缩放、平移、旋转变换理论推导及应用

文章目录

  • opencv学习笔记(十):图像缩放、平移、旋转变换理论推导及应用
    • 基础知识I——图像仿射变换
    • 基础知识II——图像插值算法
      • 1.为什么会有图像插值的概念?
      • 2.经典的图像插值算法
        • 最近邻插值(最简单的插值方法)
        • 双线性插值
        • 双三次插值
    • 缩放变换——resize函数
      • 函数原型
      • 探究将一张图片缩小a倍,再将缩小后的图像放大a倍
    • 平移变换——warpAffine函数
      • 函数原型
      • 实现一幅图像的平移
    • 旋转变换——warpAffine函数
      • 原理推导
        • 情况1:绕原点旋转
        • 情况2:绕任意点旋转
      • 函数原型
      • 实现一幅图像的旋转
      • 实现图像绕中心点无损旋转
        • 理论推导
    • 仿射变换
      • 放射变换的变换矩阵推导
      • 函数原型
      • 实现仿射变换
    • 透视变换——在车道线检测上的应用

基础知识I——图像仿射变换

仿射变换包括如下所有变换,以及这些变换任意次序次数的组合:

平移(translation)和旋转(rotation)顾名思义,两者的组合称之为欧式变换(Euclidean transformation)或刚体变换(rigid transformation);

放缩(scaling)可进一步分为uniform scaling和non-uniform scaling,前者每个坐标轴放缩系数相同(各向同性),后者不同;如果放缩系数为负,则会叠加上反射(reflection)——reflection可以看成是特殊的scaling;

刚体变换+uniform scaling 称之为,相似变换(similarity transformation),即平移+旋转+各向同性的放缩;
剪切变换(shear mapping)将所有点沿某一指定方向成比例地平移。
在这里插入图片描述

上述变换都可以通过矩阵操作进行:
没有平移或者平移量为0的所有仿射变换可以用如下变换矩阵描述:

在这里插入图片描述

为了增添平移这一变换,变换矩阵写为:

在这里插入图片描述

基础知识II——图像插值算法

1.为什么会有图像插值的概念?

以小图像放大为大图像为例:
在这里插入图片描述

从上图可以看出,当一个小图像放大为大图像时,像素点的位置坐标随之变化,放大后的图像会存在像素缺失(图中橙色点所示),如果这些位置上的像素不做处理就会造成图像严重失真,为了解决这个问题,便有了图像内插问题的提出。

2.经典的图像插值算法

  • 最近邻插值(Nearest)
  • 双线性插值(Bilinear)
  • 双三次插值(Bicubic)
最近邻插值(最简单的插值方法)

在这里插入图片描述

如上图所示,图2.1是原始图像,图2.2是图2.1放大2倍以后得到的图像,其像素点的横纵坐标均扩大为原来的两倍,那么会产生出其他位置的新像素,如图2.2中浅色圆圈所示。
最近邻插值是将图2.2中五个未知像素点横纵坐标缩小2倍,那么这5个像素点的位置一定落在图2.1中四个像素的四邻域内,对于一个未知像素的像素点来说,其像素值和离它最近的已知像素点的像素值相同。
最近邻插值简单便捷,其计算速度快,但是当一个图片需要放大较大倍数时,会出现马赛克现象。举个简单例子,当一个图像放大500倍时,此时两个原有像素点之间就存在499个待插值,那么必定会存在有连续位置上的像素值相同,这样就会出现马赛克现象。

双线性插值

双线性插值有前提假设:假设原图像的灰度是线性变化的。
在这里插入图片描述

如上图所示,假设代插点映射回原图的位置为 e ( u , v ) e(u,v) e(u,v), u u u , v v v显然都是非整数, A A A, B B B, C C C, D D D四点对应的灰度值分别为 I ( i , j ) I(i,j) I(i,j), I ( i , j + 1 ) I(i,j+1) I(i,j+1), I ( i , j + 1 ) I(i,j+1) I(i,j+1), I ( i + 1 , j + 1 ) I(i+1,j+1) I(i+1,j+1)

  • 要求出 e ( u , v ) e(u,v) e(u,v)的像素值首先要求出 e 1 ( u , j ) = e 1 ( i + d x , j ) e_{1}(u,j)=e_{1}(i+d_{x},j) e1(u,j)=e1(i+dx,j) e 2 ( u , j + 1 ) = e 2 ( i + d x , j + d y ) e_{2}(u,j+1)=e_{2}(i+d_{x},j+d_{y}) e2(u,j+1)=e2(i+dx,j+dy)的像素值。
  • x轴的单线性插值: 根据原图像灰度线性变化,可由 A A A, B B B两点的像素值以及它们之间的线性关系求出 e 1 e_{1} e1的像素值—— e 1 ( u , j ) = d x ( I ( i , j + 1 ) − I ( i , j ) ) + I ( i , j ) e_{1}(u,j)=d_{x}(I(i,j+1)-I(i,j))+I(i,j) e1(u,j)=dx(I(i,j+1)I(i,j))+I(i,j),同理可以求出 e 2 e_{2} e2
  • y轴的单线性插值: 根据 e 1 e_{1} e1 e 2 e_{2} e2两点的插值再次求线性插值即可。
    根据上述推导,双线性插值法其实是利用待插像素点四个邻接像素点的灰度值在水平和垂直方向上作线性内插,它的运算量要比最近邻域法复杂些,但克服了灰度不连续的缺点,整体视觉效果较好。同时需要注意到,它具有⭐️低通滤波⭐️的性质(该方法没有考虑图像灰度变化率的情况,只是根据位置来确定插值的像素权重,若两个像素点像素值分别为0、255,跨越了整个8bit灰度级的灰度范围,放大后这两点之间的坐标上将会填充一系列渐变的像素值,导致0、255的视觉跨度降低,也就导致某些图片上边缘模糊),图像的高频分量会在此插值过程中受损,导致效果图中的轮廓有一定的模糊,细节不够突出。
双三次插值

维基百科中对双三次插值的推导


缩放变换——resize函数

先展示一张较大图片

import cv2 
import numpy as npImg = cv2.imread ('1.png',cv2.IMREAD_UNCHANGED)
cv2.imshow('img',Img)
cv2.waitKey(0)

显示效果如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-md7uJpGj-1673570245578)(http://restar-xt.cn/wp-content/uploads/2023/01/Python显示过大图片.png)]
发现图片显示不全,那么可以通过缩放函数resize解决问题

函数原型

dst	=	cv.resize(	src, dsize[, dst[, fx[, fy[, interpolation]]]]	)
@参数:
src	  input image.输入图像
dst	  output image; it has the size dsize (when it is non-zero) or the size computed from src.size(), fx, and fy; the type of dst is the same as of src.输出图像
dsize	output image size; if it equals zero, it is computed as:
dsize = Size(round(fx*src.cols), round(fy*src.rows))
Either dsize or both fx and fy must be non-zero.输出图像的大小
fx	scale factor along the horizontal axis; when it equals 0, it is computed as
(double)dsize.width/src.cols  x轴缩放因子
fy	scale factor along the vertical axis; when it equals 0, it is computed as
(double)dsize.height/src.rows  y轴缩放因子
interpolation	interpolation method, see InterpolationFlags 插值方法

说明:对于插值方法,OpenCV提供了多种插值方法:
在这里插入图片描述

INTER_NEAREST最近邻插值
INTER_LINEAR双线性插值
INTER_CUBIC双三次插值
INTER_AREA区域插值
INTER_LANCZOS4兰索斯插值

接下来将之前展示的图片进行缩小:

import cv2 
import numpy as npImg = cv2.imread ('1.png',cv2.IMREAD_UNCHANGED)
Img_1 = cv2.resize(Img,None,None,0.1,0.1,cv2.INTER_NEAREST)cv2.imshow('Original Image',Img)
cv2.imshow('Nearest Image',Img_1)cv2.waitKey(0)

运行结果如下:
在这里插入图片描述

在这里插入图片描述

在本文开头曾介绍了最近邻、双线性、双三次插值,为了更加清晰直观地说明三种插值方式的优劣性,以同样放大倍数放大同一图片进行观察:

import cv2 
import numpy as npImg = cv2.imread ('lena.png',cv2.IMREAD_UNCHANGED)
Img_1 = cv2.resize(Img,None,None,5,5,cv2.INTER_NEAREST)
Img_2 = cv2.resize(Img,None,None,5,5,cv2.INTER_LINEAR)
Img_3 = cv2.resize(Img,None,None,5,5,cv2.INTER_CUBIC)
cv2.imshow('Original Image',Img)
cv2.imshow('Nearest Image',Img_1)//最近邻插值
cv2.imshow('Linear Image',Img_2)//双线性插值
cv2.imshow('Cubic Image',Img_3)//双三次插值
cv2.waitKey(0)

运行结果如下:
在这里插入图片描述

可见左图(最近邻插值)方块(马赛克)情况严重,中图(双线性插值)与右图(双三次插值)在lena头发处对比明显,双三次插值放大的图像边缘更加平滑。

探究将一张图片缩小a倍,再将缩小后的图像放大a倍

注意:进行缩小处理时常用区域插值,进行放大处理时常用双线性插值或双三次插值。
代码如下:

import cv2 
import numpy as npImg = cv2.imread ('lena.png',cv2.IMREAD_UNCHANGED)
Img_1=cv2.resize(Img,None,None,0.5,0.5,cv2.INTER_AREA)
Img_2=cv2.resize(Img_1,None,None,2,2,cv2.INTER_CUBIC)
cv2.imshow('Original Image',Img)
cv2.imshow('Smaller Image',Img_2)
cv2.waitKey(0)

运行结果如下:主要比较缩小再放大的图像与原图的区别。
在这里插入图片描述

从上图可看出,左图作为缩小后又放大的图像明显具有模糊(马赛克)效果,这是由于缩小时本身会损失一部分像素值,放大以后的图像这部分像素值缺失,是通过插值来填充的,为了解决缺失像素点恢复的问题可以通过图像金字塔等相关知识解决。

写在前面:接下来的平移变换和旋转变换其实都属于仿射变换,它们可以用变换矩阵达到目的,故二者使用的核心函数都是warpAffine函数,只不过平移变换的变换矩阵很简单容易求出,而且平移变换只涉及水平、竖直两个方向;而旋转变换则涉及旋转中心、旋转角度等,其对应的变换矩阵无法一眼求出,需要借助相关函数,这就是二者在使用过程中的区别。

平移变换——warpAffine函数

平移变换是矩阵操作,对图像进行矩阵操作主要有两步:

  • 构建对应矩阵
  • 进行矩阵乘法

一般使用Numpy模块来构建矩阵,矩阵数据类型为单精度浮点数float32(这是由OpenCV函数参数决定的)。

函数原型

dst	=	cv.warpAffine(	src, M, dsize[, dst[, flags[, borderMode[, borderValue]]]]	)
@参数说明:
@src	  input image.输入图像
@dst	  output image that has the size dsize and the same type as src .输出图像
@M	    2×3 transformation matrix.2*3的矩阵
@dsize	size of the output image.输出图像大小
@flags	combination of interpolation methods (see InterpolationFlags) and the optional flag WARP_INVERSE_MAP that means that M is the inverse transformation ( dst→src ).插值方法,可选参数WARP_INVERSE_MAP表示图像逆变换——dst->src
@borderMode	pixel extrapolation method (see BorderTypes); when borderMode=BORDER_TRANSPARENT, it means that the pixels in the destination image corresponding to the "outliers" in the source image are not modified by the function.像素外推方法
@borderValue	value used in case of a constant border; by default, it is 0.固定边框

关于函数中M矩阵的推导,为什么是2*3矩阵?
设图像中一个像素(像素坐标)的向量(矩阵)表示为:

在这里插入图片描述

变换矩阵为:

在这里插入图片描述

两个矩阵相乘:

在这里插入图片描述

这样就实现了像素点的平移,对原图像所有像素点做如此处理即可得到原图像平移。

实现一幅图像的平移

import numpy as np
import cv2Img = cv2.imread('lena.png',cv2.IMREAD_UNCHANGED);
M=np.float32([[1,0,50],[0,1,50]])#创造2*3矩阵,与上文推导对比可知,该矩阵可使图片沿x轴、y轴均平移50个单位长度
ImgTranslation = cv2.warpAffine(Img,M,(Img.shape[0],Img.shape[1]))
cv2.imshow('ImgTranslation',ImgTranslation)
cv2.imshow('Original',Img)
cv2.waitKey(0)

运行效果如下:
在这里插入图片描述

产生的黑色边框是由于平移后像素点填充为 ( 0 , 0 , 0 ) (0,0,0) 0,0,0造成的。

旋转变换——warpAffine函数

原理推导

情况1:绕原点旋转

在这里插入图片描述

P ( x , y ) P(x,y) P(x,y)是原始坐标, Q ( x , y ) Q(x,y) Q(x,y) P P P点旋转一定角度得到的点,先求 Q Q Q点由 P P P点坐标表出的坐标表示:
x , = D cos ⁡ ( α + β ) = D ( cos ⁡ α cos ⁡ β − sin ⁡ α sin ⁡ β ) = x cos ⁡ β − y sin ⁡ β x^,=D\cos{(\alpha+\beta)}=D(\cos{\alpha}\cos{\beta}-\sin{\alpha}\sin{\beta})=x\cos{\beta}-y\sin{\beta} x,=Dcos(α+β)=D(cosαcosβsinαsinβ)=xcosβysinβ
y , = D sin ⁡ ( α + β ) = D ( sin ⁡ α cos ⁡ β + cos ⁡ α sin ⁡ β ) = y cos ⁡ β + x sin ⁡ β = x sin ⁡ β + y cos ⁡ β y^,=D\sin{(\alpha+\beta)}=D(\sin{\alpha}\cos{\beta}+\cos{\alpha}\sin{\beta})=y\cos{\beta}+x\sin{\beta}=x\sin{\beta}+y\cos{\beta} y,=Dsin(α+β)=D(sinαcosβ+cosαsinβ)=ycosβ+xsinβ=xsinβ+ycosβ
将上述两式用矩阵表示:
在这里插入图片描述

情况2:绕任意点旋转

点绕任意中心位置旋转其实就是先将坐标系从原点位置平移后旋转再平移回来。
该旋转矩阵较情况1来说复杂一些,但是OpenCV库内置了getRotationMatrix2D函数可以方便快捷地求出旋转矩阵。

opencv的getRotationMatrix2D函数可以获取旋转变换矩阵。输入中心点坐标(centerX,centerY),旋转角度θ,缩放比例,给出M变换矩阵:

在这里插入图片描述

M变换矩阵推导如下:

  • 首先用矩阵表示某一像素点 A ( x , y ) A(x,y) A(x,y)

  • 围绕任意点旋转其实就是把原图原点先平移到任意点,旋转相应角度后再平移回来。
  • 假设任意点坐标为 B ( m x , n y ) B(mx,ny) B(mx,ny),将原点 ( 0 , 0 ) (0,0) (0,0)平移到 B B B点,其实相当于把 A A A点进行同样的平移操作:

在这里插入图片描述

  • 此时旋转中心就是新的“原点”,下面将 M M M矩阵做旋转变换:

在这里插入图片描述

  • 旋转操作完成后,即可将当前图像重新平移回去:

在这里插入图片描述

  • 化简 Y Y Y中的变换矩阵可得:

在这里插入图片描述

函数原型

warpAffine函数的函数原型见上文。
着重介绍getRotationMatrix2D函数的使用。

retval	=	cv.getRotationMatrix2D(	center, angle, scale	)
@参数说明:
@center	Center of the rotation in the source image.选定的旋转中心
@angle	Rotation angle in degrees. Positive values mean counter-clockwise rotation (the coordinate origin is assumed to be the top-left corner).旋转角度(正值意味着顺时针旋转)
@scale	Isotropic scale factor.比例各向同性比例因子。

实现一幅图像的旋转

import numpy as np
import cv2Img = cv2.imread('T.jpg',cv2.IMREAD_UNCHANGED);
M=cv2.getRotationMatrix2D((145,420),-5,1)
ImgRotation = cv2.warpAffine(Img,M,(Img.shape[0],Img.shape[1]))
cv2.imshow('ImgRotation',ImgRotation)
cv2.namedWindow('ImgRotation',1)
cv2.resizeWindow('ImgRotation',3*Img.shape[0],3*Img.shape[1])
cv2.imshow('Original',Img)
cv2.waitKey(0)

运行效果如下:
在这里插入图片描述

注意到平移和旋转处理后图像都没有完全地显示出来(有黑边),故以旋转为例,尝试写出一套实现图像无损旋转的算法。

实现图像绕中心点无损旋转

理论推导

由上文推导可知,变换矩阵 Γ \Gamma Γ如下:

在这里插入图片描述

现在假设存在一幅图像经过相应旋转变换,原图与旋转后的图相对位置关系如下图所示:

在这里插入图片描述

要使新图像能够完全显示,那么画布的长一定大于等于两条蓝线长度之和,画布的宽一定大于等于两条红线长度之和,设原图像高为 h ( r o w s ) h(rows) h(rows),宽为 w ( c o l s ) w(cols) w(cols),则用数学公式表达有:

上述两式中旋转角 β \beta β均为弧度制,但在编程中,我们并非常常使用弧度制,故还有以下表达:

注意:新的画布扩大是基于原图左上角点(原点)扩大,显示区域同样丢失了信息.

下一步,需要将画布按照旋转点位置进行平移(类比上文中绕任意点旋转等于平移再旋转再逆平移的原理),如下图所示,要将画布从蓝色区域平移至红色区域,但OpenCV的画布没有办法平移,只是由输入图像的大小决定,因此我们可以通过将图像平移回原来的位置进行解决,可以更改矩阵 M M M的平移决定值:

在这里插入图片描述

代码如下:

import math
import cmath
import cv2
import numpy as npdef opencv_rotate(img, angle):h, w = img.shape[:2]center = (w / 2, h / 2)scale = 1.0# 2.1获取M矩阵M = cv2.getRotationMatrix2D(center, angle, scale)# 2.2 新的宽高,radians(angle) 把角度转为弧度 sin(弧度)new_H = int(w * abs(math.sin(math.radians(angle))) + h * abs(math.cos(math.radians(angle))))new_W = int(h * abs(math.sin(math.radians(angle))) + w * abs(math.cos(math.radians(angle))))# 2.3 平移M[0, 2] += (new_W - w) / 2M[1, 2] += (new_H - h) / 2rotate = cv2.warpAffine(img, M, (new_W, new_H),flags = cv2.INTER_CUBIC borderValue=(255, 255, 255))return rotateIMG = cv2.imread('T.jpg',cv2.IMREAD_UNCHANGED)
opencv_rotate(IMG,60)
cv2.imshow('Rotation',opencv_rotate(IMG,90)) 
cv2.waitKey(0)

运行结果如下:

在这里插入图片描述

图片旋转中也涉及到图像插值的问题(可参考冈萨雷斯《数字图像处理》(第三版)第二章图像旋转部分的例子展示),插值方式对旋转变换后图像直边缘的保持具有重要作用。以下图片从左到右依次是上述代码采用最近邻、双线性、双三次插值得到的"T"字母直边缘放大1000倍的图像:

在这里插入图片描述

仿射变换

仿射变换是在旋转变换以及平移变换的基础上得来的。
旋转变换和平移变换不会改变输入图像的形状,即使可以通过调整缩放因子来控制输出图像的大小,但是最后的输出图像与输入图像之间没有形状上的差异,这种变换称为刚性变换。
而仿射变换并非刚性变换,它会造成图像的改变,但是并非完全无规则的改变。有以下特征:

  • 平直性:直线变换过后依然是直线。
  • 平行性:二维图形之间的相对位置关系保持不变,平行线依然是平行线,且直线上点的位置顺序不变。
    仿射变换可以写成如下形式:

{ x , = a x + b y + m y , = c x + d y + n \begin{cases} \ x^,=ax+by+m&\\ \ y^,=cx+dy+n \end{cases} { x,=ax+by+m y,=cx+dy+n

注意到上述方程组中含有6个未知数,需要6个方程构成齐次方程组进行求解,要使方程有唯一解,必须要求这三个点不在同一直线上!因此,常说三个点确定唯一的仿射变换。

放射变换的变换矩阵推导

较简单,不再赘述:

在这里插入图片描述

函数原型

这里介绍的函数是求解仿射变换变换矩阵的函数——cv2.getAffineTransform(src,dst)

retval	=	cv.getAffineTransform(	src, dst	)
@参数说明:
@src	Coordinates of triangle vertices in the source image.源图像中三角形顶点的坐标。@dst	Coordinates of the corresponding triangle vertices in the destination image.目标图像中相应三角形顶点的坐标。

实现仿射变换

import numpy as np
import cv2
#读取图片
Img = cv2.imread('T.jpg',cv2.IMREAD_UNCHANGED);
#获取图片大小
rows = Img.shape[0]
cols = Img.shape[1]
#创建原图三角点与目标图像三角点
Oritriangle = np.float32([[20,20],[20,30],[60,25]])
Afftriangle = np.float32([[20,20],[20,30],[60,10]])
#计算变换矩阵
M = cv2.getAffineTransform(Oritriangle,Afftriangle)
#实现仿射变换
Img_Aff = cv2.warpAffine(Img,M,(cols,rows),flags=cv2.INTER_CUBIC)
#展示原图与变换后图像并对比
cv2.imshow('Img_Aff',Img_Aff)
cv2.imshow('Img',Img)
cv2.waitKey(0)

运行结果如下:

在这里插入图片描述

透视变换——在车道线检测上的应用

见下一次笔记

这篇关于opencv学习笔记(十):图像缩放、平移、旋转变换理论推导及应用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/292125

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

中文分词jieba库的使用与实景应用(一)

知识星球:https://articles.zsxq.com/id_fxvgc803qmr2.html 目录 一.定义: 精确模式(默认模式): 全模式: 搜索引擎模式: paddle 模式(基于深度学习的分词模式): 二 自定义词典 三.文本解析   调整词出现的频率 四. 关键词提取 A. 基于TF-IDF算法的关键词提取 B. 基于TextRank算法的关键词提取

基于人工智能的图像分类系统

目录 引言项目背景环境准备 硬件要求软件安装与配置系统设计 系统架构关键技术代码示例 数据预处理模型训练模型预测应用场景结论 1. 引言 图像分类是计算机视觉中的一个重要任务,目标是自动识别图像中的对象类别。通过卷积神经网络(CNN)等深度学习技术,我们可以构建高效的图像分类系统,广泛应用于自动驾驶、医疗影像诊断、监控分析等领域。本文将介绍如何构建一个基于人工智能的图像分类系统,包括环境

水位雨量在线监测系统概述及应用介绍

在当今社会,随着科技的飞速发展,各种智能监测系统已成为保障公共安全、促进资源管理和环境保护的重要工具。其中,水位雨量在线监测系统作为自然灾害预警、水资源管理及水利工程运行的关键技术,其重要性不言而喻。 一、水位雨量在线监测系统的基本原理 水位雨量在线监测系统主要由数据采集单元、数据传输网络、数据处理中心及用户终端四大部分构成,形成了一个完整的闭环系统。 数据采集单元:这是系统的“眼睛”,

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

使用opencv优化图片(画面变清晰)

文章目录 需求影响照片清晰度的因素 实现降噪测试代码 锐化空间锐化Unsharp Masking频率域锐化对比测试 对比度增强常用算法对比测试 需求 对图像进行优化,使其看起来更清晰,同时保持尺寸不变,通常涉及到图像处理技术如锐化、降噪、对比度增强等 影响照片清晰度的因素 影响照片清晰度的因素有很多,主要可以从以下几个方面来分析 1. 拍摄设备 相机传感器:相机传

csu 1446 Problem J Modified LCS (扩展欧几里得算法的简单应用)

这是一道扩展欧几里得算法的简单应用题,这题是在湖南多校训练赛中队友ac的一道题,在比赛之后请教了队友,然后自己把它a掉 这也是自己独自做扩展欧几里得算法的题目 题意:把题意转变下就变成了:求d1*x - d2*y = f2 - f1的解,很明显用exgcd来解 下面介绍一下exgcd的一些知识点:求ax + by = c的解 一、首先求ax + by = gcd(a,b)的解 这个

2024年流动式起重机司机证模拟考试题库及流动式起重机司机理论考试试题

题库来源:安全生产模拟考试一点通公众号小程序 2024年流动式起重机司机证模拟考试题库及流动式起重机司机理论考试试题是由安全生产模拟考试一点通提供,流动式起重机司机证模拟考试题库是根据流动式起重机司机最新版教材,流动式起重机司机大纲整理而成(含2024年流动式起重机司机证模拟考试题库及流动式起重机司机理论考试试题参考答案和部分工种参考解析),掌握本资料和学校方法,考试容易。流动式起重机司机考试技