2011-06-18 76 views
1

我試圖通過線程來加速我的應用程序。它是一個將魚眼效果放在位圖上的應用程序。它運行良好,除了它運行緩慢。我註銷了各種方法的一些處理時間,並且我已經將它指向了過濾器類中的barrel()方法。這個方法需要一個位圖,並通過它循環扭曲的像素,這個循環大約需要40秒完成!我試過AsyncTask,但這需要40+秒。最後,我試過View.post機制,但是這產生了相同的結果。有什麼方法可以加快這個應用程序?任何想法,將不勝感激,謝謝馬特。View.post沒有超速圖像處理?

public class TouchView extends View{ 


    private File tempFile; 
    private byte[] imageArray; 
    private Bitmap bgr; 
    private Bitmap bm; 
    private Bitmap bgr2 = null;; 
    private Paint pTouch; 
    private int centreX = 1; 
    private int centreY = 1; 
    private int radius = 50; 
    private int Progress = 1; 
    private static final String TAG = "*********TouchView"; 
    private Filters f = null; 
    private boolean AsyncRunning = false; 
    // private MyTask mt = null; 



    public TouchView(Context context) { 
     super(context); 
     // TouchView(context, null); 
    } 




    public TouchView(Context context, AttributeSet attr) { 
     super(context,attr); 


     ........... code to get bitmap from camera shot......... 

     bgr2 = Bitmap.createBitmap(bm.getWidth(), bm.getHeight(), bm.getConfig()); 



     f = new Filters(); 





    }// end of touchView constructor 


    public void findCirclePixels(){ 


       new Thread(new Runnable() { 
       public void run() { 
        float prog = (float)Progress/150000; 

       final Bitmap bgr3 = f.barrel(bgr,prog); 
        TouchView.this.post(new Runnable() { 
        public void run() { 
         TouchView.this.bgr2 = bgr3; 
         TouchView.this.invalidate(); 
        } 
        }); 
       } 
       }).start(); 





     }// end of changePixel() 








    public void initSlider(final HorizontalSlider slider) 
    { 
     // Log.e(TAG, "******setting up slider*********** "); 
     slider.setOnProgressChangeListener(changeListener); 
    } 



    private OnProgressChangeListener changeListener = new OnProgressChangeListener() { 


     @Override 
     public void onProgressChanged(View v, int progress) { 
      // TODO Auto-generated method stub 


       setProgress(progress); 
      //TouchView.this.Progress = progress; 


     } 
    }; 



    @Override 
    public void onDraw(Canvas canvas){ 
     super.onDraw(canvas); 


     canvas.drawBitmap(bgr2, 0, 0, null); 




    }//end of onDraw 




    protected void setProgress(int progress2) { 
     //Log.e(TAG, "***********in SETPROGRESS"); 
     this.Progress = progress2; 



     findCirclePixels(); 
     invalidate(); 


    } 




} 

import android.graphics.Bitmap; 
import android.util.Log; 

class Filters{ 
    float xscale; 
    float yscale; 
    float xshift; 
    float yshift; 
    int [] s; 
    private String TAG = "Filters"; 
    long getRadXStart = 0; 
    long getRadXEnd = 0; 
    long startSample = 0; 
    long endSample = 0; 
    public Filters(){ 

     Log.e(TAG, "***********inside filter constructor"); 
    } 

    public Bitmap barrel (Bitmap input, float k){ 
     //Log.e(TAG, "***********INSIDE BARREL METHOD "); 

     float centerX=input.getWidth()/2; //center of distortion 
     float centerY=input.getHeight()/2; 

     int width = input.getWidth(); //image bounds 
     int height = input.getHeight(); 

     Bitmap dst = Bitmap.createBitmap(width, height,input.getConfig()); //output pic 
     // Log.e(TAG, "***********dst bitmap created "); 
      xshift = calc_shift(0,centerX-1,centerX,k); 

      float newcenterX = width-centerX; 
      float xshift_2 = calc_shift(0,newcenterX-1,newcenterX,k); 

      yshift = calc_shift(0,centerY-1,centerY,k); 

      float newcenterY = height-centerY; 
      float yshift_2 = calc_shift(0,newcenterY-1,newcenterY,k); 

      xscale = (width-xshift-xshift_2)/width; 
     // Log.e(TAG, "***********xscale ="+xscale); 
      yscale = (height-yshift-yshift_2)/height; 
     // Log.e(TAG, "***********yscale ="+yscale); 
     // Log.e(TAG, "***********filter.barrel() about to loop through bm"); 
      /*for(int j=0;j<dst.getHeight();j++){ 
       for(int i=0;i<dst.getWidth();i++){ 
       float x = getRadialX((float)i,(float)j,centerX,centerY,k); 
       float y = getRadialY((float)i,(float)j,centerX,centerY,k); 
       sampleImage(input,x,y); 
       int color = ((s[1]&0x0ff)<<16)|((s[2]&0x0ff)<<8)|(s[3]&0x0ff); 
    //   System.out.print(i+" "+j+" \\"); 

       dst.setPixel(i, j, color); 

       } 
      }*/ 

      int origPixel; 
      long startLoop = System.currentTimeMillis(); 
      for(int j=0;j<dst.getHeight();j++){ 
       for(int i=0;i<dst.getWidth();i++){ 
       origPixel= input.getPixel(i,j); 
       getRadXStart = System.currentTimeMillis(); 
       float x = getRadialX((float)j,(float)i,centerX,centerY,k); 
       getRadXEnd= System.currentTimeMillis(); 

       float y = getRadialY((float)j,(float)i,centerX,centerY,k); 

       sampleImage(input,x,y); 

       int color = ((s[1]&0x0ff)<<16)|((s[2]&0x0ff)<<8)|(s[3]&0x0ff); 
    //   System.out.print(i+" "+j+" \\"); 

       if(Math.sqrt(Math.pow(i - centerX, 2) + (Math.pow(j - centerY, 2))) <= 150){ 
       dst.setPixel(i, j, color); 
       }else{ 
        dst.setPixel(i,j,origPixel); 
       } 
       } 
      } 
      long endLoop = System.currentTimeMillis(); 
      long loopDuration = endLoop - startLoop; 
      long radXDuration = getRadXEnd - getRadXStart; 
      long sampleDur = endSample - startSample; 

      Log.e(TAG, "sample method took "+sampleDur+"ms"); 
      Log.e(TAG, "getRadialX took "+radXDuration+"ms"); 
      Log.e(TAG, "loop took "+loopDuration+"ms"); 

     // Log.e(TAG, "***********filter.barrel() looped through bm about to return dst bm"); 
     return dst; 
    } 

    void sampleImage(Bitmap arr, float idx0, float idx1) 
    { 
     startSample = System.currentTimeMillis(); 
     s = new int [4]; 
     if(idx0<0 || idx1<0 || idx0>(arr.getHeight()-1) || idx1>(arr.getWidth()-1)){ 
     s[0]=0; 
     s[1]=0; 
     s[2]=0; 
     s[3]=0; 
     return; 
     } 

     float idx0_fl=(float) Math.floor(idx0); 
     float idx0_cl=(float) Math.ceil(idx0); 
     float idx1_fl=(float) Math.floor(idx1); 
     float idx1_cl=(float) Math.ceil(idx1); 

     int [] s1 = getARGB(arr,(int)idx0_fl,(int)idx1_fl); 
     int [] s2 = getARGB(arr,(int)idx0_fl,(int)idx1_cl); 
     int [] s3 = getARGB(arr,(int)idx0_cl,(int)idx1_cl); 
     int [] s4 = getARGB(arr,(int)idx0_cl,(int)idx1_fl); 

     float x = idx0 - idx0_fl; 
     float y = idx1 - idx1_fl; 

     s[0]= (int) (s1[0]*(1-x)*(1-y) + s2[0]*(1-x)*y + s3[0]*x*y + s4[0]*x*(1-y)); 
     s[1]= (int) (s1[1]*(1-x)*(1-y) + s2[1]*(1-x)*y + s3[1]*x*y + s4[1]*x*(1-y)); 
     s[2]= (int) (s1[2]*(1-x)*(1-y) + s2[2]*(1-x)*y + s3[2]*x*y + s4[2]*x*(1-y)); 
     s[3]= (int) (s1[3]*(1-x)*(1-y) + s2[3]*(1-x)*y + s3[3]*x*y + s4[3]*x*(1-y)); 

     endSample = System.currentTimeMillis(); 
    } 

