博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【opencv学习笔记】023之像素重映射
阅读量:4076 次
发布时间:2019-05-25

本文共 4699 字,大约阅读时间需要 15 分钟。

前言

如果你想了解更多有关于计算机视觉、OpenCV、机器学习、深度学习等相关技术的内容,想与更多大佬一起沟通,那就扫描下方二维码加入我们吧!

一、映射是个什么玩意?

映射是个数学术语,指两个元素的集之间元素相互“对应”的关系,为名词。映射,或者射影,在数学及相关的领域经常等同于函数。 基于此,部分映射就相当于部分函数,而完全映射相当于完全函数。

说的简单点,每个人都有一个名字,都有身份证号,人对应人名字,对应自己的身份证号,这种对应关系就叫映射。

 

二、像素重映射是个什么玩意?

把一个图像中一个位置的像素放置到另一个图片指定位置的过程就是像素重映射。

为了完成映射过程, 有必要获得一些插值为非整数像素坐标,因为源图像与目标图像的像素坐标不是一一对应的.

简单的说就是改变图片的位置(左,右,上,下,颠倒)

for example (举个栗子):g(x, y)=f(h(x,y))。 这里g()是目标图像,f()是原图像,h(x,y)是作用于(x,y)的映射方法函数。假设有一幅图像I,满足后面条件作重映射: h(x,y)=(I.cols - x,y)这个公式是有点绕哈,有些对数学不感冒的童鞋可以看一下这个图

聪明的孩纸们,你们猜猜他俩在干嘛?对对对,在深情对视,所以这个函数的效果就是轴对称,左右翻转。

这就是数学的魅力。来来来,我们一起来体验一下。

三、像素重映射API——remap()

下面是函数原型:

cv::remap  (   	InputArray	src,	OutputArray	dst,	InputArray	map1,	InputArray	map2,	int		interpolation,	int		borderMode = BORDER_CONSTANT,	const Scalar    borderValue = Scalar()	)

下面是函数各个参数的解释:

第一个参数,InputArray类型的src,输入图像,即源图像,填Mat类的对象即可,且需为单通道8位或者浮点型图像。

第二个参数,OutputArray类型的dst,函数调用后的运算结果存在这里,即这个参数用于存放函数调用后的输出结果,需和源图片有一样的尺寸和类型

第三个参数,InputArray类型的map1,它有两种可能的表示对象。表示点(x,y)的第一个映射。表示CV_16SC2 , CV_32FC1 或CV_32FC2类型的X值。

第四个参数,InputArray类型的map2,同样,它也有两种可能的表示对象,而且他是根据map1来确定表示那种对象。若map1表示点(x,y)时。这个参数不代表任何值。表示CV_16UC1 , CV_32FC1类型的Y值(第二个值)。

第五个参数,int类型的interpolation,插值方式,之前的resize( )函数中有讲到,需要注意,resize( )函数中提到的INTER_AREA插值方式在这里是不支持的,所以可选的插值方式如下:INTER_NEAREST - 最近邻插值INTER_LINEAR – 双线性插值(默认值)INTER_CUBIC – 双三次样条插值(逾4×4像素邻域内的双三次插值)INTER_LANCZOS4 -Lanczos插值(逾8×8像素邻域的Lanczos插值)

第六个参数,int类型的borderMode,边界模式,有默认值BORDER_CONSTANT,表示目标图像中“离群点(outliers)”的像素值不会被此函数修改。

第七个参数,const Scalar&类型的borderValue,当有常数边界时使用的值,其有默认值Scalar( ),即默认值为0。

四、实战

纸上得来终觉浅,绝知此事要躬行。多说无益,代码才是王道。

1.参数函数

首先我们要先考虑,我们要做的情况有如下四种:缩小(行与列均为原来的1/2),左右翻转,上下翻转,中心旋转。下面的图表示的就是四种变换模式:

最简单的是翻转了,行不变,第一列跟最后一列转换,第二列跟倒数第二列转换……这样就实现了左右翻转。同理,列不变,行转换,实现上下翻转。如果上下左右都翻转,那就是旋转180°,也就是中心旋转啦。

还有一个就是图像缩小,图像缩小就是将长跟宽变换为原来的1/2。所以只在图像的1/4处到3/4处有新图像。将图像范围控制在0原图像的0.25-0.75之间,其他的全部为0;设置图像的x和y方向的映射。对于x方向,是列的映射。图像的每个像素点,减去原图像的1/4,再×2,就表示图像缩小1/2.不过,经过我自己的实践发现,图像宽,高缩小一半不能再后面+0.5,应该是列不加,行-0.25。

