OpenCV探索之路(八):重映射与仿射变换
重映射
重映射就是把一幅图像中某个位置的像素放置到另一个图片中指定位置的过程。
用一个数学公式来表示就是:

其中的 f 就是映射方式,也就说,像素点在另一个图像中的位置是由 f 来计算的。
在OpenCV中,用的是remap函数实现重映射。
基本重映射
#include <iostream>
#include <opencv2\opencv.hpp>
#include <opencv2\imgproc\imgproc.hpp>
#include <opencv2\highgui\highgui.hpp>
using namespace cv;
using namespace std;
//基本重映射实验
int main()
{
Mat srcImage = imread("2.jpg");
if (!srcImage.data)
{
cout << "找不到这张图片!" << endl;
return -1;
}
imshow("Src Pic", srcImage);
Mat dstImage, map_x, map_y;
dstImage.create(srcImage.size(), srcImage.type());//创建和原图一样的效果图
map_x.create(srcImage.size(), CV_32FC1);
map_y.create(srcImage.size(), CV_32FC1);
//遍历每一个像素点,改变map_x & map_y的值,实现翻转180度
for (int j = 0; j < srcImage.rows; j++)
{
for (int i = 0; i < srcImage.cols; i++)
{
map_x.at<float>(j, i) = static_cast<float>(i);
map_y.at<float>(j, i) = static_cast<float>(srcImage.rows - j);
}
}
//进行重映射操作
remap(srcImage, dstImage, map_x, map_y, INTER_LINEAR, BORDER_CONSTANT, Scalar(0, 0, 0));
imshow("重映射效果图", dstImage);
waitKey();
return 0;
}
map_x与map_y分别代表目标图中的(x,y)点在原图中的x坐标(由map_x提供)与y坐标(由map_y提供)。
运行效果,图像翻转了。

仿射变换
仿射变换指的是一个向量空间进行一次线性变换并接上一个平移,变换为另一个向量空间的过程。
图像进行仿射变换后,有以下几个特点:
二维图形之间的相对位置关系保持不变,平行线依旧是平行线,且直线上的点的位置顺序保持不变。
一个任意的仿射变换都可以表示为乘以一个矩阵(线性变换)接着再加上一个向量(平移)的形式。

三种常见形式:
- 旋转,rotation(线性变换)
- 平移,translation(向量加)
- 缩放,scale(线性变换)
仿射变换本质是一个2* 3的矩阵M乘上原图的每个坐标,得到目标图的对应点坐标。2*3矩阵M中的2表示目标点坐标的x与y,3中的第三维是平移分量。因此需要做的就是找到矩阵M,OpenCV提供 getAffineTransform 求出仿射变换, getRotationMatrix2D 来获得旋转矩阵。
这里简单说说仿射变换是怎么做到的。
现在有两幅图像(如下图),图像二是图像一经过放射变化得来的。那问题来了,我们怎么从这两个图像信息里挖掘出两图之间的映射关系?

很简单,只要在图像一种拿出三个点(1,2,3),图像二也拿出对应的三个点(1,2,3),就可以求出两图间的映射关系!
OpenCV通过两个函数的组合使用来实现仿射变换:
- 使用warpAffine来实现简单重映射
- 使用getRotationMatrix2D来获得旋转矩阵
#include<iostream>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
using namespace std;
using namespace cv;
//仿射变换实验
int main()
{
Mat src = imread("lol9.jpg");
Mat dst_warp, dst_warpRotateScale;
Point2f srcPoints[3];//原图中的三点
Point2f dstPoints[3];//目标图中的三点
//第一种仿射变换的调用方式:三点法
//三个点对的值,上面也说了,只要知道你想要变换后图的三个点的坐标,就可以实现仿射变换
srcPoints[0] = Point2f(0, 0);
srcPoints[1] = Point2f(0, src.rows - 1);
srcPoints[2] = Point2f(src.cols - 1, 0);
//映射后的三个坐标值
dstPoints[0] = Point2f(0, src.rows*0.3);
dstPoints[1] = Point2f(src.cols*0.25, src.rows*0.75);
dstPoints[2] = Point2f(src.cols*0.75, src.rows*0.25);
Mat M1 = getAffineTransform(srcPoints, dstPoints);//由三个点对计算变换矩阵
warpAffine(src, dst_warp, M1, src.size());//仿射变换
//第二种仿射变换的调用方式:直接指定角度和比例
//旋转加缩放
Point2f center(src.cols / 2, src.rows / 2);//旋转中心
double angle = 45;//逆时针旋转45度
double scale = 0.5;//缩放比例
Mat M2 = getRotationMatrix2D(center, angle, scale);//计算旋转加缩放的变换矩阵
warpAffine(dst_warp, dst_warpRotateScale, M2, src.size());//仿射变换
imshow("原始图", src);
imshow("仿射变换1", dst_warp);
imshow("仿射变换2", dst_warpRotateScale);
waitKey(0);
return 0;
}
两种仿射变换的效果如下。

有没有发现图片进行仿射变换后的背景被填充为黑色了?其实这个背景色是可以调的,像这样:
warpAffine(dst_warp, dst_warpRotateScale, M2, src.size(), 1, 0, Scalar(11,111, 211));//利用Scalar来填充不同颜色背景
然后背景色就变成这样子了:

