OpenCV实现图像变换(python)
一般对图像的变化操作有放大、缩小、旋转等,统称为几何变换,对一个图像的图像变换主要有两大步骤,一是实现空间坐标的转换,就是使图像从初始位置到终止位置的移动。二是使用一个插值的算法完成输出图像的每个像素的灰度值。其中主要的图像变换有:仿射变换、投影变换、极坐标变换。
仿射变换##
二维空间坐标的仿射变换公式:
\begin{matrix}
\overline{x} \\
\overline{y}
\end{matrix}
\right) =\left(
\begin{matrix}
a_{11} &&a_{12} \\
a_{21}&&a_{22}
\end{matrix}
\right) \left(
\begin{matrix}
x \\
y
\end{matrix}
\right) + \left(
\begin{matrix}
a_{13} \\
a_{23}
\end{matrix}
\right)
\]
在以下矩阵中:
\begin{matrix}
\overline{x} \\
\overline{y} \\
1
\end{matrix}
\right) =A \left(
\begin{matrix}
x \\
y \\
1
\end{matrix}
\right)
\]
矩阵A就是仿射矩阵,因为它最后一行为(0,0,1)
\left(
\begin{matrix}
a_{11}&a_{12}&a_{13} \\
a_{21}&a_{22}&a_{23} \\
0&0&1
1
\end{matrix}
\right)
\]
平移
平移是最简单的仿射变换如将空间坐标(x,y)沿着x轴移动100,沿着y轴移动200。平移后的坐标为(x+100,y+200)。将这个过程一般化后,假设任意的空间坐标(x,y)先沿着x轴平移Px再沿着y轴平移Py。得到的坐标为(x+Px,y+Py)。用矩阵表示这个平移过程为:
\begin{matrix}
\overline{x} \\
\overline{y} \\
1
\end{matrix}
\right) =\left(
\begin{matrix}
1 &0&Px \\
0&1&Py \\
0&0&1
\end{matrix}
\right) \left(
\begin{matrix}
x \\
y \\
1
\end{matrix}
\right)
\]
对于Px和Py若大于0则表示沿着轴正向移动,若小于0则表示沿着轴负向移动。
放大缩小
在坐标轴中以原点为中心的放大与缩小S倍是指对其x轴方向的横坐标放缩成原坐标的横坐标距离中心点(0,0)的距离的S倍并对其y轴方向的横坐标放缩成原坐标的纵坐标距离原点的距离的S倍。其中若S大于1则表示增大,若小于1则表示缩小。放缩在矩阵中的表示为:
\begin{matrix}
\overline{x} \\
\overline{y} \\
1
\end{matrix}
\right) =\left(
\begin{matrix}
s_x&0&0 \\
0&s_y&0 \\
0&0&1
\end{matrix}
\right) \left(
\begin{matrix}
x \\
y \\
1
\end{matrix}
\right)
\]
坐标(x,y)在坐标轴中以任意一点的坐标(x0,y0)为中心在水平和垂直方向上放缩S倍,放缩后的坐标为$$ ( (x_0+S_x(x-x_0),y_0+S_y(y-y_0) )$$用矩阵可以表示为:
\begin{matrix}
\overline{x} \\
\overline{y} \\
1
\end{matrix}
\right) =\left(
\begin{matrix}
1 &0&X_0 \\
0&1&Y_0 \\
0&0&1
\end{matrix}
\right) \left(
\begin{matrix}
s_x&0&0 \\
0&s_y&0 \\
0&0&1
\end{matrix}
\right) \left(
\begin{matrix}
1 &0&-X_0 \\
0&1&-Y_0 \\
0&0&1
\end{matrix}
\right) \left(
\begin{matrix}
x \\
y \\
1
\end{matrix}
\right)
\]
坐标(x,y)绕原点顺时针旋转α(α>0),cosΘ=x/p sinΘ=y/p.其中p代表(x,y)到中心点(0,0)的距离。则
cos(Θ+α)=cosΘcosα-sinΘsinα=(x/p)cosα -(y/p)sinα=Ex/p
sin(Θ+α)=sinΘcosα+cosΘsinα=(y/p)cosα -(y/p)sinα=Ey/p
化解以上公式,使用矩阵表示为:
\begin{matrix}
\overline{x} \\
\overline{y} \\
1
\end{matrix}
\right) =\left(
\begin{matrix}
cosα&-sinα&0 \\
sinα&cosα&0 \\
0&0&1
\end{matrix}
\right) \left(
\begin{matrix}
x \\
y \\
1
\end{matrix}
\right)
\]
放射矩阵的计算
如果已知坐标以及其放射变换后的矩阵,从而计算出变换后的坐标,就需要放射矩阵的计算,主要的实现方法有:方程法,矩阵法,插值算法。在OpenCV中有对应的实现函数,如使用方程法:cv2.getAffineTransform(src,dst) 该方法就是通过计算参数src到dst的对应仿射变换的矩阵,其中参数src和dst分别代表原坐标和变换后的坐标,并且均为3行2列的二维ndarray,数据必须为浮点型。实现代码:
import numpy as np
src=np.array([[0,0],[200,0],[0,200]],np.float32)
dst=np.array([[0,0],[100,0],[0,100]],np.float32)
A=cv2.getAffineTransform(src,dst)
print(A)
运行结果:
在矩阵法中,需要预先知道具体的变化步骤,比如先放大再平移还是先移动再放大
\begin{matrix}
\overline{x} \\
\overline{y} \\
1
\end{matrix}
\right) =\left(
\begin{matrix}
1 &0&X_0 \\
0&1&Y_0 \\
0&0&1
\end{matrix}
\right) \left(
\begin{matrix}
s_x&0&0 \\
0&s_y&0 \\
0&0&1
\end{matrix}
\right) \left(
\begin{matrix}
x \\
y \\
1
\end{matrix}
\right)
\]
以上的矩阵变换就是平移仿射矩阵乘以缩放仿射矩阵得到的而不是缩放仿射矩阵乘以平移仿射矩阵得到的,由于等式是由右向左运行,所以必须要知道变化顺序。矩阵的乘法并不是矩阵的点乘,再Numpy中乘法是通过dot函数实现的,关于Numpy语法可以参考我之前写的博文。我们通过一个实例来了解矩阵的乘法计算。
假设先对一矩阵等比例放大二倍,然后水平与垂直方向上分别平移100,计算该矩阵的算法如下:
import numpy as np
#先对矩阵进行放大
s=np.array([[2,0,0],[0,2,0],[0,0,1]])
#再对矩阵进行平移
t=np.array([[1,0,100],[0,1,100],[0,0,1]])
#矩阵相乘
A=np.dot(t,s)
print(A)
运行结果:
一定要注意传入dot参数的顺序。
下面介绍插值算法,我们可以将图像理解为一个二维的函数,行数为H,列数为W的图像矩阵I:Z=F(x,y), 0<=x<W,0<=y<H,x⊆N,y⊆N
矩阵的列号对应x坐标,垂直方向为y轴,行号对应y坐标,称该函数为图像函数。
利用已知的整数坐标处的函数值估算非整数坐标处的函数值的方法主要有:最近邻插值(就是从四个相邻整数坐标中找到一个最近的)输出的图像经过放大后会有锯齿状的外观。双线性插值法有两个变量的插值函数的线性插值扩展,其核心是在两个方向分别进行一次线性插值。待插点像素值取原图像中与其相邻的4个点像素值的水平、垂直两个方向上的线性内插,即根据待采样点与周围4个邻点的距离确定相应的权重,从而计算出待采样点的像素值。有的时候需要更高阶的插值函数,如三次样条插值、Lengendre中心函数和sin(axs)函数,高阶插值常用二维离散卷积运算来实现。后续博客会对二维离散卷积运算做详细的描述。
对于双线性插值法在这表一次形象化的描述:
如图:先估计f1在(x,[y])处的函数值,再估计f1在(x,[y]+1)处的函数值,最后估计f1在(x,y)处的函数值
对于空间坐标变换和插值方法在已知的仿射变换矩阵上OpenV提供了warpAffine(src,M,dsize[,flags[,borderMode[,borderValue ]]])函数
参数 | 释义 |
---|---|
src | 图像矩阵 |
M | 2行3列的仿射变换矩阵 |
dsize | 一个二元元组,输出图像的大小 |
flags | 插值法:INTE_NEAREST、INTE_LINEAR(默认)等 |
borderMode | 填充模式,如:BORDER_CONSTANT等 |
borderValue | 当borderMode=BORDER_CONSTANT时的填充值 |
下面使用python实现图像的几何变换:
import numpy as np
import cv2
import sys
import math
img=cv2.imread('yun.jpg',cv2.IMREAD_GRAYSCALE)
cv2.imwrite('yun.jpg',img)
#原图的宽高
h,w=img.shape[:2]
#仿射变换矩阵 缩小2倍
A1=np.array([[0.5,0,0],[0,0.5,0]],np.float32)
A2=cv2.warpAffine(img,A1,(w,h),borderValue=126)
#缩小后平移
B1=np.array([[0.5,0,w/4],[0,0.5,h/4]],np.float32)
B2=cv2.warpAffine(img,B1,(w,h),borderValue=126)
#使图像旋转
C1=cv2.getRotationMatrix2D((w/2.0,h/2.0),30,1)
C2=cv2.warpAffine(img,C1,(w,h),borderValue=126)
cv2.imshow('img',img)
cv2.imshow('A2',A2)
cv2.imshow('B2',B2)
cv2.imshow('C2',C2)
cv2.waitKey(0)
cv2.destroyAllWindows()
运行效果
参考文献:
[1]ROBERT G.KEYS.Cubic Convolution Interpolation for Digital Image Processing.IEEE TRANSACTIONS ON ACOUSTICS.SPEECH,AND SIGNAL PROCESSING,1981
[1]R. Hartley and A. Zisserman, “Multiple View Geometry in Computer Vision,” 2-nd edition, Cambridge University Press, 2004.
今天就先写到这吧!投影变换和极坐标变换后续再写
OpenCV实现图像变换(python)的更多相关文章
- python+opencv中最近出现的一些变化( OpenCV 官方的 Python tutorial目前好像还没有改过来?) 记一次全景图像的拼接
最近在学习过程中发现opencv有了很多变动, OpenCV 官方的 Python tutorial目前好像还没有改过来,导致大家在学习上面都出现了一些问题,现在做一个小小的罗列,希望对大家有用 做的 ...
- opencv + numpy for python
OpenCV的全称是:Open Source Computer Vision Library.OpenCV是一个基于(开源)发行的跨平台计算机视觉库,可以运行在Linux.Windows和Mac OS ...
- Ubuntu14.04(或Ubuntu16.04)安装openCV并测试python/C++
网上关于opencv的安装已经有了不少资料,但是没有一篇资料能让我一次性安装成功,因此花费了大量时间去解决各种意外,希望这篇能给一些人带去便利,节省时间. 1.安装OpenCV所需的库 1 sudo ...
- 学习CV:《OpenCV 3计算机视觉Python语言实现第2版》中文PDF+英文PDF+代码
理解与计算机视觉相关的算法.模型以及OpenCV 3 API背后的基本概念,有助于开发现实世界中的各种应用程序(比如:安全和监视领域的工具). OpenCV 3是一种先进的计算机视觉库,可以用于各种图 ...
- 使用OpenCV(C ++ / Python)进行人脸交换
-- 图3.面部对齐.左:检测到面部标志和凸包.中:凸包上的点的Delaunay三角剖分.右:通过仿射扭曲三角形进行面部对齐. 1 人脸对齐 1.1 脸部地标检测 两个脸部的几何形状非常不同,因此我们 ...
- opencv读取图像python和c++版本的结果不同
问题: 在读取同一张图像时,python读取的结果和c++读取的结果差异较大,测试图像中最大误差达到16. 原因: python的opencv采用的是4.1.1,c++采用的是3.1.0,在解析JPE ...
- 基于OpenCV全景拼接(Python)SIFT/SURF
一.实验内容: 利用sift算法,实现全景拼接算法,将给定的两幅图片拼接为一幅. 二.实验环境: 主机配置: CPU :intel core i5-7300 2.50GHZ RAM :8.0GB 运行 ...
- opencv处理验证码python代码
# -*- coding: utf-8 -*- # @Time : 2019-02-11 09:39 # @Author : cxa # @File : bgr2gry.py # @Software: ...
- OpenCV计算机视觉实战(Python版)资源
疲劳检测 pan.baidu.com/s/1Ng_-utB8BSrXlgVelc8ovw #导入工具包 from scipy.spatial import distance as dist from ...
随机推荐
- TVP思享 | 四个全新维度,极限优化HTTP性能
导语 | 当产品的用户量不断翻番时,需求会倒逼着你优化HTTP协议.那么,要想极限优化HTTP性能,应该从哪些维度出发呢?本文将由TVP陶辉老师,为大家分享四个全新维度.「TVP思享」专栏,凝结大咖思 ...
- 21.pyinstaller相关参数
pyinstaller相关参数 命令 描述 -F, ...
- 用积分方法求K次方和数列公式
这是我很早以前在高中时发现的一个通用计算K次方和数列公式的方法,很特别的地方是用了微积分中的积分方法.目前我还没有发现有谁提出和我一样的方法,如果哪位读者有相关发现,麻烦告知我. 大家很多人都知道高斯 ...
- 从零开始入门 K8s | GPU 管理和 Device Plugin 工作机制
作者 | 车漾 阿里巴巴高级技术专家 本文整理自<CNCF x Alibaba 云原生技术公开课>第 20 讲. 关注"阿里巴巴云原生"公众号,回复关键词" ...
- PGSQL 字符串作为查询参数的处理
刚从mysql转到pgsql,不太熟悉用法,今天在查询的时候有一个查询参数是字符串,一直没有这一列的错误 ERROR: column "A 桥梁" does not exist L ...
- 一款精美的Toast第三方库的简单使用
以前一直用的安卓原生Toast,个人感觉Toast这东西,没必要花功夫,知道看到了Toasty这东西,立刻被圈粉了,真的非常好看. 项目地址 我们都知道,安卓原生Toast的用法是 Toast.mak ...
- codeforces 上的找两人的幸运天
Bob and Alice are often participating in various programming competitions. Like many competitive pro ...
- dp-划分数 (递推)
问题描述 : 有 n 个无区别的物品 , 将他们分成 不超过 m 堆, 问有多少种分法 ? 例如 : n = 4 , m = 3 , 则总共有的分法是 1 + 2 +1 , 0 + 1 + 3 , 0 ...
- C++ 中的 unique 函数
unique 函数是用来去除一个集合中重复元素的函数 若是在数组中,则调用此函数后,返回的除去重复元素的下一个指针的地方 若是在 vector中,则会返回重复元素下一个位置的迭代器,在调用erase函 ...
- TCP/IP协议与HTTP协议(二)
TCP/IP协议是传输层协议,主要解决数据如何在网络中传输,而HTTP是应用层协议,主要解决如何包装数据. 1.TCP连接 手机能够使用联网功能是因为手机底层实现了TCP/IP协议,可以使手机终端通过 ...