OpenCV:04图像的基本变换

图像的放大与缩小

关键API:resize(src, dsize[, dst[, fx[, fy[, interpolation]]]])
其中:

  • src:要缩放的图片
  • dsize:缩放之后的图片大小,用元组和列表表示均可,如果按照xy轴比例进行放缩,则要写出dsize = None
  • dst:可选参数,缩放之后的输出图片(一般用不上)
  • fx,fyx轴和y轴的缩放比,即宽度和高度的缩放比
  • interpolation:插值算法——> 例如当图片被放大时,我们怎么去填充空白区域,就用到了此算法,其中:

    • INTER_NEAREST:邻近插值,速度快,效果差
    • INTER_LINEAR:双线性插值,使用原图中的四个点进行插值**(默认方法)**
    • INTER_CUBIC:三次插值,使用原图中的16个点进行插值
    • INTER_AREA:区域插值,效果最好,计算时间最长

放缩到指定大小:

import cv2
import numpy as np

# 读取图片
dog = cv2.imread('./dog.jpeg')
cat = cv2.imread('./cat.jpeg')


# 读取图片大小
print("cat.shape:",cat.shape) # (480, 640, 3)   
print("dog.shape:",dog.shape) # (360, 499, 3)   # shape函数显示:(行(高度),列(宽度),通道数)

#把猫缩放成和狗一样大 ——> 注意opencv中的显示:先是宽度,再是高度,而我们正常显示shape时是先行(高度)后列(宽度)
new_cat = cv2.resize(cat,(499,360)) # 要反过来!

print("new_cat.shape:",new_cat.shape) # (360, 499, 3)

cv2.imshow('new_img',np.hstack((new_cat,dog))) # 如果能成功拼到一起,则修改成功!

cv2.waitKey()
cv2.destroyAllWindows()

结果:

cat.shape: (480, 640, 3)
dog.shape: (360, 499, 3)
new_cat.shape: (360, 499, 3)

在这里插入图片描述


根据xy轴的比例进行放缩:

import cv2
import numpy as np

# 读取图片
cat = cv2.imread('./cat.jpeg')


# 读取图片大小
print("cat.shape:",cat.shape) # (480, 640, 3)   
  # shape函数显示:(行(高度),列(宽度),通道数)

# 还可以按照x,y轴的比例进行缩放 ——> 此时要把参数dsize写成None
new_cat = cv2.resize(cat,dsize = None,fx = 0.5,fy = 0.5)

print("new_cat.shape:",new_cat.shape) # (360, 499, 3)

cv2.imshow('cat',cat) 
cv2.imshow('new_cat',new_cat) 

cv2.waitKey()
cv2.destroyAllWindows()

结果:

cat.shape: (480, 640, 3)
new_cat.shape: (240, 320, 3)

可以看到xy轴都缩小了一半
在这里插入图片描述


仿射变换

仿射变换是图像旋转、缩放、平移的总称。具体的做法是通过一个矩阵和原图片进行坐标运算,得到新的坐标,完成变换,所以仿射变换的关键就是这个矩阵

仿射变换不会改变每个像素点上的RGB色彩,只会改变像素对应的位置 ——> 我们只要找出其中对应的数学关系,就可以用一个矩阵一次性地把所有的点变过去

通过仿射变换,图像可以通过一系列的几何变换来实现平移、旋转等多种操作。该变换能够保持图像的平直性和平行性。平直性是指图像经过仿射变换后,直线仍然是直线;平行性是指图像在完成仿射变换后,平行线仍然是平行线。

关键API:cv2.warpAffine(src, M, dsize[, dst[, flags[, borderMode[, borderValue]]]])
其中:

  • M变换矩阵
  • dsize输出图片大小——> 最好和原图大小一致
  • flag:与resize()中的插值算法一致 (用默认值即可)
  • mode:边界外推法标志,即当图像超出边界时该怎么办 (此处用默认值即可)
  • value:填充边界值 (用默认值即可)

