bilinear和bicubic的算法封装

   by chuckGao 2009

     最近在研究对视频流放大播放时进行图形缩放的bilinear和bicubic算法。这里给出最近一个项目中对图像进行2倍放大的算法。而对于算法的优化,可以考虑用建立缩放映射表的方法。

bilinear算法:

int bilinear_scale
(long newx,
 long newy,
 unsigned long oldBytesperline,
 unsigned long newBytesperline,
 int format,
 unsigned char* newImage,
 Image image)
{
        unsigned char* ptr;

        if (newx==0 || newy==0){
                return SIZE_ERROR;
        }

        if (image.width==newx && image.height==newy){
                newImage = image.bits;
                return NOT_TRANS;
        }

        float xScale, yScale, fX, fY;
        xScale = (float)0.5;
        yScale = (float)0.5;


                long ifX, ifY, ifX1, ifY1, xmax, ymax;
                float ir1, ir2, ig1, ig2, ib1, ib2, dx, dy;
                unsigned char r,g,b;
                scale_RGBQUAD rgb1, rgb2, rgb3, rgb4;
                xmax = image.width-1;
                ymax = image.width-1;
                for(long y=0; y<newy; y++){  /*算法优化by chuckGao:如果图像height>width,修改使程序减少for跨层计算*/

                                fY = y * yScale;
                                ifY = (int)fY;
                                ifY1 = min(ymax, ifY+1);
                                dy = fY - ifY;
                                for(long x=0; x<newx; x++){
                                        fX = x * xScale;
                                        ifX = (int)fX;
                                        ifX1 = min(xmax, ifX+1);
                                        dx = fX - ifX;
                                        // Interpolate using the four nearest pixels in the source
                                      
        
               unsigned char* ptr;
                                                ptr = image.bits + ifY*oldBytesperline + ifX*format;
                                                rgb1.rgbRed = *ptr++;
                                                rgb1.rgbGreen= *ptr++;
                                                rgb1.rgbBlue =*ptr;
                                                ptr = image.bits + ifY*oldBytesperline + ifX1*format;
                                                rgb2.rgbRed = *ptr++;
                                                rgb2.rgbGreen= *ptr++;
                                                rgb2.rgbBlue =*ptr;
                                                ptr = image.bits + ifY1*oldBytesperline + ifX*format;
                                                rgb3.rgbRed = *ptr++;
                                                rgb3.rgbGreen= *ptr++;
                                                rgb3.rgbBlue =*ptr;
                                                ptr = image.bits + ifY1*oldBytesperline + ifX1*format;
                                                rgb4.rgbRed = *ptr++;
                                                rgb4.rgbGreen= *ptr++;
                                                rgb4.rgbBlue =*ptr;


                                        // Interplate in x direction:
                                        ir1 = rgb1.rgbRed   + (rgb3.rgbRed   - rgb1.rgbRed)   * dy;
                                        ig1 = rgb1.rgbGreen + (rgb3.rgbGreen - rgb1.rgbGreen) * dy;
                                        ib1 = rgb1.rgbBlue  + (rgb3.rgbBlue  - rgb1.rgbBlue)  * dy;
                                        ir2 = rgb2.rgbRed   + (rgb4.rgbRed   - rgb2.rgbRed)   * dy;
                                        ig2 = rgb2.rgbGreen + (rgb4.rgbGreen - rgb2.rgbGreen) * dy;
                                        ib2 = rgb2.rgbBlue  + (rgb4.rgbBlue  - rgb2.rgbBlue)  * dy;
                                        // Interpolate in y:
                                        r = (unsigned char)(ir1 + (ir2-ir1) * dx);
                                        g = (unsigned char)(ig1 + (ig2-ig1) * dx);
                                        b = (unsigned char)(ib1 + (ib2-ib1) * dx);
                                        // Set output
                                      
          ptr = newImage + y*newBytesperline + x*format;
          
                                       
                         *ptr++ = (unsigned char)r;
                         *ptr++ = (unsigned char)g;
                         *ptr   = (unsigned char)b;

 

                                }
                        }
                    return 0;

}

 

 

bicubic算法:

