[转]openCV: 线性插值方法进行图像放大
图像的放大可以用插值的方法,其中一种简单的插值就是线性插值,线性插值虽然简单,却非常有效。 线性插值 所谓线性插值就是说:有一组离散数据{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
还没有评论,来说两句吧...