仿射变换之图像的平移

平移矩阵:
矩阵中的每个像素由(x,y)组成(x,y)表示这个像素的坐标,假设沿x轴平移tx,沿y轴平移ty,那么最后得到的坐标为(x^ , y^) = ( x + tx , y + ty ),用矩阵来表示就是:
在这里插入图片描述
补充(因为我忘了?):矩阵乘法 = 第一个矩阵的行 × 第二个矩阵的列 ——(1 × x + 0 × y + tx × 1 ) + (0 × x + 1 × y + ty × 1 ) + (0 × x + 0 × y + 1 × 1 )

tx = 沿x轴方向向右平移的距离(向左为负) ;ty = 沿y轴方向向下平移的距离(向上为负) ——原点在图片左上角

例:
将图片向右平移200个像素点,上下不平移

# 将图片向右平移200个像素点

import cv2
import numpy as np

cat = cv2.imread('./cat.jpeg')

# 打印图像cat的高度、宽度,便于设置参数dsize
h,w,ch = cat.shape # 注意!shape()输出是先高度(行),后宽度(列)

# 变换矩阵 ——> 要求矩阵类型最小是float32位
M = np.float32([ [1,0,200],[0,1,0] ])


# 平移操作
new_cat = cv2.warpAffine(cat,M,dsize = (w,h)) # dsize为输出图片的大小,注意!opencv是先宽度(列),后高度(行),要反过来

cv2.imshow('new_cat',new_cat) 
cv2.imshow('cat',cat) 

cv2.waitKey()
cv2.destroyAllWindows()

结果:
在这里插入图片描述


仿射变换之获取变换矩阵M

方法一:利用旋转角度获取变换矩阵

仿射变换的难点就是计算变换矩阵,OpenCV提供了计算变换矩阵的API

关键API:cv2.getRotationMatrix2D(center, angle, scale)

# 在进行图像的旋转操作时,手动计算变换矩阵不太方便,而opencv提供了获取旋转变换矩阵的API
import cv2
import numpy as np

dog = cv2.imread('./cat.jpeg')

# 打印图像cat的高度、宽度,便于设置参数dsize
h,w,ch = dog.shape # 注意!shape()输出是先高度(行),后宽度(列)

# 获取变换矩阵 变换矩阵一定是2D的(二维)
m = cv2.getRotationMatrix2D((100,100),15,1) #以 (100,100)为原点(左上角为(0,0));逆时针旋转15°;scale = 1表示不缩放

new_dog = cv2.warpAffine(dog,m,(w,h))

cv2.imshow('new_dog',new_dog) 
cv2.imshow('dog',dog) 

cv2.waitKey()
cv2.destroyAllWindows()

结果:
在这里插入图片描述


方法二:利用变换前后对应点的关系获取变换矩阵

关键API:getAffineTransform(src, dst)
其中:

  • src:原目标的三个点src = np.float32([ [x1 , y1] , [x2 , y2] , [x3 , y3] ])
  • dst:对应变换后的三个点dst = np.float32([ [x^1 , y^1] , [x^2 , y^2] , [x^3 , y^3] ])

通过三点可以确定变换后的位置,相当于解方程,3个点对应3个方程,能解出偏移的参数和旋转的角度

也就是说我们可以不通过角度,而是通过将原目标的三个点src和对应变换后的三个点dst一一对应,建立三元一次方程(旋转偏移的参数和旋转角度的方程)

左边为旋转前的图,右边为旋转后的图,绿色点分别为srcdst
在这里插入图片描述

例子:

# 通过三个点来确定变换矩阵

import cv2
import numpy as np

cat = cv2.imread('./cat.jpeg')

# 打印图像cat的高度、宽度,便于设置参数dsize
h,w,ch = cat.shape # 注意!shape()输出是先高度(行),后宽度(列)

