OpenCV 实现重新映射(53)

news2024/11/21 2:34:10

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

上一篇:OpenCV 实现霍夫圆变换(52)
下一篇 :OpenCV实现仿射变换(54)

目标

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

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

理论

什么是重映射?

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

      

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

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

      

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

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

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

C++代码
 

  • 这个程序是做什么的?
    • 加载图像
    • 每秒将 4 个不同的重新映射过程中的 1 个应用于图像,并在窗口中无限期地显示它们。
    • 等待用户退出程序
    • 教程代码如下所示。您也可以从这里下载
     
     
    #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

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

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

相关文章

mysql-sql-练习题-4-标记(排名 条件判断)

标记 标记找规律连续登录2-7天用户建表排名找规律 最大连胜次数建表多次排名 找规律输出更多数据 标记计数 百分比 标记找规律 连续登录2-7天用户 建表 create table continuous_login(user_id1 integer comment 用户id,date_login date comment 登陆日期 ) comment 用户登录…

一加12/11/10/Ace2/Ace3手机上锁回锁BL无限重启黑屏9008模式救砖

一加12/11/10/Ace2/Ace3手机官方都支持解锁BL&#xff0c;搞机的用户也比较多&#xff0c;相对于其他品牌来说&#xff0c;并没有做出限制&#xff0c;这也可能是搞机党最后的救命稻草。而厌倦了root搞机的用户&#xff0c;就习惯性回锁BL&#xff0c;希望彻底变回官方原来的样…

约瑟夫问题新解法

前言 又碰到了约瑟夫问题&#xff0c;这样的题目本来用环形链表模拟的话就能做出来。然而&#xff0c;最近新学习了一种做法&#xff0c;实在是有点震惊到我了。无论是思路上&#xff0c;还是代码量上&#xff0c;都是那么的精彩。就想也震惊一下其他人。谁能想到原来模拟出来四…

Go-变量

可以理解为一个昵称 以后这个昵称就代指这些信息 var sg string "czy" 声明赋值 package mainimport "fmt"func main() {var sg string "陈政洋"fmt.Println(sg)var age int 73fmt.Println(age)var flag bool truefmt.Println(flag) } …

【JVM】内存调优——内存泄漏、内存溢出

内存调优 什么是内存泄漏、内存泄漏&#xff1f; 内存泄漏&#xff1a;在Java中如果不再使用一个对象&#xff0c;但是该对象依然在GC ROOT的引用链上&#xff0c;这个对象就不会被垃圾回收器回收。内存溢出&#xff1a;内存的使用量超过了Java虚拟机可以分配的上限&#xff…

ARP欺骗使局域网内设备断网

一、实验准备 kali系统&#xff1a;可使用虚拟机软件模拟 kali虚拟机镜像链接&#xff1a;https://www.kali.org/get-kali/#kali-virtual-machines 注意虚拟机网络适配器采用桥接模式 局域网内存在指定断网的设备 二、实验步骤 打开kali系统命令行&#xff1a;ctrlaltt可快…

栈的表达式求值中的应用——逆波兰表达式求值+中缀表达式转后缀表达式

文章目录 1. 逆波兰表达式&#xff08;后缀表达式&#xff09;求值思路讲解AC代码 2. 中缀表达式转后缀表达式分析方法总结 3. 中缀表达式求值 1. 逆波兰表达式&#xff08;后缀表达式&#xff09;求值 链接: link 这道题目叫做逆波兰表达式求值&#xff0c;那什么是逆波兰表…

使用PyTorch从头实现Transformer

前言 本文使用Pytorch从头实现Transformer&#xff0c;原论文Attention is all you need paper&#xff0c;最佳解读博客&#xff0c;学习视频GitHub项目地址Some-Paper-CN。本项目是译者在学习长时间序列预测、CV、NLP和机器学习过程中精读的一些论文&#xff0c;并对其进行了…

05月04日(周六)30场比赛前瞻

今日数据&#xff1a; 昨日复盘&#xff1a; 欧洲五大联赛指的是欧洲影响力及竞技水平排名前五的足球联赛&#xff0c;通常包括英格兰足球联赛&#xff08;The Premier League&#xff09;、西班牙足球甲级联赛&#xff08;La Liga&#xff09;、意大利足球甲级联赛&#xff0…

vue2人力资源项目3主页

