Navigation


Remapping 重映射¶



目标

本教程向你展示如何使用OpenCV函数 remap 来实现简单重映射.



理论



重映射是什么意思?

  • 把一个图像中一个位置的像素放置到另一个图片指定位置的过程.
  • 为了完成映射过程, 有必要获得一些插值为非整数像素坐标,因为源图像与目标图像的像素坐标不是一一对应的.
  • 我们通过重映射来表达每个像素的位置 :

这里

如何使用OpenCV函数 remap 来实现简单重映射_#include

是目标图像,

如何使用OpenCV函数 remap 来实现简单重映射_图像处理_02

是源图像,

如何使用OpenCV函数 remap 来实现简单重映射_图像处理_03

是作用于

如何使用OpenCV函数 remap 来实现简单重映射_#include_04

的映射方法函数.

  • 让我们来思考一个快速的例子. 想象一下我们有一个图像 , 我们想满足下面的条件作重映射:

会发生什么? 图像会按照

如何使用OpenCV函数 remap 来实现简单重映射_OpenCV_05

轴方向发生翻转. 例如, 源图像如下:看到红色圈关于 x 的位置改变(

如何使用OpenCV函数 remap 来实现简单重映射_OpenCV_05

轴水平翻转):

  • 通过 OpenCV 的函数 remap 提供一个简单的重映射实现.


代码

  1. 本程序做什么?
  • 装载一幅图像.
  • 程序按秒循环, 在一个窗口中顺序出现4种重映射过程对相同的图像.
  • 等待用户按 ‘ESC’ 键退出程序。
  1. 下面是本教程代码. 你也可以从 这里 下载。
#include "opencv2/highgui/highgui.hpp"
 #include "opencv2/imgproc/imgproc.hpp"
 #include <iostream>
 #include <stdio.h>

 using namespace cv;

 /// Global variables
 Mat src, dst;
 Mat map_x, map_y;
 char* remap_window = "Remap demo";
 int ind = 0;

 /// Function Headers
 void update_map( void );

 /**
 * @function main
 */
 int main( int argc, char** argv )
 {
   /// Load the image
   src = imread( argv[1], 1 );

  /// Create dst, map_x and map_y with the same size as src:
  dst.create( src.size(), src.type() );
  map_x.create( src.size(), CV_32FC1 );
  map_y.create( src.size(), CV_32FC1 );

  /// Create window
  namedWindow( remap_window, CV_WINDOW_AUTOSIZE );

  /// Loop
  while( true )
  {
    /// Each 1 sec. Press ESC to exit the program
    int c = waitKey( 1000 );

    if( (char)c == 27 )
      { break; }

    /// Update map_x & map_y. Then apply remap
    update_map();
    remap( src, dst, map_x, map_y, CV_INTER_LINEAR, BORDER_CONSTANT, Scalar(0,0, 0) );

    /// Display results
    imshow( remap_window, dst );
  }
  return 0;
 }

 /**
 * @function update_map
 * @brief Fill the map_x and map_y matrices with 4 types of mappings
 */
 void update_map( void )
 {
   ind = ind%4;

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


说明

  1. 首先准备程序用到的变量:
Mat src, dst;
Mat map_x, map_y;
char* remap_window = "Remap demo";
int ind = 0;
  1. 加载一幅图像:
src = imread( argv[1], 1 );
  1. 创建目标图像和两个映射矩阵.( x 和 y )
dst.create( src.size(), src.type() );
map_x.create( src.size(), CV_32FC1 );
map_y.create( src.size(), CV_32FC1 );
  1. 创建一个窗口用于展示结果.
namedWindow( remap_window, CV_WINDOW_AUTOSIZE );
  1. 建立一个间隔1000毫秒的循环,每次循环执行更新映射矩阵参数并对源图像进行重映射处理(使用 mat_x mat_y),然后把更新后的目标图像显示出来:
while( true )
{
  /// Each 1 sec. Press ESC to exit the program
  int c = waitKey( 1000 );

  if( (char)c == 27 )
    { break; }

  /// Update map_x & map_y. Then apply remap
  update_map();
  remap( src, dst, map_x, map_y, CV_INTER_LINEAR, BORDER_CONSTANT, Scalar(0,0, 0) );

  /// Display results
  imshow( remap_window, dst );
}

上面用到的重映射函数 remap. 参数说明:

  • src: 源图像
  • dst: 目标图像,与 src 相同大小
  • map_x: x方向的映射参数. 它相当于方法
  • 如何使用OpenCV函数 remap 来实现简单重映射_图像处理_07

  • 的第一个参数
  • map_y: y方向的映射参数. 注意 map_ymap_xsrc 的大小一致。
  • CV_INTER_LINEAR: 非整数像素坐标插值标志. 这里给出的是默认值(双线性插值).
  • BORDER_CONSTANT: 默认

如何更新重映射矩阵 mat_xmat_y? 请继续看:

  1. 更新重映射矩阵: 我们将分别使用4种不同的映射:
  1. 图像宽高缩小一半,并显示在中间:

所有成对的参数

如何使用OpenCV函数 remap 来实现简单重映射_OpenCV_08

处理后都符合:

如何使用OpenCV函数 remap 来实现简单重映射_#include_09


如何使用OpenCV函数 remap 来实现简单重映射_OpenCV_10

  1. 图像上下颠倒:
  2. 如何使用OpenCV函数 remap 来实现简单重映射_OpenCV_11

  3. 图像左右颠倒:
  4. 如何使用OpenCV函数 remap 来实现简单重映射_OpenCV_12

  5. 同时执行b和c的操作:
  6. 如何使用OpenCV函数 remap 来实现简单重映射_图像处理_13


下面的代码片段说明上述的映射过程. 在这里 map_x 代表第一个坐标 h(i,j) , map_y 是第二个坐标.



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





结果

  1. 上面的代码编译后, 运行时给一个图片路径参数. 例如,使用下面的图片:
  2. 图像宽高缩小一半,并显示在中间:
  3. 图像上下颠倒:
  4. 图像左右颠倒:
  5. 两个方向同时颠倒:

如何使用OpenCV函数 remap 来实现简单重映射_OpenCV_14


翻译者

opencvzy@ OpenCV中文网站 <java5100@gmail.com>


Help and Feedback

You did not find what you were looking for?


Table Of Contents

Previous topic

霍夫圆变换

Next topic

仿射变换

This Page

Quick search


Enter search terms or a module, class or function name.


Navigation


© Copyright 2011, opencv dev team. Last updated on Mar 30, 2012. Created using Sphinx 1.1.3.