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.边缘检测基础 图像的边缘是图像的基本特征,边缘点是灰度阶跃变化的像素点,即灰度值的导数较大或极大的地方,边缘检测是图像识别的第一步.用图像的一阶微分和二阶微分来增强图像的灰度跳变,而边缘也就是灰度 ...
随机推荐
- 原型,原型链,给予原型和class的继承
学习react的时候遇到了class方式的继承语法,原理和代码的解释很详细,值得一读. 原型每个函数(构造函数)都有一个 prototype 属性,指向该函数(构造函数)的原型对象.实例没有 prot ...
- 【转】ArcGIS ADF 实时轨迹问题初步解决方案
Web ADF 实时轨迹是指在Web客户端指定一资源项,并对资源项进行实进跟踪并绘制出轨迹图.实时绘制可采用Ajax实现服务端与客户端无刷新动态绘制,在.net2.0 框架下可轻易实现:通过客户端时钟 ...
- Springboot + 持久层框架JOOQ
简介 官网链接 JOOQ是一套持久层框架,主要特点是: 逆向工程,自动根据数据库结构生成对应的类 流式的API,像写SQL一样 提供类型安全的SQL查询,JOOQ的主要优势,可以帮助我们在写SQL时就 ...
- JsonResponse和HttpResponse
1.联系 JsonResponse继承HttpResponse 2.区别 JsonResponse 数据类型装自动换成json字符串并相应到前端,传到前端的是数据类型而非json字符串 HttpRes ...
- Java入门 - 语言基础 - 12.Number和Math类
原文地址:http://www.work100.net/training/java-number-math.html 更多教程:光束云 - 免费课程 Number和Math类 序号 文内章节 视频 1 ...
- [bzoj3527] [洛谷P3338] [Zjoi2014]力
Description 给出n个数qi,给出Fj的定义如下: \[ F_j=\sum\limits_{i<j} \frac{q_iq_j}{(i-j)^2} - \sum\limits_{i&g ...
- 用postman导出excel文件
原文地址:https://jingyan.baidu.com/article/915fc414559b4351394b2084.html 现在的web和移动开发,常常会调用服务器提供restful接口 ...
- 靶机-BTRSys 2.1 Walkthrough
BTRSys 2.1 https://www.vulnhub.com/entry/btrsys-v21,196/ 参考:https://www.jianshu.com/p/9813095ce04d 提 ...
- basic-pentesting-1 靶机提权
原文地址:https://www.payload.com.cn/ basic-pentesting-1 下载地址: https://www.vulnhub.com/entry/basic-pent ...
- 第二次作业hzw
第二次作业 | GIT地址 | 地址链接 | |--|--| |GIT用户名 | BRYANT333 | |学号后五位|24240| |博客地址|我的博客| |作业链接|第二次作业地址| 一.环境配置 ...