OpenCV中的像素重映射原理及实战分析

news2024/11/24 4:48:16

引言

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

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

 

一、什么是像素重映射

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

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

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

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

7ebf7ae6da174ab1b2603896f7a83982.jpeg

没错,就是轴对称,左右翻转。 这就是数学的魅力。我们一起来体验一下。

 

二、像素重映射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/2),左右翻转,上下翻转,中心旋转。下面的图表示的就是四种变换模式:

e52d377734ff489e911cf7251e4ba53a.jpeg

最简单的是翻转了,行不变,第一列跟最后一列转换,第二列跟倒数第二列转换……这样就实现了左右翻转。同理,列不变,行转换,实现上下翻转。如果上下左右都翻转,那就是旋转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<float>(row, col) = 2 * (col - (img.cols*0.25));
          map_y.at<float>(row, col) = 2 * (row - (img.rows*0.25) - 0.25);
        }
        else
        {
          map_x.at<float>(row, col) = 0;
          map_y.at<float>(row, col) = 0;
        }
        break;
      case 1:
        map_x.at<float>(row, col) = (img.cols - col - 1);
        map_y.at<float>(row, col) = row;
        break;
      case 2:
        map_x.at<float>(row, col) = col;
        map_y.at<float>(row, col) = (img.rows - row - 1);
        break;
      case 3:
        map_x.at<float>(row, col) = (img.cols - col - 1);
        map_y.at<float>(row, col) = (img.rows - row - 1);
        break;

      default:
        break;
     }
   }
}

效果如下图所示:

ecb7d84752b242a18635278c4568cb24.jpeg

x和y都加上0.5

83f4b3f5f12947faaccc9ea5f27b8b79.jpeg 

x和y都不加0.5 

2c54098148c644aa9f0c0f4f2622c1ad.jpeg 

 x不加,y-0.25

 

完整代码

#define INPUT_TITLE "input image"
#define OUTPUT_TITLE "remap image"

#include<iostream>
#include<opencv2\opencv.hpp>

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:/测试程序/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<float>(row, col) = 2 * (col - (img.cols*0.25));
          map_y.at<float>(row, col) = 2 * (row - (img.rows*0.25)-0.25);
        }
        else
        {
          map_x.at<float>(row, col) = 0;
          map_y.at<float>(row, col) = 0;
        }
        break;
      case 1:
        map_x.at<float>(row, col) = (img.cols - col - 1);
        map_y.at<float>(row, col) = row;
        break;
      case 2:
        map_x.at<float>(row, col) = col;
        map_y.at<float>(row, col) = (img.rows - row - 1);
        break;
      case 3:
        map_x.at<float>(row, col) = (img.cols - col - 1);
        map_y.at<float>(row, col) = (img.rows - row - 1);
        break;

      default:
        break;
      }
    }
  }
}

 效果图

b65783ef2f644e729f04ce58acfede70.jpeg

a474b1884bba48cab6b4693a5049a00d.jpeg

4ed94ad2f3b449f7952ac420185123d0.jpeg

ea5589bfb59b434f982544e01950cd6f.jpeg

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1217870.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

最新计算机网络考试试题分析与整理

博主今天下午刚刚考完试&#xff0c;针对今天计网考试知识点进行整理总结&#xff0c;希望可以对大家有所帮助~ 目录 1.先看简答大题共五道 1.1CRC冗余码计算 1.2tcp拥塞控制 1.3tcp报文段 1.4RIP路由表更新 1.5子网划分 2.再看填空题七道 2.1网络边缘端系统间的通信关…

ClickHouse的表引擎

1 表引擎的使用 表引擎是ClickHouse的一大特色。可以说&#xff0c; 表引擎决定了如何存储表的数据。包括&#xff1a; 数据的存储方式和位置&#xff0c;写到哪里以及从哪里读取数据。支持哪些查询以及如何支持。并发数据访问。索引的使用&#xff08;如果存在&#xff09;。是…

安装最新版IntelliJ IDEA来开发Java应用程序

安装最新版IntelliJ IDEA来开发Java应用程序 Install the Latest Version of IntelliJ IDEA to Develop Java Applications 本文简要介绍如何安装配置JetBrains IntelliJ IDEA集成开发环境&#xff0c;从而开发Java应用程序&#xff1b;文中侧重实际操作和编程步骤&#xff0…

海康Visionmaster-环境配置:VB.Net 二次开发环境配 置方法

Visual Basic 进行 VM 二次开发的环境配置分为三步。 第一步&#xff0c;使用 VS 新建一个框架为.NET Framework 4.6.1&#xff0c;平台去勾选首选 32 为的工程&#xff0c;重新生成解决方案&#xff0c;保证工程 Debug 下存在 exe 文件&#xff0c;最后关闭新建工程&#xff1…

51单片机应用从零开始(五)·加减乘除运算

51单片机应用从零开始&#xff08;一&#xff09;-CSDN博客 51单片机应用从零开始&#xff08;二&#xff09;-CSDN博客 51单片机应用从零开始&#xff08;三&#xff09;-CSDN博客 51单片机应用从零开始&#xff08;四&#xff09;-CSDN博客 详解 KEIL C51 软件的使用建立工程…

2023年05月 Python(六级)真题解析#中国电子学会#全国青少年软件编程等级考试

Python等级考试(1~6级)全部真题・点这里 一、单选题(共25题,每题2分,共50分) 第1题 明明每天坚持背英语单词,他建立了英语单词错题本文件“mistakes.txt”,将每天记错的单词增加到该文件中,下列打开文件的语句最合适的是?( ) A: f = open(“mistakes.txt”) B: …

基于SSM的学生疫情信息管理系统设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

C++打怪升级(十一)- STL之list

~~~~ 前言1. list是什么2. list接口函数的使用1. 构造相关默认构造n个val构造迭代器范围构造拷贝构造 2 赋值运算符重载函数2 析构函数3 迭代器相关begin 和 endrbegin 和rend 4 容量相关emptysize 5 元素访问相关frontback 6 修改相关push_backpop_backpush_frontpop_frontins…

Codewhisperer 使用评价

最近亚⻢逊推出了一款基于机器学习的 AI 编程助手 Amazon CodeWhisperer&#xff0c;可以实时提供代码建议。在编写代码时&#xff0c;它会自动根据现有的代码和注释给出建议。Amazon CodeWhisperer 与GitHub Copilot类似&#xff0c;主要的功能有: 代码补全注释和文档补全代码…

SpringCloud-Gateway修改Response响应体,并解决大数据量返回不全等问题

官网相关案例&#xff1a; Spring Cloud Gatewayhttps://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#the-modifyresponsebody-gatewayfilter-factory ModifyRequestBodyGatewayFilterFactory类: https://github.com/spring-cloud/spring-cloud-gate…

设计基于STM32F103C8T6微控制器的巡线小车

巡线小车是一种能够在一条预定线追踪路径的小车&#xff0c;广泛应用于工业自动化、物流仓储、智能家居等领域。本设计将使用STM32F103C8T6微控制器来实现一个基础的巡线小车。 硬件组成&#xff1a;1. STM32F103C8T6微控制器开发板&#xff1a;作为巡线小车的核心控制器&…

MFC保存窗口客户区为图片

首先的窗口输出一些内容&#xff1b; 菜单单击函数代码&#xff1b; void CgetmypicView::OnTestGetmypic() {// TODO: 在此添加命令处理程序代码HWND hwnd this->GetSafeHwnd();HDC hDC ::GetWindowDC(hwnd);//获取DC RECT rect;::GetClientRect(hwnd, &rect)…

windows与wsl互传文件

1.把windows上的文件传到wsl中&#xff0c;\\wsl.localhost\Ubuntu-22.04\mnt\wsl 将你要传的文件放到wsl这个路径下&#xff0c;Ubuntu-22.04是我的子系统&#xff0c;换成自己对应的 2.把wsl中的文件传到windows中 将wsl中的文件放到 /mnt/c 或 /mnt/d 中&#xff0c;这两…

ClickHouse SQL操作

基本上来说传统关系型数据库&#xff08;以MySQL为例&#xff09;的SQL语句&#xff0c;ClickHouse基本都支持&#xff0c;这里不会从头讲解SQL语法只介绍ClickHouse与标准SQL&#xff08;MySQL&#xff09;不一致的地方。 1 Insert 基本与标准SQL&#xff08;MySQL&#xff09…

python趣味编程-5分钟实现一个简单贪吃蛇游戏(含源码、步骤讲解)

在本教程《如何用 Python 制作游戏》中,我们将为名为“简单贪吃蛇游戏”的游戏制作一个程序。 Python 中的贪吃蛇游戏:项目信息 项目名称:Python 游戏摘要:Python提供了一个名为pygame的内置库,用于开发游戏。使用的语言:Python 与 Tkinter GUI 库Python版本(推荐):2.…

Python ... takes 0 positional arguments but 1 was given

最近&#xff0c;博主在学习python时遇到这么个报错&#xff0c; 系统&#xff1a;windows10 开发环境&#xff1a;VS Code Python版本&#xff1a;3.12 错误重现&#xff1a; class Dog:def __init__(self):passdef eatSomething(self):self.eatBone()def eatBone():prin…

NewStarCTF2023 Reverse Week3 EzDLL WP

分析 这里调用了z3h.dll中的encrypt函数。 用ida64载入z3h.dll 直接搜索encrypt 找到了一个XTEA加密。接着回去找key和密文。 发现key 这里用了个调试状态来判断是否正确&#xff0c;v71&#xff0c;要v7&#xff1d;1才会输出Right&#xff0c;即程序要处于飞调试状态。 可…

spark性能调优 | 内存优化

目录 我们先了解一下有哪些内存温馨提示RDD示范(spark版本2.1.1)RDD进行优化Df和Ds进行示范 我们先了解一下有哪些内存 1.storage内存 存储数据&#xff0c;缓存 可预估2.shuffle内存 计算join groupby 不可预估spark1.6之前 静态管理的&#xff0c;spark1.6之…

Django部署时静态文件配置的坑

Django部署时静态文件配置配置的坑 近期有个需求是用django进行开发部署&#xff0c;结果发现静态文件配置的坑是真的多&#xff0c;另外网上很多的内容也讲不清楚原理&#xff0c;就是这样这样&#xff0c;又那样那样&#xff0c;进了不少坑&#xff0c;这里记录一下关于css,…

SQL基础理论篇(六):多表的连接方式

文章目录 简介笛卡尔积等值连接非等值连接外连接自连接其他SQL92与SQL99中连接的区别不同DBMS下使用连接的注意事项参考文献 简介 SQL92中提供了5类连接方式&#xff0c;分别是笛卡尔积、等值连接、非等值连接、外连接(左连接、右连接、全外连接(full outer join、全连接))和自…