UIImage 之间的 2D 像素级碰撞检测

发布于 2024-12-11 02:22:42 字数 2631 浏览 0 评论 0原文

我正在尝试编写一种方法来检测两个 UIImage 何时发生碰撞,仅考虑不透明像素。需要明确的是,当 UIImageView 上 alpha 分量大于 0 的像素与另一个 UIImageView 上 alpha 分量大于 0 的像素重叠时,该方法返回 TRUE。

该方法应该类似于:

- (void)checkCollisionBetweenImage:(UIImage *)img1 inFrame:(CGRect)frame1 andImage:(UIImage *)img2 inFrame:(CGRect)frame2;

因此它接收要检查的两个图像,其框架独立传递,因为必须转换坐标位置以匹配(UIImageView.frame 不会这样做)。

[更新1] 我将使用我在上一个问题中使用的一段代码进行更新,但是该代码并不总是有效。我想问题在于所使用的 UIImages 不一定位于同一个超级视图中。

检测两个图像之间的像素碰撞/重叠

if (!CGRectIntersectsRect(frame1, frame2)) return NO;
NSLog(@"OverlapsPixelsInImage:withImage:> Images Intersect");

UIImage *img1 = imgView1.image;
UIImage *img2 = imgView2.image;
CGImageRef imgRef1 = [img1 CGImage];
CGImageRef imgRef2 = [img2 CGImage];

float minx = MIN(frame1.origin.x, frame2.origin.x);
float miny = MIN(frame1.origin.y, frame2.origin.y);
float maxx = MAX(frame1.origin.x + frame1.size.width, frame2.origin.x + frame2.size.width);
float maxy = MAX(frame1.origin.y + frame1.size.height, frame2.origin.y + frame2.size.height);
CGRect canvasRect = CGRectMake(0, 0, maxx - minx, maxy - miny);

size_t width = floorf(canvasRect.size.width);
size_t height = floorf(canvasRect.size.height);

NSUInteger bitsPerComponent = 8;
NSUInteger bytesPerRow = 4 * width;
unsigned char *rawData = malloc(canvasRect.size.width * canvasRect.size.height * 4 * bitsPerComponent);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

CGContextRef context = CGBitmapContextCreate(rawData, width, height, bitsPerComponent, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast);

CGColorSpaceRelease(colorSpace);

CGContextTranslateCTM(context, 0, canvasRect.size.height);
CGContextScaleCTM(context, 1.0, -1.0);

CGContextClipToMask(context, CGRectMake(frame2.origin.x - minx, frame2.origin.y - miny, frame2.size.width, frame2.size.height), imgRef2);
CGContextDrawImage(context, CGRectMake(frame1.origin.x - minx, frame1.origin.y - miny, frame1.size.width, frame1.size.height), imgRef1);

CGContextRelease(context);

int byteIndex = 0;
for (int i = 0; i < width * height; i++)
{
    int8_t alpha = rawData[byteIndex + 3];
    if (alpha > 64) 
    {
        NSLog(@"collided in byte: %d", i);
        free(rawData);
        return YES;
    }
    byteIndex += 4;
}

free(rawData);

return NO;

[更新 2] 在绘制蒙版图像之前,我使用了据称需要的另一条线。

CGContextSetBlendMode(context, kCGBlendModeCopy);

还是不行。奇怪的是,我一直在检查碰撞时检测到的 alpha 值,它们是随机数。这很奇怪,因为我使用的图像只有完全不透明或完全透明,中间没有任何东西。

I'm trying to code a method which detects when two UIImages collide taking into account only the non-transparent pixels. Just to be clear, a method that returns TRUE when a pixel with its alpha component greater than 0 on a UIImageView overlaps with a pixel also with its alpha component greater than 0 on the other UIImageView.

The method should be something like:

- (void)checkCollisionBetweenImage:(UIImage *)img1 inFrame:(CGRect)frame1 andImage:(UIImage *)img2 inFrame:(CGRect)frame2;