int bicubic_scale
(long newx,
 long newy,
 unsigned long oldBytesperline,
 unsigned long newBytesperline,
 int format,
 unsigned char* newImage,
 Image image)
{
        unsigned char* ptr;

        if (newx==0 || newy==0){
                return SIZE_ERROR;
        }

        if (image.width==newx && image.height==newy){
                return NOT_TRANS;
        }

        float xScale, yScale, fX, fY;
        xScale = (float)0.5;
        yScale = (float)0.5;

        // bicubic interpolation by chuckGao

                float f_x, f_y, a, b, rr, gg, bb, r1, r2;
                int   i_x, i_y, xx, yy;
                scale_RGBQUAD rgb;

                for(long y=0; y<newy; y++){

                        f_y = (float) y * yScale - 0.5f;
                        i_y = (int) floor(f_y);
                        a   = f_y - (float)floor(f_y);
                        for(long x=0; x<newx; x++){
                                f_x = (float) x * xScale - 0.5f;
                                i_x = (int) floor(f_x);
                                b   = f_x - (float)floor(f_x);

                                rr = gg = bb = 0.0f;
                                for(int m=-1; m<3; m++) {
                                        r1 = kernelBSpline((float) m - a);
                                        yy = i_y+m;
                                        if (yy<0) yy=0;
                                        if (yy>=image.height) yy = image.height-1;
                                        for(int n=-1; n<3; n++) {
                                                r2 = r1 * kernelBSpline(b - (float)n);
                                                xx = i_x+n;
                                                if (xx<0) xx=0;
                                                if (xx>=image.width){
                                                    xx=image.width-1;
                                                }

                                                ptr  = image.bits + yy*oldBytesperline + xx*format;
                                                rgb.rgbRed = *ptr++;
                                                rgb.rgbGreen= *ptr++;
                                                rgb.rgbBlue  = *ptr;


                                                rr += rgb.rgbRed * r2;
                                                gg += rgb.rgbGreen * r2;
                                                bb += rgb.rgbBlue * r2;
                                        }
                                }

                              
                                 ptr = newImage + y*newBytesperline + x*format;
                                 *ptr++ = (unsigned char)rr;
                                 *ptr++ = (unsigned char)gg;
                                 *ptr   = (unsigned char)bb;

                            

                        }
                }

        return 0;
}

 

float kernelBSpline(const float x)
{
        if (x>2.0f) return 0.0f;
        // thanks to Kristian Kratzenstein
        float a, b, c, d;
        float xm1 = x - 1.0f; // Was calculatet anyway cause the "if((x-1.0f) < 0)"
        float xp1 = x + 1.0f;
        float xp2 = x + 2.0f;

        if ((xp2) <= 0.0f) a = 0.0f; else a = xp2*xp2*xp2; // Only float, not float -> double -> float
        if ((xp1) <= 0.0f) b = 0.0f; else b = xp1*xp1*xp1;
        if (x <= 0) c = 0.0f; else c = x*x*x;
        if ((xm1) <= 0.0f) d = 0.0f; else d = xm1*xm1*xm1;

        return (0.16666666666666666667f * (a - (4.0f * b) + (6.0f * c) - (4.0f * d)));

}

 

在windows上用QT写了一个opencv的视频采集程序,今天测试的结果为:

1.对于640x480放大到1280x960,采用bicubic算法,fps = 1 or 2,采用bilinear算法,fps为6,而不进行缩放的图像播放fps为12

2.预计改换显示大小为320x240,放大到640x480时fps有所增强

3.这里的fps值只是近似得到,并不绝对,只能进行相对比较

 

 

(9月22日补充)

对于图像缩放算法的优化,在很大程度上是对其运算速度进行c语言级甚至是汇编级的优化。首先要做c语言级的优化,一般采用两种方法:

1.运算流程的优化,尽量减少跨层计算

2.以空间换时间,牺牲内存空间以加快计算速度

 

在基本清楚优化原则的前提下,也要对如下概念有清楚的认识:

1.算法中涉及到的int、long、short(包括unsigned)以及float、double等数值类型的掌握。要知道,对于图像缩放后精度的控制,必须清楚的知道计算时这些类型数据的情况,比如在对float类型数据(假设变量名为rgb)赋值时:

float rgb = 0.5 和float rgb = 0.5f在精度上就有所差异,前者自动转换类型为double型,64位数据,而后者为float 32位

 

2.在32-bit计算机中,long和int的size一般是相等的,即占4bytes,32位。但计算时,特别在malloc时,还是应慎重使用sizeof(long)来确定其大小

 

3.抛开算法本身不谈,计算中数据类型为unsigned char的运算肯定比float的快,但精确度肯定不如后者。在实际编程中的取舍可以根据图像显示效果和速度来决定

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值