基本原理
:
1、最近邻插值
:变换后的目标图像某点像素值等于源图像中与变换前相应点
最近的点的像素值。具体操作为,设水平方向和垂直方向缩放的比例分别为w和h,那么目标图像中的点des(x,y)对应的源图像中的点src的坐标为(x0,y0)=(x/w,y/h)。其中,x0,y0可能为小数,故对其四舍五入,即
(x0,y0)=int(x0+0.5,y0+0.5),因此
点des(x,y)的像素值就是点src
(x0,y0)的像素值。
2、双线性插值:由1中最近邻插值中的
四舍五入前的点
src
(x0,y0)得到它的2*2区域4个邻域像素点的坐标,即
(x1,y1)=(
int(
x0),int(y0))
,
(x1,y2)=int(x1,y1+1),
(x2,y1)=(x1+1,y1),
(x2,y2)=(x1+1,y1+1),然后计算权重q1=(x0-x1)*(y0-y1),
q2=(1.0-(x0-x1))*(y0-y1),
q4=(x0-x1)*(1.0-(y0-y1)),
q3=(1.0-(x0-x1))*
(1.0-(y0-y1),用value(x,y)表示点
(x,y)处的像素值,则
目标图像中的点des(x,y)对应
像素值
value(x,y)=
value(x2,y2)*q1+
value(x1,y2)*q2+
value(x1,y1)*q3+
value(x2,y1)*q4,
c/c++实现及处理效果:
1、最近邻插值
void GeometryTrans::Zoom(float ratioX, float ratioY)
//释放旧的输出图像缓冲区
if(m_pImgDataOut!=NULL){
delete []m_pImgDataOut;
m_pImgDataOut=NULL;
//输出图像的宽和高
m_imgWidthOut=int(m_imgWidth*ratioX+0.5) ;
m_imgHeightOut=int(m_imgHeight*ratioY+0.5);
//输入图像每行像素字节数
int lineByteIn=(m_imgWidth*m_nBitCount/8+3)/4*4;
//输出图像每行像素字节数
int lineByteOut=(m_imgWidthOut*m_nBitCount/8+3)/4*4;
//申请缓冲区,存放输出结果
m_pImgDataOut=new unsigned char[lineByteOut*m_imgHeightOut];
//每像素字节数,输入图像与输出图像相同
int pixelByte=m_nBitCount/8;
//输出图像在输入图像中待插值的位置坐标
int coordinateX, coordinateY;
//循环变量,输出图像的坐标
int i, j;
//循环变量,像素的每个通道
int k;
//近邻插值
for(i=0; i< m_imgHeightOut; i++){
for(j=0; j<m_imgWidthOut; j++){
//输出图像坐标为(j,i)的像素映射到原图中的坐标值,即插值位置
coordinateX=j/ratioX+0.5;
coordinateY=i/ratioY+0.5;
//若插值位置在输入图像范围内,则近邻插值
if(0<=coordinateX&&coordinateX<m_imgWidth
&& coordinateY>=0&&coordinateY<m_imgHeight){
for(k=0;k<pixelByte;k++)
*(m_pImgDataOut + i * lineByteOut + j*pixelByte + k)
=*(m_pImgData+ coordinateY*lineByteIn+ coordinateX*pixelByte + k) ;
else //若不在输入图像范围内,则置255
for(k=0;k<pixelByte;k++)
*(m_pImgDataOut + i * lineByteOut + j*pixelByte+k) = 255;
}
2、双线性插值
void GeometryTrans::Zoom(float ratioX, float ratioY)
//释放旧的输出图像缓冲区
if(m_pImgDataOut!=NULL){
delete []m_pImgDataOut;
m_pImgDataOut=NULL;
//输出图像的宽和高
m_imgWidthOut=int(m_imgWidth*ratioX+0.5) ;
m_imgHeightOut=int(m_imgHeight*ratioY+0.5);
//输入图像每行像素字节数
int lineByteIn=(m_imgWidth*m_nBitCount/8+3)/4*4;
//输出图像每行像素字节数
int lineByteOut=(m_imgWidthOut*m_nBitCount/8+3)/4*4;
//申请缓冲区,存放输出结果
m_pImgDataOut=new unsigned char[lineByteOut*m_imgHeightOut];
//每像素字节数,输入图像与输出图像相同
int pixelByte=m_nBitCount/8;
//输出图像在输入图像中待插值的位置坐标
float coordinateX, coordinateY;
//循环变量,输出图像的坐标
int i, j;
//循环变量,像素的每个通道
int k;
int y1,y2, x1,x2;
float fx1,fx2, fy1, fy2;
//双线性插值
for(i=0; i< m_imgHeightOut; i++)
coordinateY = i/ratioY;
y1 = (int)coordinateY;
if(y1 == m_imgHeightOut-1)
y2 = y1;
else y2 = y1 + 1;
fy1 = coordinateY-y1;
fy2 = (float)1.0 - fy1;
for(j=0; j<m_imgWidthOut; j++)
coordinateX = j/ratioX;
x1 = (int)coordinateX;
if(x1 == m_imgWidthOut-1)
x2 = x1;
else x2 = x1+1;
fx1 = coordinateX-x1;
fx2 = (float)1.0 - fx1;
//所求的源图像中的2*2区域4个邻近象素点坐标为(x1, y1) (x1, y2) (x2, y1) (x2,y2)
//计算4个权重
float s1 = fx1*fy1;
float s2 = fx2*fy1;
float s3 = fx2*fy2;
float s4 = fx1*fy2;
//输出图像坐标为(j,i)的像素映射到原图中的坐标值,即插值位置
//若插值位置在输入图像范围内,则双线性插值
if(0<=coordinateX&&coordinateX<m_imgWidth
&& coordinateY>=0&&coordinateY<m_imgHeight)
for(k=0;k<pixelByte;k++)
*(m_pImgDataOut + i * lineByteOut + j*pixelByte + k)
=(int)((*(m_pImgData+ y2*lineByteIn+ x2*pixelByte + k))*s1+
(*(m_pImgData+ y2*lineByteIn+ x1*pixelByte + k))*s2+
(*(m_pImgData+ y1*lineByteIn+ x1*pixelByte + k))*s3+
(*(m_pImgData+ y1*lineByteIn+ x2*pixelByte + k))*s4);
else //若不在输入图像范围内,则置255
for(k=0;k<pixelByte;k++)
*(m_pImgDataOut + i * lineByteOut + j*pixelByte+k) = 255;
}
总结:由处理效果可知,最近邻插值有锯齿现象,灰度值不连续,而
双线性插值灰度值连续,图像比较平滑。