14

I'm having troubles cropping image. For me CICrop filter is not working properly. If my CIVector x and y (origins) are 0 everything working fine (image is cropped from left bottom corner), image is cropped by my rectangle width and height, but if CIVector origins (x and y) aren't 0 in my cropped image becomes space (because CICrop filter cropping from bottom left corner no matter what origins (x and y) are).

I'm cropping CIImage with rectangle, source:

CIVector *cropRect =[CIVector vectorWithX:150 Y:150 Z: 300 W: 300];

CIFilter *cropFilter = [CIFilter filterWithName:@"CICrop"];   

[cropFilter setValue:myCIImage forKey:@"inputImage"];
[cropFilter setValue:cropRect forKey:@"inputRectangle"];

CIImage *croppedImage = [cropFilter valueForKey:@"outputImage"];

Output Image with CIVector X 150 and Y 150: (I drawn the border for clarity)

enter image description here

Output Image with CIVector X 0 and Y 0:

enter image description here

Original Image:

enter image description here

What I'm doing wrong? Or is it supposed to do this?

j0k
  • 22,600
  • 28
  • 79
  • 90
Justin Boo
  • 10,132
  • 8
  • 50
  • 71

3 Answers3

29

Are you sure the output image is the size you are expecting? How are you drawing the output image?

The CICrop filter does not reduce the size of the original image, it just blanks out the content you don't want.

To get the result you want you probably need to just do this:

[image drawAtPoint:NSZeroPoint fromRect:NSMakeRect(150, 150, 300, 300) operation:NSCompositeSourceOver fraction:1.0];

If you want an actual CIImage as output rather than just drawing it, just do this:

CIImage* croppedImage = [image imageByCroppingToRect:CGRectMake(150, 150, 300, 300)];

//you also need to translate the origin   
CIFilter* transform = [CIFilter filterWithName:@"CIAffineTransform"];
NSAffineTransform* affineTransform = [NSAffineTransform transform];
[affineTransform translateXBy:-150.0 yBy:-150.0];
[transform setValue:affineTransform forKey:@"inputTransform"];
[transform setValue:croppedImage forKey:@"inputImage"];
CIImage* transformedImage = [transform valueForKey:@"outputImage"];
Rob Keniger
  • 45,830
  • 6
  • 101
  • 134
  • Thanks Rob! It's good for drawing image, but how to do it if I need cropped CIImage, not for drawing, but CIImage. Convert to NSImage lockfocus -> draw image -> unlockfocus -> convert to CIImage. Hmm I think this is not good, maybe You can suggest me how to get just fully cropped CIImage? Thank You very much again for Your help Rob. +1 – Justin Boo Mar 11 '12 at 17:47
  • I've added an example of the `imageByCroppingToRect:` method to my answer, which will achieve what you want. – Rob Keniger Mar 11 '12 at 23:48
  • Hmm.. this doesn't work for me, same problem. Look at my question I added update code at the bottom. Thanks for patience Rob. – Justin Boo Mar 12 '12 at 07:01
  • Actually, the image is correct, it's just that the `extent` of the resulting image is {150,150,300,300} instead of {0,0,300,300}. I have added a transform to my answer which fixes this. I tested it here and it seems to work fine. – Rob Keniger Mar 12 '12 at 07:22
  • You are right Rob. Thank You very much, now it's working fine. – Justin Boo Mar 12 '12 at 07:47
  • @RobKeniger In terms of efficiency, should we use Affine Transform or CICrop filter? – Roi Mulia Aug 30 '17 at 04:17
  • @RoiMulia they do different things, but neither will affect performance in any noticeable way. – Rob Keniger Aug 31 '17 at 04:49
  • @RobKeniger Thanks for answering. I'm doing a research over AVFoundation. Specifically on AVMutableComposition etc'. The final results I'm going to send to an Apple Engineer that suppose to verify/decline my conclusions. If you have knowledge in this area, I'd love to share some of my conclusion (on a private channel of course). I'd be a great honor to do so! – Roi Mulia Aug 31 '17 at 04:52
  • @RoiMulia sorry, but I've never used the `AVMutableComposition` APIs so wouldn't be much help… – Rob Keniger Aug 31 '17 at 04:54
  • @RobKeniger Haha that's fine. Thank you Rob. Have a great weekend! – Roi Mulia Aug 31 '17 at 04:57
9

It's important to note that the coordinate system of a view is top-left-corner, whereas CIImage is bottom left. This will make you crazy if you don't catch it when you're doing these transforms! This other post describes a one-directional conversion: Changing CGrect value to user coordinate system.

Community
  • 1
  • 1
1

This is how CICrop works -- it crop the rect you specified, and the un-cropped area becomes transparent. If you print extent you will see that it is still the same original rect.

As suggested, you can do a translation. This is now just 1 line, in Swift 5:

let newImage = myCIImage.transformed(by: CGAffineTransform(translationX: -150, y: -150)
samwize
  • 25,675
  • 15
  • 141
  • 186