简体   繁体   中英

How to detect when the non-transparent part of an UIImage is in contact with another non-transparent part of an UIImage

I am having trouble accomplishing something that I thought was going to be much easier. I am trying to run a method whenever a non transparent part of a picture inside a UIImage touches another non-transparent part of an image contained within a UIImage. I have included an example to help further explain my question.

我问题的一个直观例子

As you can see in the image above, I have two triangles that are both inside a UIImage. The triangles are both PNG pictures. Only the triangle is visible because the background has been made transparent. Both of the UIImages are inside a UIImageView. I want to be able to run a method when the visible part of the triangle touches the visible part of the other triangle. Can someone please help me?

The brute force solution to this problem is to create a 2D array of bool s for each image, where each array entry is true for an opaque pixel, and false for the transparent pixels. If CGRectIntersectsRect returns true (indicating a possible collision), then the code scans the two arrays (with appropriate offsets depending on relative positions) to check for an actual collision. That gets complicated, and is computationally intensive.

One alternative to the brute force method is to use OpenGLES to do all of the work. This is still a brute force solution, but it offloads the work to the GPU, which is much better at such things. I'm not an expert on OpenGLES, so I'll leave the details to someone else.

A second alternative is to place restrictions on the problem that allow it to be solved more easily. For example, given two triangles A and B, collisions can only occur if one of the vertices of A is contained within the area of B, or if one of the vertices of B is in A. This problem can be solved using the UIBezierPath class in objective-C. The UIBezierPath can be used to create a path in the shape of a triangle. Then the containsPoint: method of UIBezierPath can be used to check if the vertex of the opposing triangle is contained in the area of the target triangle.

In summary, the solution is to add a UIBezierPath property to each object. Initialize the UIBezierPath to approximate the object's shape. If CGRectIntersectsRect indicates a possible collision, then check if the vertices of one object are contained in the area of the other object using the containsPoint: method.

What I did is:

  • counted the amount of non alpha pixels in image A
  • did the same for image B
  • merged A + B image into one image: C
  • compared the resulting pixel count

If pixes amount was less after merging then we have a hit.

if (C.count < A.count + B.count) -> we have a hit

+ (int)countPoints:(UIImage *)img
{

    CGImageRef cgImage = img.CGImage;
    NSUInteger width = img.size.width;
    NSUInteger height = img.size.height;
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

    size_t bitsPerComponent = 8;
    size_t bytesPerPixel    = 1;
    size_t bytesPerRow      = width * bitsPerComponent * bytesPerPixel;
    size_t dataSize         = bytesPerRow * height;

    unsigned char *bitmapData = malloc(dataSize);
    memset(bitmapData, 0, dataSize);

    CGContextRef bitmap = CGBitmapContextCreate(bitmapData, width, height, bitsPerComponent, width, NULL,(CGBitmapInfo)kCGImageAlphaOnly);

    CGColorSpaceRelease(colorSpace);

    CGContextTranslateCTM(bitmap, 0, img.size.height);
    CGContextScaleCTM(bitmap, 1.0, -1.0);

    CGContextDrawImage(bitmap, CGRectMake(0, 0, width, height), cgImage);

    int p = 0;
    int i = 0;
    while (i < width * height) {

        if (bitmapData[i] > 0) {
            p++;
        }
        i++;
    }

    free(bitmapData);
    bitmapData = NULL;
    CGContextRelease(bitmap);
    bitmap = NULL;

    //NSLog(@"points: %d",p);

    return p;
}
+ (UIImage *)marge:(UIImage *)imageA withImage:(UIImage *)imageB {

    CGSize itemSize = CGSizeMake(imageA.size.width,  imageB.size.width);
    UIGraphicsBeginImageContext(itemSize);

    CGRect rect = CGRectMake(0,
                             0,
                             itemSize.width,
                             itemSize.height);
    [imageA drawInRect:rect];
    [imageB drawInRect:rect];

    UIImage *overlappedImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return overlappedImage;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM