[转]openCV: 线性插值方法进行图像放大

向右看齐 2022-08-04 10:39 310阅读 0赞








图像的放大可以用插值的方法,其中一种简单的插值就是线性插值,线性插值虽然简单,却非常有效。




线性插值

所谓线性插值就是说:有一组离散数据{a(1),a(2),…,a(n)},我们想要知道a(k)和a(k+1)之间的数a(m) (k<m<k+1)是多少。但因为数据是离散的,我们只知道a(k)和a(k+1),因此我们只能对a(m)进行一个估计,这个估计的值就叫插值。一种比较合理的估计是a(k)和a(k+1)之间某点的值可能是a(k)+(a(k+1)-a(k))m,m是[0,1]之间的一个常小数,这就叫线性插值。如下图







图像的线性插值放大

图像就是一个象素矩阵,可以表示为 p(i,j)。现在用p(i,j)表示原图像中的某个点,ps(i,j)表示放大后的图像的某个点,放大过程如下:

首先计算需要插值的位置

新图像的某个点ps(x,y) 的值为

ps(x,y) = p(m,n)

m = 原图像高×(x÷新图像高)

n = 原图像宽×(y÷新图像宽)

m,n 一般会是一个小数,就是原图像需要插值的位置

知道了插值位置接下来就要对原图像进行插值了,如下图




其中p(i,n) ,p(m,j) , p(i+1,n) , p(m,j+1) , p(m,n) 就是用线性插值方法插进去的,

p(i,n) = p(i,j) + (p(i,j+1) - p(i,j)) × (n-j)

p(m,j) = p(i,j) + (p(i+1,j) - p(i,j)) × (m-i)

p(i+1,n) = p(i+1,j) + (p(i+1,j+1) - p(i+1,j)) × (n-j)

p(m,j+1) = p(i,j+1) + (p(i+1,j+1) - p(i,j+1)) × (m-i)

p(m,n) = p(i,n) +(p(i+1,n) - p(i,n)) × (m-i)

i = floor(m)

j = floor(n)

floor是向下取整

这样放大图像的每一个点的值ps(x,y)就全有了,把他写到新图像中就完成了图像的线性插值放大。




VC实现

我们用OpenCV(beta_5)库来读取图像,然后手工插值放大。程序是MFC/DOC/VIEW结构



首先接入OpenCV(beta_5)库


#include “highgui.h”                 //Includes


#pragma comment(lib,”highgui.lib”)   //Link to .lib


#pragma comment(lib,”cxcore.lib”)    //Link to .lib




class CLinerDoc : public CDocument


{



// 属性


public:


     IplImage img;     //Original image


     IplImage img_s;   //Scaled image



};


 


CLinerDoc::CLinerDoc()


:img(NULL)


,img_s(NULL)


{



}


 


BOOL CLinerDoc::OnNewDocument()


