【问题标题】:Get BoundingBox of a transparent Image?获取透明图像的边界框?
【发布时间】:2010-03-23 15:43:06
【问题描述】:

我将透明的 .png 加载到 UIImage 中。

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

感谢您的帮助

【问题讨论】:

标签: iphone c objective-c


【解决方案1】:

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

您希望image 的矩形包含所有 alpha 大于 threshold 的像素(这相当于说所有不在此矩形中的像素的 alpha 都低于 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;
}

现在您已经获得了图像中边界框的像素坐标,您应该能够将其转换为设备坐标。

【讨论】:

  • 可能存在(虽然不常见)问题。 xshrinkHorizontally 中是unsigned,但您正在循环使用for(x = img-&gt;width - 1; x &gt;= 0; x--) 以从右侧缩小。与shrinkVertically 中的y 类似。因为getPixelAlpha 检查边界,所以不会有未定义的行为,但是如果阈值太高(与图像相比),它将无限循环。此外,您可以通过不重新考虑已处理的像素来稍微加快搜索速度(尽管 big-O 性能不会改变)。
  • 你的意思是,图片的尺寸是(0,0)还是(w,0)还是(0,h)?
  • 好吧,如果允许Images 的维度为0,那将是另一个问题。然而,我的意思是,如果没有一个像素的 alpha 通道大于或等于threshold。说threshold = 0xFF,但所有像素都有getPixelAlpha(img,x,y) &lt;= 0xFE(正如我所说,不常见)。那么lineAlphaMax &gt;= threshold 永远不会是真的,所以你永远不会break 退出外循环。相反,循环将按预期运行,直到循环迭代器 x--x0 时运行(对于 shrinkHorizontally)。这将导致x 换行到UINT_MAX,即&gt;= 0。循环将永远运行。
  • 当然,没问题。我刚刚注意到您在将(pixel &amp; 0xFF000000); 转换为getPixelAlpha 之前未能转移它。这将始终返回0。另外,我可能会在这里遇到一点语言律师(别担心,这与类型宽度无关),但请确保 img-&gt;heightimg-&gt;width&gt; 0&lt;= INT_MAX
  • 已修复。解决方案并不详尽;)
【解决方案2】:
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];

【讨论】:

    猜你喜欢
    • 2013-10-02
    • 2019-12-24
    • 2019-05-11
    • 1970-01-01
    • 1970-01-01
    • 2016-08-02
    • 2020-12-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多