前言
图像缩放是最常用的图像操作,最近实现了一次双线性插值,适用于单通道8位灰度图像,可以同时处理缩小,放大。
加速手段有三个:1) 使用可分离方式,先后处理行和列, 2)构建缓冲区,以避免对某些行重复插值。3) 使用整形运算,避免浮点运算。
代码
typedef struct _Image{ int w; int h; int c; int step; int type; void* data; } Image; static void _ieInterpImageBilinear8UC1_RowFilter(unsigned char* src, long* dst, int len, int* leftIdx, int* rightIdx, long* weight, int shift) { int i, j; for(i = 0, j = 1; i < len - 2; i+=2, j+=2){ dst[i] = ((1<<shift) - weight[i])*src[leftIdx[i]] + weight[i]*src[rightIdx[i]]; dst[j] = ((1<<shift) - weight[j])*src[leftIdx[j]] + weight[j]*src[rightIdx[j]]; } for( ; j < len; j++){ dst[j] = ((1<<shift) - weight[j])*src[leftIdx[j]] + weight[j]*src[rightIdx[j]]; } } static void _ieInterpImageBilinear8UC1(Image* src, Image* dst) { int i, j; int sw, sh, sstep; int dw, dh, dstep; unsigned char *sdata, *ddata; float horScaleRatio, verScaleRatio; long *rowBuf1, *rowBuf2; long *upLinePtr, *downLinePtr, *tempPtr; long *horWeight; int *horLeftIdx, *horRightIdx; int preVerUpIdx, preVerDownIdx; int shift = 8; sw = src->w; sh = src->h; sstep = src->step; sdata = (unsigned char*)(src->data); dw = dst->w; dh = dst->h; dstep = dst->step; ddata = (unsigned char*)(dst->data); horScaleRatio = sw / (float)(dw); verScaleRatio = sh / (float)(dh); rowBuf1 = new long[dw]; rowBuf2 = new long[dw]; horWeight = new long[dw]; horLeftIdx = new int[dw]; horRightIdx = new int[dw]; //col interpolation //计算目标图像像素横向的左右邻居序号,和权重。 for(i = 0; i < dw; i++){ float pos = (i + 0.5f) * horScaleRatio; horLeftIdx[i] = (int)(IET_MAX(pos - 0.5f, 0)); horRightIdx[i] = (int)(IET_MIN(pos + 0.5f, sw-1)); horWeight[i] = (long) (fabs(pos - 0.5f - horLeftIdx[i]) * (1<<shift)); } preVerUpIdx = -1; preVerDownIdx = -1; upLinePtr = rowBuf1; downLinePtr = rowBuf2; for(j = 0; j < dh; j++){ float pos = (j + 0.5f) * verScaleRatio; int verUpIdx = (int)(IET_MAX(pos - 0.5f, 0)); int verDownIdx = (int)(IET_MIN(pos + 0.5f, sh-1)); long verWeight = (long) (fabs(pos - 0.5f - verUpIdx) * (1<<shift)); if(verUpIdx == preVerUpIdx && verDownIdx == preVerDownIdx){ ;//do nothing } else if(verUpIdx == preVerDownIdx){ IET_SWAP(upLinePtr, downLinePtr, tempPtr); _ieInterpImageBilinear8UC1_RowFilter(sdata + sstep*verDownIdx, downLinePtr, dw, horLeftIdx, horRightIdx, horWeight, shift); }else{ _ieInterpImageBilinear8UC1_RowFilter(sdata + sstep*verUpIdx, upLinePtr, dw, horLeftIdx, horRightIdx, horWeight, shift); _ieInterpImageBilinear8UC1_RowFilter(sdata + sstep*verDownIdx, downLinePtr, dw, horLeftIdx, horRightIdx, horWeight, shift); } for(i = 0; i < dw; i++){ ddata[dstep*j + i] = (unsigned char) ( (((1<<shift) - verWeight)*upLinePtr[i] + verWeight*downLinePtr[i]) >> (2*shift) ); } preVerUpIdx = verUpIdx; preVerDownIdx = verDownIdx; } delete []rowBuf1; delete []rowBuf2; delete []horWeight; delete []horLeftIdx; delete []horRightIdx; }
速度提升
使用四次展开循环,速度提升。code如下:
static void _ieInterpImageBilinear8UC1_Ver3_RowFilter(unsigned char* src, long* dst, int len, int* leftIdx, int* rightIdx, long* weight, int shift) { int i; for(i = 0; i < len - 4; i+=4){ *dst++ = ((1<<shift) - weight[i])*src[leftIdx[i]] + weight[i]*src[rightIdx[i]]; *dst++ = ((1<<shift) - weight[i+1])*src[leftIdx[i+1]] + weight[i+1]*src[rightIdx[i+1]]; *dst++ = ((1<<shift) - weight[i+2])*src[leftIdx[i+2]] + weight[i+2]*src[rightIdx[i+2]]; *dst++ = ((1<<shift) - weight[i+3])*src[leftIdx[i+3]] + weight[i+3]*src[rightIdx[i+3]]; } for( ; i < len; ++i){ *dst++ = ((1<<shift) - weight[i])*src[leftIdx[i]] + weight[i]*src[rightIdx[i]]; } } static void _ieInterpImageBilinear8UC1_Ver3(Image* src, Image* dst) { int i, j; int sw, sh, sstep; int dw, dh, dstep; unsigned char *sdata, *ddata; float horScaleRatio, verScaleRatio; long *rowBuf1, *rowBuf2; long *upLinePtr, *downLinePtr, *tempPtr; long *horWeight; int *horLeftIdx, *horRightIdx; int preVerUpIdx, preVerDownIdx; int shift = 8; sw = src->w; sh = src->h; sstep = src->step; sdata = (unsigned char*)(src->data); dw = dst->w; dh = dst->h; dstep = dst->step; ddata = (unsigned char*)(dst->data); horScaleRatio = sw / (float)(dw); verScaleRatio = sh / (float)(dh); rowBuf1 = new long[dw]; rowBuf2 = new long[dw]; horWeight = new long[dw]; horLeftIdx = new int[dw]; horRightIdx = new int[dw]; //col interpolation //计算目标图像像素横向的左右邻居序号,和权重。 for(i = 0; i < dw; i++){ float pos = (i + 0.5f) * horScaleRatio; horLeftIdx[i] = (int)(IET_MAX(pos - 0.5f, 0)); horRightIdx[i] = (int)(IET_MIN(pos + 0.5f, sw-1)); horWeight[i] = (long) (fabs(pos - 0.5f - horLeftIdx[i]) * (1<<shift)); } preVerUpIdx = -1; preVerDownIdx = -1; upLinePtr = rowBuf1; downLinePtr = rowBuf2; for(j = 0; j < dh; j++){ float pos = (j + 0.5f) * verScaleRatio; int verUpIdx = (int)(IET_MAX(pos - 0.5f, 0)); int verDownIdx = (int)(IET_MIN(pos + 0.5f, sh-1)); long verWeight = (long) (fabs(pos - 0.5f - verUpIdx) * (1<<shift)); if(verUpIdx == preVerUpIdx && verDownIdx == preVerDownIdx){ ;//do nothing } else if(verUpIdx == preVerDownIdx){ IET_SWAP(upLinePtr, downLinePtr, tempPtr); _ieInterpImageBilinear8UC1_Ver3_RowFilter(sdata + sstep*verDownIdx, downLinePtr, dw, horLeftIdx, horRightIdx, horWeight, shift); }else{ _ieInterpImageBilinear8UC1_Ver3_RowFilter(sdata + sstep*verUpIdx, upLinePtr, dw, horLeftIdx, horRightIdx, horWeight, shift); _ieInterpImageBilinear8UC1_Ver3_RowFilter(sdata + sstep*verDownIdx, downLinePtr, dw, horLeftIdx, horRightIdx, horWeight, shift); } unsigned char* _ptr = ddata + dstep*j; for(i = 0; i < dw-4; i+=4){ *_ptr++ = (unsigned char) ( (((1<<shift) - verWeight)*upLinePtr[i] + verWeight*downLinePtr[i]) >> (2*shift) ); *_ptr++ = (unsigned char) ( (((1<<shift) - verWeight)*upLinePtr[i+1] + verWeight*downLinePtr[i+1]) >> (2*shift) ); *_ptr++ = (unsigned char) ( (((1<<shift) - verWeight)*upLinePtr[i+2] + verWeight*downLinePtr[i+2]) >> (2*shift) ); *_ptr++ = (unsigned char) ( (((1<<shift) - verWeight)*upLinePtr[i+3] + verWeight*downLinePtr[i+3]) >> (2*shift) ); } for(; i < dw; i++){ *_ptr++ = (unsigned char) ( (((1<<shift) - verWeight)*upLinePtr[i] + verWeight*downLinePtr[i]) >> (2*shift) ); } preVerUpIdx = verUpIdx; preVerDownIdx = verDownIdx; } delete []rowBuf1; delete []rowBuf2; delete []horWeight; delete []horLeftIdx; delete []horRightIdx; }=========================================================转载请注明出处:http://blog.csdn.net/songzitea/article/details/11096361
=========================================================