【OpenCv】图像的相关变换

图像平移

图像平移的本质是一个线性变换。如果图像在y轴平移 d y d_y dy 个单位,在x轴平移 d x d_x dx 个单位,则有
[ x y 1 ] = [ 1 0 d x 0 1 d y 0 0 1 ] [ x 0 y 0 1 ] \begin{bmatrix}x \\y\\1\end{bmatrix} = \begin{bmatrix} 1 &0 & d_x \\ 0 & 1 & d_y \\ 0 & 0 & 1 \end{bmatrix} \begin{bmatrix} x_0 \\ y_0 \\ 1 \end{bmatrix} xy1 = 100010dxdy1 x0y01
即平移后点的坐标为:
x = x 0 + d x , y = y 0 + d y x=x_0+d_x ,y=y_0+d_y x=x0+dxy=y0+dy
如果 d x d_x dx小于0则表示向左平移, d y d_y dy大于0则表示向上平移。构建完平移矩阵后由放射变换函数cv2.warpAffine 计算变换后的平移图像。

 cv2.warpAffine(src, M, dsize,flags,borderMode, borderValue)

参数说明
src:输入图像
M:仿射变换矩阵(2行3列)
dsize:输出图像的大小 (width, height)
flags:插值方法的组合,默认线性插值cv2.INTER_LINEAR 还有

  • cv2.INTER_NEAREST(最近邻插值)
    cv2.INTER_AREA (区域插值)
    cv2.INTER_CUBIC(三次样条插值)
    cv2.INTER_LANCZOS4(Lanczos插值)

borderMode:边界像素模式
borderValue:边界填充值; 默认情况下为黑色填充

import cv2
import numpy as np
img = cv2.imread('rose.png')
H = np.float32([[1, 0, 50], [0, 1, 20]]) #变换矩阵:设置平移变换所需的计算矩阵:2行3列
#[[1,0,50],[0,1,20]]   表示平移变换:其中50表示水平方向上的平移距离,20表示竖直方向上的平移距离。

rows, cols = img.shape[:2]
res = cv2.warpAffine(img, H, (cols, rows),borderValue=(255,255,255))  
cv2.imshow('origin_picture', img)
cv2.imshow('translation', res)
cv2.waitKey(0)
cv2.destroyAllWindows()

在这里插入图片描述

图像缩放

图像缩放是指图像大小按照指定的比例或者按照指定的缩放图像大小进行放大或者缩小。

cv2.resize(src,dsize=None,fx,fy,interpolation)
  • 参数说明:
    src:原图像
    dsize: 缩放后的图像大小,比例因子二选一
    fx,fy:x 和 y 方向上的缩放比例
    interpolation:插值方法

常见的插值方法
• 默认为 flags=cv2.INTER_NEAREST(最近邻插值)
• cv2.INTER_LINEAR,双线性插值
• cv2.INTER_CUBIC 三次样条插值 4x4像素邻域
• cv2.INTER_LANCZOS4 Lanczos插值,8x8像素邻域
• cv2.INTER_AREA 区域插值
官网中说要缩小图片,通常最好的插值方法是 cv.INTER_AREA;要放大一张图片,通常最好的是 cv.INTER_CUBIC (速度慢)或者 cv.INTER_LINEAR (速度快一些但结果仍然不错)。
接下来简单的介绍最近邻插值和双线性插值。

最近邻插值

最近邻插值法nearest_neighbor是最简单的灰度值插值。也称作零阶插值,就是令变换后像素的灰度值等于距它最近的输入像素的灰度值。
其中 x x x y y y表示输出图像像素的坐标, x 0 x_0 x0, y 0 y_0 y0表示输入图像像素的坐标

  如下图所示,将一幅3X3的图像放大到4X4,用 d ( x , y ) d(x, y) d(x,y)表示目标图像, s ( x , y ) s(x, y) s(x,y)表示原图像,我们有如下公式:

