????????图像几何变换是计算机视觉和图像处理领域中的重要技术。它通过对图像进行平移、旋转、缩放、翻转等操作,改变图像的大小、位置或方向,以实现对图像的变换和处理。
????????图像几何变换在很多应用中都有广泛的应用,例如:
????????图像几何变换的实现通常基于线性代数和几何学的原理。在实际应用中,可以使用各种图像处理库和工具,如OpenCV、numpy和scikit-image等,来实现图像几何变换操作。这些工具提供了丰富的函数和算法,使得图像几何变换变得简单和高效。
????????OpenCV提供了两个转换函数,cv.warpAffine和cv.warpPerspective,可以用它们实现各种类型的变换。cv2.warpAffine() 采用 2x3 变换矩阵作为输入;cv2.warpPerspective ()采用 3x3 变换矩阵作为输入。
cv2.warpAffine()函数是用于执行图像几何变换的函数之一,返回值为输出图像,语法如下:
cv2.warpAffine(src, M, dsize[, dst[, flags[, borderMode[, borderValue]]]])
参数说明:
cv2.warpPerspective()
?是 OpenCV 中用于执行透视变换的函数之一,函数的返回值为输出图像。它可以根据用户指定的变换矩阵对图像进行透视变换。函数的语法如下:
cv2.warpPerspective(src, M, dsize[, dst[, flags[, borderMode[, borderValue]]]])
参数说明:
????????扩展缩放只是改变图像的尺寸大小。OpenCV 提供的函数cv2.resize()可以实现这个功能。图像的尺寸可以自己手动设置,也可以指定缩放因子。我们可以选择使用不同的插值方法。在缩放时推荐用cv2.INTER_AREA,扩展时推荐使用cv2.INTER_CUBIC(慢))和v2.INTER_LINEAR。默认情况下所有改变图像尺寸大小的操作使用的插值方法都是cv2.INTER_LINEAR。你可以使用下任意一种方法改变图像的尺寸。
cv2.resize()函数的返回值为输出图像,语法如下:
cv2.resize(src, dsize[, dst[, fx[, fy[, interpolation]]]])
参数说明:
import cv2
import numpy as np
img=cv2.imread('messi5.jpg')
# 下面的None 本应是输出图像的尺寸,但是因为后面我们设置了缩放因子
# 因此这里为None
res=cv2.resize(img,None,fx=2,fy=2,interpolation=cv2.INTER_CUBIC)
#OR
# 这里呢我们直接设置输出图像的尺寸,所以不用设置缩放因子
height,width=img.shape[:2]
res=cv2.resize(img,(2*width,2*height),interpolation=cv2.INTER_CUBIC)
while(1):
cv2.imshow('res',res)
cv2.imshow('img',img)
if cv2.waitKey(1) & 0xFF == 27:
break
cv2.destroyAllWindows()
常见的插值算法:
INTER_NEAREST 最近邻插值
INTER_LINEAR 双线性插值
INTER_CUBIC 双三次插值
INTER_AREA 使用像素面积关系进行重采样。它可能是图像抽取的首选方法,因为它可以提供无摩尔纹的结果。但是当图像缩放时,它类似于INTER_NEAREST方法。.
INTER_LANCZOS4 8x8邻域上的兰索斯插值
INTER_LINEAR_EXACT 位精确双线性插值
INTER_NEAREST_EXACT 位精确最近邻插值。这将产生与PIL,scikit-image或Matlab中的最近邻方法相同的结果.
INTER_MAX 插值码的掩码
????????平移是对象位置的移动。如果您知道 (x,y) 方向的偏移量(tx,ty),可以创建转换矩阵M如下:
需要使用numpy数组构建这个矩阵,把它变成一个数据类型为 np.float32 的 Numpy 数组,并传递给 cv.warpAffine()函数。?M = np.float32([[1,0,tx],[0,1,ty]]),看看下面这个例子吧,它被移动了
(100,50)个像素。
?
import numpy as np
import cv2
img = cv2.imread('../Resources/msser.jpg')
rows,cols,_ = img.shape
M = np.float32([[1,0,100],[0,1,50]])
# dst(x,y)=src(1x+0y+100, 0x+1y+50)=src(x+100,y+50)
dst = cv2.warpAffine(img,M,(cols,rows))
cv.imshow('img',dst)
cv.waitKey(0)
cv.destroyAllWindows()
如果更改转换矩阵M,还可以实现各种变换操作当 M = np.float32([[-1,0,cols],[0,-1,rows]])
可以实现图像XY方向的翻转。
警告:函数cv2.warpAffine() 的第三个参数的是输出图像的大小,它的格式应该是图像的宽、高。应记住的是图像的宽对应的是列数高对应的是行数。
对一个图像旋转角度θ,需要使用下面的旋转矩阵:
M = np.float32([[cos θ, -sin θ],[sin θ, cos θ]]),但OpenCV允许在任意地方进行旋转,所以旋转矩阵应该为
即,M = np.float32([[α, β, (1-α).center_x - β.center_y],[-β, α, β.center_x + (1-α).center_y]])
其中α = scale · cos θ, ? β = scale · sin θ,为更方便地构建旋转矩阵,OpenCV提供了一个旋转矩阵构建函数cv2.getRotationMatrix2D。下面的例子是在不缩放的情况下将图像旋转?90 度。
import cv2
import numpy as np
img=cv2.imread('messi5.jpg',0)
rows,cols=img.shape
# 第一个参数为旋中心,第二个为旋转角度,第三个为旋转后的缩放因子
# 可以通过设置旋转中心、缩放因子以及窗口大小来防止旋转后超出边界的问题
M=cv2.getRotationMatrix2D((cols/2,rows/2),45,0.6)
# 第三个参数是输出图像的尺寸中心
dst=cv2.warpAffine(img,M,(2*cols,2*rows))
while(1):
cv2.imshow('img',dst)
if cv2.waitKey(1)&0xFF==27:
break
cv2.destroyAllWindows()
?
????????在仿射变换中,原图中所有平行线在结果图像中同样平行。为创建这个矩阵,需要从原图像中找到三个点以及他们在输出图像中的位置,然后cv2.getAffineTransForm()会创建一个2X3的矩阵。最后这个矩阵会被传给函数cv2.warpAffine()。来看看下面的例子以及我选择的点,标记为绿色的点。
import cv2
import numpy as np
from matplotlib import pyplot as plt
img=cv2.imread('drawing.png')
rows,cols,ch=img.shape
pts1=np.float32([[50,50],[200,50],[50,200]])
pts2=np.float32([[10,100],[200,50],[100,250]])
M=cv2.getAffineTransform(pts1,pts2)
dst=cv2.warpAffine(img,M,(cols,rows))
plt.subplot(121,plt.imshow(img),plt.title('Input'))
plt.subplot(121,plt.imshow(img),plt.title('Output'))
plt.show()
?
????????对于透视变换,我们需要一个3x3转换矩阵。在变换前后直线还是直线。要构建这个变换矩阵,需要在原图上找到4个点,以及他们在输出图上对应的位置,这四个点中任意三个都不能共线,这个变换矩阵可以通过函数cv2.getPerspectiveTransform()构建,然后这个矩阵传给函数v2.warpPerspective()。
import cv2
import numpy as np
from matplotlib import pyplot as plt
img=cv2.imread('sudokusmall.png')
rows,cols,ch=img.shape
pts1 = np.float32([[56,65],[368,52],[28,387],[389,390]])
pts2 = np.float32([[0,0],[300,0],[0,300],[300,300]])
M=cv2.getPerspectiveTransform(pts1,pts2)
dst=cv2.warpPerspective(img,M,(300,300))
plt.subplot(121,plt.imshow(img),plt.title('Input'))
plt.subplot(121,plt.imshow(img),plt.title('Output'))
plt.show()