降采样函数的高效实现
所谓降采样,就是将图像的尺寸缩减为原来的一半,隔行隔列取值,降采样在构建图像金字塔时是需要反复使用的。
假如原图像尺寸为
W×H
,那么降采样之后尺寸变为
W2×H2
,长度和宽度是奇数还是偶数,都会自动向下取整。
另外之所以发这么一个小儿科功能的文章是因为本人患有重度强迫症,这么简单的功能OpenCV肯定有,但我就是不想用,我不知道它是如何实现的,对速度不放心。由于强迫症,我对于图像数据的访问,坚持以下几个原则:
- 能用一维向量就坚决不用二维的,因为连续存储的数据本来就是按照一维线性存储的,所谓二维是人类具象化的产物
- 能用指针就坚决不要难过数组下标,因为根据标准C,访问指针要比访问数组更高效,访问数组时涉及到下标的索引计算,这对我来说是绝不能容忍的
- 在使用指针一直出错烧脑时才用回数组
由此,编写了如下的函数,能看懂就尽量看吧,反正不好看,看不懂也直接可以拿来用,目前只处理了8位灰度图,太小儿科,在此露相纯粹是展示一下强迫症的魅力,就是为了追求处理的快速性,不惜脑细胞的码这种代码,反正我就认为这样的代码运行起来快速高效
unsigned char* downSampling(unsigned char *src, int width, int height, int *dwidth, int *dheight)
{
int oddw = width % 2;
int oddh = height % 2;
int flag;
*dwidth = width / 2;
*dheight = height / 2;
unsigned char *dst = Malloc(unsigned char, (*dwidth) * (*dheight));
if(oddw + oddh == 0)flag = 0;
else if(oddw + oddh == 2) flag = 3;
else if(oddw == 0 && oddh == 1) flag = 1;
else flag = 2;
int i;
unsigned char *pCur, *pEnd, *pdCur, *pdEnd;
switch(flag)
{
case 0:
for(i = 0, pCur = src, pEnd = src + width * height, pdCur = dst, pdEnd = dst + (*dwidth) * (*dheight); pdCur < pdEnd; pCur += 2, pdCur++)
{
i++;
*pdCur=*pCur;
if(i==*dwidth)
{
pCur+=width;
i=0;
}
}
break;
case 1:
for(i = 0, pCur = src, pEnd = src + width * height, pdCur = dst, pdEnd = dst + (*dwidth) * (*dheight); pdCur < pdEnd; pCur += 2, pdCur++)
{
i++;
*pdCur=*pCur;
if(i==*dwidth)
{
pCur+=width;
i=0;
}
}
break;
case 2:
for(i = 0, pCur = src, pEnd = src + width * height, pdCur = dst, pdEnd = dst + (*dwidth) * (*dheight); pdCur < pdEnd; pCur += 2, pdCur++)
{
i++;
*pdCur=*pCur;
if(i==*dwidth)
{
pCur+=width+1;
i=0;
}
}
break;
case 3:
for(i = 0, pCur = src, pEnd = src + width * height, pdCur = dst, pdEnd = dst + (*dwidth) * (*dheight); pdCur < pdEnd; pCur += 2, pdCur++)
{
i++;
*pdCur=*pCur;
if(i==*dwidth)
{
pCur+=width+1;
i=0;
}
}
break;
}
return dst;
}
FAQ:
- 为什么分了4个case ? 因为涉及到长度和宽度不一定为偶数啊,要是奇数时到行末地址要跳格的,自己好好想想;
- 为什么四种情况的前两种和后两种完全一样 ? 这是强迫症病人为以后可能出现的其他种情况留作升级用的备胎;
- 为什么用C语言?我只会C语言