{



     int i,j;


 


     double xs=3.0,ys=3.0;


     //Load the original image


     img=cvLoadImage(“C://Documents and Settings//Administrator//Desktop//Desktop//Desktop_Girl_v1.jpg”);


     //Apply memory for scaled image


     img_s=cvCreateImage(cvSize((int)img->widthxs,(int)img->heightys),img->depth,img->nChannels);


    


     //Scale by linear interpolation


     double xm,ym;


     unsigned char vff0,vff1,vff2,vcf0,vcf1,vcf2,vfc0,vfc1,vfc2,vcc0,vcc1,vcc2;


     unsigned char v0,v1,v2;


     for(i=0;i<img_s->height;i++){


         for(j=0;j<img_s->width;j++){


 


              //Middle pixel


              xm=(img->width-1)j/(double)img_s->width;


              ym=(img->height-1)i/(double)img_s->height;


 


              //4 neighbor pixels of 3 color            vff0=img->imageData[((int)floor(ym))img->widthStep+((int)floor(xm))img->nChannels+0];     vff1=img->imageData[((int)floor(ym))img->widthStep+((int)floor(xm))img->nChannels+1];


     vff2=img->imageData[((int)floor(ym))img->widthStep+((int)floor(xm))img->nChannels+2];


     vcf0=img->imageData[((int)floor(ym))img->widthStep+((int)ceil(xm))img->nChannels+0];


     vcf1=img->imageData[((int)floor(ym))img->widthStep+((int)ceil(xm))img->nChannels+1];


     vcf2=img->imageData[((int)floor(ym))img->widthStep+((int)ceil(xm))img->nChannels+2];


     vfc0=img->imageData[((int)ceil(ym))img->widthStep+((int)floor(xm))img->nChannels+0];


     vfc1=img->imageData[((int)ceil(ym))img->widthStep+((int)floor(xm))img->nChannels+1];


     vfc2=img->imageData[((int)ceil(ym))img->widthStep+((int)floor(xm))img->nChannels+2];


     vcc0=img->imageData[((int)ceil(ym))img->widthStep+((int)ceil(xm))img->nChannels+0];


     vcc1=img->imageData[((int)ceil(ym))img->widthStep+((int)ceil(xm))img->nChannels+1];


     vcc2=img->imageData[((int)ceil(ym))img->widthStep+((int)ceil(xm))img->nChannels+2];


 


              //Perform linear interpolation


              v0=vff0+(vcf0-vff0)(xm-(int)xm)


              +(vfc0+(vcc0-vfc0)(xm-(int)xm)-vff0-(vcf0-vff0)(xm-(int)xm))(ym-(int)ym);


              v1=vff1+(vcf1-vff1)(xm-(int)xm)


              +(vfc1+(vcc1-vfc1)(xm-(int)xm)-vff1-(vcf1-vff1)(xm-(int)xm))(ym-(int)ym);


              v2=vff2+(vcf2-vff2)(xm-(int)xm)


              +(vfc2+(vcc2-vfc2)(xm-(int)xm)-vff2-(vcf2-vff2)(xm-(int)xm))(ym-(int)ym);


 


              //Set pixel of scaled image


              img_s->imageData[iimg_s->widthStep+jimg_s->nChannels+0]=v0;


              img_s->imageData[iimg_s->widthStep+jimg_s->nChannels+1]=v1;


              img_s->imageData[iimg_s->widthStep+jimg_s->nChannels+2]=v2;


         }


     }


     return TRUE;


}


 


void CLinerDoc::OnCloseDocument()


{


     //Release created image


     cvReleaseImage(&img_s);



}


 


void CLinerView::OnDraw(CDC pDC)


{


     CLinerDoc pDoc = GetDocument();


     ASSERT_VALID(pDoc);


     if (!pDoc)


         return;


 


     int i,j;


     CLinerDoc doc=(CLinerDoc)this->GetDocument();


     IplImage img=doc->img;         //Original image


     IplImage img_s=doc->img_s;      //Scaled image


     int xOri=10,yOri=10;


 


     COLORREF c;


     if(img){


         //Show original image


         for(i=0;i<img->height;i++){


              for(j=0;j<img->width;j++){


                   c=RGB(img->imageData[iimg->widthStep+jimg->nChannels+2],


                        img->imageData[iimg->widthStep+jimg->nChannels+1],


                       img->imageData[iimg->widthStep+jimg->nChannels+0]);


                   pDC->SetPixel(j+yOri,i+xOri,c);


              }


         }


     }


     if(img_s){


         //Show scaled image


         for(i=0;i<img_s->height;i++){


              for(j=0;j<img_s->width;j++){


                   c=RGB(img_s->imageData[iimg_s->widthStep+jimg_s->nChannels+2],


                       img_s->imageData[iimg_s->widthStep+jimg_s->nChannels+1],


                       img_s->imageData[iimg_s->widthStep+jimg_s->nChannels+0]);


                   pDC->SetPixel(j+yOri2+img->width,i+xOri,c);


              }


         }


     }


}



放大效果见下图




左边是原始图像,右边是用线性插值放大3倍后的,似模似样吧 :-)


转自:

http://hi.baidu.com/haozi2638/blog/item/27f88cb107392a5e09230238.html

发表评论

表情:
评论列表 (有 0 条评论,310人围观)

还没有评论,来说两句吧...

相关阅读

    相关 图像放大与缩小—

    Opencv中对于图像的放大与缩小主要有两种类型,一种是图像金字塔pyrUp和pyrDown函数,另外一种是更通用的resize函数允许你指定目标图像的尺寸。 一:图像金字塔