最近將一個matlab程式轉為c++,途中遇到interp2這個傢伙,我是左查右查,發現網上沒有人總結這個玩意,於是我來初探一下,還是別有洞天的,嘿嘿。
1、關於interp2
Vq = interp2(X,Y,V,Xq,Yq,'linear',0),X和Y表示採樣點的座標,可以是向量或者矩陣,比如我們要畫一個網格,網格點座標可以理解為採樣點的座標。Xq和Yq表示查詢點的座標,同樣可以是向量或者矩陣,即我們需要插值的地方,當然它的步長小於或等於X和Y的步長,相當於對網格進行細化。V是採樣點處的值。Vq即得到插值點處的值。感覺有點囉嗦,看下面的吧。
這個函數是幹什麼的呢。假設一幅灰階映像,座標矩陣是X和Y,一個表示行,一個表示列,對應的像素值矩陣為V。現在在Xq和Yq處對它進行雙線性插值,即返回新插值點的像素值矩陣Vq。
現在咱們看個列子:
[X,Y] = meshgrid(-3:3); %產生網格座標矩陣,步長為1V = peaks(X,Y); %產生一個三維高斯分布figuresurf(X,Y,V) title('Original Sampling');[Xq,Yq] = meshgrid(-3:0.25:3); %產生插值點座標矩陣,步長為0.25Vq = interp2(X,Y,V,Xq,Yq); %進行插值,返回Vqfiguresurf(Xq,Yq,Vq);title('Linear Interpolation Using Finer Grid');
第一幅映像是橫縱座標都為[-3,3],函數值為常態分佈的立體映像。第二幅映像在第一幅映像基礎上進行雙線性插值得出的結果,從圖中可以看出,其結構更加精細。
2、c++代碼
在opencv函數庫中,可以用remap函數來完成相同的功能。當然,在使用這個函數之前,你得完成opencv的配置。
voidremap(InputArray src, OutputArray dst, InputArray map1, InputArray map2, int interpolation, intborderMode=BORDER_CONSTANT, const Scalar& borderValue=Scalar())
src是源映像
dst是經過插值之後輸出的靶心圖表像
map1和map2是插值點座標,類型為CV_16SC2,CV_32FC1和CV_32FC2,此處需注意,如果map1是(x,y)的形式,那麼map2是空映射。
interpolation是插值方法的類型:INTER_NEAREST,INTER_LINEAR,INTER_AREA,INTER_CUBIC,INTER_LANCZOS4 。
intborderMode是邊界模式,當borderMode=BORDER_TRANSPARENT時,靶心圖表像對應源映像的外點不被修改。
borderValue,當邊界是固定的時被使用,其值為0。
下面我們看一下這個函數的使用:
#include "stdafx.h"#include "highgui.h"#include "cv.h"using namespace cv;using namespace std;int main( int argc, char** argv ){//generate flowmap model CvFileStorage* fx=cvOpenFileStorage( "result.txt",0,CV_STORAGE_WRITE);//ask storage for save file Mat xmesh = cvCreateMat(3, 3, 5);Mat ymesh = cvCreateMat(3, 3, 5);for(int i = 0; i < xmesh.rows; i++)for(int j = 0; j < xmesh.cols; j++){xmesh.at(i,j)=i*0.5; ymesh.at(i,j)=j*0.5; }//generate optical flow folder Mat u=cvCreateMat(3, 3, 5); Mat v=cvCreateMat(3, 3, 5); for(int i = 0; i (i,j)=(i+1)*0.1; v.at(i,j)=(j+1)*0.1; } remap(u,v,ymesh,xmesh,INTER_LINEAR,0,cvScalarAll(0)); //convert mat to IplimageIplImage* xmesh_a = cvCloneImage(&(IplImage) xmesh);IplImage* ymesh_a = cvCloneImage(&(IplImage) ymesh);IplImage* u_a = cvCloneImage(&(IplImage) u);IplImage* v_a = cvCloneImage(&(IplImage) v); //save end to txtcvWrite(fx, "xmesh",xmesh_a,cvAttrList());cvWrite(fx, "ymesh",ymesh_a,cvAttrList());cvWrite(fx, "u",u_a,cvAttrList());cvWrite(fx, "v",v_a,cvAttrList()); cvReleaseFileStorage(&fx); waitKey(); }
結果如下:
%YAML:1.0xmesh: !!opencv-image width: 3 height: 3 origin: top-left layout: interleaved dt: f data: [ 0., 0., 0., 5.00000000e-001, 5.00000000e-001, 5.00000000e-001, 1., 1., 1. ]ymesh: !!opencv-image width: 3 height: 3 origin: top-left layout: interleaved dt: f data: [ 0., 5.00000000e-001, 1., 0., 5.00000000e-001, 1., 0., 5.00000000e-001, 1. ]u: !!opencv-image width: 3 height: 3 origin: top-left layout: interleaved dt: f data: [ 1.00000001e-001, 1.00000001e-001, 1.00000001e-001, 2.00000003e-001, 2.00000003e-001, 2.00000003e-001, 3.00000012e-001, 3.00000012e-001, 3.00000012e-001 ]v: !!opencv-image width: 3 height: 3 origin: top-left layout: interleaved dt: f data: [ 1.00000001e-001, 1.00000001e-001, 1.00000001e-001, 1.50000006e-001, 1.50000006e-001, 1.50000006e-001, 2.00000003e-001, 2.00000003e-001, 2.00000003e-001 ]
觀察這個結果,你會驚奇的發現opencv中的remap函數真的實現了matlab中的interp2函數,歐耶,perfect。