agens-no/AGGeometryKit

Possible to perspective-distort an image?

chadkouse opened this issue · 17 comments

I need to take an image and transform it into a new quad to give the image a perspective distortion. I want to take a rectangular image and skew. So far I haven't been able to determine how to do this. Ideally this transformation would not require the image to be added to a view since my purposes don't require me to display the image on the screen but do require me to process hundreds of these as fast as possible.

I appreciate any help or advice, thanks!

I need like a [UIImage drawInQuad:....] Method

Well, you don't need to add them to screen in order to process them. I think the demo is showcasing this.

But you need to define the quad, alas find the corners of what you want to deskew. OpenCV might help you with finding corners.

@snown might me able to fill in here as well. And do please look at the other issues.

Thanks for the reply. The issue that seems closely related is #8

However it seems to be using deprecated methods/categories.

Have you had a look at the code in AGKCATransform3DWithUIImageExample

- (void)cropImage:(UIImage *)image toQuad:(AGKQuad)quad
{
    static int count = 0;
    static dispatch_queue_t queue;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        queue = dispatch_queue_create("agk.cropImageToQuad", 0);
    });

    count++;
    [self.activityIndicator startAnimating];

    dispatch_async(queue, ^{

        UIImage *result = [image imageByCroppingToQuad:quad destinationSize:self.result.boundsSize];

        dispatch_async(dispatch_get_main_queue(), ^{
            self.result.image = result;

            count--;

            if(count == 0)
            {
                [self.activityIndicator stopAnimating];
            }
        });
    });
}

The problem you described can be breaked down into 2 issues

  1. For each image find the proper quad to crop to
  2. Crop to the given quad

Let me know which of these you are struggling with.

For my use case a crop may work but I was looking to not crop the image but instead just distort it from a rectangle to a quad. I'll see if cropping is good enough though

Maybe "crop" is not the proper wording - sorry if that was confusing. You want a deskewed UIImage, right? Well, the API to deskew images is contained within AGK. All you need is to pass the correct arguments.

Do you want to deskew the images and save them or just deskew them whenever the user is about to display them? (both is possible with AGK)

Drawings, illustration and very concise text is needed in order for me to guide you to the right places to look. I am sorry, but this has been most confusing.

You're right, sorry I should have sent this sooner.

I will try your suggestions, thanks!

example

The reason I want to do this is to ultimately draw it into another larger image like this:
example

That is very easy with AGK. I'm on the go now, but i'll give you some code in 3-16 hours. =

I would greatly appreciate it as I am hours into this search 👍

    UIImage *original = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://weknowmemes.com/wp-content/uploads/2013/11/doge-meme-13.jpg"]]];

    CGSize size = original.size;
    CGRect imageBounds = CGRectMake(0, 0, size.width, size.height);

    // Arbitrary example
    AGKQuad quadrilateral = AGKQuadMake(CGPointMake(size.width * 0.0, size.height * 0.2),
                                        CGPointMake(size.width * 1.0, size.height * 0.0),
                                        CGPointMake(size.width * 0.9, size.height * 1.0),
                                        CGPointMake(size.width * 0.2, size.height * 0.8));

    CATransform3D transform = CATransform3DWithAGKQuadFromBounds(quadrilateral, imageBounds);

    UIImage *result = [original imageWithTransform:transform anchorPoint:CGPointZero];

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    [UIImageJPEGRepresentation(original, 0.9) writeToFile:[documentsDirectory stringByAppendingPathComponent:@"source.jpg"] atomically:YES];
    [UIImageJPEGRepresentation(result, 0.9) writeToFile:[documentsDirectory stringByAppendingPathComponent:@"output.jpg"] atomically:YES];

    NSLog(@"Documents: %@", documentsDirectory);

The original
source

The result
output

You're the king of geometry -- Thanks I will see how this works in my application!

All of this can be done multithreaded. You'll notice the edges is a little bit rough. This can be improved by improving the resampling algorithm. If this is not meeting your criteria I suggest looking into OpenCV as they are doing all this and more.

So you can either try to find a good quad matching your needs or you could do a perspective distort with plain CATransform3D. I'm sure stackoverflow will be of help with the latter option. If you decide to open a stackoverflow post I'd be happy to add some bounty of 150 to ensure good answers.

Worked great and pretty good performance even single threaded. Thanks a lot!

Glad to hear that!