VC中用线性插值方法进行图像放大

来源:互联网 发布:腾讯手机管家软件 编辑:程序博客网 时间:2024/05/02 00:42
VC中用线性插值方法进行图像放大

Lingch   
Post2Ling@hotmail.com

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

线性插值
所谓线性插值就是说:有一组离散数据{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->width*xs,(int)img->height*ys),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[i*img_s->widthStep+j*img_s->nChannels+0]=v0;

              img_s->imageData[i*img_s->widthStep+j*img_s->nChannels+1]=v1;

              img_s->imageData[i*img_s->widthStep+j*img_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[i*img->widthStep+j*img->nChannels+2],

                        img->imageData[i*img->widthStep+j*img->nChannels+1],

                       img->imageData[i*img->widthStep+j*img->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[i*img_s->widthStep+j*img_s->nChannels+2],

                       img_s->imageData[i*img_s->widthStep+j*img_s->nChannels+1],

                       img_s->imageData[i*img_s->widthStep+j*img_s->nChannels+0]);

                   pDC->SetPixel(j+yOri*2+img->width,i+xOri,c);

              }

         }

     }

}


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

原创粉丝点击