上篇博客用实现了基于双线性插值算法的图像缩放,主要函数zoom中大量使用了指针。采用指针来读取图像像素,优点是执行速度快,缺点是代码不易阅读。本篇采用opencv库中自带的cvGet2D()和cvSet2D()函数来读写图像像素,虽然执行速度较慢,但代码阅读性强,简单明了。
下面是主要函数zoom的实现,其他部分参考我的上一篇博客。
void zoom(IplImage* src, IplImage* dst)
{
int srcWidth = src->width;
int srcHeight = src->height;
int dstWidth = dst->width;
int dstHeight = dst->height;
//源图像与目标图像的宽高比例,这里减1很重要,否则有时报错,有时不报错。这点困扰了我很久
const float tx = (srcWidth-1.0f)/(dstWidth-1.0f);
const float ty = (srcHeight-1.0f)/(dstHeight-1.0f);
CvPoint2D32f uv;//存储源图像的浮点坐标
CvPoint3D32f f1;
CvPoint3D32f f2;
for (int j=0; j<dstHeight-1; j++)
{
for (int i=0; i<dstWidth-1; i++)
{
uv.x = i*tx;
uv.y = j*ty;
int iu = (int)uv.x;
int iv = (int)uv.y;
CvScalar p1, p2, p3, p4, s;
p1=cvGet2D(src, iv, iu);
p2=cvGet2D(src, iv, iu+1);
p3=cvGet2D(src, iv+1, iu);
p4=cvGet2D(src, iv+1, iu+1);
f1.x = p1.val[0]*(1-Abs(uv.x-iu))+p2.val[0]*(uv.x-iu);
f1.y = p1.val[1]*(1-Abs(uv.x-iu))+p2.val[1]*(uv.x-iu);
f1.z = p1.val[2]*(1-Abs(uv.x-iu))+p2.val[2]*(uv.x-iu);
f2.x = p3.val[0]*(1-Abs(uv.x-iu))+p4.val[0]*(uv.x-iu);
f2.y = p3.val[1]*(1-Abs(uv.x-iu))+p4.val[1]*(uv.x-iu);
f2.z = p3.val[2]*(1-Abs(uv.x-iu))+p4.val[2]*(uv.x-iu);
s.val[0] = f1.x*(1-Abs(uv.y-iv))+f2.x*(Abs(uv.y-iv));
s.val[1] = f1.y*(1-Abs(uv.y-iv))+f2.y*(Abs(uv.y-iv));
s.val[2] = f1.z*(1-Abs(uv.y-iv))+f2.z*(Abs(uv.y-iv));
cvSet2D(dst, j, i, s);
}
//这里添加上最后一列
cvSet2D(dst, j, dstWidth-1, cvGet2D(dst, j, dstWidth-2));
}
//这里添加上最后一行
for(int i=0; i<dstWidth; i++)
{
cvSet2D(dst, dstHeight-1, i, cvGet2D(dst, dstHeight-2, i));
}
}