如何将UIImage转换为CIImage,以及反之。

77

我正在尝试从屏幕上显示的ImageView中获取CIImage

UIImage *image = myImageView.image;

将图像UIImage转换为CIImage

CIImage *cImage = [....];

如何做到这一点?

8个回答

140
CIImage *ciImage = [UIImage imageNamed:@"test.png"].CIImage;
UIImage *uiImage = [[UIImage alloc] initWithCIImage:ciImage];

为了解决当myUIImage.CIImage返回nil时(就像[UIImageView image]一样),你可以使用[CIImage imageWithCGImage:myUIImage.CGImage]代替。

Swift版本:

let ciImage = UIImage(named: "test.png")!.ciImage
let uiImage = UIImage(ciImage: ciImage)

解决当myUIImage.ciImage返回nil的情况,可以改为使用CIImage(cgImage: myUIImage!.cgImage!)


3
就目前而言,总会有要求分配内存的情况。[UIImage imageWithCIImage:ciImage] 等同于 [[[UIImage alloc] initWithCIImage:ciImage] autorelease] - Adam Kaplan
52
请注意,如果使用CGImageRef初始化UIImage,则CIImage将为nil,这段代码将无法正常工作。 - Mr Rogers
4
使用 ...WithCIImage: 创建的 UIImage 在调整大小时存在一些问题,因为大多数使用 UIImage 的框架需要一个 CGImage。因此,您需要首先使用 createCGImage:fromRect: 或类似的方法进行渲染。 - Binarian
3
为了解决 myUIImage.CIImage 返回 nil 的情况,你可以使用 [CIImage imageWithCGImage:myUIImage.CGImage] - Dylan Hand
如果可能的话,最好使用imageWithCIImage:scale:orientation而不是imageWithCIImage CIImage * aCIImage = [CIImage imageWithData:imageData];UIImage * anImage = [UIImage imageWithCIImage:aCIImage scale:1.0 orientation:orientation]; - alones

33

虽然Changxing Wang的回答基本上是正确的,但苹果表示UIImage.CIImage不总是有效。具体来说,来自PocketCoreImage:

// Create a CIImage from the _inputImage.  While UIImage has a property returning
// a CIImage representation of it, there are cases where it will not work.  This is the
// most compatible route.
_filteredImage = [[CIImage alloc] initWithCGImage:_inputImage.CGImage options:nil];

苹果公司也使用以下代码,但对我无效:

[UIImage imageWithCIImage:_filteredImage] 

这是我个人的实现,改编自此帖子,对我而言确实有效:

// result is a CIImage, output of my filtering.  
// returnImage is (obviously) a UIImage that I'm going to return.
CIContext *context = [CIContext contextWithOptions:nil];
UIImage *returnImage = 
[UIImage imageWithCGImage:[context createCGImage:result fromRect:result.extent]];

1
除非绝对必要,否则请小心设置上下文,因为这是一项通常很昂贵的任务。我建议将其设置为@property并在处理图像转换之前创建它。不过,如果您只需要执行一次此操作,则上述解决方案应该可以正常工作。 - SushiGrass Jacob
创建的CGImageRef将被保留。您必须保留对它的引用,并在创建UIImage后调用CGImageRelease(cgimage)。否则,内存将泄漏。 - HotJard
你的代码有泄漏:[context createCGImage...] 创建了一个 CGContextRef,必须释放(即使在 ARC 中)。由于你没有将其分配给变量,因此无法释放它,在这里会泄漏相当多的内存。 - xaphod

26

这是最兼容的方法:

UIImage* u =[UIImage imageNamed:@"image.png"];
CIImage* ciimage = [[CIImage alloc] initWithCGImage:u.CGImage];

现在使用 CIImage...

还有 Swift 版本:

let i1 = UIImage(named: "testImage")
if let cgi1 = i1?.cgImage {
   let ci = CIImage(cgImage: cgi1)
   //use ci
}

(在if let语句中修正了拼写错误)


2
从UIImage创建CIImage,使用initWithCGImage是唯一可行的解决方案。使用'uiimagei.CIImage'不起作用,它总是为空。 - crojassoto

13

这是一个完整的代码示例,我在我的项目中使用过。

- (UIImage *)makeUIImageFromCIImage:(CIImage *)ciImage {
    CIContext *context = [CIContext contextWithOptions:nil];
    CGImageRef cgImage = [context createCGImage:ciImage fromRect:[ciImage extent]];

    UIImage* uiImage = [UIImage imageWithCGImage:cgImage];
    CGImageRelease(cgImage);

    return uiImage;
}

CIImage 基本上是图像的配方。如果你尝试直接从 CIImage 转换为 UIImage,会遇到问题。例如,调用

NSData * UIImageJPEGRepresentation (
   UIImage *image,
   CGFloat compressionQuality
);

将返回nil


12
func toCIImage(image: UIImage) -> CIImage {
    return image.CIImage ?? CIImage(CGImage: image.CGImage!)
}

func toUIImage(image: CIImage) -> UIImage {
    return UIImage(CIImage: image)
}

如果不是由CIImage构建的,则不会转换任何内容,将返回nil。 - user924

9

5

以下是changx的答案,Swift示例:

guard let ciimage = CIImage(image: uiimage) else { return }
let image = UIImage(CIImage: ciimage)

1
如果不是由CIImage构建的,则不会转换任何内容,将返回nil。 - user924
你不需要上下文吗? - Chewie The Chorkie

1

当将UIImage转换为CIImage时,我遇到了两种情况,有时它是nil,有时不是。下面的代码解决了这个问题:

CIImage *ciImage;
ciImage=[[CIImage alloc] initWithImage:imageToConvert];
if (ciImage==nil)
    ciImage=imageToConvert.CIImage;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接