OpenCV3入门(九)图像几何变换
1、图像缩放
假设图像x轴的缩放因子Sx, y轴方向的缩放因子Sy,相应的变换表达式为:
函数原型为:
CV_EXPORTS_W void resize( InputArray src, OutputArray dst,
Size dsize, double fx = , double fy = ,
int interpolation = INTER_LINEAR );
示例程序如下。
img = imread("D:\\WORK\\5.OpenCV\\LeanOpenCV\\pic_src\\pic9.bmp");
imshow("原图", img);
resize(img, img2, Size(), 0.5, 0.5);
imshow("缩放图1", img2);
resize(img, img3, Size(), 0.8, 0.5);
imshow("缩放图2", img3);
运行效果如下图。
resize(img, img2, Size(), 1.2, 1.2);
2、图像平移
假设图像x轴的平移量Tx, y轴方向的平移量Ty,相应的变换表达式为:
仿射变换的原理为:
dst(x,y)=src(M11x+M12y+M13,M21x+M22y+M23)
平移操作可以使用OpenCV的仿射变换函数来实现,使用的变换矩阵为:
函数原型为:
CV_EXPORTS_W void warpAffine( InputArray src, OutputArray dst,
InputArray M, Size dsize,
int flags = INTER_LINEAR,
int borderMode = BORDER_CONSTANT,
const Scalar& borderValue = Scalar());
图像平移示例。
img = imread("D:\\WORK\\5.OpenCV\\LeanOpenCV\\pic_src\\pic9.bmp", IMREAD_GRAYSCALE);
imshow("原图", img); // x轴平移20,y轴平移10, 2 * 3矩阵
Mat M = Mat::zeros(, , CV_32FC1);
M.at<float>(, ) = ;
M.at<float>(, ) = ;
M.at<float>(, ) = ;
M.at<float>(, ) = ;
warpAffine(img, img2, M, img.size());
imshow("平移图", img2);
3、图像旋转
假设点P0(x0,y0),角度为a,令L=|OP|=sqrt(x*x + y*y).
P0旋转b度到P1(x1,y1),则
x1=L*cos(a+b)=L* cos(a)*cos(b) – L*sin(a)*sin(b) = x0*cos(b) - y0*sin(b)
y1=L*sin(a+b)=L* sin(a)*cos(b) + L*cos(a)*sin(b) = y0*cos(b) + x0*sin(b)
OpenCV内置仿射变换的旋转函数,支持任意点为中心的图像旋转,函数原型为:
CV_EXPORTS_W Mat getRotationMatrix2D( Point2f center, double angle, double scale );
示例代码如下。
img = imread("D:\\WORK\\5.OpenCV\\LeanOpenCV\\pic_src\\pic9.bmp");
imshow("原图", img); Point center = Point(img.cols / , img.rows / );
Mat m1= getRotationMatrix2D(center, , 1.0);
Mat m2 = getRotationMatrix2D(center, , 0.7);
Mat m3 = getRotationMatrix2D(center, , 1.2);
warpAffine(img, img1, m1, img.size());
warpAffine(img, img2, m2, img.size());
warpAffine(img, img3, m3, img.size());
imshow("img1", img1);
imshow("img2", img2);
imshow("img3", img3);
修改旋转角度效果如下图。
Mat m1= getRotationMatrix2D(center, 180, 1.0);
Mat m2 = getRotationMatrix2D(center, 270, 0.7);
如果旋转点的坐标原点不在图片中心,则图片绕着指定点旋转。
Point center = Point(, ); Mat m1= getRotationMatrix2D(center, , 1.0); Mat m2 = getRotationMatrix2D(center,-, 1.0);
对应的矩阵为:
m1=
[0.8660254037844387, 0.4999999999999999, 0;
-0.4999999999999999, 0.8660254037844387, 0]
m2=
[0.7071067811865476, -0.7071067811865476, 0;
0.7071067811865476, 0.7071067811865476, 0]
输出效果如下图。
4、图像重映射
重映射就是把一个图像中一个为之的像素放置到另一个图片指定位置过程。由于映射后的图像在原图中可能没有对应的整数坐标点像素,所以为了完成重映射需要做一些插值作为非整数像素坐标。我们通过重映射来表达每个像素的位置(x, y):g(x, y)=f(h(x,y))
OpenCV使用remap函数完成重映射功能,函数原型为:
CV_EXPORTS_W void remap( InputArray src, OutputArray dst,
InputArray map1, InputArray map2,
int interpolation, int borderMode = BORDER_CONSTANT,
const Scalar& borderValue = Scalar());
测试代码如下。
void update_map(int ind, Mat &map_x, Mat &map_y)
{
for (int i = ; i < map_x.rows; i++)
{
for (int j = ; j < map_x.cols; j++)
{
switch (ind)
{
case :
if (j > map_x.cols*0.25 && j < map_x.cols*0.75 && i > map_x.rows*0.25 && i < map_x.rows*0.75)
{
map_x.at<float>(i, j) = * (j - map_x.cols*0.25f) + 0.5f;
map_y.at<float>(i, j) = * (i - map_x.rows*0.25f) + 0.5f;
}
else
{
map_x.at<float>(i, j) = ;
map_y.at<float>(i, j) = ;
}
break;
case :
map_x.at<float>(i, j) = (float)j;
map_y.at<float>(i, j) = (float)(map_x.rows - i);
break;
case :
map_x.at<float>(i, j) = (float)(map_x.cols - j);
map_y.at<float>(i, j) = (float)i;
break;
case :
map_x.at<float>(i, j) = (float)(map_x.cols - j);
map_y.at<float>(i, j) = (float)(map_x.rows - i);
break;
default:
break;
} // end of switch
}
}
} int main() {
Mat src = imread("D:\\WORK\\5.OpenCV\\LeanOpenCV\\pic_src\\pic9.bmp");
imshow("原图", src); Mat dst(src.size(), src.type());
Mat map_x(src.size(), CV_32FC1);
Mat map_y(src.size(), CV_32FC1); update_map(, map_x, map_y);
remap(src, img1, map_x, map_y, INTER_LINEAR, BORDER_CONSTANT, Scalar(, , ));
imshow("img1", img1); update_map(, map_x, map_y);
remap(src, img2, map_x, map_y, INTER_LINEAR, BORDER_CONSTANT, Scalar(, , ));
imshow("img2", img2); update_map(, map_x, map_y);
remap(src, img3, map_x, map_y, INTER_LINEAR, BORDER_CONSTANT, Scalar(, , ));
imshow("img3", img3); update_map(, map_x, map_y);
remap(src, img4, map_x, map_y, INTER_LINEAR, BORDER_CONSTANT, Scalar(, , ));
imshow("img4", img4); waitKey();
}
输入图像:
代码实现四种remap效果。
remap后的图像:
例子2:x轴不压缩,y轴按照一元二次曲线进行压缩,对称抽为src.rows / 2。当y= src.rows / 2,对应变换前的图坐标src.rows,所以图像被压缩。当y=[ src.rows / 2,src.rows]时,y轴被反转。
for (int i = ; i < src.rows; i++)
{
for (int j = ; j < src.cols; j++)
{
map_x.at<float>(i, j) = j;
map_y.at<float>(i, j) = (float)((- * pow(i- src.rows / , ) / pow(src.rows / , )) + ) * src.rows;
}
}
5、参考文献
1、《OpenCV3 编程入门》,电子工业出版社,毛星雨著
2、《学习OpenCV》,清华大学出版社,Gary Bradski, Adrian kaehler著
3、Remapping
https://docs.opencv.org/3.4/d1/da0/tutorial_remap.html
4、OpenCV图像旋转
https://www.cnblogs.com/konglongdanfo/p/9135501.html
技术博客,转载请注明。
OpenCV3入门(九)图像几何变换的更多相关文章
- C#数字图像处理算法学习笔记(三)--图像几何变换
C#数字图像处理算法学习笔记(三)--图像几何变换 几何图像处理包括 图像的平移变换,镜像变换,旋转变换,伸缩变换,在这里仅以水平镜像为例,通过代码来理解其基本操作方式: 翻转前:
- 网络编程懒人入门(九):通俗讲解,有了IP地址,为何还要用MAC地址?
1.前言 标题虽然是为了解释有了 IP 地址,为什么还要用 MAC 地址,但是本文的重点在于理解为什么要有 IP 这样的东西.本文对读者的定位是知道 MAC 地址是什么,IP 地址是什么. (本文同步 ...
- C#基础入门 九
C#基础入门 九 集合 对于很多应用程序,需要创建和管理相关对象组,有两种方式可以将对象分组,一是创建对象数组,如 object[] obj=new object[3]{1,2.33,"st ...
- cesium编程入门(九)实体 Entity
cesium编程入门(九)实体 Entity 在cesium编程入门(五)绘制形状提到过添加实体的方法,这一节聊一聊实体相关的一些内容: 先来看 Entity 的各个属性 id 唯一标志,如果没设置, ...
- matlab之原始处理图像几何变换
(一)图像几何变换理论知识 (1)图像的平移与比例 图像的平移很简单,平移前后的坐标分别为(x,y)和(x',y'),则满足的关系式为 x'= x +Tx: y'= y +Ty: 其中Tx与Ty分别为 ...
- OpenCV3入门(四)图像的基础操作
1.访问图像像素 1)灰度图像 2)彩色图像 OpenCV中的颜色顺序是BGR而不是RGB. 访问图像的像素在OpenCV中就是访问Mat矩阵,常用的有三种方法. at定位符访问 Mat数据结构,操作 ...
- OpenCV3入门(六)图像滤波
1.图像滤波理论 1.1图像滤波理论 图像滤波即在尽量保留图像细节特征的条件下对目标图像的噪声进行抑制,是图像预处理中不可缺少的操作.消除图像中的噪声又叫做图像滤波或平滑,滤波的目的有两个,一是突出特 ...
- OpenCV3入门(七)图像形态学
1.膨胀 所谓的图片的膨胀处理,其实就是在图像的边缘添加像素值,使得整体的像素值扩张,进而达到图像的膨胀效果. 对Z2上元素集合A和结构体元素S,使用S对A进行腐蚀,记作: A⊕S={z|(S)z ∩ ...
- OpenCV3入门(八)图像边缘检测
1.边缘检测基础 图像的边缘是图像的基本特征,边缘点是灰度阶跃变化的像素点,即灰度值的导数较大或极大的地方,边缘检测是图像识别的第一步.用图像的一阶微分和二阶微分来增强图像的灰度跳变,而边缘也就是灰度 ...
随机推荐
- 【转】最受欢迎的8位Java牛人
本文由 ImportNew - 唐尤华 翻译自 javatyro.如需转载本文,请先参见文章末尾处的转载要求. 下面是8位Java牛人,他们为Java社区编写框架.产品.工具或撰写书籍改变了Java编 ...
- Linux上的Tomcat地址映射,且404错误解决
问题:现在想要加一个下载文件功能,但是文件地址不在tomcat的webapps下,需要通过地址映射到tomcat下面再通过链接执行下载文件功能. 解决方法有两种: 方法一: 用方法一的前提是不用启动服 ...
- Java配置文件读取中文乱码问题
背景 这是我之前在做的用友服务对接开发,昨天领导拿给财务测试时告诉我有乱码,当时我第一想法是用友那边的编码格式有问题,因为还在做其他任务,我说等问一下用友他们用的什么编码格式我们这边改一下,然后今天早 ...
- kubernetes concepts -- Replication Controller
Edit This Page ReplicationController NOTE: A Deployment that configures a ReplicaSet is now the reco ...
- Heroku学习 - 利用Heroku app实现 OrgA 查询Org B 的数据数据
最近研究了一番如何通过Heroku应用对OrgA开放一个接口,参数传递的是一个SQL,APP的负责将SQL通过callout的形式调用目标OrgB Rest API来获取数据并返回给OrgA.我是用的 ...
- Springboot + 持久层框架JOOQ
简介 官网链接 JOOQ是一套持久层框架,主要特点是: 逆向工程,自动根据数据库结构生成对应的类 流式的API,像写SQL一样 提供类型安全的SQL查询,JOOQ的主要优势,可以帮助我们在写SQL时就 ...
- 洛谷 P5424 [USACO19OPEN]Snakes
题目链接 题目描述 传说,数千年前圣帕特里克消灭了哞尔兰所有的蛇.然而,蛇们现在卷土重来了!圣帕特里克节是在每年的3月17日,所以Bessie要用彻底清除哞尔兰所有的蛇来纪念圣帕特里克. Bessie ...
- 同一个环境同时使用python2和python3的方法
1.首先安装好p2和p3,配置好环境变量.在CMD内执行python返回版本号,返回结果根据配置的环境变量而定,如果p2的环境变量配置在前面,则返回p2的版本号,反之则p3 2.然后把各版本目录下的p ...
- lareval 快速搭建管理后台
一.环境及软件 window X64 phpstudy_x64_8.1.0.1.exe 集成环境 下载地址 https://www.xp.cn/ Nginx1.15.11 MySQL5.7.26 PH ...
- windows RabbitMQ安装与配置
windows RabbitMQ安装与配置 1.安装Erlang 下载地址: http://www.erlang.org/downloads 注意: 右键以管理员身份进行安装,否则将导致后续无法启动 ...