OpenCV 实现重新映射

返回:OpenCV系列文章目录(持续更新中......)

上一篇:OpenCV 实现霍夫圆变换
下一篇 :OpenCV实现仿射变换

目标

在本教程中,您将学习如何:

一个。使用 OpenCV 函数 cv::remap 实现简单的重新映射例程。

理论

什么是重映射?

  • 它是从图像中的一个位置获取像素并将它们定位在新图像中的另一个位置的过程。
  • 为了完成映射过程,可能需要对非整数像素位置进行一些插值,因为源图像和目标图像之间并不总是存在一对一的像素对应关系。
  • 我们可以表示每个像素位置的重新映射(x,y)如:

      

    哪里g()是重新映射的图像,f()源图像和ℎ(x,y)是操作的映射函数(x,y).

  • 让我们举个简单的例子。想象一下,我们有一个图像我而且,比如说,我们想做一个重新映射,以便:

      

    会发生什么?很容易看出,图像会在x方向。例如,考虑输入图像:

观察红色圆圈相对于 x 如何改变位置(考虑到x水平方向):

  • 在 OpenCV 中,函数 cv::remap 提供了一个简单的重新映射实现。

Code

C++JavaPython

  • What does this program do?
    • Loads an image
    • Each second, apply 1 of 4 different remapping processes to the image and display them indefinitely in a window.
    • Wait for the user to exit the program
  • The tutorial code's is shown lines below. You can also download it from here
     
    #include "opencv2/imgcodecs.hpp"
    #include "opencv2/highgui.hpp"
    #include "opencv2/imgproc.hpp"
    #include <iostream>
     
    using namespace cv;
     
    void update_map( int &ind, Mat &map_x, Mat &map_y );
     
    int main(int argc, const char** argv)
    {
     CommandLineParser parser(argc, argv, "{@image |chicky_512.png|input image name}");
     std::string filename = parser.get<std::string>(0);
     Mat src = imread( samples::findFile( filename ), IMREAD_COLOR );
     if (src.empty())
     {
     std::cout << "Cannot read image: " << filename << std::endl;
     return -1;
     }
     
     Mat dst(src.size(), src.type());
     Mat map_x(src.size(), CV_32FC1);
     Mat map_y(src.size(), CV_32FC1);
     
     const char* remap_window = "Remap demo";
     namedWindow( remap_window, WINDOW_AUTOSIZE );
     
     int ind = 0;
     for(;;)
     {
     update_map(ind, map_x, map_y);
     remap( src, dst, map_x, map_y, INTER_LINEAR, BORDER_CONSTANT, Scalar(0, 0, 0) );
     
     imshow( remap_window, dst );
     
     char c = (char)waitKey( 1000 );
     if( c == 27 )
     {
     break;
     }
     }
     return 0;
    }
     
    void update_map( int &ind, Mat &map_x, Mat &map_y )
    {
     for( int i = 0; i < map_x.rows; i++ )
     {
     for( int j = 0; j < map_x.cols; j++ )
     {
     switch( ind )
     {
     case 0:
     if( j > map_x.cols*0.25 && j < map_x.cols*0.75 && i > map_x.rows*0.25 && i < map_x.rows*0.75 )
     {
     map_x.at<float>(i, j) = 2*( j - map_x.cols*0.25f ) + 0.5f;
     map_y.at<float>(i, j) = 2*( i - map_x.rows*0.25f ) + 0.5f;
     }
     else
     {
     map_x.at<float>(i, j) = 0;
     map_y.at<float>(i, j) = 0;
     }
     break;
     case 1:
     map_x.at<float>(i, j) = (float)j;
     map_y.at<float>(i, j) = (float)(map_x.rows - i);
     break;
     case 2:
     map_x.at<float>(i, j) = (float)(map_x.cols - j);
     map_y.at<float>(i, j) = (float)i;
     break;
     case 3:
     map_x.at<float>(i, j) = (float)(map_x.cols - j);
     map_y.at<float>(i, j) = (float)(map_x.rows - i);
     break;
     default:
     break;
     } // end of switch
     }
     }
     ind = (ind+1) % 4;
    }

解释

  • 加载图像

     
     Mat src = imread( samples::findFile( filename ), IMREAD_COLOR );
     if (src.empty())
     {
     std::cout << "Cannot read image: " << filename << std::endl;
     return -1;
     }

  • 创建目标映像和两个映射矩阵(对于 x 和 y )

    Mat dst(src.size(), src.type());
     Mat map_x(src.size(), CV_32FC1);
     Mat map_y(src.size(), CV_32FC1);

  • 创建一个窗口以显示结果

     const char* remap_window = "Remap demo";
     namedWindow( remap_window, WINDOW_AUTOSIZE );

  • 建立循环。每隔 1000 毫秒,我们就会更新映射矩阵(mat_x 和 mat_y),并将它们应用于我们的源图像:

     int ind = 0;
     for(;;)
     {
     update_map(ind, map_x, map_y);
     remap( src, dst, map_x, map_y, INTER_LINEAR, BORDER_CONSTANT, Scalar(0, 0, 0) );
     
     imshow( remap_window, dst );
     
     char c = (char)waitKey( 1000 );
     if( c == 27 )
     {
     break;
     }
     }

