一般对图像的变化操作有放大、缩小、旋转等,统称为几何变换,对一个图像的图像变换主要有两大步骤,一是实现空间坐标的转换,就是使图像从初始位置到终止位置的移动。二是使用一个插值的算法完成输出图像的每个像素的灰度值。其中主要的图像变换有:仿射变换、投影变换、极坐标变换。

仿射变换##

二维空间坐标的仿射变换公式:

\[\left(
\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)
\]

在以下矩阵中:

\[\left(
\begin{matrix}
\overline{x} \\
\overline{y} \\
1
\end{matrix}
\right) =A \left(
\begin{matrix}
x \\
y \\
1
\end{matrix}
\right)
\]

矩阵A就是仿射矩阵,因为它最后一行为(0,0,1)

\[A=
\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)。用矩阵表示这个平移过程为:

\[\left(
\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则表示缩小。放缩在矩阵中的表示为:

\[\left(
\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) )$$用矩阵可以表示为:

\[\left(
\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

化解以上公式,使用矩阵表示为:

\[\left(
\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)

运行结果:



在矩阵法中,需要预先知道具体的变化步骤,比如先放大再平移还是先移动再放大

\[\left(
\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)的更多相关文章

  1. python+opencv中最近出现的一些变化( OpenCV 官方的 Python tutorial目前好像还没有改过来?) 记一次全景图像的拼接

    最近在学习过程中发现opencv有了很多变动, OpenCV 官方的 Python tutorial目前好像还没有改过来,导致大家在学习上面都出现了一些问题,现在做一个小小的罗列,希望对大家有用 做的 ...

  2. opencv + numpy for python

    OpenCV的全称是:Open Source Computer Vision Library.OpenCV是一个基于(开源)发行的跨平台计算机视觉库,可以运行在Linux.Windows和Mac OS ...

  3. Ubuntu14.04(或Ubuntu16.04)安装openCV并测试python/C++

    网上关于opencv的安装已经有了不少资料,但是没有一篇资料能让我一次性安装成功,因此花费了大量时间去解决各种意外,希望这篇能给一些人带去便利,节省时间. 1.安装OpenCV所需的库 1 sudo ...

  4. 学习CV:《OpenCV 3计算机视觉Python语言实现第2版》中文PDF+英文PDF+代码

    理解与计算机视觉相关的算法.模型以及OpenCV 3 API背后的基本概念,有助于开发现实世界中的各种应用程序(比如:安全和监视领域的工具). OpenCV 3是一种先进的计算机视觉库,可以用于各种图 ...

  5. 使用OpenCV(C ++ / Python)进行人脸交换

    -- 图3.面部对齐.左:检测到面部标志和凸包.中:凸包上的点的Delaunay三角剖分.右:通过仿射扭曲三角形进行面部对齐. 1 人脸对齐 1.1 脸部地标检测 两个脸部的几何形状非常不同,因此我们 ...

  6. opencv读取图像python和c++版本的结果不同

    问题: 在读取同一张图像时,python读取的结果和c++读取的结果差异较大,测试图像中最大误差达到16. 原因: python的opencv采用的是4.1.1,c++采用的是3.1.0,在解析JPE ...

  7. 基于OpenCV全景拼接(Python)SIFT/SURF

    一.实验内容: 利用sift算法,实现全景拼接算法,将给定的两幅图片拼接为一幅. 二.实验环境: 主机配置: CPU :intel core i5-7300 2.50GHZ RAM :8.0GB 运行 ...

  8. opencv处理验证码python代码

    # -*- coding: utf-8 -*- # @Time : 2019-02-11 09:39 # @Author : cxa # @File : bgr2gry.py # @Software: ...

  9. OpenCV计算机视觉实战(Python版)资源

    疲劳检测 pan.baidu.com/s/1Ng_-utB8BSrXlgVelc8ovw #导入工具包 from scipy.spatial import distance as dist from ...

随机推荐

  1. 解决vue中element组件样式修改无效

    vue中element组件样式修改无效 <style> .detail{ .el-input__inner { height: 48px; } } </style> 直接写st ...

  2. 恕我直言,牛逼哄哄的MongoDB你可能只会30%

    MongoDB闪亮登场 自我介绍 MongoDB 是一个基于分布式文件存储的数据库.由 C++ 语言编写.旨在为 WEB 应用提供可扩展的高性能数据存储解决方案. MongoDB 是一个介于关系数据库 ...

  3. Spring学习记录6——ThreadLocal简介

    Spring通过各种模板类降低了开发者使用各种数据持久化技术的难度.这些模板类是线程安全的,所以 多个DAO可以复用同一个模板实例而不会发生冲突.在使用模板类访问底层数据时,模板类需要绑定数据连接或者 ...

  4. Iaas/paas/saas 三种模式分别都是做什么?

    任何一个在互联网上提供其服务的公司都可以叫做云计算公司.其实云计算分几层的,分别是Infrastructure(基础设施)-as-a- Service,Platform(平台)-as-a-Servic ...

  5. MySql笔记(一)

    目录 MySql笔记(一) 每天给自己一个希望,努力做好自己,不为明天烦恼,不为昨天叹息.当梦想还在,告诉自己:努力,就总能遇见更好的自己! MySql笔记(一) 1.创建数据库以及删除 1.创建数据 ...

  6. Unity3d游戏角色描边

    本文发布于游戏程序员刘宇的个人博客,欢迎转载,请注明来源https://www.cnblogs.com/xiaohutu/p/10834491.html 游戏里经常需要在角色上做描边,这里总结一下平时 ...

  7. 高通量计算框架HTCondor(一)——概述

    目录 1. 正文 2. 目录 3. 参考 4. 相关 1. 正文 HTCondor是威斯康星大学麦迪逊分校构建的分布式计算软件和相关技术,用来处理高通量计算(High Throughput Compu ...

  8. C语言进阶——全局变量

    全局变量 ·定义在函数外面的变量是全局变量 ·全局变量具有全局的生存期和作用域 ·它们与任何函数都无关 ·在任何函数内部都可以使用它们 全局变量初始化 ·没有做初始化的全局变量会得到0值 ·指针会得到 ...

  9. 机器学习环境配置系列一之CUDA

    本文配置的环境为redhat6.9+cuda10.0+cudnn7.3.1+anaonda6.7+theano1.0.0+keras2.2.0+jupyter远程,其中cuda的版本为10.0. 第一 ...

  10. 使用dlib自带的面向梯度直方图(HOG)和线性分类器方法来检测人脸

    之前使用opencv里面CascadeClassifier(级联分类器)来识别人脸, 下面使用dlib库来实现人脸识别. dlib是一个开源的库,它包含了很多内容有机器学习,图像处理,数值算法等等. ...