# 获取变换矩阵:需要原始图片的三个点坐标 "src",和变换之后对应的三个点的坐标 "dst"
src = np.float32([ [200,100] , [300,100] , [200,300]])
dst = np.float32([ [100,150] , [360,200] , [280,120]])
m = cv2.getAffineTransform(src,dst)

new_cat = cv2.warpAffine(cat,m,(w,h))

cv2.imshow('new_cat',new_cat) 
cv2.imshow('cat',cat) 

cv2.waitKey()
cv2.destroyAllWindows()

结果:
在这里插入图片描述
(变换得雀食抽象,我也没去仔细算,会用就行?)


透视变换

透视变换就是将一种坐标系变成另一种坐标系,简单地来说就是可以把一张 “斜” 的图变 “正”——> 就像我们在二维平面(纸)上画出三维物体(正方形的3D结构)那样 类似于斜二侧画法

在这里插入图片描述

图5.24所示:从图像的底部去观察图,图像底部距离眼睛较近,所以宽度不变,但图像顶部距离眼睛较远,宽度就会等比缩小,于是观察者就会得到如图5.26的透视效果

OpenCV中需要通过定位图像的四个点来进行计算透视效果,四个点的位置如图,OpenCV根据四个点的位置变化来计算出其他像素的位置变化透视效果不能保证图像的“平直性”和“平行性”

在这里插入图片描述

在这里插入图片描述
关键API: 获取变换矩阵cv2.getPerspectiveTransform(src, dst),需要四个点,即图片的四个角
其中:

  • src:变换前图片的四个点**(随意选取)**,但一般我们会选择原图片的四个顶点
  • dst:变换后图片的四个点,和src一样,我们一般选择新图片的四个顶点

关键API: 透视变换cv2.warpPerspective(src, M, dsize[, dst[, flags[, borderMode[, borderValue]]]])
其中:

  • src:原图
  • M变换矩阵,对于透视矩阵来说,M是一个3*3的矩阵
  • dsize输出图片大小——> 最好和原图大小一致
  • flag:与resize()中的插值算法一致 (用默认值即可)
  • mode:边界外推法标志,即当图像超出边界时该怎么办 (此处用默认值即可)
  • value:填充边界值 (用默认值即可)
# 仿射变换——> 对坐标系的变换,通过原先图片的四个点和变换后图片的四个点构造方程组


# 在此例,我们相当于用仿射变换把书中这一页抠出来并且摆正

import cv2
import numpy as np

# 我们图片大小为宽1276×高1702
book = cv2.imread('./book.jpg')

# 打印图像cat的高度、宽度,便于设置图像中的四个点和设置参数dsize
h,w,ch = book.shape # 注意!shape()输出是先高度(行),后宽度(列)


# 获取变换矩阵 ——> 顺序:左上,左下,右上,右下
# src = np.float32([[200,200],[1700,100],[200,1000],[1700,1200]])
# dst = np.float32([[0,0],[1700,0],[0,1100],[1700,1100]])   # 格式为[h,w],在图像中横轴是w,纵轴是h

# 获取变换矩阵 ——> 顺序:左上,,右上,左下,右下
src = np.float32([[200,200],[50,1000],[800,0],[700,1100]])
dst = np.float32([[0,0],[0,1100],[900,0],[900,1100]])
m = cv2.getPerspectiveTransform(src,dst)


# 透视变换
new_book = cv2.warpPerspective(book,m,(900,1100))

# 由于我们的图太大了,需要再设置窗口大小
cv2.namedWindow('new_book',cv2.WINDOW_NORMAL)
cv2.resizeWindow('new_book',640,480)
cv2.imshow('new_book',new_book)

cv2.namedWindow('book',cv2.WINDOW_NORMAL)
cv2.resizeWindow('book',640,480)
cv2.imshow('book',book) 

cv2.waitKey()
cv2.destroyAllWindows()

效果不太好?先记录下来吧
在这里插入图片描述

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码

)">
< <上一篇
下一篇>>