2010-03-23 9 views
7

carico un file .png trasparente in un oggetto UII.Ottieni BoundingBox di un'immagine trasparente?

Come calcolare la vera casella di delimitazione. Per esempio. se l'immagine reale è più piccola delle dimensioni .png.

Grazie per l'aiuto

+5

Lasciatemi riformulare: "Come trovo il rettangolo più piccolo in un'immagine parzialmente trasparente che contiene tutti i pixel con un valore alfa sopra una certa soglia?". E 'questo che intendevi? –

+1

Hai una risposta da http://stackoverflow.com/questions/6521987/crop-uiimage-to-alpha e la risposta di user404709 funziona per me. –

risposta

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!"); 
} 

Se si desidera che l'immagine da ridimensionare alle dimensioni della visualizzazione dell'immagine è possibile chiamare

[myImageView sizeToFit]; 
8

Supponendo "scatola di un'immagine di delimitazione" è semplicemente un rettangolo nell'immagine, specificato in coordinate pixel.

si desidera che il rettangolo di image che contiene tutti i pixel con un alfa maggiore di threshold (che equivale a dire che tutti i pixel che non sono in questo rettangolo hanno un alfa inferiore threshold). Dopodiché puoi trasformare questo rettangolo in coordinate dello schermo (o qualunque cosa tu voglia).

L'algoritmo di base è di iniziare con un rettangolo contenente l'intera immagine, quindi ridurre il rettangolo orizzontalmente, quindi verticalmente (o verticalmente poi orizzontalmente).

Non so Objective-C, così ho messo il codice in puro C (alcune funzioni sono solo per rendere il codice più chiaro):

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; 
} 

Ora che avete le coordinate del rettangolo di selezione casella in pixel nell'immagine, dovresti essere in grado di trasformarla in coordinate del dispositivo.

+0

C'è un possibile (anche se non comune) problema. 'x' è' unsigned' in 'shrinkHorizontally', ma stai eseguendo il ciclo con' for (x = img-> width - 1; x> = 0; x -) 'per restringere a destra. Simile per 'y' in' shrinkVertically'. Non ci sarà un comportamento indefinito poiché 'getPixelAlpha' controlla i limiti, ma se la soglia è troppo alta (rispetto all'immagine), si fermerà a ciclo indefinito. Inoltre, potresti velocizzare la ricerca non riconsiderando i pixel già elaborati (anche se le prestazioni di big-O non cambieranno). – jerry

+0

Vuoi dire, la dimensione dell'immagine è (0,0) o (w, 0) o (0, h)? – Synxis

+0

Bene, questo è un altro problema se 'Image's può avere una dimensione essere' 0'. Ciò che intendevo, tuttavia, è se non ci fosse un pixel il cui canale alfa fosse maggiore o uguale a 'threshold'. Dì "threshold = 0xFF" ma tutti i pixel hanno 'getPixelAlpha (img, x, y) <= 0xFE' (come ho detto, non comune). Quindi 'lineAlphaMax> = threshold' non sarà mai vero, quindi non uscirai mai dal ciclo esterno. Invece, il ciclo funzionerà come previsto fino a quando l'iteratore del ciclo 'x -' gira quando 'x' è' 0' (per 'shrinkHorizontally'). Questo farà sì che 'x' si sposti su' UINT_MAX', che è '> = 0'. Il ciclo funzionerà per sempre. – jerry