【OpenCV】-重映射

简介: 【OpenCV】-重映射
1、重映射的概念

重映射是把一幅图像中某位置的像素放置到另一个图片指定位置的过程。为了完成重映射过程,需要获得一些插值为非整数像素的坐标,因为源图像与目标图像像素坐标不是一一对应的。如下:

g(x,y)=f(h(x,y))

g()是目标图像,f()是源图像,而h(x,y)是作用于(x,y)的映射方法函数。

2、实现重映射:remap()函数

remap()函数会根据指定的映射形式,将源图像进行重映射几何变换:

dst(x,y)=src(mapx(x,y),mapy(x,y))

void remap(InputArray src,OutputArray dst,InputArray map1,InputArray map2,int interpolation,intborderMode=BORDER_CONSTANT,const Scalar& borderValue=Scalar())

第一个参数:输出图像

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

第三个参数:InputArray类型的 map1,有两种可能的表示对象

表示点(x,y)的第一映射

表示CV_16SC2,CV_32FC1,CV_32FC2类型的X值

第四个参数:InputArray类型的 map2,有两种可能的表示对象

若map1表示点(x,y)时,这个参数不代表任何值

表示CV_16UC1,CV_32FC1类型的Y值

第五个参数:int 类型的interpolation,插值方式,所选的插值方式如下:

INTER_NEAREST——最近邻插值

INTER_LINEAR——双线性插值(默认值)

INTER_CUBIC——双三次样条插值

INTER_LANCZOS4——Lanczos插值

第六个参数:边界模式

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

3、基本重映射

说明:下面是精简后的以remap函数为核心的示例程序

