Iphone 如何更改UIImage的饱和度?

Iphone 如何更改UIImage的饱和度?,iphone,cocoa-touch,uikit,core-graphics,Iphone,Cocoa Touch,Uikit,Core Graphics,我有一张UIImage,想把它的饱和度调整到+10%左右。有没有标准的方法或函数可以用于此目的?没有那么简单的。最简单的解决方案可能是使用已知像素格式创建内存中的CGContext,将图像绘制到该上下文中,然后读取/修改已知格式缓冲区中的像素 我认为CG不支持带有独立饱和度通道的颜色空间,因此您必须将RGB转换为HSV或HSL,或者直接在RGB空间中进行计算 直接在RGB中进行计算的一种方法可能如下所示: average = (R + G + B) / 3; red_delta = (R -

我有一张UIImage,想把它的饱和度调整到+10%左右。有没有标准的方法或函数可以用于此目的?

没有那么简单的。最简单的解决方案可能是使用已知像素格式创建内存中的CGContext,将图像绘制到该上下文中,然后读取/修改已知格式缓冲区中的像素

我认为CG不支持带有独立饱和度通道的颜色空间,因此您必须将RGB转换为HSV或HSL,或者直接在RGB空间中进行计算


直接在RGB中进行计算的一种方法可能如下所示:

average = (R + G + B) / 3;
red_delta = (R - average) * 11 / 10;
green_delta = (G - average) * 11 / 10;
blue_delta = (B - average) * 11 / 10;

R = average + red_delta;
G = average + green_delta;
B = average + blue_delta;
// clip R,G,B to be in 0-255 range

这将使远离平均值的通道进一步移动约10%。这几乎就像增加饱和度一样,尽管它会使某些颜色的色调发生变化

从基于视图的应用程序模板开始,创建UIView的新子类,如下所示:

// header file
@interface DesatView : UIView {
     UIImage *image;
     float saturation;
}
@property (nonatomic, retain) UIImage *image;
@property (nonatomic) float desaturation;
@end  

// implementation file
#import "DesatView.h"
@implementation DesatView
@synthesize image, desaturation;

-(void)setSaturation:(float)sat;
    {
        saturation = sat;
        [self setNeedsDisplay];
    }

- (id)initWithFrame:(CGRect)frame {
     if (self = [super initWithFrame:frame]) {
          self.backgroundColor = [UIColor clearColor]; // else background is black
          desaturation = 0.0; // default is no effect
     }
     return self;
}

- (void)drawRect:(CGRect)rect {
     CGContextRef context = UIGraphicsGetCurrentContext();
     CGContextSaveGState(context);

     CGContextTranslateCTM(context, 0.0, self.bounds.size.height); // flip image right side up
     CGContextScaleCTM(context, 1.0, -1.0);

     CGContextDrawImage(context, rect, self.image.CGImage);
     CGContextSetBlendMode(context, kCGBlendModeSaturation);
     CGContextClipToMask(context, self.bounds, image.CGImage); // restricts drawing to within alpha channel
     CGContextSetRGBFillColor(context, 0.0, 0.0, 0.0, desaturation);
     CGContextFillRect(context, rect);

     CGContextRestoreGState(context); // restore state to reset blend mode
}
@end
现在,在视图控制器的viewDidLoad方法中,将视图置于屏幕上,并按如下方式设置其饱和度:

- (void)viewDidLoad {
    [super viewDidLoad];  

    DesatView *dv = [[DesatView alloc] initWithFrame:CGRectZero];
    dv.image = [UIImage imageNamed:@"someImage.png"];
    dv.frame = CGRectMake(0, 0, dv.image.size.width, dv.image.size.height);
    dv.center = CGPointMake(160, 240); // put it mid-screen
    dv.desaturation = 0.2; // desaturate by 20%,

    [self.view addSubview:dv];  // put it on screen   
}  
 dv.saturation = 0.8; // desaturate by 80%  
按如下方式更改饱和度:

- (void)viewDidLoad {
    [super viewDidLoad];  

    DesatView *dv = [[DesatView alloc] initWithFrame:CGRectZero];
    dv.image = [UIImage imageNamed:@"someImage.png"];
    dv.frame = CGRectMake(0, 0, dv.image.size.width, dv.image.size.height);
    dv.center = CGPointMake(160, 240); // put it mid-screen
    dv.desaturation = 0.2; // desaturate by 20%,

    [self.view addSubview:dv];  // put it on screen   
}  
 dv.saturation = 0.8; // desaturate by 80%  

显然,如果您想在单个方法之外使用它,那么应该将dv设置为视图控制器的ivar。希望这能有所帮助。

这里是Bessey hack的一个实现(将此代码放入UIImage类别中)。它的速度不快,而且它肯定会改变颜色,但它有点有效

+ (CGFloat) clamp:(CGFloat)pixel
{
      if(pixel > 255) return 255;
      else if(pixel < 0) return 0;
      return pixel;
}

- (UIImage*) saturation:(CGFloat)s
{
      CGImageRef inImage = self.CGImage;
      CFDataRef ref = CGDataProviderCopyData(CGImageGetDataProvider(inImage)); 
      UInt8 * buf = (UInt8 *) CFDataGetBytePtr(ref); 
      int length = CFDataGetLength(ref);

      for(int i=0; i<length; i+=4)
      {
            int r = buf[i];
            int g = buf[i+1];
            int b = buf[i+2];

            CGFloat avg = (r + g + b) / 3.0;
            buf[i] = [UIImage clamp:(r - avg) * s + avg];
            buf[i+1] = [UIImage clamp:(g - avg) * s + avg];
            buf[i+2] = [UIImage clamp:(b - avg) * s + avg];
      }

      CGContextRef ctx = CGBitmapContextCreate(buf,
                              CGImageGetWidth(inImage), 
                              CGImageGetHeight(inImage), 
                              CGImageGetBitsPerComponent(inImage),
                              CGImageGetBytesPerRow(inImage), 
                              CGImageGetColorSpace(inImage),
                              CGImageGetAlphaInfo(inImage));

      CGImageRef img = CGBitmapContextCreateImage(ctx);
      CFRelease(ref);
      CGContextRelease(ctx);
      return [UIImage imageWithCGImage:img];
}

这有一个CoreImage过滤器<代码>颜色控制 只需将
inputstation
设置为<1.0以降低饱和度,或设置为>1.0以增加饱和度

下面是我在
UIImage
的一个类别中添加的一个方法,用于对图像进行去饱和

-(UIImage*) imageDesaturated {
    CIContext *context = [CIContext contextWithOptions:nil];
    CIImage *ciimage = [CIImage imageWithCGImage:self.CGImage];
    CIFilter *filter = [CIFilter filterWithName:@"CIColorControls"];
    [filter setValue:ciimage forKey:kCIInputImageKey];
    [filter setValue:@0.0f forKey:kCIInputSaturationKey];
    CIImage *result = [filter valueForKey:kCIOutputImageKey];
    CGImageRef cgImage = [context createCGImage:result fromRect:[result extent]];
    UIImage *image = [UIImage imageWithCGImage:cgImage];
    CGImageRelease(cgImage);
    return image;
}

我刚刚测试了Mike Pollard的方法,它是正确的

这是swift 3的版本

let ciimage = CIImage.init(cgImage: self.givenImage.cgImage)
let filter = CIFilter.init(name: "CIColorControls")
filter?.setValue(ciimage, forKey: kCIInputImageKey)
filter?.setValue(0.0, forKey: kCIInputSaturationKey)
let result = filter?.value(forKey: kCIOutputImageKey) as! CIImage
let cgimage = CIContext.init(options: nil).createCGImage(result, from: result.extent)
let image = UIImage.init(cgImage: cgimage!)
斯威夫特5
为什么不直接调用setter中的[self setNeedsDisplay]进行去饱和呢?我的大脑出于某种未知的原因避免覆盖合成setter,但你是对的。我会改变答案。这会降低饱和度,你会怎样增加饱和度?+1。我认为这可能会泄漏
cgImage
,尽管插入了
CFAutorelease(cgImage)返回之前
应该解决这个问题。您还可以使用
kCIInputImageKey
kciinputstationkey
而不是
@“inputImage”和
@“inputstation”
,以及
@0.0f
而不是
[NSNumber numberWithFloat:0.0f]
。迈克,我建议您使用
UIImage*image=[UIImage imageWithCGImage:cgImage比例:self.scale方向:self.imageOrientation]
因为它可以确保保持原始图像的比例和方向,这在处理视网膜设备时尤为重要。虽然这样做有效,但实际上需要大量处理!确保在调度线程上执行此操作。这对jpg图像很好,但对png图像不起作用。请不要发布相同的答案。相反,旗为duplicate@Jean-弗朗索瓦·法布仔细看,它并不完全相同