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

来源:互联网 发布:pandorabox安装python 编辑:程序博客网 时间:2024/05/01 09:45

#include <stdio.h>
#include "opencv2/core/core.hpp"
#include "opencv2/features2d/features2d.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/nonfree/nonfree.hpp"
#include "opencv2/gpu/gpu.hpp"

#include <math.h>

#ifndef _DEBUG
#pragma  comment(lib,"IlmImf.lib")  
#pragma  comment(lib,"libjasper.lib")   
#pragma  comment(lib,"libjpeg.lib")  
#pragma  comment(lib,"libpng.lib")      
#pragma  comment(lib,"libtiff.lib") 
#pragma  comment(lib,"zlib.lib")  
#pragma  comment(lib,"opencv_calib3d2411.lib")
#pragma  comment(lib,"opencv_contrib2411.lib")
#pragma  comment(lib,"opencv_core2411.lib")
#pragma  comment(lib,"opencv_features2d2411.lib")
#pragma  comment(lib,"opencv_flann2411.lib")
#pragma  comment(lib,"opencv_gpu2411.lib")
#pragma  comment(lib,"opencv_highgui2411.lib")
#pragma  comment(lib,"opencv_imgproc2411.lib")
#pragma  comment(lib,"opencv_legacy2411.lib")
#pragma  comment(lib,"opencv_ml2411.lib")
#pragma  comment(lib,"opencv_nonfree2411.lib")
#pragma  comment(lib,"opencv_objdetect2411.lib")
#pragma  comment(lib,"opencv_ocl2411.lib")
#pragma  comment(lib,"opencv_photo2411.lib")
#pragma  comment(lib,"opencv_stitching2411.lib")
#pragma  comment(lib,"opencv_superres2411.lib")
#pragma  comment(lib,"opencv_ts2411.lib")
#pragma  comment(lib,"opencv_video2411.lib")
#pragma  comment(lib,"opencv_videostab2411.lib")
#else
#pragma  comment(lib,"zlibd.lib")
#pragma  comment(lib,"IlmImfd.lib")
#pragma  comment(lib,"libjasperd.lib")
#pragma  comment(lib,"libjpegd.lib")
#pragma  comment(lib,"libpngd.lib")
#pragma  comment(lib,"libtiffd.lib")
#pragma  comment(lib,"opencv_calib3d2411d.lib")
#pragma  comment(lib,"opencv_contrib2411d.lib")
#pragma  comment(lib,"opencv_core2411d.lib")
#pragma  comment(lib,"opencv_features2d2411d.lib")
#pragma  comment(lib,"opencv_flann2411d.lib")
#pragma  comment(lib,"opencv_gpu2411d.lib")
#pragma  comment(lib,"opencv_highgui2411d.lib")
#pragma  comment(lib,"opencv_imgproc2411d.lib")
#pragma  comment(lib,"opencv_legacy2411d.lib")
#pragma  comment(lib,"opencv_ml2411d.lib")
#pragma  comment(lib,"opencv_nonfree2411d.lib")
#pragma  comment(lib,"opencv_objdetect2411d.lib")
#pragma  comment(lib,"opencv_ocl2411d.lib")
#pragma  comment(lib,"opencv_photo2411d.lib")
#pragma  comment(lib,"opencv_stitching2411d.lib")
#pragma  comment(lib,"opencv_superres2411d.lib")
#pragma  comment(lib,"opencv_ts2411d.lib")
#pragma  comment(lib,"opencv_video2411d.lib")
#pragma  comment(lib,"opencv_videostab2411d.lib")
#endif


using namespace cv;


// remapping an image by creating wave effects
void wave(const cv::Mat &image, cv::Mat &result) {

 // the map functions
 cv::Mat srcX(image.rows,image.cols,CV_32F); // x-map
 cv::Mat srcY(image.rows,image.cols,CV_32F); // y-map

 // creating the mapping
 for (int i=0; i<image.rows; i++) {
  for (int j=0; j<image.cols; j++) {

   srcX.at<float>(i,j)= j;
   srcY.at<float>(i,j)= i+3*sin(j/6.0);

   // horizontal flipping
   // srcX.at<float>(i,j)= image.cols-j-1;
   // srcY.at<float>(i,j)= i;
  }
 }

 // applying the mapping
 remap(image,  // source image
  result, // destination image
  srcX,   // x map
  srcY,   // y map
  INTER_LINEAR); // interpolation method
}