void update_map( int &ind, Mat &map_x, Mat &map_y )
{
 for( int i = 0; i < map_x.rows; i++ )
 {
 for( int j = 0; j < map_x.cols; j++ )
 {
 switch( ind )
 {
 case 0:
 if( j > map_x.cols*0.25 && j < map_x.cols*0.75 && i > map_x.rows*0.25 && i < map_x.rows*0.75 )
 {
 map_x.at<float>(i, j) = 2*( j - map_x.cols*0.25f ) + 0.5f;
 map_y.at<float>(i, j) = 2*( i - map_x.rows*0.25f ) + 0.5f;
 }
 else
 {
 map_x.at<float>(i, j) = 0;
 map_y.at<float>(i, j) = 0;
 }
 break;
 case 1:
 map_x.at<float>(i, j) = (float)j;
 map_y.at<float>(i, j) = (float)(map_x.rows - i);
 break;
 case 2:
 map_x.at<float>(i, j) = (float)(map_x.cols - j);
 map_y.at<float>(i, j) = (float)i;
 break;
 case 3:
 map_x.at<float>(i, j) = (float)(map_x.cols - j);
 map_y.at<float>(i, j) = (float)(map_x.rows - i);
 break;
 default:
 break;
 } // end of switch
 }
 }
 ind = (ind+1) % 4;
}

结果

  1. 编译上面的代码后,您可以执行它,并给出一个图像路径作为参数。例如,使用下图:

  1. 这是将其减小到一半大小并居中的结果:

  1. 把它颠倒过来:

  1. 在 x 方向上反映它

  1. 在两个方向上反映它:


参考文献:

1、《Remapping》------Ana Huamán

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Socket编程实验

文章目录 服务端&#xff1a;客户端&#xff1a;使用说明&#xff1a;封装后服务端&#xff1a;封装后客户端 听学弟学妹们反馈&#xff0c;好像老师发的socket编程实验指导里的代码跑不起来。 今天花了一大把时间写了下socket编程代码 现在附上能跑的c代码&#xff1a; 最重要…

nosql数据库 redis

一、介绍 1、redis与mysql的区别&#xff1a; Redis是一种基于键值对的内存数据库&#xff0c;数据存储在内存中&#xff0c;因此读写速度非常快。它支持多种数据结构&#xff0c;如字符串、哈希、列表等。 MySQL是一种关系型数据库&#xff0c;数据以表格的形式组织存储在磁…

12.6.1 实验5:IOS恢复

1、实验目的 通过本实验可以掌握&#xff1a; copy方式恢复IOS的步骤。TFTPDNLD方式恢复IOS的步骤。Xmodem方式恢复IOS的步骤。 2、实验拓扑 路由器IOS恢复的实验拓扑如下图所示。 3、实验步骤 如果工作中不慎误删除路由器IOS&#xff0c;或者升级了错误版本的IOS&#xff…

Sylar C++高性能服务器学习记录06 【线程模块-代码分析篇】

早在19年5月就在某站上看到sylar的视频了&#xff0c;一直认为这是一个非常不错的视频&#xff0c;还有幸加了sylar本人的wx&#xff0c;由于本人一直是自学编程&#xff0c;基础不扎实&#xff0c;也没有任何人的督促&#xff0c;没能坚持下去&#xff0c;每每想起倍感惋惜。恰…

机器学习day3

一、距离度量 1.欧氏距离 2.曼哈顿距离 3.切比雪夫距离 4.闵可夫斯基距离 二、特征与处理 1.数据归一化 数据归一化是一种将数据按比例缩放&#xff0c;使之落入一个小的特定区间的过程。 代码实战 运行结果 2.数据标准化 数据标准化是将数据按照其均值和标准差进行缩放的过…

2024最新版JavaScript逆向爬虫教程-------基础篇之面向对象

目录 一、概念二、对象的创建和操作2.1 JavaScript创建对象的方式2.2 对象属性操作的控制2.3 理解JavaScript创建对象2.3.1 工厂模式2.3.2 构造函数2.3.3 原型构造函数 三、继承3.1 通过原型链实现继承3.2 借用构造函数实现继承3.3 寄生组合式继承3.3.1 对象的原型式继承3.3.2 …

paddle ocr v4 微调训练文字识别模型实践

识别步骤参考&#xff1a;https://github.com/PaddlePaddle/PaddleOCR/blob/main/doc/doc_ch/recognition.md 微调步骤参考:https://github.com/PaddlePaddle/PaddleOCR/blob/release/2.7.1/doc/doc_ch/finetune.md 训练必要性 原始模型标点符号和括号容易识别不到 数据准备…

【漏洞复现】Weblogic 任意文件上传漏洞(CVE-2018-2894)

漏洞简介 Oracle在7月更新中&#xff0c;修复了Weblogic Web Service Test Page中一处任意文件上传漏洞&#xff0c;Web Service Test Page在"生产模式"下默认不开启&#xff0c;所以该漏洞有一定限制&#xff0c;利用该漏洞&#xff0c;可以上传任意.jsp文件&#x…

