2010-03-23 48 views
7

我加载一个透明的PNG到UIImage。获取透明图像的BoundingBox?

如何计算真实的边界框。例如。如果真实图像小于.png尺寸。

感谢您的帮助

+5

让我改述一下:“如何在部分透明的图像中找到最小的矩形,其中包含alpha值高于某个阈值的所有像素?”。这是你的意思吗? – 2010-03-23 16:24:41

+1

从http://stackoverflow.com/questions/6521987/crop-uiimage-to-alpha得到了答案,user404709的答案适用于我。 – 2012-03-19 04:45:06

回答

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

如果您希望图像尺寸调整到图像视图的大小,你可以调用

[myImageView sizeToFit]; 
8

假设“边界图像框”是一个简单的矩形在图像中,在像素坐标中指定。

你想要的image其中包含的所有像素具有α比threshold更大的矩形(也就相当于说,不在此矩形中的所有像素具有比threshold阿尔法更低)。之后,你可以在屏幕坐标(或任何你想要的)中变换这个矩形。

基本算法是从包含整个图像的矩形开始,然后水平缩小矩形,然后垂直缩小(或垂直然后水平)。

我不知道的Objective-C,所以我把代码中的纯C(某些功能只是为了让代码更清晰的):

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

现在,你有边界的坐标在你的图像像素框中,你应该能够在设备坐标中进行转换。

+0

有可能(虽然不常见)的问题。 'x'在'shrinkHorizo​​ntally'中是'unsigned',但是你正在用'for(x = img-> width - 1; x> = 0; x - )'循环以从右边缩小。类似于'shrinkVertically'中的'y'。由于getPixelAlpha检查边界,所以不会有未定义的行为,但是如果阈值太高(与图像相比),它将无限循环。此外,通过不重新考虑已处理的像素(尽管大O性能不会改变),您可以加快搜索速度。 – jerry 2013-03-26 21:02:54

+0

你的意思是,图像的大小是(0,0)还是(w,0)或(0,h)? – Synxis 2013-03-27 08:46:38

+0

那么,如果'Image'允许维数为'0',那是另一个问题。然而,我的意思是,如果没有像素的alpha通道大于或等于'threshold'。说'threshold = 0xFF',但所有像素都有'getPixelAlpha(img,x,y)<= 0xFE'(正如我所说的,不常见)。然后'lineAlphaMax> = threshold'永远不会是真的,所以你永远不会从外部循环中'破坏'。相反,循环将按预期运行,直到循环迭代器'x - '在'x'为'0'时运行('shrinkHorizo​​ntally')。这会导致'x'换行到'UINT_MAX',它是'> = 0'。循环将永远运行。 – jerry 2013-03-27 14:30:51