So it receives both images to be checked with its frame passed independently since the coordinate positions must be converted to match (UIImageView.frame won't do).

[UPDATE 1]
I'll update with a piece of code I used in a previous question I made, this code however doesn't always work. I guess the problem lies in the fact that the UIImages used aren't necessarily in the same superview.

Detect pixel collision/overlapping between two images

if (!CGRectIntersectsRect(frame1, frame2)) return NO;
NSLog(@"OverlapsPixelsInImage:withImage:> Images Intersect");

UIImage *img1 = imgView1.image;
UIImage *img2 = imgView2.image;
CGImageRef imgRef1 = [img1 CGImage];
CGImageRef imgRef2 = [img2 CGImage];

float minx = MIN(frame1.origin.x, frame2.origin.x);
float miny = MIN(frame1.origin.y, frame2.origin.y);
float maxx = MAX(frame1.origin.x + frame1.size.width, frame2.origin.x + frame2.size.width);
float maxy = MAX(frame1.origin.y + frame1.size.height, frame2.origin.y + frame2.size.height);
CGRect canvasRect = CGRectMake(0, 0, maxx - minx, maxy - miny);

size_t width = floorf(canvasRect.size.width);
size_t height = floorf(canvasRect.size.height);

NSUInteger bitsPerComponent = 8;
NSUInteger bytesPerRow = 4 * width;
unsigned char *rawData = malloc(canvasRect.size.width * canvasRect.size.height * 4 * bitsPerComponent);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

CGContextRef context = CGBitmapContextCreate(rawData, width, height, bitsPerComponent, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast);

CGColorSpaceRelease(colorSpace);

CGContextTranslateCTM(context, 0, canvasRect.size.height);
CGContextScaleCTM(context, 1.0, -1.0);

CGContextClipToMask(context, CGRectMake(frame2.origin.x - minx, frame2.origin.y - miny, frame2.size.width, frame2.size.height), imgRef2);
CGContextDrawImage(context, CGRectMake(frame1.origin.x - minx, frame1.origin.y - miny, frame1.size.width, frame1.size.height), imgRef1);

CGContextRelease(context);

int byteIndex = 0;
for (int i = 0; i < width * height; i++)
{
    int8_t alpha = rawData[byteIndex + 3];
    if (alpha > 64) 
    {
        NSLog(@"collided in byte: %d", i);
        free(rawData);
        return YES;
    }
    byteIndex += 4;
}

free(rawData);

return NO;

[UPDATE 2]
I used another line supposedly required just before drawing the masked image.

CGContextSetBlendMode(context, kCGBlendModeCopy);

Still doesn't work. Curiously, I've been checking the alpha values detected on collision and they are random numbers. It's curious because the images I'm using have only full opacity or full transparency, nothing in between.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

药祭#氼 2024-12-18 02:22:43

嗯...您的问题是您的图像后面有白色方块,并且您不希望白色框发生碰撞,但您希望其中的图像发生碰撞?出色地...
我不认为你可以根据颜色检查碰撞。你需要做的是下载一些图像编辑软件(如gimp)并裁剪出白色背景。

Hrmm... Is your problem that your images have white squares behind them and you don't want the white boxes to collide, but you want the images inside them to collide? Well...
I don't think you can check collision based on colors. What you need to do is download some image editing software (like gimp) and crop out the white background.

软甜啾 2024-12-18 02:22:42

检查实际帧交叉点 ->给你一个矩形。
检查矩形中一张图像中的每个像素的 alpha > >如果是,则将当前坐标转换为另一个图像的坐标,然后如果该像素的 alpha > 0。 0 你成功了。重复直到完成矩形。
如果您发现了热门产品,请尽早停止。

Check for the actual frame intersection -> gives you a rectangle.
Check every pixel in one of the images in the rectangle for alpha > 0. If so then convert the current coordinate into the other image's and then if the alpha of that pixel > 0 you have a hit. Repeat until the rectangle is done.
Stop early if you have fount a hit.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文