OpenCV 实现重新映射

news/2024/11/20 13:43:51/

返回: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


http://www.ppmy.cn/news/1443612.html

相关文章

学习记录695@EasyExcel 读取数据每一行都为null

原代码 import lombok.Data; import lombok.experimental.Accessors;Data public class ExcelData{/*** createtime*/ExcelProperty(value "姓名")private String name;/*** updatetime*/ExcelProperty(value "班级")private String class; }String fil…

【C++风云录】发现天空之美:使用C++库进行气象图像处理与分析

发现天空之美&#xff1a;使用C库进行气象图像处理与分析 前言 随着环境监测和气象学领域的不断发展&#xff0c;需要借助高效的工具和库来处理和分析大量的数据。C作为一种强大的编程语言&#xff0c;提供了丰富的库和工具&#xff0c;为环境监测和气象学领域的开发人员提供…

python下常用的图像处理工具

在Python中&#xff0c;常用的图像处理工具有很多&#xff0c;以下是一些常见的和推荐的工具&#xff1a; OpenCV&#xff1a;OpenCV&#xff08;Open Source Computer Vision Library&#xff09;是最流行的计算机视觉库之一&#xff0c;它包含大量的图像处理函数&#xff0c…

HarmonyOS hsp制作与引用

1. HarmonyOS hsp制作与引用 1.1 介绍 HSP动态共享包&#xff08;模块&#xff09;,应用内HSP指的是专门为某一应用开发的HSP&#xff0c;只能被该应用内部其他HAP/HSP使用&#xff0c;用于应用内部代码、资源的共享。应用内HSP跟随其宿主应用的APP包一起发布&#xff0c;与该…

CSS详解(二)

接上篇CSS详解&#xff08;一&#xff09;-CSDN博客 1、网页布局本质 网页布局的本质是通过 CSS 将各种 HTML 元素&#xff08;即“盒子”&#xff09;摆放到页面中合适的位置。这包括设置元素的尺寸、位置、边距、填充、对齐方式、浮动等。这些盒子通过 CSS 的各种布局机制进…

Word图片被隐藏了怎么办?

背景 如下图&#xff0c;插入的图片被隐藏了 解决办法 选中图片&#xff0c;右上角有个图标&#xff0c;选择嵌入型 继续选中图片&#xff0c;在状态栏里的段落中&#xff0c;点击小箭头到设置里&#xff08;即段落设置&#xff09; 将行距改成单倍行距 完成

第三节课,后端登录【1】

一、总任务 二、登录接口 get 请求&#xff0c;有缺陷&#xff0c;长度有限制 三、登录逻辑 四、代码书写位置 4.1 编写业务逻辑的位置 五、写代码 5.1 代码1 5.1.1 细节 按 CtrlAltShiftL ,快速格式化 5.1. 2 自动生成接口参数 先/** 再回车 效果图 5.2 按 alt enter …

手动在Ubuntu22.04上部署LAMP环境

简介 LAMP环境是常用的Web开发环境之一&#xff0c;其中LAMP分别代表Linux、Apache、MySQL和PHP。本文介绍如何在Ubuntu操作系统的ECS实例内部署LAMP环境。 准备工作 该实例必须满足以下条件&#xff1a; 实例已分配公网IP地址或绑定弹性公网IP&#xff08;EIP&#xff09;。…