5

Estoy tratando de implementar una aplicación que utiliza el filtro de distorsión shpere. Estoy usando un algoritmo de here que cambia la ubicación de los píxeles mediante los métodos getPixel() y setpixel(). Mi problema es que es demasiado lento para dispositivos Android y hay aplicaciones que implementan la misma esfera (y otras) filtran mucho más rápido que mi enfoque. (por ejemplo, la aplicación Picsay Pro) ¿Alguien podría compartir o dar instrucciones para encontrar o implementar algoritmos de distorsión rápida?Buscando algoritmos rápidos de distorsión de imagen

filtro real que implementa el algoritmo:

public boolean sphereFilter(Bitmap b, boolean bSmoothing) 
{ 
    int nWidth = b.getWidth(); 
    int nHeight = b.getHeight(); 

    Point [][] pt = new Point[nWidth][nHeight]; 
    Point mid = new Point(); 
    mid.x = nWidth/2; 
    mid.y = nHeight/2; 

    double theta, radius; 
    double newX, newY; 

    for (int x = 0; x < nWidth; ++x) 
     for (int y = 0; y < nHeight; ++y) 
     { 
      pt[x][y]= new Point(); 
     } 

    for (int x = 0; x < nWidth; ++x) 
     for (int y = 0; y < nHeight; ++y) 
     { 
      int trueX = x - mid.x; 
      int trueY = y - mid.y; 
      theta = Math.atan2((trueY),(trueX)); 

      radius = Math.sqrt(trueX*trueX + trueY*trueY); 

      double newRadius = radius * radius/(Math.max(mid.x, mid.y)); 

      newX = mid.x + (newRadius * Math.cos(theta)); 

      if (newX > 0 && newX < nWidth) 
      { 
       pt[x][y].x = (int) newX; 
      } 
      else 
      { 
       pt[x][y].x = 0; 
       pt[x][y].y = 0; 
      } 

      newY = mid.y + (newRadius * Math.sin(theta)); 

      if (newY > 0 && newY < nHeight && newX > 0 && newX < nWidth) 
      {     
       pt[x][ y].y = (int) newY; 
      } 
      else 
      { 
       pt[x][y].x = pt[x][y].y = 0; 
      } 
     } 
    offsetFilterAbs(b, pt); 
    return true; 
} 

El código que sustituye a las posiciones de los pixeles calculados.

public boolean offsetFilterAbs(Bitmap b, Point[][] offset) 
{ 
     int nWidth = b.getWidth(); 
     int nHeight = b.getHeight(); 

     int xOffset, yOffset; 

     for(int y=0;y < nHeight;++y) 
     { 
      for(int x=0; x < nWidth; ++x) 
      { 
       xOffset = offset[x][y].x; 
       yOffset = offset[x][y].y; 

       if (yOffset >= 0 && yOffset < nHeight && xOffset >= 0 && xOffset < nWidth) 
       { 
        b.setPixel(x, y, b.getPixel(xOffset, yOffset)); 
       }     
      }    
     } 

    return true; 
} 
+0

posible duplicado de [Image Warping - Algoritmo de efecto de bulto] (http://stackoverflow.com/questions/5055625/image-warping-bulge-effect-algorithm) –

+0

Sí, es casi un duplicado, pero tenga en cuenta que la la respuesta aceptada a esa pregunta es * no * realmente la que quiere aquí; lo que quiere es el sombreador GLSL. –

+0

@BlueRaja, actualmente estoy usando el mismo algoritmo que el de su enlace y todavía es demasiado lento para dispositivos Android – Tony

Respuesta

5

actualmente estoy usando mismo algoritmo con el de su enlace ya y todavía es demasiado lento para los dispositivos Android

Desde mi link in the comments above:

 
Given 
r = Sqrt((x - 0.5)^2 + (y - 0.5)^2) 
a = ArcTan2(y - 0.5, x - 0.5) 
n = Bulge factor (default = 1) 

Set 
x' = r^n * Cos(a) + 0.5 
y' = r^n * Sin(a) + 0.5 

(Recuerde que, en esta ecuación, x y y abarcan desde 0 hasta 1. Si sus dimensiones abarcan desde 0 hasta w, reemplace 0.5 con w/2)

Usando a bit of math, podemos ver que

 
Cos(a) = Cos(ArcTan2(y - 0.5, x - 0.5)) 
     = (x - 0.5)/r 
Sin(a) = Sin(ArcTan2(y - 0.5, x - 0.5)) 
     = (y - 0.5)/r 

Esto hace que la ecuación final resultante

 
r = (x - 0.5)^2 + (y - 0.5)^2 
n = Bulge factor (default = 0) 

Set 
x' = r^n * (x - 0.5) + 0.5 
y' = r^n * (y - 0.5) + 0.5 

(que eliminan la raíz cuadrada ya que tomamos el resultado para una potencia real de todos modos ... así que para hacer que esto sea equivalente deberíamos usar n/2 en lugar de n, pero si na vez que estamos definiendo "abultamiento-factor", que sólo puede dejar de lado la división adicional)

Con sólo un puñado de multiplicaciones y una sola exponenciación real, esto es, probablemente, el más rápido usted puede esperar conseguir.

+1

+1 No voy a responder esta porque mi Android-fu es nula. Pero quizás el OP debería probar algunos perfiles básicos de su código y ver cuáles son los consumidores de tiempo dominante. O tal vez la eliminación de las operaciones trigonométricas superfluas sea suficiente. –

+0

@ belisarius He intentado crear un perfil de mi código y ambas funciones (calcular las nuevas posiciones x, y y reemplazarlas) toman aproximadamente 2000ms por cada una que es muy pobre en comparación con "Picsay Pro". – Tony

+1

@Tony * Picsay Pro * probablemente lo hace usando OpenGL ... y sin crear miles de objetos 'Punto' innecesarios. –

Cuestiones relacionadas