bilinear和bicubic的演算法封裝

來源:互聯網
上載者:User

   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的快,但精確度肯定不如後者。在實際編程中的取捨可以根據映像顯示效果和速度來決定

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.