【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方向反转

相关文章
|
5月前
|
计算机视觉 Python
OpenCV中拆分通道、合并通道、alpha通道的讲解及实战演示(附python源码 超详细)
OpenCV中拆分通道、合并通道、alpha通道的讲解及实战演示(附python源码 超详细)
133 0
|
11天前
|
算法 TensorFlow 算法框架/工具
基于直方图的图像阈值计算和分割算法FPGA实现,包含tb测试文件和MATLAB辅助验证
这是一个关于图像处理的算法实现摘要,主要包括四部分:展示了四张算法运行的效果图;提到了使用的软件版本为VIVADO 2019.2和matlab 2022a;介绍了算法理论,即基于直方图的图像阈值分割,通过灰度直方图分布选取阈值来区分图像区域;并提供了部分Verilog代码,该代码读取图像数据,进行处理,并输出结果到&quot;result.txt&quot;以供MATLAB显示图像分割效果。
|
5月前
|
计算机视觉 开发者 Python
OpenCV合并图像中加权和与覆盖的讲解与实战(附Python源码)
OpenCV合并图像中加权和与覆盖的讲解与实战(附Python源码)
96 0
|
2月前
|
计算机视觉 Python
OpenCV 4基础篇| OpenCV图像的拆分和合并
OpenCV 4基础篇| OpenCV图像的拆分和合并
|
2月前
|
存储 算法 数据可视化
|
5月前
|
计算机视觉 Python
使用YOLOv8和PySimpleGUI构建目标计数GUI
使用YOLOv8和PySimpleGUI构建目标计数GUI
|
5月前
|
计算机视觉
OpenCV(六):多通道分离与合并
OpenCV(六):多通道分离与合并
38 0
|
10月前
STM32端口重映射的问题
STM32端口重映射的问题
99 0
|
Java
剪裁NV21任意一部分的代码
剪裁NV21任意一部分的代码
95 0
|
API 计算机视觉
OpenCV 像素重映射(cv::remap)
OpenCV 像素重映射(cv::remap)
510 0
OpenCV 像素重映射(cv::remap)