主页权限验证 前置守卫开启进度条&#xff0c;后置守卫关闭进度条 import router from /router import nProgress from nprogress// 导入进度条&#xff08;模板自带&#xff09; import nprogress/nprogress.css// 导入进度条样式&#xff08;模板自带&#xff09; // 前置守…

java中对文件的基本操作

文件IO 文件IO。啥叫文件的IO&#xff1f; 他就是指&#xff1a;1.Input&#xff08;输入&#xff09;2.Output&#xff08;输出&#xff09;。 比如&#xff0c;我们的电脑可以从网络中下载文件&#xff0c;也可以通过网络上传文件等等很多的例子&#xff0c;都体现了输入和…

Xamarin.Android项目使用ConstraintLayout约束布局

Xamarin.AndroidX.ConstraintLayout Xamarin.Android.Support.Constraint.Layout Xamarin.AndroidX.ConstraintLayout.Solver Xamarin.AndroidX.DataBinding.ViewBinding Xamarin.AndroidX.Legacy.Support.Core.UI Xamarin.AndroidX.Lifecycle.LiveData ![在这里插入图片描述]…

android天气实战

页面绘制 问题1、下拉框需要背景为透明 我懒得写全部省份就写了5个所以不需要往下 图标准备 iconfont-阿里巴巴矢量图标库几坤年没来这了好怀念啊&#xff0c;图标库选择下雨的图标等 准备网络请求 0、API接口准备 api免费七日天气接口API 未来一周天气预报api (tianqiap…

SVM直观理解

https://tangshusen.me/2018/10/27/SVM/ https://www.bilibili.com/video/BV16T4y1y7qj/?spm_id_from333.337.search-card.all.click&vd_source8272bd48fee17396a4a1746c256ab0ae SVM是什么? 先来看看维基百科上对SVM的定义: 支持向量机&#xff08;英语&#xff1a;su…

[BLE] Heart Rate Protocol - Sensor

写在前面 目前我从网上找到的有关BLE心率协议的博文内容良莠不齐&#xff0c;很难让人根据文章内容来全面理解心率服务&#xff1b;此外SIG网站上有关心率服务的文档比较多&#xff0c;内容比较碎&#xff0c;需要读者从多个文档中将需要的内容拼接起来&#xff0c;因此写下这…

【动态规划】路径问题|不同路径I|不同路径II|珠宝的最高价值|下降路径的最小和|最小路径和|

一、不同路径I 62. 不同路径 - 力扣&#xff08;LeetCode&#xff09; &#x1f4a1;细节&#xff1a; 1.多开一行和一列&#xff08;跟一维数组多开一个位置一样&#xff09;&#xff0c;这样方便初始化 2.状态转移方程&#xff1a;注意走一步并不是多一种走的路径&#xff0…

在编程的世界里,我相信每一行代码都是一次对未来的投资

&#x1f600;前言 突然有感而发也是激励自己互勉 &#x1f3e0;个人主页&#xff1a;尘觉主页 文章目录 在编程的世界里&#xff0c;我相信每一行代码都是一次对未来的投资类似句子编程的本质代码的价值构建可持续的未来结语 在编程的世界里&#xff0c;我相信每一行代码都是一…

数据库基础--MySQL多表查询之外键约束

MySQL多表关系 一对一 顾名思义即一个对应一个的关系&#xff0c;例如身份证号对于每个人来说都是唯一的&#xff0c;即个人信息表与身份证号信息表是一对一的关系。车辆信息表与车牌信息表也是属于一对一的关系。 一对多 即一个表当中的一个字段信息&#xff0c;对应另一张…

【数据库原理及应用】期末复习汇总高校期末真题试卷02

试卷 一、填空题 数据库系统是指计算机系统中引入数据库后的系统&#xff0c;一般由数据库、________、应用系统、数据库管理员和用户构成。当数据库的存储结构发生了改变&#xff0c;由数据库管理员对________映象作相应改变&#xff0c;可以使________保持不变&#xff0c;…

vue快速入门(五十一)历史模式

注释很详细&#xff0c;直接上代码 上一篇 新增内容 历史模式配置方法 默认哈希模式&#xff0c;历史模式与哈希模式在表层的区别是是否有/#/ 其他差异暂不深究 源码 //导入所需模块 import Vue from "vue"; import VueRouter from "vue-router"; import m…