iOS图片裁剪、旋转、格式转换

iOS图片裁剪、旋转、格式转换

在使用 CoreML 对图片进行识别时,有时模型需要接收特定格式的图片,这就需要我们先对图片做好处理,再传递给模型。比如,我在一个识别人脸面部表情的程序中,就需要先裁剪出人脸区域,做成适当大小的灰度图,再交给 MLModel 进行识别。

此篇文章汇总了一些对图片进行处理的函数。

CMSampleBufferRef 转 UIImage

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
- (UIImage *)getImageFromSampleBuffer:(CMSampleBufferRef) buffer {
CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(buffer);
CVPixelBufferLockBaseAddress(imageBuffer, 0);
void *baseAddress = 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 quartzImage = CGBitmapContextCreateImage(context);
CVPixelBufferUnlockBaseAddress(imageBuffer, 0);
CGContextRelease(context);
CGColorSpaceRelease(colorSpace);
UIImage *image = [UIImage imageWithCGImage:quartzImage];
CGImageRelease(quartzImage);
return image;
}

CGImageRef 转 CVPixelBufferRef

这个函数中对图像做了一些翻转变化,而且还将图片转为了 8 位的灰度图,请注意色彩空间等地方。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
- (CVPixelBufferRef) pixelBufferFromCGImage: (CGImageRef) image {
NSDictionary *options = @{
(NSString*)kCVPixelBufferCGImageCompatibilityKey : @YES,
(NSString*)kCVPixelBufferCGBitmapContextCompatibilityKey : @YES,
};

CVPixelBufferRef pxbuffer = NULL;

CVReturn status = CVPixelBufferCreate(kCFAllocatorDefault, CGImageGetWidth(image),
CGImageGetHeight(image), kCVPixelFormatType_OneComponent8, (__bridge CFDictionaryRef) options,
&pxbuffer);
if (status!=kCVReturnSuccess) {
NSLog(@"Operation failed");
}
NSParameterAssert(status == kCVReturnSuccess && pxbuffer != NULL);

CVPixelBufferLockBaseAddress(pxbuffer, 0);
void *pxdata = CVPixelBufferGetBaseAddress(pxbuffer);

CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceGray(); //灰度
CGContextRef context = CGBitmapContextCreate(pxdata, CGImageGetWidth(image),
CGImageGetHeight(image), 8, CVPixelBufferGetBytesPerRow(pxbuffer), rgbColorSpace,
kCGImageAlphaNone);

NSParameterAssert(context);

CGContextConcatCTM(context, CGAffineTransformMakeRotation(0));
//CGAffineTransform flipVertical = CGAffineTransformMake( 1, 0, 0, -1, 0, CGImageGetHeight(image) );
//CGContextConcatCTM(context, flipVertical);
CGAffineTransform flipHorizontal = CGAffineTransformMake( -1.0, 0.0, 0.0, 1.0, CGImageGetWidth(image), 0.0 );
CGContextConcatCTM(context, flipHorizontal);
CGContextDrawImage(context, CGRectMake(0, 0, CGImageGetWidth(image),
CGImageGetHeight(image)), image);
CGColorSpaceRelease(rgbColorSpace);
CGContextRelease(context);
CVPixelBufferUnlockBaseAddress(pxbuffer, 0);
return pxbuffer;
}

CVPixelBufferRef 转 UIImage

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
- (UIImage *)imageFromPixelBuffer:(CVPixelBufferRef)pixelBufferRef {
CVImageBufferRef imageBuffer = pixelBufferRef;

CVPixelBufferLockBaseAddress(imageBuffer, 0);
void *baseAddress = CVPixelBufferGetBaseAddress(imageBuffer);
size_t width = CVPixelBufferGetWidth(imageBuffer);
size_t height = CVPixelBufferGetHeight(imageBuffer);
size_t bufferSize = CVPixelBufferGetDataSize(imageBuffer);
size_t bytesPerRow = CVPixelBufferGetBytesPerRowOfPlane(imageBuffer, 0);

CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();
CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, baseAddress, bufferSize, NULL);

CGImageRef cgImage = CGImageCreate(width, height, 8, 32, bytesPerRow, rgbColorSpace, kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrderDefault, provider, NULL, true, kCGRenderingIntentDefault);
UIImage *image = [UIImage imageWithCGImage:cgImage];
CGImageRelease(cgImage);
CGDataProviderRelease(provider);
CGColorSpaceRelease(rgbColorSpace);

CVPixelBufferUnlockBaseAddress(imageBuffer, 0);
return image;
}

