您的位置:首页 > 运维架构

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

2009-11-08 14:11 513 查看
图像的放大可以用插值的方法,其中一种简单的插值就是线性插值,线性插值虽然简单,却非常有效。

线性插值
所谓线性插值就是说:有一组离散数据{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倍后的,似模似样吧 :-)

转自:
http://hi.baidu.com/haozi2638/blog/item/27f88cb107392a5e09230238.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: