2011-06-19 14 views
5

Mam następującą klasę, która przetwarza bitmapę, aby umieścić na niej zniekształcenie typu "rybie oko".Jak zoptymalizować przetwarzanie obrazu klasy

Zabrakło mi moją aplikację poprzez TraceView i okazało się, że praktycznie cały czas przetwarzania jest wydawana przelotowego bitmapy.
Jeden programista zasugerował, aby nie używać funkcji float, ponieważ spowalnia to działanie grafiki. Również użycie math.pow() i ceil() nie jest konieczne?
W tej chwili wstawienie efektu przez zapętlenie całej bitmapy zajmuje około 42 sekund, tak sekund :)
Próbowałem zastąpić zmiennoprzecinkowe ints i to zmniejszyło czas do 37 sekund, ale efekt nie jest dłużej obecne na mapie bitowej.
Argument k jest początkowo zmiennoprzecinkowy i ustawia poziom zniekształceń, np. 0.0002F, jeśli przekażę int, efekt nie działa.

Czy ktoś może wskazać mi właściwy kierunek optymalizacji tego procesu? Raz już zoptymalizowany go Chciałbym przyjrzeć się być może nie zapętlenie przez całą bitmapę i być może wprowadzenie obwiedni wokół efektu lub przy użyciu algorytmu poniżej, który określa, czy piksel znajduje się wewnątrz okręgu o promieniu 150.

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 

[aktualizacja] Utworzono tablice jako zmienną instancji i utworzono je w konstruktorze Filter(). Czy to masz na myśli? Aplikacja działała przez 84 s (błąd), ale teraz działa na 69 sekund. wydaje się, że nie wylogowano również GC.

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

     Log.e(TAG, "***********inside filter constructor"); 
     s = new int[4]; 
     scalar = new int[4]; 
     s1 = new int[4]; 
     s2 = new int[4]; 
     s3 = new int[4]; 
     s4 = new int[4]; 
    } 

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

     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"); 
      Debug.stopMethodTracing(); 
     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);*/ 

     s1 = getARGB(arr,(int)idx0_fl,(int)idx1_fl); 
     s2 = getARGB(arr,(int)idx0_fl,(int)idx1_cl); 
     s3 = getARGB(arr,(int)idx0_cl,(int)idx1_cl); 
     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

was może spróbować delegowania to na kodzie przeglądarki stosie: http://codereview.stackexchange.com/ –

+0

@joe ok dzięki, ja pisał to – turtleboy

Odpowiedz

1

Z tego co widzę, kod jest w następujący sposób:

for (every pixel in bitmap){ 
    getPixel(); 
    ...do something to pixel... 
    setPixel(); 
} 

W getPixel() i setPixel() wywołania funkcji są stosunkowo drogie. Zamiast wywoływać je w pętli, możesz spróbować ustawić wszystkie piksele w tablicy używając getPixels(), a następnie uzyskać dostęp do każdego piksela przez tablicę. Zapoznaj się z tym answer.

Jeśli to nadal nie jest wystarczająca, spróbuj kodowania wyżej w C++ przez NDK.

+0

@jim lim Cześć, tak, ostatnio zakodowałem aplikację tygodnia, aby to zrobić, a następnie użył "Bitmap.createBitmap (array, x, y, config);" metoda. przetwarzanie trwało od 50 sekund do 6 sekund! dzięki – turtleboy

+0

Lim cześć, myślę, że ndk może być drogą. Czy potrzebuję oprogramowania visual studio dla telefonów do integracji C++ z Androidem? lub czy po prostu potrzebuję jakiegokolwiek kompilatora C++, aby utworzyć pliki klasy, a następnie wywołać je za pośrednictwem narzędzia ndk? dzięki matt – turtleboy

+0

Nie, nie potrzebujesz żadnej technologii Microsoftu, aby tworzyć rzeczy dla Androida. Pobierz NDK i przetestuj niektóre z [przykładowych aplikacji] (http://developer.android.com/sdk/ndk/overview.html#samples), aby zobaczyć, jak z niego korzystać. W skrócie, piszesz kod C/C++ i korzystasz z kompilatora dostarczonego przez NDK. Pisałem także o NDK [tutaj] (http://blog.jh-lim.com/2011/07/compiling-open-source-libraries-for-android-part-2/) i [tutaj] (http : //blog.jh-lim.com/2011/06/compiling-open-source-libraries-for-android-part-1/). –

0

Jedno można spróbować się uniknąć tworzenia/odtworzenie tablice int w „sampleImage” i „” przy uruchamianiu getARGB je raz na zewnątrz dwóch zagnieżdżonych pętli i przekazywanie ich do tych metod. Nie byłoby to najlepszą praktyką z punktu widzenia łatwości kodowania. Unikałoby to jednak wielokrotnego tworzenia obiektów, inicjowania macierzy i pobierania narzutów. Są one znacznie droższe niż operacje arytmetyczne w pozostałej części kodu.

+0

@btreat yep postaram to jako kiedy uruchamiam aplikację wydaje się być dużo GC przed wyświetleniem obrazu – turtleboy

+0

@ btreat zaktualizowałem post dzięki – turtleboy

+0

@turtleboy - tak, to jest to, co sugerowałem. Wygląda na to, że przyniosło poprawę o 15-20%, co jest dobrym początkiem. Inną możliwością optymalizacji byłoby zapisanie niektórych wartości, które przechodzą do obliczeń s [0-3] na końcu przykładowego obrazu w zmiennych lokalnych. – btreat

2

Po pierwsze - zmierz niektóre funkcje i sprawdź, gdzie znajdują się wąskie gardła. Nie próbuj optymalizować przez zgadywanie.

Mimo, że będę teraz próba powiedział zadanie :)

Wykonanie operacji sqrt() na piksel jest dość drogie - jesteś porównując do stałej, więc zamiast placu stała i porównać wartość pogodzić z że:

if((Math.pow(i - centerX, 2) + (Math.pow(j - centerY, 2))) <= 150*150){ 

również za pomocą pow(x,2) do kwadratu coś jest prawdopodobnie wywołując funkcję biblioteki dla pow(), konwersja float s do double s robi algorytmu zasilania podnoszenia ogólnego przeznaczenia i Nawrócenie float s. Po prostu użyj zamiast tego x*x.

if(((i-centerX)*(i-centerX) + (j-centerY)*(j-centerY)) <= 150){ 
Powiązane problemy