生成灰度图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
- (UIImage*)grayImage:(UIImage*)sourceImage {
int width = sourceImage.size.width;
int height = sourceImage.size.height;
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();
CGContextRef context = CGBitmapContextCreate (nil, width, height,8,0, colorSpace,kCGImageAlphaNone);
CGColorSpaceRelease(colorSpace);
if (context ==NULL) {
return nil;
}
CGContextDrawImage(context,CGRectMake(0,0, width, height), sourceImage.CGImage);
UIImage *grayImage = [UIImage imageWithCGImage:CGBitmapContextCreateImage(context)];
CGContextRelease(context);
return grayImage;
}

图片裁剪

1
2
3
4
5
6
7
8
9
10
11
12
- (UIImage*)getSubImage:(CGRect)rect cgImage:(CGImageRef)cgImage {
CGImageRef subImageRef = CGImageCreateWithImageInRect(cgImage, rect);
CGRect smallBounds = CGRectMake(0, 0, CGImageGetWidth(subImageRef), CGImageGetHeight(subImageRef));

UIGraphicsBeginImageContext(smallBounds.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextDrawImage(context, smallBounds, subImageRef);
UIImage* smallImage = [UIImage imageWithCGImage:subImageRef];
UIGraphicsEndImageContext();
CGImageRelease(subImageRef);
return smallImage;
}

图片旋转

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
- (UIImage*)rotateImageWithAngle:(UIImage*)vImg Angle:(CGFloat)vAngle IsExpand:(BOOL)vIsExpand {
CGSize imgSize = CGSizeMake(vImg.size.width * vImg.scale, vImg.size.height * vImg.scale);

CGSize outputSize = imgSize;
if (vIsExpand) {
CGRect rect = CGRectMake(0, 0, imgSize.width, imgSize.height);
//旋转
rect = CGRectApplyAffineTransform(rect, CGAffineTransformMakeRotation(vAngle*M_PI/180.0));

outputSize = CGSizeMake(CGRectGetWidth(rect), CGRectGetHeight(rect));
}

UIGraphicsBeginImageContext(outputSize);
CGContextRef context = UIGraphicsGetCurrentContext();

CGContextTranslateCTM(context, outputSize.width / 2, outputSize.height / 2);
CGContextRotateCTM(context, vAngle*M_PI/180.0);
CGContextTranslateCTM(context, -imgSize.width / 2, -imgSize.height / 2);

[vImg drawInRect:CGRectMake(0, 0, imgSize.width, imgSize.height)];

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

return image;
}

CGImageRef 转 CVPixelBufferRef

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
- (CVPixelBufferRef) pixelBufferColorfulFromCGImage: (CGImageRef) image
{
NSDictionary *options = @{
(NSString*)kCVPixelBufferCGImageCompatibilityKey : @YES,
(NSString*)kCVPixelBufferCGBitmapContextCompatibilityKey : @YES,
(NSString*)kCVPixelBufferIOSurfacePropertiesKey: [NSDictionary dictionary]
};
CVPixelBufferRef pxbuffer = NULL;

CGFloat frameWidth = CGImageGetWidth(image);
CGFloat frameHeight = CGImageGetHeight(image);

CVReturn status = CVPixelBufferCreate(kCFAllocatorDefault,
frameWidth,
frameHeight,
kCVPixelFormatType_32BGRA,
(__bridge CFDictionaryRef) options,
&pxbuffer);

NSParameterAssert(status == kCVReturnSuccess && pxbuffer != NULL);

CVPixelBufferLockBaseAddress(pxbuffer, 0);
void *pxdata = CVPixelBufferGetBaseAddress(pxbuffer);
NSParameterAssert(pxdata != NULL);

CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();

CGContextRef context = CGBitmapContextCreate(pxdata,
frameWidth,
frameHeight,
8,
CVPixelBufferGetBytesPerRow(pxbuffer),
rgbColorSpace,
(CGBitmapInfo)kCGImageAlphaNoneSkipFirst);
NSParameterAssert(context);
CGContextConcatCTM(context, CGAffineTransformIdentity);
CGContextDrawImage(context, CGRectMake(0,
0,
frameWidth,
frameHeight),
image);
CGColorSpaceRelease(rgbColorSpace);
CGContextRelease(context);

CVPixelBufferUnlockBaseAddress(pxbuffer, 0);

return pxbuffer;
}

以上各个函数基本都要操作指针,所以一定要注意手动释放内存,否则会造成非常严重的内存泄漏。

# iOS
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×