I got camera preview layer where the camera preset is 1280x720. above the preview layer i added a square UIView with border.
My goal is getting cropped Image from camera.
Method to extract data from camera
-(CGImageRef)createImageFromBuffer:(CVImageBufferRef)buffer
left:(size_t)left
top:(size_t)top
width:(size_t)width
height:(size_t)height CF_RETURNS_RETAINED {
size_t bytesPerRow = CVPixelBufferGetBytesPerRow(buffer);
size_t dataWidth = CVPixelBufferGetWidth(buffer);
size_t dataHeight = CVPixelBufferGetHeight(buffer);
if (left + width > dataWidth ||
top + height > dataHeight) {
[NSException raise:NSInvalidArgumentException format:@"Crop rectangle does not fit within image data."];
}
size_t newBytesPerRow = ((width*4+0xf)>>4)<<4;
CVPixelBufferLockBaseAddress(buffer,0);
int8_t *baseAddress = (int8_t *)CVPixelBufferGetBaseAddress(buffer);
size_t size = newBytesPerRow*height;
int8_t *bytes = (int8_t *)malloc(size * sizeof(int8_t));
if (newBytesPerRow == bytesPerRow) {
memcpy(bytes, baseAddress+top*bytesPerRow, size * sizeof(int8_t));
} else {
for (int y=0; y<height; y++) {
memcpy(bytes+y*newBytesPerRow,
baseAddress+left*4+(top+y)*bytesPerRow,
newBytesPerRow * sizeof(int8_t));
}
}
CVPixelBufferUnlockBaseAddress(buffer, 0);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef newContext = CGBitmapContextCreate(bytes,
width,
height,
8,
newBytesPerRow,
colorSpace,
kCGBitmapByteOrder32Little|
kCGImageAlphaNoneSkipFirst);
CGColorSpaceRelease(colorSpace);
CGImageRef result = CGBitmapContextCreateImage(newContext);
CGContextRelease(newContext);
free(bytes);
return result;
}
code to rotate image
- (CGImageRef)createRotatedImage:(CGImageRef)original degrees:(float)degrees CF_RETURNS_RETAINED {
if (degrees == 0.0f) {
CGImageRetain(original);
return original;
} else {
double radians = degrees * M_PI / 180;
#if TARGET_OS_EMBEDDED || TARGET_IPHONE_SIMULATOR
radians = -1 * radians;
#endif
size_t _width = CGImageGetWidth(original);
size_t _height = CGImageGetHeight(original);
CGRect imgRect = CGRectMake(0, 0, _width, _height);
CGAffineTransform __transform = CGAffineTransformMakeRotation(radians);
CGRect rotatedRect = CGRectApplyAffineTransform(imgRect, __transform);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(NULL,
rotatedRect.size.width,
rotatedRect.size.height,
CGImageGetBitsPerComponent(original),
0,
colorSpace,
kCGBitmapAlphaInfoMask & kCGImageAlphaPremultipliedFirst);
CGContextSetAllowsAntialiasing(context, FALSE);
CGContextSetInterpolationQuality(context, kCGInterpolationNone);
CGColorSpaceRelease(colorSpace);
CGContextTranslateCTM(context,
+(rotatedRect.size.width/2),
+(rotatedRect.size.height/2));
CGContextRotateCTM(context, radians);
CGContextDrawImage(context, CGRectMake(-imgRect.size.width/2,
-imgRect.size.height/2,
imgRect.size.width,
imgRect.size.height),
original);
CGImageRef rotatedImage = CGBitmapContextCreateImage(context);
CFRelease(context);
return rotatedImage;
}
}
Extracting the data:
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection {
if(self.lastDecodeTime && [self.lastDecodeTime timeIntervalSinceNow]>-DECODE_LIMIT_TIME){
return;
}
if ( self.scannerDisabled)
return;
self.lastDecodeTime=[NSDate date];
CVImageBufferRef videoFrame = CMSampleBufferGetImageBuffer(sampleBuffer);
CGFloat cameraFrameWidth = CVPixelBufferGetWidth(videoFrame);
CGFloat cameraFrameHeight = CVPixelBufferGetHeight(videoFrame);
CGPoint rectPoint = self.rectangleView.frame.origin;
rectPoint = [self.previewLayer convertPoint:rectPoint fromLayer:self.view.layer];
CGPoint cameraPoint = [self.previewLayer captureDevicePointOfInterestForPoint:rectPoint];
CGPoint matrixPoint = CGPointMake(cameraPoint.x*cameraFrameWidth,cameraPoint.x*cameraFrameHeight);
CGFloat D = self.rectangleView.frame.size.width*2.0;
CGRect matrixRect = CGRectMake(matrixPoint.x, matrixPoint.y, D, D);
CGImageRef videoFrameImage = [self createImageFromBuffer:videoFrame left:matrixRect.origin.x top:matrixRect.origin.y width:matrixRect.size.width height:matrixRect.size.height];
CGImageRef rotatedImage = [self createRotatedImage:videoFrameImage degrees:self.rotationDeg];
CGImageRelease(videoFrameImage);
...
...
...
}
for debugging i added a small image view at top left to see the cropped result.. you can see i'm in the right direction BUT there is some kind of offset. i'm assuming since the camera buffer is 1280x720 and the iphone screen got different aspect so there is some kind of crop which may be the offset i'm dealing with..
attached the screenshot, you can see the crop image isn't centred

p.s here is the output settings
AVCaptureVideoDataOutput *output = [AVCaptureVideoDataOutput new];
NSDictionary *rgbOutputSettings = [NSDictionary dictionaryWithObject:
[NSNumber numberWithInt:kCMPixelFormat_32BGRA] forKey:(id)kCVPixelBufferPixelFormatTypeKey];
[output setVideoSettings:rgbOutputSettings];
Any ideas ?