    int [] getARGB(Bitmap buf,int x, int y){ 

     int rgb = buf.getPixel(y, x); // Returns by default ARGB. 
     int [] scalar = new int[4]; 
     scalar[0] = (rgb >>> 24) & 0xFF; 
     scalar[1] = (rgb >>> 16) & 0xFF; 
     scalar[2] = (rgb >>> 8) & 0xFF; 
     scalar[3] = (rgb >>> 0) & 0xFF; 
     return scalar; 
    } 

    float getRadialX(float x,float y,float cx,float cy,float k){ 

     x = (x*xscale+xshift); 
     y = (y*yscale+yshift); 
     float res = x+((x-cx)*k*((x-cx)*(x-cx)+(y-cy)*(y-cy))); 
     return res; 
    } 

    float getRadialY(float x,float y,float cx,float cy,float k){ 

     x = (x*xscale+xshift); 
     y = (y*yscale+yshift); 
     float res = y+((y-cy)*k*((x-cx)*(x-cx)+(y-cy)*(y-cy))); 
     return res; 
    } 

    float thresh = 1; 

    float calc_shift(float x1,float x2,float cx,float k){ 

     float x3 = (float)(x1+(x2-x1)*0.5); 
     float res1 = x1+((x1-cx)*k*((x1-cx)*(x1-cx))); 
     float res3 = x3+((x3-cx)*k*((x3-cx)*(x3-cx))); 

     if(res1>-thresh && res1 < thresh) 
     return x1; 
     if(res3<0){ 
     return calc_shift(x3,x2,cx,k); 
     } 
     else{ 
     return calc_shift(x1,x3,cx,k); 
     } 
    } 



}// end of filters class 
+0

使用Traceview可以更全面地瞭解您的時間花在哪裏。 http://developer.android.com/guide/developing/debugging/debugging-tracing.html – CommonsWare

+0

@CommonsWare嗨,我已經創建了一個名爲barrel.trace的跟蹤文件並將它拖到我的桌面上。我如何啓動traceview工具?我已經嘗試了sdk/tools文件夾並單擊了traceview,但該窗口剛剛關閉 – turtleboy

+0

打開命令提示符。切換到你的'tools /'目錄。運行'traceview ...',其中'...'是跟蹤文件的路徑。或者,如果您使用的是Eclipse,Traceview是您可以打開的視角。 – CommonsWare

回答

2

在幾乎所有計算機創建時,浮點數學都很糟糕。但是,它確實吸引那些缺乏浮點協處理器支持的設備,比如Android設備的一半。因此,擺脫浮點運算,如每一個位:

  • 你並不需要通過浮點運行整數ceil()floor()方法

  • 你並不需要計算sqrt()來比較150,而不是跳過sqrt()和比較反對22500

  • 你不需要浮點pow()計算某物的平方;相反,使用稱爲「乘法」

  • 先進的數學運算,我懷疑,半像素將不管在你的計算一噸,所以也許你並不需要centerXcenterYfloat

  • 而且等等

在一個捏,你可能需要使用像Google地圖加載項一樣的技巧供Android使用。通常情況下,你會想到十進制度的經緯度,但這意味着很多浮點數學。谷歌地圖以微小的角度(10^6度)使用經度和緯度,以便能夠在定點數學中進行所有計算,但仍保持合理的精度。

無論所有這些都會使性能下降到你認爲合理的程度,我不能說。但是,在開始抱怨Android代碼的質量之前,您應該確保確保您的代碼質量合理,就像您在上次評論中所做的一樣。

+0

好的感謝您的意見。關於Android的代碼,我根本沒有任何貶義,相反,我強調我認爲我的代碼存在問題,因爲40秒確實太慢了,而且我確信Android可以更快地處理位圖。基本上我想知道如果我已經正確地實施了我的代碼關於Android生命週期,事件調用等等,也許有一些我做錯了,我優化應用程序之前我糾正。希望是有道理的。謝謝 – turtleboy

+0

@turtleboy:啊,好的。最終,您可能需要使用NDK for C/C++代碼(或蜂窩上的Renderscript Compute)。但是我認爲,去代碼化你的代碼對於幫助來說很有幫助。 – CommonsWare

+0

好的。我不確定你是否意味着我要做下面的事情,但是我已經把所有的浮點數都放在了過濾器類中,並且用math.ciel()完成了。它已經減少了5秒的處理時間,但效果不再出現在位圖上。 – turtleboy