d ( d s t X , d s t Y ) = s ( d s t X s r c W i d t h d s t W i d t h , d s t Y s r c H e i g h t d s t H e i g h t ) \begin{array}{c} d(dst_{X}, dst_{Y}) = s(\frac{dst_{X}src_{Width}} {dst_{Width}}, \frac{dst_{Y}src_{Height}} {dst_{Height}}) \end{array} d(dstX,dstY)=s(dstWidthdstXsrcWidth,dstHeightdstYsrcHeight)
其中 s r c W i d t h d s t W i d t h \frac{src_{Width}} {dst_{Width}} dstWidthsrcWidth表示缩放前后x轴的比例, s r c H e i g h t d s t H e i g h t \frac{src_{Height}} {dst_{Height}} dstHeightsrcHeight表示缩放前后y轴的比例

d ( 0 , 0 ) = s ( 0 ∗ 0.75 , 0 ∗ 0.75 ) = s ( 0 , 0 ) = 56 d ( 0 , 1 ) = s ( 0 ∗ 0.75 , 1 ∗ 0.75 ) = s ( 0 , 0.75 ) = s ( 0 , 1 ) = 65 d ( 0 , 2 ) = s ( 0 ∗ 0.75 , 2 ∗ 0.75 ) = s ( 0 , 1.50 ) = s ( 0 , 2 ) = 12 d ( 0 , 3 ) = s ( 0 ∗ 0.75 , 3 ∗ 0.75 ) = s ( 0 , 2.25 ) = s ( 0 , 2 ) = 12 . . . \begin{array}{c} d(0,0)=s(0*0.75,0*0.75)=s(0,0)=56 \\ d(0,1)=s(0*0.75,1*0.75)=s(0,0.75)=s(0,1)=65 \\ d(0,2)=s(0*0.75,2*0.75)=s(0,1.50)=s(0,2)=12\\ d(0,3)=s(0*0.75,3*0.75)=s(0,2.25)=s(0,2)=12 \\ ...\\ \end{array} d(0,0)=s(00.75,00.75)=s(0,0)=56d(0,1)=s(00.75,10.75)=s(0,0.75)=s(0,1)=65d(0,2)=s(00.75,20.75)=s(0,1.50)=s(0,2)=12d(0,3)=s(00.75,30.75)=s(0,2.25)=s(0,2)=12...

需要注意的是直角坐标以左上角为坐标原点,并且像素位置没有小数点,因此要四舍五入。因此最近邻插值会出现色块现像。

双线性插值

双线性插值实际上是从2个方向一共进行了3次单线性插值
我们先了解一下单线性插值,请看下图:
在这里插入图片描述
两点确定一条直线有:
( y − y 0 ) / ( x − x 0 ) = ( y 1 − y 0 ) / ( x 1 − x 0 ) (y-y_0)/(x-x_0)=(y_1-y_0)/(x_1-x_0) (yy0)/(xx0)=(y1y0)/(x1x0)
整理得
在这里插入图片描述
如果把y看成灰度值则上面可以写成:
在这里插入图片描述
其实右边f前面两个式子可以看成权重,当P点靠近哪一点那么那个权重就占比大,接下来看下图根据上面公式求p点坐标

1.在x方向进行单线性插值有:
在这里插入图片描述
2.在y方向进行单线性插值有:
在这里插入图片描述

import cv2
import numpy as np

img = cv2.imread('girl.png')
# 方法一:通过设置缩放比例
res1 = cv2.resize(img, None, fx=3, fy=3, 
                  interpolation=cv2.INTER_CUBIC)
height, width = img.shape[:2]
# 方法二:直接设置图像的大小
#cv2.INTER_NEAREST(最近邻插值) cv2.INTER_AREA (区域插值) cv2.INTER_CUBIC(三次样条插值) cv2.INTER_LANCZOS4(Lanczos插值)
res2 = cv2.resize(img, (int(0.6*width), int(0.6*height)),interpolation=cv2.INTER_LANCZOS4)

cv2.imshow('origin', img)
cv2.imshow('res2', res2)#可以输入res1对比
cv2.waitKey(0)
cv2.destroyAllWindows()

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

图像旋转

