OpenCV 实现重新映射(53)

返回: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 个应用于图像,并在窗口中无限期地显示它们。
    • 等待用户退出程序
    • 教程代码如下所示。您也可以从这里下载
    cpp 复制代码
     
    #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;
    }

解释

  • 加载图像

    cpp 复制代码
     
     Mat src = imread( samples::findFile( filename ), IMREAD_COLOR );
     if (src.empty())
     {
     std::cout << "Cannot read image: " << filename << std::endl;
     return -1;
     }
  • 创建目标映像和两个映射矩阵(对于 x 和 y )

    cpp 复制代码
    Mat dst(src.size(), src.type());
     Mat map_x(src.size(), CV_32FC1);
     Mat map_y(src.size(), CV_32FC1);
  • 创建一个窗口以显示结果

    cpp 复制代码
     const char* remap_window = "Remap demo";
     namedWindow( remap_window, WINDOW_AUTOSIZE );
  • 建立循环。每隔 1000 毫秒,我们就会更新映射矩阵(mat_xmat_y),并将它们应用于我们的源图像:

    cpp 复制代码
     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;
     }
     }
cpp 复制代码
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

相关推荐
lulu_gh_yu28 分钟前
数据结构之排序补充
c语言·开发语言·数据结构·c++·学习·算法·排序算法
成富44 分钟前
文本转SQL(Text-to-SQL),场景介绍与 Spring AI 实现
数据库·人工智能·sql·spring·oracle
凤枭香1 小时前
Python OpenCV 傅里叶变换
开发语言·图像处理·python·opencv
CSDN云计算1 小时前
如何以开源加速AI企业落地,红帽带来新解法
人工智能·开源·openshift·红帽·instructlab
ULTRA??1 小时前
C加加中的结构化绑定(解包,折叠展开)
开发语言·c++
艾派森1 小时前
大数据分析案例-基于随机森林算法的智能手机价格预测模型
人工智能·python·随机森林·机器学习·数据挖掘
hairenjing11231 小时前
在 Android 手机上从SD 卡恢复数据的 6 个有效应用程序
android·人工智能·windows·macos·智能手机
小蜗子1 小时前
Multi‐modal knowledge graph inference via media convergenceand logic rule
人工智能·知识图谱
SpikeKing1 小时前
LLM - 使用 LLaMA-Factory 微调大模型 环境配置与训练推理 教程 (1)
人工智能·llm·大语言模型·llama·环境配置·llamafactory·训练框架
凌云行者2 小时前
OpenGL入门005——使用Shader类管理着色器
c++·cmake·opengl