OpenCV开发笔记(七十五):相机标定矫正中使用remap重映射进行畸变矫正

若该文为原创文章,转载请注明原文出处
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/136293833
各位读者,知识无穷而人力有穷,要么改需求,要么找专业人士,要么自己研究
红胖子(红模仿)的博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结合等等)持续更新中…(点击传送门)

OpenCV开发专栏(点击传送门)

上一篇:《OpenCV开发笔记(七十四):OpenCV3.4.1+ffmpeg3.4.8交叉编译移植到海思平台Hi35xx平台》
下一篇:持续补充中…


前言

  相机标定,重映射可以进行插值映射从而矫正图像,这是一种方法,也有矩阵映射方法,本篇使用重映射方式解说畸变矫正的计算原理。


Demo

  横向纵向区域固定拉伸:
  在这里插入图片描述

  横向纵向拉伸:
  在这里插入图片描述

  右下角拉伸:
  在这里插入图片描述


相机畸变矫正

  标定相机需要做两件事:

  • 纠正畸变的影响
  • 根据图像重构三位场景

纠正畸变的影响

  Opencv提供了可以直接使用的矫正算法,即通过输入原始图像和由函数cv::calibrateCamera()得到的畸变系数,生成校正后的图像。(注意:这里可使用用cv::undistort()使用该算法直接完成所需任务,也可以使用函数cv::iniitUndistorRectifyMap()和cv::remap()来更有效的处理。


矫正映射remap(畸变映射)

  当进行图像矫正时,必须指定输入图像的每个像素在输出图像中移动到的位置,成为“矫正映射”(畸变映射)。

双通道浮点数表示方式

  N x M的矩阵A中,重映射由双通道浮点数的N x M的矩阵B表示,对于图像A中的任意一点aPoint(i, j),映射为b1Point(i’, j’)和b2Point(i’, j’),在A中假设i=2,j=3,那么(假设重映射之后4.5,5.5)在B1中b1Point(i’, j’)值为4.5,b2Point(i’, j’)值为5.5,由于坐标是浮点数,那么需要插值得到整数位置以及中间过渡的区域颜色(平滑处理)。
  在这里插入图片描述

双矩阵浮点数表示方式

  双矩阵浮点数表示,N x M的矩阵A中,重映射由一对N x M的矩阵B和C描述,这里所有的N x M矩阵都是单通道浮点矩阵,在A中的点aPoint(i, j),重映射矩阵B中的点bPoint(i,j)存储了重映射后的i’ (映射后的i坐标), 重映射矩阵C中的点cPoint(i,j)存储了重映射后的j’(映射后的j坐标)。
  在这里插入图片描述

定点表示方式

  映射由双通道有符号整数矩阵(即CV_16SC2类型)表示。该方式与双通道浮点数表示方式相同,但使用此格式要快得多(笔者理解:由浮点数插值改为整数插值,会要快一些,但是肯定双通道浮点数的表示方式图像效果会稍微好一些)。
  在这里插入图片描述


remap核心关键

  在于得到插值的坐标系来映射新位置的x和y位置,要渐近等,所以本方法的核心关键在于得到标定后的矩阵,得到映射矩阵的方式可以自己写算法,也可以使用其他方式,后续文章继续深入这块。


函数原型

void remap( InputArray src,
          OutputArray dst,
          InputArray map1,
          InputArray map2,
          int interpolation,
          int borderMode = BORDER_CONSTANT,
          const Scalar& borderValue = Scalar());
  • 参数一:InputArray类型的src,一般为cv::Mat;
  • 参数二:OutputArray类型的dst,目标图像。它的大小与map1相同,类型与src相同。
  • 参数三:InputArray类型的map1,它有两种可能的表示对象:表示点(x,y)的第一个映射或者表示CV_16SC2 , CV_32FC1 或CV_32FC2类型的x值。
  • 参数四:InputArray类型的map2,它也有两种可能的表示对象,而且他是根据map1来确定表示哪种对象。若map1表示点(x,y)时,这个参数不代表任何值,否则,表示CV_16UC1 , rCV_32FC1类型的y值(第二个值)。
  • 参数五:int类型的interpolation,使用的插值方法;
  • 参数六:int类型的borderMode,边界处理方式;
  • 参数七:Scalar类型的borderValue,重映射后,离群点的背景,需要broderMode设置为BORDER_CONSTRANT时才有效。(离群点:当图片大小为400x300,那么对应的map1和map2范围为0399、0299,小于0或者大于299的则为离散点,使用该颜色填充);

Demo源码

void OpenCVManager::testRemap2()
{
    std::string srcFilePath = "D:/qtProject/openCVDemo/openCVDemo/modules/openCVManager/images/25.jpg";

    // 步骤一:读取文件
    cv::Mat srcMat = cv::imread(srcFilePath);
    // 缩放一下
    int width = 400;
    int height = 400;
    cv::resize(srcMat, srcMat, cv::Size(width, height));
    // 步骤二:映射矩阵
    cv::Mat mapX;
    cv::Mat mapY;
    mapX.create(srcMat.size(), CV_32FC1);
    mapY.create(srcMat.size(), CV_32FC1);
    // 算法:这里400x400,将0~100放大至0~200,将100~400映射为200~400
    // 算法:这里400x400,将0~100放大至0~200,将100~400映射为200~400
#if 0
    for(int row = 0; row < srcMat.rows; row++)
    {
        for(int col = 0; col < srcMat.cols; col++)
        {
//            if(true)
            if(col < 200)
            {
                mapX.at<float>(row, col) = static_cast<float>(col * 1.0f / 2);
            }else{
                mapX.at<float>(row, col) = static_cast<float>(100 + (col - 200) * 1.0f / 2 * 3);
            }
//            if(true)
            if(row < 200)
            {
                mapY.at<float>(row, col) = static_cast<float>(row * 1.0f / 2);
            }else{
                mapY.at<float>(row, col) = static_cast<float>(100 + (row - 200) * 1.0f / 2 * 3);
            }
        }
    }
#endif
#if 0
    for(int row = 0; row < srcMat.rows; row++)
    {
        for(int col = 0; col < srcMat.cols; col++)
        {
            // 这里是 0~200 缩放为 0~100 缩小                               // 比例系数
            if(col == 0)
            {
                mapX.at<float>(row, col) = static_cast<float>(col);
            }else if(col < 200)
            {
                mapX.at<float>(row, col) = static_cast<float>(col * 1.0f / 2 * (col * 1.0f / 199));
            }else{
                mapX.at<float>(row, col) = static_cast<float>(col * 1.0f / 2 * (col * 1.0f / 199));
            }
            if(row == 0)
            {
                mapY.at<float>(row, col) = static_cast<float>(row);
            }else if(row < 200)
            {
                mapY.at<float>(row, col) = static_cast<float>(row * 1.0f / 2 * (row * 1.0f / 199));
            }else{
                mapY.at<float>(row, col) = static_cast<float>(row * 1.0f / 2 * (row * 1.0f / 199));
            }
        }
    }
#endif
#if 1
    for(int row = 0; row < srcMat.rows; row++)
    {
        for(int col = 0; col < srcMat.cols; col++)
        {
            //                                                             比例系数 0~1.0(400~800)/400
            mapX.at<float>(row, col) = static_cast<float>(col * ((col + 1 + 400) * 1.0f / 800));
            mapY.at<float>(row, col) = static_cast<float>(row * ((row + 1 + 400) * 1.0f / 800));
        }
    }
#endif

    cv::Mat dstMat;
    cv::remap(srcMat,
              dstMat,
              mapX,
              mapY,
              CV_INTER_LINEAR,
              cv::BORDER_CONSTANT,
              cv::Scalar(255, 0, 0));

    cv::imshow("1", srcMat);
    cv::imshow(_windowTitle.toStdString(), dstMat);
    cv::waitKey(0);
}

对应工程模板v1.66.0

  在这里插入图片描述


上一篇:《OpenCV开发笔记(七十四):OpenCV3.4.1+ffmpeg3.4.8交叉编译移植到海思平台Hi35xx平台》
下一篇:持续补充中…


本文章博客地址:https://blog.csdn.net/qq21497936/article/details/136293833

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

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

相关文章

【C语言基础】:操作符详解(二)

文章目录 操作符详解一、上期扩展二、单目操作符三、逗号表达式四、下标访问[]、 函数调用()五、结构成员访问操作符六、操作符的属性&#xff1a;优先级、结合性1. 优先级2. 结合性 操作符详解 上期回顾&#xff1a;【C语言基础】&#xff1a;操作符详解(一) 一、上期扩展 …

YOLO学习中的琐碎知识点

目录 一、导入的库 二、名词介绍 &#xff08;1&#xff09;pytorch张量 &#xff08;2&#xff09;边界框&#xff08;bounding box&#xff09; 三、pycharm操作 &#xff08;1&#xff09;参数设置 四、文件认识 五、YOLO如何训练自己的模型 一、导入的库 import to…

五.AV Foundation 视频播放 - 标题和字幕

引言 本篇博客主要介绍使用AV Foundation加载视频资源的时候&#xff0c;如何获取视频标题&#xff0c;获取字幕并让其显示到播放界面。 设置标题 资源标题的元数据内容&#xff0c;我们需要从资源的commonMetadata中获取&#xff0c;在加载AVPlayerItem的时候我们已经指定了…

vue2实现无感刷新token

&#x1f3ac; 江城开朗的豌豆&#xff1a;个人主页 &#x1f525; 个人专栏 :《 VUE 》 《 javaScript 》 &#x1f4dd; 个人网站 :《 江城开朗的豌豆&#x1fadb; 》 ⛺️ 生活的理想&#xff0c;就是为了理想的生活 ! 目录 &#x1f4d8; 引言&#xff1a; &#x1f4…

大概了解一下G1收集器

在上一篇文章中&#xff08;链接&#xff1a;大概了解一下CMS收集器&#xff09;我们提到&#xff0c;CMS是一种主要针对旧生代对象进行回收的收集器。与CMS不同&#xff0c;G1号称“全功能的垃圾收集器”&#xff0c;对初生代内存和旧生代内存均进行管理。鉴于此&#xff0c;这…

如何多环境切换?如何在微服务配置多环境?

问题本质: nacos配置中心的配置是如何被项目读取到的&#xff1f;(nacos的配置中心和项目是如何联系的&#xff1f;) 注意&#xff1a;nacos有配置管理和服务管理&#xff0c;别弄混。自动注册的是服务管理&#xff01;&#xff01;&#xff01; 1. 如何注册到nacos服务管理中心…

如何使用视频号下载提取器提取视频,推荐2种方法使用!

视频号下载提取视频号视频&#xff0c;推荐大家2个方法​&#xff01; 前者简单&#xff0c;后者较为复杂&#xff0c;不过都可以提取视频号视频&#xff0c;大家可根据实际情况来使用​。 视频号下载工具提取器​&#xff1f; 1&#xff1a;通过搜一搜的这款搜索引擎找到自己…

【前端素材】推荐优质后台管理系统Xmino Admin平台模板(附源码)

一、需求分析 后台管理系统通常是指一个用于管理网站、应用程序或系统的管理界面&#xff0c;通常由管理员使用。其功能和设计思路可以根据具体需求和系统复杂性有所不同&#xff0c;但一般包括以下几个方面的功能和设计考虑&#xff1a; 功能分析&#xff1a; 用户管理&…

vant安装教程(基于vue3)

1、先安装 npm i vant 如果不行安装这个 yarn add vant 2、在main.js中引入即可 import { createApp } from vue import App from ./App.vue import router from ./router import store from ./store import { Button } from vant; import vant/lib/index.css;createApp(App).…

qt-C++笔记之事件过滤器

qt-C笔记之事件过滤器 —— 杭州 2024-02-25 code review! 文章目录 qt-C笔记之事件过滤器一.使用事件过滤器和不使用事件过滤器对比1.1.使用事件过滤器1.2.不使用事件过滤器1.3.比较 二.Qt 中事件过滤器存在的意义三.为什么要重写QObject的eventFilter方法&#xff1f;使用QO…

土耳其商务团一行莅临优积科技考察交流

7月31日土耳其商务代表Emre Arif Parlak等一行三人莅临优积科技考察交流&#xff0c;公司CEO刘其东携团队成员热情接待并深入交流。 商务团首先参观了我司产品生产基地&#xff0c;详细了解了钢结构模块的生产加工工艺流程和质量控制体系。随后参观了我司模块化学校样板房、模块…

Jmeter系列(2)目录介绍

目录 Jmeter目录介绍bin目录docsextrasliblicensesprintable_docs Jmeter目录介绍 在学习Jmeter之前&#xff0c;需要先对工具的目录有些了解&#xff0c;也会方便后续的学习 bin目录 examplesCSV目录中有CSV样例jmeter.batwindow 启动文件jmeter.shMac/linux的启动文件jmete…

企业想要高效上云?如何实现?

进入数字化、智能化时代以后&#xff0c;企业数字化转型已成为企业发展的必然趋势。浪潮之中&#xff0c;越来越多的企业开始积极探索上云路径&#xff0c;云上创新已经成为企业加速数字化转型&#xff0c;提升竞争力的必经之路。 赞奇与华为携手共创云桌面SaaS产品—赞奇云工作…

医院管理系统小程序

**&#x1f345;点赞收藏关注 → 私信领取本源代码、数据库&#x1f345; 本人在Java毕业设计领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目希望你能有所收获&#xff0c;少走一些弯路。&#x1f345;关注我不迷路&#x1f345;**一 、设计说明 1.1 研究背景…

解决方案 || 在Windows中运行含有bash命令的开源代码仓库

在Windows中运行含有bash命令的开源代码仓库 文章目录 在Windows中运行含有bash命令的开源代码仓库问题分析解决方案使用Git Bash使用Windows Subsystem for Linux (WSL)使用Cygwin 结论 问题分析 在开源社区中&#xff0c;许多项目都是基于Unix-like系统&#xff08;如Linux或…

EXCEL如何从另一个表查找匹配信息

目录 1.背景&#xff1a;我们有一个目标呈现表&#xff0c;想要从另一个表中查询得到信息&#xff0c;比如根据身份证id查询该id的名字、性别等个人基本信息&#xff0c;或者从另一个财务信息表查询该id的工资信息等&#xff1b; 2.基础方法&#xff1a;利用VLOOKUP函数根据单…

操作系统--设备管理

一、设备控制器 我们的电脑设备可以接非常多的输入输出设备&#xff0c;比如键盘、鼠标、显示器、网卡、硬盘、打印机、音响等等&#xff0c;每个设备的用法和功能都不同。为了屏蔽设备之间的差异&#xff0c;每个设备都有一个叫设备控制器&#xff08;Device Control&#xf…

淘金优化算法GRO求解不闭合MD-MTSP,可以修改旅行商个数及起点(提供MATLAB代码)

一、淘金优化算法GRO 淘金优化算法&#xff08;Gold rush optimizer&#xff0c;GRO&#xff09;由Kamran Zolf于2023年提出&#xff0c;其灵感来自淘金热&#xff0c;模拟淘金者进行黄金勘探行为。淘金优化算法&#xff08;Gold rush optimizer&#xff0c;GRO&#xff09;提…

PostgreSQL 与MySQL 对比使用

一、前言 博主的系统既有 用到MySQL 也有用到PostgreSQL &#xff0c;之所以用到这两种数据库&#xff0c;主要是现在都是国产替代&#xff0c;虽然说这两款数据库也不是国产的&#xff0c;但是相对开源&#xff0c;oracle是不让用了。所以现在使用比较多的就是这两个关系型数据…

Canvas动画之豌豆射手

&#x1f339;作者主页&#xff1a;青花锁 &#x1f339;简介&#xff1a;Java领域优质创作者&#x1f3c6;、Java微服务架构公号作者&#x1f604; &#x1f339;简历模板、学习资料、面试题库、技术互助 &#x1f339;文末获取联系方式 &#x1f4dd; 往期热门专栏回顾 专栏…