2010-03-23 13 views
7

cargo un .png transparente en un UIImage.Obtener BoundingBox de una imagen transparente?

Cómo calculo el cuadro delimitador real. P.ej. si la imagen real es más pequeña que las dimensiones .png.

Gracias por ayudar a

+5

Permítanme reformular: "¿Cómo puedo encontrar el rectángulo más pequeño en una imagen parcialmente transparente que contiene todos los píxeles con un valor alfa por encima de un cierto umbral?". ¿Es eso lo que querías decir? –

+1

Obtuve una respuesta de http://stackoverflow.com/questions/6521987/crop-uiimage-to-alpha y la respuesta del usuario404709 me funciona. –

Respuesta

0
CGRect myImageViewRect = [myImageView frame]; 
CGSize myImageSize = [[myImageView image]size]; 

if(myImageSize.width < myImageViewRect.size.width){ 
    NSLog(@"it's width smaller!"); 
} 
if(myImageSize.height < myImageViewRect.size.height){ 
    NSLog(@"it's height smaller!"); 
} 

Si desea que la imagen para cambiar el tamaño al tamaño de la vista de la imagen se puede llamar

[myImageView sizeToFit]; 
8

Asumiendo "cuadro de una imagen de delimitación" es simplemente un rectángulo en la imagen, especificada en coordenadas de píxel.

desea que el rectángulo de image que contiene todos los píxeles con un alfa mayor que threshold (que es equivalente a decir que todos los píxeles que no están en este rectángulo tienen un alfa menor que threshold). Después de eso, puedes transformar este rectángulo en coordenadas de pantalla (o lo que quieras).

El algoritmo básico es comenzar con un rectángulo que contenga toda la imagen, luego encoger el rectángulo horizontalmente, luego verticalmente (o verticalmente y luego horizontalmente).

No sé Objective-C, por lo que poner el código en C puro (algunas funciones son sólo para hacer el código más claro):

typedef struct Rectangle 
{ 
    unsigned int x1, y1, x2, y2; 
} Rectangle; 

typedef struct Image 
{ 
    unsigned int height,width; 
    unsigned int* data; 
} Image; 

unsigned char getPixelAlpha(Image* img, unsigned int x, unsigned int y) 
{ 
    unsigned int pixel = 0; // default = fully transparent 

    if(x >= img->width || y >= img->height) 
     return pixel; // Consider everything not in the image fully transparent 

    pixel = img->data[x + y * img->width]; 
    return (unsigned char)((pixel & 0xFF000000) >> 24); 
} 

void shrinkHorizontally(Image* img, unsigned char threshold, Rectangle* rect) 
{ 
    int x, y; 

    // Shrink from left 
    for(x = 0; x < (int)img->width; x++) 
    { 
     // Find the maximum alpha of the vertical line at x 
     unsigned char lineAlphaMax = 0; 
     for(y = 0; y < (int)img->height; y++) 
     { 
      unsigned char alpha = getPixelAlpha(img,x,y); 
      if(alpha > lineAlphaMax) 
       lineAlphaMax = alpha; 
     } 

     // If at least on pixel of the line if more opaque than 'threshold' 
     // then we found the left limit of the rectangle 
     if(lineAlphaMax >= threshold) 
     { 
      rect->x1 = x; 
      break; 
     } 
    } 


    // Shrink from right 
    for(x = img->width - 1; x >= 0; x--) 
    { 
     // Find the maximum alpha of the vertical line at x 
     unsigned char lineAlphaMax = 0; 
     for(y = 0; y < (int)img->height; y++) 
     { 
      unsigned char alpha = getPixelAlpha(img,x,y); 
      if(alpha > lineAlphaMax) 
       lineAlphaMax = alpha; 
     } 

     // If at least on pixel of the line if more opaque than 'threshold' 
     // then we found the right limit of the rectangle 
     if(lineAlphaMax >= threshold) 
     { 
      rect->x2 = x; 
      break; 
     } 
    } 
} 

// Almost the same than shrinkHorizontally. 
void shrinkVertically(Image* img, unsigned char threshold, Rectangle* rect) 
{ 
    int x, y; 

    // Shrink from up 
    for(y = 0; y < (int)img->height; y++) 
    { 
     // Find the maximum alpha of the horizontal line at y 
     unsigned char lineAlphaMax = 0; 
     for(x = 0; x < (int)img->width; x++) 
     { 
      unsigned char alpha = getPixelAlpha(img,x,y); 
      if(alpha > lineAlphaMax) 
       lineAlphaMax = alpha; 
     } 

     // If at least on pixel of the line if more opaque than 'threshold' 
     // then we found the up limit of the rectangle 
     if(lineAlphaMax >= threshold) 
     { 
      rect->y1 = x; 
      break; 
     } 
    } 


    // Shrink from bottom 
    for(y = img->height- 1; y >= 0; y--) 
    { 
     // Find the maximum alpha of the horizontal line at y 
     unsigned char lineAlphaMax = 0; 
     for(x = 0; x < (int)img->width; x++) 
     { 
      unsigned char alpha = getPixelAlpha(img,x,y); 
      if(alpha > lineAlphaMax) 
       lineAlphaMax = alpha; 
     } 

     // If at least on pixel of the line if more opaque than 'threshold' 
     // then we found the bottom limit of the rectangle 
     if(lineAlphaMax >= threshold) 
     { 
      rect->y2 = x; 
      break; 
     } 
    } 
} 

// Find the 'real' bounding box 
Rectangle findRealBoundingBox(Image* img, unsigned char threshold) 
{ 
    Rectangle r = { 0, 0, img->width, img->height }; 
    shrinkHorizontally(img,threshold,&r); 
    shrinkVertically(img,threshold,&r); 
    return r; 
} 

Ahora que tiene las coordenadas de la delimitación cuadro en píxel en su imagen, debería poder transformarlo en las coordenadas del dispositivo.

+0

Hay un problema posible (aunque poco común). 'x' está' unsigned' en 'shrinkHorizontally', sin embargo, está bucleando con' for (x = img-> width - 1; x> = 0; x -) 'para contraer desde la derecha. Similar para 'y' en' shrinkVertically'. No habrá un comportamiento indefinido ya que 'getPixelAlpha' verifica los límites, pero si el umbral es demasiado alto (en comparación con la imagen), se repetirá indefinidamente. Además, podría acelerar un poco la búsqueda al no reconsiderar los píxeles ya procesados ​​(aunque el rendimiento del gran O no cambiará). – jerry

+0

¿Quiere decir que el tamaño de la imagen es (0,0) o (w, 0) o (0, h)? – Synxis

+0

Bueno, ese es otro problema si 'Image's se permite tener una dimensión sea' 0'. Lo que quise decir, sin embargo, es si no había un píxel cuyo canal alfa fuera mayor o igual que 'umbral'. Diga 'threshold = 0xFF' pero todos los píxeles tienen' getPixelAlpha (img, x, y) <= 0xFE' (como dije, poco común). Entonces 'lineAlphaMax> = threshold' nunca será verdadero, por lo que nunca' saldrá 'del bucle externo. En cambio, el bucle se ejecutará como se espera hasta que el iterador de bucle 'x -' se ejecute cuando 'x' sea' 0' (para 'shrinkHorizontally'). Esto hará que 'x' se ajuste a' UINT_MAX', que es '> = 0'. El ciclo se ejecutará para siempre. – jerry

Cuestiones relacionadas