#include<opencv2/opencv.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<iostream>
using namespace std;
using namespace cv;
int main()
{
  Mat srcImage, dstImage;
  Mat map_x, map_y;
  //载入原始图像
  srcImage = imread("E:\\Pec\\car.jpg", 1);
  imshow("【原始图】", srcImage);
  //创建和原始图一样的效果图,x重映射图,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
  for (int j = 0; j < srcImage.rows; j++)
  {
    for (int i = 0; i < srcImage.cols; i++)
    {
            //通过at获取像素值
      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(0);
}

4、实现多重映射
#include<opencv2/opencv.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<iostream>
using namespace std;
using namespace cv;
#define WINDOW_NAME "【程序窗口】"
Mat g_srcImage, g_dstImage;
Mat g_map_x, g_map_y;
int update_map(int key);
static void ShowHelpText();
int main()
{
  system("color 2F");
  ShowHelpText();
  //载入原始图像
  g_srcImage = imread("E:\\Pec\\car.jpg", 1);
  imshow("【原始图】", g_srcImage);
  //创建和原始图一样的效果图,x重映射图,y重映射图
  g_dstImage.create(g_srcImage.size(), g_srcImage.type());
  g_map_x.create(g_srcImage.size(), CV_32FC1);
  g_map_y.create(g_srcImage.size(), CV_32FC1);
  namedWindow(WINDOW_NAME, WINDOW_AUTOSIZE);
  imshow(WINDOW_NAME, g_srcImage);
  while (1)
  {
    int key = waitKey(0);
    if ((key & 255) == 27)
    {
      cout << "程序退出......" << endl;
      break;
    }
    update_map(key);
    //根据按下键盘按键来更新map_x & map_y的值,然后调用remap()进行重映射
    remap(g_srcImage, g_dstImage, g_map_x, g_map_y, INTER_LINEAR, BORDER_CONSTANT, Scalar(0, 0, 0));
    imshow(WINDOW_NAME, g_dstImage);
  }
  return 0;
}
int update_map(int key)
{
  //双层循环,遍历每一个像素点,改变map_x和Map_y
  for (int j = 0; j < g_srcImage.rows; j++)
  {
    for (int i = 0; i < g_srcImage.cols; i++)
    {
      switch (key)
      {
        case '1'://按键1按下,进行第一重映射操作
          if (i > g_srcImage.cols*0.25&&i<g_srcImage.cols*0.75&&j>g_srcImage.rows*0.25&&j < g_srcImage.rows*0.75)
          {
            g_map_x.at<float>(j, i) = 2 * (i - g_srcImage.cols*0.25) + 0.5;
            g_map_y.at<float>(j, i) = 2 * (j - g_srcImage.rows*0.25) + 0.5;
          }
          else
          {
            g_map_x.at<float>(j, i) = 0;
            g_map_y.at<float>(j, i) = 0;
          }
          break;
        case '2': //按键2按下,进行第二重映射操作
          g_map_x.at<float>(j, i) = static_cast<float>(i);
          g_map_y.at<float>(j, i) = static_cast<float>(g_srcImage.rows - j);
          break;
        case '3':
          g_map_x.at<float>(j, i) = static_cast<float>(g_srcImage.cols-i);
          g_map_y.at<float>(j, i) = static_cast<float>(j);
          break;
        case '4':
          g_map_x.at<float>(j, i) = static_cast<float>(g_srcImage.cols - i);
          g_map_y.at<float>(j, i) = static_cast<float>(g_srcImage.rows - j);
          break;
      }
    }
  }
  return 1;
}
static void ShowHelpText()
{
  cout << "\n\n\n\t欢迎来到重映射示例程序\n";
  cout << "\n\n\n\t按键操作如下:" ;
  cout << "\n\n\n\t键盘按下【ESC】-退出程序" ;
  cout << "\n\n\n\t键盘按下【1】-第一种映射方式,缩小2倍" ;
  cout << "\n\n\n\t键盘按下【2】-第二种映射方式,y方向翻转" ;
  cout << "\n\n\n\t键盘按下【3】-第三种映射方式,x方向反转" ;
  cout << "\n\n\n\t键盘按下【4】-第四种映射方式,x,y方向反转" ;
}

第一种映射方式,缩小2倍

第二种映射方式,y方向翻转

第三种映射方式,x方向反转

第四种映射方式,x,y方向反转

相关文章
|
8月前
GEE——Google dynamic world中在影像导出过程中无法完全导出较大面积影像的解决方案(投影的转换)EPSG:32630和EPSG:4326的区别
GEE——Google dynamic world中在影像导出过程中无法完全导出较大面积影像的解决方案(投影的转换)EPSG:32630和EPSG:4326的区别
151 0
|
8月前
|
存储 算法 数据可视化
|
8月前
|
计算机视觉 Python
OpenCV 4基础篇| OpenCV图像的拆分和合并
OpenCV 4基础篇| OpenCV图像的拆分和合并
|
8月前
|
传感器 数据采集 编解码
基于EinScan-S的编码结构光方法空间三维模型重建
基于EinScan-S的编码结构光方法空间三维模型重建
|
8月前
|
计算机视觉
OpenCV(九):LUT查找表
OpenCV(九):LUT查找表
222 0
|
传感器 编解码 计算机视觉
使用星凸随机超曲面模型对扩展对象和分组目标进行形状跟踪(Matlab代码实现)
使用星凸随机超曲面模型对扩展对象和分组目标进行形状跟踪(Matlab代码实现)
161 0
使用星凸随机超曲面模型对扩展对象和分组目标进行形状跟踪(Matlab代码实现)
STM32端口重映射的问题
STM32端口重映射的问题
153 0
|
存储 计算机视觉 C++
【OpenCV • c++】颜色数据结构与颜色空间转换
【OpenCV • c++】颜色数据结构与颜色空间转换
376 0
|
计算机视觉
三天学会opencv(十一)——形态学操作应用-提取水平与垂直线
三天学会opencv(十一)——形态学操作应用-提取水平与垂直线
129 0
三天学会opencv(十一)——形态学操作应用-提取水平与垂直线
|
存储 API C#
C#编程学习12:使用ArcEngine+C#进行栅格数据读取和像素值修改思路剖析
C#编程学习12:使用ArcEngine+C#进行栅格数据读取和像素值修改思路剖析

热门文章

最新文章