最后写一个对图片旋转任何角度的代码。
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
using namespace cv;
using namespace std;
#define PIC_BEGIN_NUM 100 //这里定义你的起始图片编号
#define ANGLE_START -45 //旋转角度的开始
#define ANGLE_END 0 //旋转角度的结束
#define ANGLE_STEP 2 //旋转角度步长
int main(int argc, char **argv)
{
//Read a single-channel image
const char* filename = "lol9.jpg";
Mat srcImg = imread(filename, 1);
imshow("source", srcImg);
Point center(srcImg.cols / 2, srcImg.rows / 2); //图片中心为旋转点
char file[20];
int count = PIC_BEGIN_NUM;
Mat tmpimg;
for (int tmp = ANGLE_START; tmp < ANGLE_END; tmp += ANGLE_STEP)
{
Mat rotMatS = getRotationMatrix2D(center, tmp, 0.5); //图片缩小到原来的0.5倍
warpAffine(srcImg, tmpimg, rotMatS, srcImg.size(), 1, 0, Scalar(0, 0, 0));//填充黑色背景
sprintf(file, "%d.jpg", count++); //旋转图片以1.jpg 2.jpg 的名字格式保存
imwrite(file, tmpimg);
}
waitKey(0);
return 0;
}
这里的代码实现对图片旋转2度、4度...45度的功能,并将这些旋转后的图像保存先来。
然后文件夹下就出现旋转好的图片了!

OpenCV探索之路(八):重映射与仿射变换的更多相关文章
- OpenCV学习笔记(九) 重映射、仿射变换
重映射 通过重映射来表达每个像素的位置 : 这里 是目标图像, 是源图像, 是作用于 的映射方法函数.想象一下我们有一个图像 , 我们想满足下面的条件作重映射:,图像会按照 轴方向发生翻 ...
- OpenCV——重映射、仿射变换
#include <opencv2/opencv.hpp> #include <iostream> #include <math.h> using namespac ...
- opencv 5 图像转换(3 重映射 仿射变换 直方图均衡化)
重映射 实现重映射(remap函数) 基础示例程序:基本重映射 //---------------------------------[头文件.命名空间包含部分]------------------- ...
- 【OpenCV新手教程之十七】OpenCV重映射 & SURF特征点检測合辑
本系列文章由@浅墨_毛星云 出品.转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/30974513 作者:毛星云(浅墨) ...
- opencv之重映射
好久没写呆码了 今天发个重映射 #include "opencv2/video/tracking.hpp" #include "opencv2/imgproc/imgpr ...
- opencv —— remap 重映射
重映射的概念 重映射,就是把一幅图像中某位置的像素放置到另一个图片指定位置的过程. 实现重映射:remap 函数 将图像进行重映射几何变换,基于的公式为:dst (x, y) = src ( mapx ...
- opencv::像素重映射
像素重映射(cv::remap) 简单点说就是把输入图像中各个像素按照一定的规则映射到另外一张图像的对应位置上去,形成一张新的图像. Remap( InputArray src, // 输入图像 Ou ...
- OpenCV函数 重映射
重映射是什么意思? 把一个图像中一个位置的像素放置到另一个图片指定位置的过程. 为了完成映射过程, 有必要获得一些插值为非整数像素坐标,因为源图像与目标图像的像素坐标不是一一对应的. 我们通过重映射来 ...
- OpenCV探索之路(二十四)图像拼接和图像融合技术
图像拼接在实际的应用场景很广,比如无人机航拍,遥感图像等等,图像拼接是进一步做图像理解基础步骤,拼接效果的好坏直接影响接下来的工作,所以一个好的图像拼接算法非常重要. 再举一个身边的例子吧,你用你的手 ...
随机推荐
- VSCode里的一些有用的插件
1.EaseServer 作用:开启本地 http server,然后在browser里打开html: 在调试页面的时候,打开页面比较方便,不需要先开启server,再打开html 2.Debugge ...
- poptest老李谈动态口令原理
poptest老李谈动态口令原理 poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.如果对课程感兴趣,请大家咨询qq:908 ...
- AngularJS1.X学习笔记1-整体看看
听说 明天是愚人节,这与我有什么关系呢!我可 不想被愚弄,但是但是,我这么笨怎么才能不被愚弄呢?左思右想,我决定从现在开始闭关,闭关干啥哩?学习!学习AngularJS.以前学习过Angular的,不 ...
- JavaWeb总结(四)—JSP深入解析
一.JSP域对象 1.JSP属性范围(域对象范围) JSP提供了四个域对象,分别是pageContext.request.session.application. pageContext: 属性范围仅 ...
- day001-html知识点总结(二)不常见但很重要的元素汇总
一..vertical-align:设置垂直对齐方式,主要用于: 1.单元格内容的垂直对齐 2.对于行内块级元素,如<img>,设置行内元素的基线相对于该行内块级元素的所在行的基线对齐,例 ...
- Python学习_argsparse
# -*- coding: utf-8 -*- import argparse args = "-f hello.txt -n 1 2 3 -x 100 -y b -z a -q hello ...
- redis 字符串
redis 字符串 概述 redis 没有使用 c 语言风格的字符串表示(以 "\0" 作为结尾), 而是使用自定义的 sds 结构 字符串结构 定义位置 (src/sds.h) ...
- 分享我的学习记录 svn地址
地址:svn://121.42.160.2/myproject 用户名:scaner 密码:zhinengkan 这个用户只有读权限,没有修改的权限,如果有什么建议或代码中有不对的地方,欢迎再留言中告 ...
- PMD教程
1.单词 violations outline:错误大纲2.错误级别 红色 很高的错误 橙色 错误 黄色 很高的警告 绿色 警告 蓝色 输出信息3.提示 Avoid excessively long ...
- 五十行javascript代码实现简单的双向数据绑定
五十行javascript代码实现简单的双向数据绑定 Vue框架想必从事前端开发的同学都使用过,它的双向数据绑定机制能给我们带来很大的方便.今天闲着没事,尝试着实现一下双向数据绑定,接下来给大家分享一 ...