int main()
{
 cv::Mat image= cv::imread("boldt.jpg",0);
 // image is resize for book printing
 cv::resize(image, image, cv::Size(), 0.6, 0.6);

 cv::namedWindow("Image");
 cv::imshow("Image",image);

 cv::Mat result;
 wave(image,result);

 cv::namedWindow("Remapped image");
 cv::imshow("Remapped image",result);

 cv::waitKey();
 return 0;
}


Remapping 重映射¶

目标¶

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

理论¶

重映射是什么意思?¶

  • 把一个图像中一个位置的像素放置到另一个图片指定位置的过程.

  • 为了完成映射过程, 有必要获得一些插值为非整数像素坐标,因为源图像与目标图像的像素坐标不是一一对应的.

  • 我们通过重映射来表达每个像素的位置 (x,y) :

    g(x,y) = f ( h(x,y) )

    这里 g() 是目标图像,f() 是源图像,h(x,y) 是作用于(x,y) 的映射方法函数.

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

    h(x,y) = (I.cols - x, y )

    会发生什么? 图像会按照 x 轴方向发生翻转. 例如, 源图像如下:

    Original test image

    看到红色圈关于 x 的位置改变( x 轴水平翻转):

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

代码¶

  1. 本程序做什么?
    • 装载一幅图像.
    • 程序按秒循环, 在一个窗口中顺序出现4种重映射过程对相同的图像.
    • 等待用户按 ‘ESC’ 键退出程序。
  2. 下面是本教程代码. 你也可以从 这里 下载。
 #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;
  2. 加载一幅图像:

    src = imread( argv[1], 1 );
  3. 创建目标图像和两个映射矩阵.( x 和 y )

    dst.create( src.size(), src.type() );map_x.create( src.size(), CV_32FC1 );map_y.create( src.size(), CV_32FC1 );
  4. 创建一个窗口用于展示结果.

    namedWindow( remap_window, CV_WINDOW_AUTOSIZE );
  5. 建立一个间隔1000毫秒的循环,每次循环执行更新映射矩阵参数并对源图像进行重映射处理(使用 mat_xmat_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方向的映射参数. 它相当于方法 h(i,j) 的第一个参数
    • map_y: y方向的映射参数. 注意 map_ymap_xsrc 的大小一致。
    • CV_INTER_LINEAR: 非整数像素坐标插值标志. 这里给出的是默认值(双线性插值).
    • BORDER_CONSTANT: 默认

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

  6. 更新重映射矩阵: 我们将分别使用4种不同的映射:

    1. 图像宽高缩小一半,并显示在中间:

      h(i,j) = ( 2*i - src.cols/2  + 0.5, 2*j - src.rows/2  + 0.5)

      所有成对的参数 (i,j) 处理后都符合:\dfrac{src.cols}{4}<i<\dfrac{3 \cdot src.cols}{4}\dfrac{src.rows}{4}<j<\dfrac{3 \cdot src.rows}{4}

    2. 图像上下颠倒: h( i, j ) = (i, src.rows - j)

    3. 图像左右颠倒: h(i,j) = ( src.cols - i, j )

    4. 同时执行b和c的操作: h(i,j) = ( src.cols - i, src.rows - j )

下面的代码片段说明上述的映射过程. 在这里 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. 上面的代码编译后, 运行时给一个图片路径参数. 例如,使用下面的图片:

    Original test image
  2. 图像宽高缩小一半,并显示在中间:

    Result 0 for remapping
  3. 图像上下颠倒:

    Result 0 for remapping
  4. 图像左右颠倒:

    Result 0 for remapping
  5. 两个方向同时颠倒:

Result 0 for remapping

翻译者¶

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



0 0
原创粉丝点击