I need to adjust the contrast and brightness of the CGImageRef my means of CoreGraphics/Quartz.
Any ideas how to do it ?
Quartz guildeline and online search didn't give many results.
Please don't refer to OpenGL solution.
You want Core Image. The filter for your purpose is CIColorControls.
also if you want to improve the behavior you can use GCD, enjoy!
CIContext *ctxt63 = [CIContext contextWithOptions:nil];
CIFilter *filter63 = [CIFilter filterWithName:#"CIColorControls"];
[filter63 setDefaults];
[filter63 setValue:input forKey:kCIInputImageKey];
[filter63 setValue:#1.8 forKeyPath:kCIInputSaturationKey];
[filter63 setValue:[NSNumber numberWithFloat:0.8] forKey:#"inputBrightness"];
[filter63 setValue:[NSNumber numberWithFloat:3.0] forKey:#"inputContrast"];
CIImage *output63 = [filter63 outputImage];
//Aplicar el filtro en segundo plano
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
CGImageRef res63 = [ctxt63 createCGImage:output63 fromRect:[output63 extent]];
dispatch_async(dispatch_get_main_queue(), ^{
UIImage *img63 = [UIImage imageWithCGImage:res63];
CGImageRelease(res63);
self.photoView.image = img63;
});
});
Related
I have a problem. I use 2 image. One is download from internet. the other is captured by camera of iPhone.
I use CIDetector to detect face in 2 images. It work perfect in image that download from internet. But the other, it's can't detect or detect wrong.
I check in many images. That result is the same.
Try this
NSDictionary *options = [NSDictionary dictionaryWithObject: CIDetectorAccuracyLow forKey: CIDetectorAccuracy];
CIDetector *detector = [CIDetector detectorOfType: CIDetectorTypeFace context: nil options: options];
CIImage *ciImage = [CIImage imageWithCGImage: [image CGImage]];
NSNumber *orientation = [NSNumber numberWithInt:[image imageOrientation]+1];
NSDictionary *fOptions = [NSDictionary dictionaryWithObject:orientation forKey: CIDetectorImageOrientation];
NSArray *features = [detector featuresInImage:ciImage options:fOptions];
for (CIFaceFeature *f in features) {
NSLog(#"left eye found: %#", (f. hasLeftEyePosition ? #"YES" : #"NO"));
NSLog(#"right eye found: %#", (f. hasRightEyePosition ? #"YES" : #"NO"));
NSLog(#"mouth found: %#", (f. hasMouthPosition ? #"YES" : #"NO"));
if(f.hasLeftEyePosition)
NSLog(#"left eye position x = %f , y = %f", f.leftEyePosition.x, f.leftEyePosition.y);
if(f.hasRightEyePosition)
NSLog(#"right eye position x = %f , y = %f", f.rightEyePosition.x, f.rightEyePosition.y);
if(f.hasMouthPosition)
NSLog(#"mouth position x = %f , y = %f", f.mouthPosition.x, f.mouthPosition.y);
}
if you're using the front camera always in portrait add this
NSDictionary* imageOptions = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:6] forKey:CIDetectorImageOrientation];
NSArray* features = [detector featuresInImage:image options:imageOptions];
For more info
sample: https://github.com/beetlebugorg/PictureMe
iOS Face Detection Issue
Face Detection issue using CIDetector
https://stackoverflow.com/questions/4332868/detect-face-in-iphone?rq=1
I try to this code above. It's can detect images captured by Iphone. But it's can't detect image download from Internet. This is my code
NSDictionary *options = [NSDictionary dictionaryWithObject: CIDetectorAccuracyLow forKey: CIDetectorAccuracy];
CIDetector *detector = [CIDetector detectorOfType: CIDetectorTypeFace context: nil options: options];
CIImage *ciImage = [CIImage imageWithCGImage: [facePicture CGImage]];
NSDictionary* imageOptions = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:6] forKey:CIDetectorImageOrientation];
NSArray *features = [detector featuresInImage:ciImage options:imageOptions];
And when it's detect face. I show by code
for (CIFaceFeature *feature in features) {
// // Set red feature color
CGRect faceRect = [feature bounds];
CGContextSetRGBFillColor(context, 0.0f, 0.0f, 0.0f, 0.5f);
CGContextSetStrokeColorWithColor(context, [UIColor whiteColor].CGColor);
CGContextSetLineWidth(context, 2.0f * scale);
CGContextAddRect(context, feature.bounds);
CGContextDrawPath(context, kCGPathFillStroke);
CGContextDrawImage(context, faceRect, [imgDraw CGImage]);
it's not right position. It's move to right a distance.
I had the same problem. You can change size of the image before detection.
CGSize size = CGSizeMake(cameraCaptureImage.size.width, cameraCaptureImage.size.height);
UIGraphicsBeginImageContext(size);
[cameraCaptureImage drawInRect:CGRectMake(0, 0, size.width, size.height)];
cameraCaptureImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
Does anyone knows how to release memory while using core image framework to apply HUE changes on image?
Here is my code:-
CIImage *inputImage = [[CIImage alloc] initWithImage:currentImage];
CIFilter * controlsFilter = [CIFilter filterWithName:#"CIHueAdjust"];
[controlsFilter setValue:inputImage forKey:kCIInputImageKey];
[controlsFilter setValue:[NSNumber numberWithFloat:slider.value] forKey:#"inputAngle"];
CIImage *displayImage = controlsFilter.outputImage;
UIImage *finalImage = [UIImage imageWithCIImage:displayImage];
CIContext *context = [CIContext contextWithOptions:nil];
if (displayImage == nil || finalImage == nil) {
// We did not get output image. Let's display the original image itself.
photoEditView.image = currentImage;
}else {
// We got output image. Display it.
photoEditView.image = [UIImage imageWithCGImage:[context createCGImage:displayImage fromRect:displayImage.extent]];
}
context = nil;
[inputImage release];
I think you need to release this one as well :
[context createCGImage:displayImage fromRect:displayImage.extent]
by using the CGImageRelease(CGImageRef) method.
I am trying to process image using Core Image. I have created UIImage category to do it.
I have added QuartzCore and CoreImage frameworks to project, imported CoreImage/CoreImage.h and used this code:
CIImage *inputImage = self.CIImage;
CIFilter *exposureAdjustmentFilter = [CIFilter filterWithName:#"CIExposureAdjust"];
[exposureAdjustmentFilter setDefaults];
[exposureAdjustmentFilter setValue:inputImage forKey:#"inputImage"];
[exposureAdjustmentFilter setValue:[NSNumber numberWithFloat:5.0f] forKey:#"inputEV"];
CIImage *outputImage = [exposureAdjustmentFilter valueForKey:#"outputImage"];
CIContext *myContext = [CIContext contextWithOptions:nil];
return [UIImage imageWithCGImage:[myContext createCGImage:outputImage fromRect:outputImage.extent]];
But I have got nil output image from the filter.
I have also tried to use CIHueAdjust with the same result.
Than you in advance
UPDATE: I have found solution. It was necessary to alloc new CIImage, not only pass reference to UIImage.CIImage this way:
CIImage *inputImage = [[CIImage alloc] initWithImage:self];
Try following code:-
CIImage *inputImage = [[CIImage alloc] initWithImage:[UIImage imageNamed:#"old-country-rain.jpg"]];
CIFilter * controlsFilter = [CIFilter filterWithName:#"CIExposureAdjust"];
[controlsFilter setValue:inputImage forKey:kCIInputImageKey];
[controlsFilter setValue:[NSNumber numberWithFloat: 2.0f] forKey:#"inputEV"];
NSLog(#"%#",controlsFilter.attributes);
CIImage *displayImage = controlsFilter.outputImage;
UIImage *finalImage = [UIImage imageWithCIImage:displayImage];
CIContext *context = [CIContext contextWithOptions:nil];
if (displayImage == nil || finalImage == nil) {
// We did not get output image. Let's display the original image itself.
imageView.image = [UIImage imageNamed:#"old-country-rain.jpg"];
}else {
// We got output image. Display it.
imageView.image = [UIImage imageWithCGImage:[context createCGImage:displayImage fromRect:displayImage.extent]];
}
This code mostly works, but the resulting data seems to loose a color channel (is what I am thinking) as the resulting image data when displayed is tinted blue!
Here is the code:
UIImage* myImage=[UIImage imageNamed:#"sample1.png"];
CGImageRef imageRef=[myImage CGImage];
CVImageBufferRef pixelBuffer = [self pixelBufferFromCGImage:imageRef];
The method pixelBufferFromCGIImage was grabbed from another post on stackoverflow here: How do I export UIImage array as a movie? (although this application is unrelated to what I am trying to do) it is
+ (CVPixelBufferRef)pixelBufferFromCGImage:(CGImageRef)image
{
CGSize frameSize = CGSizeMake(CGImageGetWidth(image), CGImageGetHeight(image));
NSDictionary *options = #{
(__bridge NSString *)kCVPixelBufferCGImageCompatibilityKey: #(NO),
(__bridge NSString *)kCVPixelBufferCGBitmapContextCompatibilityKey: #(NO)
};
CVPixelBufferRef pixelBuffer;
CVReturn status = CVPixelBufferCreate(kCFAllocatorDefault, frameSize.width,
frameSize.height, kCVPixelFormatType_32ARGB, (__bridge CFDictionaryRef) options,
&pixelBuffer);
if (status != kCVReturnSuccess) {
return NULL;
}
CVPixelBufferLockBaseAddress(pixelBuffer, 0);
void *data = CVPixelBufferGetBaseAddress(pixelBuffer);
CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(data, frameSize.width, frameSize.height,
8, CVPixelBufferGetBytesPerRow(pixelBuffer), rgbColorSpace,
(CGBitmapInfo) kCGImageAlphaNoneSkipLast);
CGContextDrawImage(context, CGRectMake(0, 0, CGImageGetWidth(image),
CGImageGetHeight(image)), image);
CGColorSpaceRelease(rgbColorSpace);
CGContextRelease(context);
CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);
return pixelBuffer;
}
I am thinking it has something to do with the relationship between kCVPixelFormatType_32ARGB and kCGImageAlphaNoneSkipLast though I have tried every combination and get either the same result or a application crash. Once again, this gets the UIImage data into CVImageBufferRef but when I display the image on screen, it appears to loose a color channel and shows up tinted blue. The image is a png.
The solution is that this code works perfectly as intended. :) The issue was in using the data in creating an OpenGL texture. Completely unrelated to this code. Anyone searching for how to Convert UIImage to CVImageBufferRef, your answer is in the above code!
If anyone is still looking for a solution to this problem, I solved it by switching the BOOLs in the pixelBuffer's options:
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:NO], kCVPixelBufferCGImageCompatibilityKey,
[NSNumber numberWithBool:NO], kCVPixelBufferCGBitmapContextCompatibilityKey,
nil];
From NO to YES:
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], kCVPixelBufferCGImageCompatibilityKey,
[NSNumber numberWithBool:YES], kCVPixelBufferCGBitmapContextCompatibilityKey,
nil];
I encounter the same problem and find some samples: http://www.cakesolutions.net/teamblogs/2014/03/08/cmsamplebufferref-from-cgimageref
try to change
CGBitmapInfo bitmapInfo = (CGBitmapInfo)kCGBitmapByteOrder32Little |
kCGImageAlphaPremultipliedFirst)
Here's what really works:
+ (CVPixelBufferRef)pixelBufferFromImage:(CGImageRef)image {
CGSize frameSize = CGSizeMake(CGImageGetWidth(image), CGImageGetHeight(image)); // Not sure why this is even necessary, using CGImageGetWidth/Height in status/context seems to work fine too
CVPixelBufferRef pixelBuffer = NULL;
CVReturn status = CVPixelBufferCreate(kCFAllocatorDefault, frameSize.width, frameSize.height, kCVPixelFormatType_32BGRA, nil, &pixelBuffer);
if (status != kCVReturnSuccess) {
return NULL;
}
CVPixelBufferLockBaseAddress(pixelBuffer, 0);
void *data = CVPixelBufferGetBaseAddress(pixelBuffer);
CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(data, frameSize.width, frameSize.height, 8, CVPixelBufferGetBytesPerRow(pixelBuffer), rgbColorSpace, (CGBitmapInfo) kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);
CGContextDrawImage(context, CGRectMake(0, 0, CGImageGetWidth(image), CGImageGetHeight(image)), image);
CGColorSpaceRelease(rgbColorSpace);
CGContextRelease(context);
CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);
return pixelBuffer;
}
You can change the pixel buffer back to a UIImage (and then display or save it) to confirm that it works with this method:
+ (UIImage *)imageFromPixelBuffer:(CVPixelBufferRef)pixelBuffer {
CIImage *ciImage = [CIImage imageWithCVPixelBuffer:pixelBuffer];
CIContext *context = [CIContext contextWithOptions:nil];
CGImageRef myImage = [context createCGImage:ciImage fromRect:CGRectMake(0, 0, CVPixelBufferGetWidth(pixelBuffer), CVPixelBufferGetHeight(pixelBuffer))];
UIImage *image = [UIImage imageWithCGImage:myImage];
// Uncomment the following lines to say the image to your application's document directory
//NSString *imageSavePath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:#"myImageFromPixelBuffer.png"]];
//[UIImagePNGRepresentation(image) writeToFile:imageSavePath atomically:YES];
return image;
}
Just to clarify the answer above: I've ran into the same issue because my shader code was expecting two layered samples within a image buffer, while I used a single layer buffer
This line took the rgb values from one sample and passed them to (I don't know what), but the end result is full colored image.
gl_FragColor = vec4(texture2D(SamplerY, texCoordVarying).rgb, 1);
It sounds like it might be that relationship. Possibly have it be a jpg and RGB instead of indexed colors with a png?
I use AVCaptureSessionPhoto to allow the user to take high-resolution photos. Upon taking a photo, I use the captureOutput:didOutputSampleBuffer:fromConnection: method to retrieve a thumbnail at the time of capture. However, although I try to do minimal work in the delegate method, the app becomes sort of laggy (I say sort of because it is still useable). Also, the iPhone tends to run hot.
Is there some way of reducing the amount of work the iPhone has to do?
I set up the AVCaptureVideoDataOutput by doing the following:
self.videoDataOutput = [[AVCaptureVideoDataOutput alloc] init];
self.videoDataOutput.alwaysDiscardsLateVideoFrames = YES;
// Specify the pixel format
dispatch_queue_t queue = dispatch_queue_create("com.myapp.videoDataOutput", NULL);
[self.videoDataOutput setSampleBufferDelegate:self queue:queue];
dispatch_release(queue);
self.videoDataOutput.videoSettings = [NSDictionary dictionaryWithObject: [NSNumber numberWithInt:kCVPixelFormatType_32BGRA]
forKey:(id)kCVPixelBufferPixelFormatTypeKey];
Here's my captureOutput:didOutputSampleBuffer:fromConnection (and assisting imageRefFromSampleBuffer method):
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
fromConnection:(AVCaptureConnection *)connection {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
if (videoDataOutputConnection == nil) {
videoDataOutputConnection = connection;
}
if (getThumbnail > 0) {
getThumbnail--;
CGImageRef tempThumbnail = [self imageRefFromSampleBuffer:sampleBuffer];
UIImage *image;
if (self.prevLayer.mirrored) {
image = [[UIImage alloc] initWithCGImage:tempThumbnail scale:1.0 orientation:UIImageOrientationLeftMirrored];
}
else {
image = [[UIImage alloc] initWithCGImage:tempThumbnail scale:1.0 orientation:UIImageOrientationRight];
}
[self.cameraThumbnailArray insertObject:image atIndex:0];
dispatch_async(dispatch_get_main_queue(), ^{
self.freezeCameraView.image = image;
});
CFRelease(tempThumbnail);
}
sampleBuffer = nil;
[pool release];
}
-(CGImageRef)imageRefFromSampleBuffer:(CMSampleBufferRef)sampleBuffer {
CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
CVPixelBufferLockBaseAddress(imageBuffer,0);
uint8_t *baseAddress = (uint8_t *)CVPixelBufferGetBaseAddress(imageBuffer);
size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer);
size_t width = CVPixelBufferGetWidth(imageBuffer);
size_t height = CVPixelBufferGetHeight(imageBuffer);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(baseAddress, width, height, 8, bytesPerRow, colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);
CGImageRef newImage = CGBitmapContextCreateImage(context);
CVPixelBufferUnlockBaseAddress(imageBuffer,0);
CGContextRelease(context);
CGColorSpaceRelease(colorSpace);
return newImage;
}
minFrameDuration is deprecated, this may work:
AVCaptureConnection *stillImageConnection = [stillImageOutput connectionWithMediaType:AVMediaTypeVideo];
stillImageConnection.videoMinFrameDuration = CMTimeMake(1, 10);
To improve, we should setup our AVCaptureVideoDataOutput by:
output.minFrameDuration = CMTimeMake(1, 10);
We specify a minimum duration for each frame (play with this settings to avoid having too many frames waiting in the queue because it can cause memory issues). It is similar to the inverse of the maximum frame-rate. In this example we set a min frame duration of 1/10 seconds so a maximum frame-rate of 10fps. We say that we are not able to process more than 10 frames per second.
Hope that help!