• 【图像处理】快速双线性插值


    前言

    图像缩放是最常用的图像操作,最近实现了一次双线性插值,适用于单通道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
    =========================================================
  • 相关阅读:
    【Silverlight】Bing Maps开发应用与技巧二:自定义图钉标注控件和动态ToolPanel
    视频挖掘
    可视化工具
    Windows开机自启动程序的方法
    从MPEG到H.264:视频压缩标准演进历史
    Marginal distribution
    Applying data mining for ontology building
    combinatory categorial grammar 文章群
    prod place ment , aggregate words of particular actors
    北京软件著作权登记网
  • 原文地址:https://www.cnblogs.com/pangblog/p/3347947.html
Copyright © 2020-2023  润新知