图像旋转是以图像中心作为原点旋转一定得角度,需要注意的圆心坐标的变换。
设点 P 0 ( x 0 , y 0 ) P_{0}(x_{0},y_{0}) P0(x0,y0) 逆时针旋转 θ \theta θ 角后的对应点为 P ( x , y ) P(x,y) P(x,y),根据极坐标公式旋转后坐标为:
在这里插入图片描述
对应的矩阵如下:
[ x y 1 ] = [ c o s θ − s i n θ 0 s i n θ c o s θ 0 0 0 1 ] [ x 0 y 0 1 ] \begin{bmatrix}x \\y\\1\end{bmatrix} =\begin{bmatrix} cos\theta &-sin\theta & 0 \\ sin\theta & cos\theta & 0 \\ 0 & 0 & 1 \end{bmatrix} \begin{bmatrix} x_0 \\ y_0 \\ 1 \end{bmatrix} xy1 = cosθsinθ0sinθcosθ0001 x0y01

cv2.getRotationMatrix2D(center, angle, scale)

参数说明:
center:图片的旋转中心
angle:旋转角度
scale:缩放比例,正逆时针,负为顺时针

import cv2
img=cv2.imread('girl.png')
rows,cols=img.shape[:2]
M=cv2.getRotationMatrix2D((cols/2,rows/2),45,1)#旋转矩阵
dst=cv2.warpAffine(img,M,(cols,rows),borderValue=(0,255,255))

cv2.imshow('img', img)
cv2.imshow('img1',dst)
cv2.waitKey(0)
cv2.destroyAllWindows()

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

放射变换

放射变换是旋转、平移、伸缩等一系列的操作。原来的直线仿射变换后还是直线,直线比例保持不变,原来的平行线经过仿射变换之后还是平行线。

在几何上,一个向量空间进行一次线性变换并接上一个平移,变换为另一个向量空间。通常图像的旋转加上拉升就是图像仿射变换,仿射变换需要一个M矩阵实现,但是由于仿射变换比较复杂,很难找到这个M矩阵。
OpenCV提供了根据变换前后三个点的对应关系来自动求解M的函数

M = cv2.getAffineTransform(pos1,pos2)

参数说明:
pos1 :表示变换前的位置
pos2 :表示变换后的位置

import cv2
import numpy as np

img = cv2.imread('girl.png')
rows, cols = img.shape[:2]
#设置图像仿射变换矩阵
pos1 = np.float32([[50,50], [200,50], [50,200]])
pos2 = np.float32([[10,100], [200,50], [100,250]])
M = cv2.getAffineTransform(pos1, pos2)

#图像仿射变换
result = cv2.warpAffine(img, M, (2*cols, 2*rows))
#显示图像
cv2.imshow("original", img)
cv2.imshow("result", result)
#等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()

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

透视变换

透视变换是将图像从一个视平面投影到另外一个视平面的过程,透视变换的变换矩阵是一个3x3的矩阵。透视变换的作用域是一个三维坐标系, 而仿射变换则是二维平面变换。仿射变换也可以看做是一种z轴方向不变的透视变换。

M = cv2.getPerspectiveTransform(pos1, pos2)

参数说明:
pos1 :表示透视变换前的4个点对应位置
pos2 :表示透视变换后的4个点对应位置
得到透视变换矩阵后可以使用下面函数进行透视变换

cv2.warpPerspective(src,M,(cols,rows))
import cv2
import numpy as np
import matplotlib.pyplot as plt
#读取图片
src = cv2.imread('girl.png')
#获取图像大小
rows, cols = src.shape[:2]
#设置图像透视变换矩阵
pos1 = np.float32([[114, 82], [287, 156],
                   [8, 100], [143, 177]])
pos2 = np.float32([[0, 0], [188, 0], 
                   [0, 262], [188, 262]])
M = cv2.getPerspectiveTransform(pos1, pos2)
#图像透视变换
result = cv2.warpPerspective(src, M, (2*cols,2*rows))
#显示图像
cv2.imshow("original", src)
cv2.imshow("result", result)
#等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小白哒哒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值