void updata_map() {	for (int row = 0; row < img.rows; row++)	{		for (int col = 0; col < img.cols; col++)		{			switch (index)			{				//index = 0 ,图像的行跟列为为原来的1/2。				//index = 1,为左右翻转(列变换,行不变)				//index = 2,为上下翻转(行变换,列不变)				//index = 3,为中心旋转							case 0:				if (col > (img.cols*0.25) && col<(img.cols*0.75) && row>(img.rows*0.25) && row < (img.rows*0.75)) {					map_x.at
(row, col) = 2 * (col - (img.cols*0.25)); map_y.at
(row, col) = 2 * (row - (img.rows*0.25) - 0.25); } else { map_x.at
(row, col) = 0; map_y.at
(row, col) = 0; } break; case 1: map_x.at
(row, col) = (img.cols - col - 1); map_y.at
(row, col) = row; break; case 2: map_x.at
(row, col) = col; map_y.at
(row, col) = (img.rows - row - 1); break; case 3: map_x.at
(row, col) = (img.cols - col - 1); map_y.at
(row, col) = (img.rows - row - 1); break; default: break; } } }

以下三个图分别是:

             都加上0.5;                            都不加0.5;                         x不加,y-0.25;

      

2.全部代码

【源代码】

#define INPUT_TITLE "input image"#define OUTPUT_TITLE "remap image"#include
#include
using namespace std;using namespace cv;Mat img, src;//img 输入图像 ; src 最终输出的图像Mat map_x, map_y;int index = 0;void updata_map();int main() { img = imread("D:/个人/学习/c++/测试程序/ConsoleApplication6/image/circle1.bmp"); if (!img.data) { cout << "ERROR : could not load image."; return -1; } namedWindow(INPUT_TITLE, CV_WINDOW_AUTOSIZE); namedWindow(OUTPUT_TITLE, CV_WINDOW_AUTOSIZE); imshow(INPUT_TITLE, img); //建立映射表 map_x.create(img.size(), CV_32FC1); map_y.create(img.size(), CV_32FC1); int c = 0; while (true) { c = waitKey(500); index = c % 4; if ((char)c == 27) { break; } updata_map(); remap(img, src, map_x, map_y, INTER_LINEAR, BORDER_CONSTANT, Scalar(0, 0, 255)); imshow(OUTPUT_TITLE, src); } return 0;}void updata_map() { for (int row = 0; row < img.rows; row++) { for (int col = 0; col < img.cols; col++) { switch (index) { //index = 0 ,图像的行跟列为为原来的1/2。 //index = 1,为左右翻转(列变换,行不变) //index = 2,为上下翻转(行变换,列不变) //index = 3,为中心旋转 case 0: if (col > (img.cols*0.25) && col<(img.cols*0.75) && row>(img.rows*0.25) && row < (img.rows*0.75)) { map_x.at
(row, col) = 2 * (col - (img.cols*0.25)); map_y.at
(row, col) = 2 * (row - (img.rows*0.25)-0.25); } else { map_x.at
(row, col) = 0; map_y.at
(row, col) = 0; } break; case 1: map_x.at
(row, col) = (img.cols - col - 1); map_y.at
(row, col) = row; break; case 2: map_x.at
(row, col) = col; map_y.at
(row, col) = (img.rows - row - 1); break; case 3: map_x.at
(row, col) = (img.cols - col - 1); map_y.at
(row, col) = (img.rows - row - 1); break; default: break; } } }}

【效果图】

你可能感兴趣的文章
Unity之MVC 模式
查看>>
turret
查看>>
再谈AR中的图像识别算法
查看>>
开发增强现实(AR)教程——识别图的那些坑
查看>>
unity3d英语单词拼写小游戏Pics Quiz Maker With Categories 3.0
查看>>
unity填色绘画游戏Drawing Coloring Extra Edition
查看>>
unity缓动插件DOTween Pro v1.0.1
查看>>
unity 3d音效如何设置?,近大远小
查看>>
Unity3D无限奔跑者Playmaker v1.5
查看>>
Unity塔防游戏源码Warfront Defenders Playmaker Kit v1.7
查看>>
今天清理C盘空间,发现Unity的一个问题
查看>>
c#的Boolean.Parse用法
查看>>
NP完全问题
查看>>
avoid
查看>>
entity
查看>>
rear
查看>>
roof
查看>>
wiper
查看>>
chase
查看>>
unity中Camera.ScreenToWorldPoint
查看>>