用Redis实现获取验证码,外加安全策略

安全策略 一小时内只能获取三次&#xff0c;一天内只能获取五次 Redis存储结构 代码展示 import cn.hutool.core.util.RandomUtil; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.junit.jupiter.api.Test; import org.spri…

正点原子[第二期]Linux之ARM(MX6U)裸机篇学习笔记-6

前言&#xff1a; 本文是根据哔哩哔哩网站上“正点原子[第二期]Linux之ARM&#xff08;MX6U&#xff09;裸机篇”视频的学习笔记&#xff0c;在这里会记录下正点原子 I.MX6ULL 开发板的配套视频教程所作的实验和学习笔记内容。本文大量引用了正点原子教学视频和链接中的内容。…

RK3588 - RKNN(Rockchip 神经处理单元)的逆向工程

本文翻译自https://jas-hacks.blogspot.com/2024/02/rk3588-reverse-engineering-rknn.html RK3588 NPU 的内部操作和功能主要隐藏在名为RKNPU2的闭源 SDK 中。由于对大型语言模型 (LLM) 的兴趣以及对transform模型最佳矩阵乘法的追求&#xff0c;想了解 RKNPU SDK 新引入的矩阵…

值得让英伟达CEO黄仁勋亲自给OpenAI配送的AI服务器!一文带你了解算力,GPU,CPU!

大家好&#xff0c;我是木易&#xff0c;一个持续关注AI领域的互联网技术产品经理&#xff0c;国内Top2本科&#xff0c;美国Top10 CS研究生&#xff0c;MBA。我坚信AI是普通人变强的“外挂”&#xff0c;所以创建了“AI信息Gap”这个公众号&#xff0c;专注于分享AI全维度知识…

【C++】双指针算法:和为s的两个数字

1.题目 虽然在牛客上是个中等题&#xff0c;但我感觉是比较简单的。大家在看完这篇文章后可以看看我的上一篇文章&#xff1a;有效三角形的个数。本文章的题目的解法只是有效三角形的个数这道题目的一个环节。看懂这篇文章后可以更好的解决有效三角形个数那道题目&#xff01; …

电力系统IEC-104报文主要常用详解

文章目录 1️⃣ IEC-1041.1 前言1.2 报文分类1.3 U帧报文1.3.1 常见报文1.3.1 报文解析 1.4 S帧报文1.4.1 说明1.4.2 报文解析 1.5 I帧报文1.5.1 报文解析 1.6 控制域I帧报文S帧报文U帧报文介绍 1.7 ASDU1.7.1 常见类型标识1.7.2 常见结构限定词1.7.3 常见传送原因1.7.4 信息体…

艾瑞泽5汽车电子控制单元CAN通信数据读写车辆网络系统交互接口

艾瑞泽5的网关接口数据交换通常涉及车辆内部电子设备之间的信息传输&#xff0c;包括车身系统、娱乐系统、远程控制、车辆状态监控、CAN数据采集分析、整车DBC控制策略等信息。 艾瑞泽5作为一款采用CAN协议的汽车&#xff0c;其CAN通信的开发可以提高车辆的安全性、可靠性和实…

Visual Studio Code使用

目录 1.python的调试 2.c的运行 方法1&#xff1a; 方法2&#xff1a; 3.c的调试 3.1调试方法一&#xff1a;先生成执行文件&#xff0c;再调试 3.2调试方法二&#xff1a;同时生成执行文件&#xff0c;调试 4.tasks.json 与launch.json文件的参考 4.1C生成执行文件tas…

uniapp H5实现签名

第一种&#xff1a;跳转签名页面 1、创建审核页面audit.vue <template><view><uni-section title""><view class"auditClass"><uni-forms :model"baseFormData" ref"baseFormRef" :rules"rules&quo…

数据结构初阶——树和二叉树

数据结构初阶——树和二叉树 1. 树的概念和结构1.1 树的概念1.2 树的表示 2. 二叉树2.1 二叉树的概念和结构2.2 二叉树的存储结构2.2.1 顺序存储2.2.2 链式存储 3. 二叉树的顺序结构及实现——堆3.1 堆的概念和结构3.2 堆的实现3.2.1 堆的定义3.2.2 堆的向上调整3.2.3 堆的向下…

【网络安全】安全事件管理处置 — 事件分级分类

专栏文章索引&#xff1a;网络安全 有问题可私聊&#xff1a;QQ&#xff1a;3375119339 目录 一、安全事件分级 二、应急事件分级 三、安全事件分类 四、常见安全事件原因分析 1.web入侵 2.漏洞攻击 3.网络攻击 一、安全事件分级 在对安全事件的应急响应过程中&#xf…

【Hadoop】-Apache Hive概述 Hive架构[11]

目录 Apache Hive概述 一、分布式SQL计算-Hive 二、为什么使用Hive Hive架构 一、Hive组件 Apache Hive概述 Apache Hive是一个在Hadoop上构建的数据仓库基础设施&#xff0c;它提供了一个SQL-Like查询语言来分析和查询大规模的数据集。Hive将结构化查询语言&#xff08;…