图像的简单几何变换
先看一下关于图像几何变换的简介:
几何变换不改变图像的像素值,只是在图像平面上进行像素的重新安排。
适当的几何变换可以最大程度地消除由于成像角度、透视关系乃至镜头自身原因所造成的几何失真所产生的负面影响。有利于我们在后续的处理和识别工作中将注意力集中子图像内容本身,更确切地说是图像中的对象,而不是该对象的角度和位置等。几何变换常常作为图像处理应用的预处理步骤,是图像归一化的核心工作之一。
一个几何变换需要两部分运算:首先是空间变换所需的运算,如平移、缩放、旋转和正平行投影等,需要用它来表示输出图像与输入图像之间的(像素)映射关系;此外,还需要使用灰度差值算法,因为按照这种变换关系进行计算,输出图像的像素可能被映射到输入图像的非整数坐标上。
(一)图形的平移
对于图像的平移非常简单,在平移之前,我们需要先构造一个移动矩阵,所谓移动矩阵,就是让说明白在x轴方向上移动多少距离,在y轴上移动多少距离。
通过numpy来构造这个矩阵,并将其传给仿射函数cv2.warpAffine( )
仿射函数cv2.warpAffine( )接受三个参数,需要进行图像变换的原始图像矩阵,移动矩阵以及图像变换的大小(这里要说明一下,图像本身并不会放大或缩小,而是图像显示区域的大小)
img = cv2.imread('4.jpg')
# 构造移动矩阵H
# 在x轴方向移动多少距离,在y轴方向移动多少距离
H = np.float32([[1, 0, 50], [0, 1, 25]])
rows, cols = img.shape[:2]
print(img.shape)
print(rows, cols)
res = cv2.warpAffine(img, H, (cols, rows)) # 注意这里rows和cols需要反置,个人感觉这里是一个坑
cv2.imshow('origin_picture', img)
cv2.imshow('new_picture', res)
cv2.waitKey(0)
(二)图像的放大和缩小
图像的放大和缩小有一个专门的函数,就是cv2.resize( ),这其中就需要设置缩放的比例,一种办法是设置缩放因子,另一种办法是直接设置图像的大小,在缩放以后,图像必然会发生变化,这就涉及到图像的插值问题。
缩放有几种不同的插值(interpolation)方法,在缩小时推荐使用cv2.INTER_AREA,扩大时推荐使用cv2.INTER_CUBIC和cv2.INTER_LINEAR。
img = cv2.imread('4.jpg')
# 一是通过设置图像缩放比例,即缩放因子,来对图像进行放大或缩小
res1 = cv2.resize(img, None, fx=2, fy=2, interpolation=cv2.INTER_LINEAR)
height, width = img.shape[:2]
# 二是直接设置图像的大小,不需要缩放因子
res2 = cv2.resize(img, (int(0.8*width), int(0.8*height)), interpolation=cv2.INTER_AREA)
cv2.imshow('origin_picture', img)
cv2.imshow('res1', res1)
cv2.imshow('res2', res2)
cv2.waitKey(0)
关于插值算法有很多,我这里举一个例子。
最近邻插值算法:选择离它映射到的位置最近的输入像素的灰度值为插值结果。
通过图像长和宽的比例,将原有的图像映射到所需要的图像上。这里涉及到对图像矩阵元素的操作,对于其如何计算的可以看代码,也可以联系我,从数学的角度解释。
# need_height参数不得超过原来图像高的两倍,这是由临近插值算法本身的性质所决定的
# need_width参数则可以任意选取
def pic_interpolation(img, need_height, need_width):height, width, channels = img.shapeprint(height, width, channels)emptyImage = np.zeros((need_height, need_width, channels), np.uint8)sh = need_height/heightsw = need_width/widthfor i in range(need_height):for j in range(need_width):x = round(i/sh)y = math.floor(j/sw)emptyImage[i, j] = img[x, y]return emptyImageimg = cv2.imread("4.jpg")
zoom = pic_interpolation(img, 220, 180)
cv2.imshow("nearest neighbor", zoom)
cv2.imshow("image", img)
cv2.waitKey(0)
(三)图像的旋转
对于图像的旋转,我们需要构造旋转矩阵。一般的图像的旋转矩阵是在原点处进行变换的
为了能够在任意位置进行旋转变换,OpenCV采用了另一种方式
为了构造这个矩阵,OpenCV提供了一个函数:cv2.getRotationMarix2D( ),这个函数需要三个参数,旋转中心,旋转角度,旋转后图像的缩放比例:
img = cv2.imread('4.jpg')
rows, cols = img.shape[:2]
# 第一个参数是旋转中心,第二个参数是旋转角度,第三个参数是缩放比例
M1 = cv2.getRotationMatrix2D((cols/2, rows/2), 45, 0.5)
M2 = cv2.getRotationMatrix2D((cols/2, rows/2), 45, 2)
M3 = cv2.getRotationMatrix2D((cols/2, rows/2), 45, 1)
res1 = cv2.warpAffine(img, M1, (cols, rows))
res2 = cv2.warpAffine(img, M2, (cols, rows))
res3 = cv2.warpAffine(img, M3, (cols, rows))
cv2.imshow('res1', res1)
cv2.imshow('res2', res2)
cv2.imshow('res3', res3)
cv2.waitKey(0)
cv2.destroyAllWindows()
(四)图像的仿射
仿射变换是指在向量空间中进行一次线性变换(乘以一个矩阵)并加上一个平移(加上一个向量),变换为另一个向量空间的过程。
Affine Transform描述了一种二维仿射变换的功能,它是一种二维坐标之间的线性变换,保持二维图形的“平直性”(即变换后直线还是直线,圆弧还是圆弧)和“平行性”(其实是保持二维图形间的相对位置关系不变,平行线还是平行线,而直线上的点位置顺序不变,另特别注意向量间夹角可能会发生变化)。仿射变换可以通过一系列的原子变换的复合来实现包括:平移(Translation)、缩放(Scale)、翻转(Flip)、旋转(Rotation)和错切(Shear)。
仿射变化也是需要一个M矩阵就可以,但是由于仿射变换比较复杂,很难找到这个矩阵,opencv提供了根据变换前后三个点的对应关系来自动求解M, 这个函数是cv2.getAffineTransoform(pts1, pts2)
事实上,仿射变换代表的是两幅图之间的关系,我们通常使用2x3矩阵来表示仿射变换如下:
img = cv2.imread('4.jpg')
rows, cols = img.shape[:2]
pts1 = np.float32([[50, 50], [200, 50], [50, 200]])
pts2 = np.float32([[10, 100], [200, 50], [100, 250]])
# 类似于构造矩阵
M = cv2.getAffineTransform(pts1, pts2)
res = cv2.warpAffine(img, M, (cols, rows))
cv2.imshow('原图', img)
cv2.imshow('res', res)
cv2.waitKey(0)
cv2.destroyAllWindows()
(五)图像的透射
仿射变换(affine transform)与透视变换(perspective transform)在图像还原、图像局部变化处理方面有重要意义。通常,在2D平面中,仿射变换的应用较多,而在3D平面中,透视变换又有了自己的一席之地。两种变换原理相似,结果也类似,可针对不同的场合使用适当的变换。
基于3×3矩阵进行的变换,叫透视变换或者单应性映射。
仿射变换可以形象的表示成以下形式。一个平面内的任意平行四边形ABCD可以被仿射变换映射为另一个平行四边形A’B’C’D’。通俗的解释就是,可以将仿射变换想象成一幅图像画到一个胶版上,在胶版的角上推或拉,使其变形而得到不同类型的平行四边形。相比较仿射变换,透射变换更具有灵活性,一个透射变换可以将矩形转变成梯形。
img = cv2.imread('4.jpg')
rows, cols = img.shape[:2]
pts1 = np.float32([[56, 65], [238, 52], [28, 237], [239, 240]])
pts2 = np.float32([[0, 0], [200, 0], [0, 200], [200, 200]])
M = cv2.getPerspectiveTransform(pts1, pts2)
res = cv2.warpPerspective(img, M, (cols, rows))
cv2.imshow('yuantu', img)
cv2.imshow('res', res)
cv2.waitKey(0)
cv2.destroyAllWindows()