【问题标题】:How to programmatically change the hue of UIImage?如何以编程方式更改 UIImage 的色调?
【发布时间】:2012-07-18 07:07:50
【问题描述】:

我对图像处理非常陌生。我必须在我的 iPhone 应用程序项目中实现色调效果。因此,我需要更改UIImage 的色调。请为此提供任何示例代码或教程链接。

提前致谢

【问题讨论】:

    标签: iphone objective-c image-processing hue


    【解决方案1】:

    首先,您需要确定是将图像制作为固定色调,还是旋转现有色调。两者的示例如下所示。

    固定色调

    可以使用标准绘图工具修复色调 - 只需确保将混合模式设置为 kCGBlendModeHue,并使用适当的色调进行绘制。这源自 Nitish 的解决方案,尽管我发现使 saturation 小于 1.0 的结果不一致。这种方法确实允许改变 alpha,但对于 100% 以外的真实饱和度,您可能需要进行第二轮绘制。

    - (UIImage*) imageWithImage:(UIImage*) source fixedHue:(CGFloat) hue alpha:(CGFloat) alpha;
    // Note: the hue input ranges from 0.0 to 1.0, both red.  Values outside this range will be clamped to 0.0 or 1.0.
    {
        // Find the image dimensions.
        CGSize imageSize = [source size];
        CGRect imageExtent = CGRectMake(0,0,imageSize.width,imageSize.height);
    
        // Create a context containing the image.
        UIGraphicsBeginImageContext(imageSize);
        CGContextRef context = UIGraphicsGetCurrentContext();    
        [source drawAtPoint:CGPointMake(0,0)];
    
        // Draw the hue on top of the image.
        CGContextSetBlendMode(context, kCGBlendModeHue);
        [[UIColor colorWithHue:hue saturation:1.0 brightness:1 alpha:alpha] set];
        UIBezierPath *imagePath = [UIBezierPath bezierPathWithRect:imageExtent];
        [imagePath fill];
    
        // Retrieve the new image.
        UIImage *result = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();    
    
        return result;
    }
    

    旋转色调

    要旋转色调,您需要 Core Image 滤镜。下面的代码将 UIImage 转换为 CIImage,然后将结果转换回 UIImage 进行显示。根据您的图片的来源,您可以避免其中一个或两个步骤。

    很方便,Core Image Programming Guide: Using Core Image Filters 中的第一个示例使用 CIHueAdjust 过滤器。

    // #import <CoreImage/CoreImage.h>
    // Partially from https://developer.apple.com/library/mac/#documentation/graphicsimaging/conceptual/CoreImaging/ci_tasks/ci_tasks.html
    - (UIImage*) imageWithImage:(UIImage*) source rotatedByHue:(CGFloat) deltaHueRadians;
    {
        // Create a Core Image version of the image.
        CIImage *sourceCore = [CIImage imageWithCGImage:[source CGImage]];
    
        // Apply a CIHueAdjust filter
        CIFilter *hueAdjust = [CIFilter filterWithName:@"CIHueAdjust"];
        [hueAdjust setDefaults];
        [hueAdjust setValue: sourceCore forKey: @"inputImage"];
        [hueAdjust setValue: [NSNumber numberWithFloat: deltaHueRadians] forKey: @"inputAngle"];
        CIImage *resultCore = [hueAdjust valueForKey: @"outputImage"];
    
        // Convert the filter output back into a UIImage.
        // This section from http://stackoverflow.com/a/7797578/1318452
        CIContext *context = [CIContext contextWithOptions:nil];
        CGImageRef resultRef = [context createCGImage:resultCore fromRect:[resultCore extent]];
        UIImage *result = [UIImage imageWithCGImage:resultRef];
        CGImageRelease(resultRef);
    
        return result;
    }
    

    【讨论】:

    • 您好 Dondragmer,感谢您的精彩回答。你知道我们是否可以避免为 UIImage 的透明区域设置色调?
    • 嘿 Sid,我在仅将色调应用于图像的不透明部分时遇到了同样的问题。你找到解决办法了吗?
    • Swift 版本如下。不透明度也没有问题。
    【解决方案2】:
    - (void) changeToHue:(float)hue saturation:(float)saturation {
        UIGraphicsBeginImageContext(self.bounds.size);
        CGContextRef context = UIGraphicsGetCurrentContext();    
        UIView *hueBlend = [[UIView alloc] initWithFrame:self.bounds];
        hueBlend.backgroundColor = [UIColor colorWithHue:hue saturation:saturation brightness:1 alpha:1];
        CGContextDrawImage(context, self.bounds, self.image.CGImage);
        CGContextSetBlendMode(context, kCGBlendModeHue);
        [hueBlend.layer renderInContext:context];
        self.image = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();    
    }
    

    【讨论】:

      【解决方案3】:

      在 Apple 的 Swift 博客中,我看到了这个照片过滤应用教程:https://developer.apple.com/swift/blog/?id=16

      以下是编辑的示例代码,用于创建一个包含的方法,该方法返回一个应用了随机色调的 UIImage。

      func applyHue(source: UIImage) -> UIImage {
          // Create a place to render the filtered image
          let context = CIContext(options: nil)
      
          // Create an image to filter
          let inputImage = CIImage(image: source)
      
          // Create a random color to pass to a filter
          let randomColor = [kCIInputAngleKey: (Double(arc4random_uniform(314)) / 100)]
      
          // Apply a filter to the image
          let filteredImage = inputImage!.imageByApplyingFilter("CIHueAdjust", withInputParameters: randomColor)
      
          // Render the filtered image
          let renderedImage = context.createCGImage(filteredImage, fromRect: filteredImage.extent)
      
          // Return a UIImage
          return UIImage(CGImage: renderedImage)
      }
      

      【讨论】:

        【解决方案4】:

        上面 Dondragmer 的旋转代码的 Swift 版本

        // Convert the filter output back into a UIImage.
        // This section from http://stackoverflow.com/a/7797578/1318452
        func imageWithImage(source: UIImage, rotatedByHue: CGFloat) -> UIImage {
            // Create a Core Image version of the image.
            let sourceCore = CIImage(CGImage: source.CGImage)
            // Apply a CIHueAdjust filter
            let hueAdjust = CIFilter(name: "CIHueAdjust")
            hueAdjust.setDefaults()
            hueAdjust.setValue(sourceCore, forKey: "inputImage")
            hueAdjust.setValue(CGFloat(rotatedByHue), forKey: "inputAngle")
            let resultCore  = hueAdjust.valueForKey("outputImage") as CIImage!
            let context = CIContext(options: nil)
            let resultRef = context.createCGImage(resultCore, fromRect: resultCore!.extent())
            let result = UIImage(CGImage: resultRef)
            return result!
        }
        

        【讨论】:

          【解决方案5】:

          以 Dondragmer 出色的固定色调示例为起点。这是我的修改,以解决透明区域设置为相同色调的问题。

          - (UIImage*) imageWithImage:(NSString *)name fixedHue:(CGFloat) hue alpha:(CGFloat) alpha;
          // Note: the hue input ranges from 0.0 to 1.0, both red.  Values outside this range will be clamped to 0.0 or 1.0.
          {
              UIImage *source = [UIImage imageNamed:name];
          
              // Find the image dimensions.
              CGSize imageSize = [source size];
              CGRect imageExtent = CGRectMake(0,0,imageSize.width,imageSize.height);
          
              // Create a context containing the image.
              UIGraphicsBeginImageContext(imageSize);
              CGContextRef context = UIGraphicsGetCurrentContext();
          
              [source drawAtPoint:CGPointMake(0,0)];
          
              // Setup a clip region using the image
              CGContextSaveGState(context);
              CGContextTranslateCTM(context, 0, source.size.height);
              CGContextScaleCTM(context, 1.0, -1.0);
              CGContextClipToMask(context, imageExtent, source.CGImage);
          
              //[[UIColor colorWithHue:hue saturation:1.0 brightness:1 alpha:alpha] set];
              CGContextFillRect(context, imageExtent);
          
              // Draw the hue on top of the image.
              CGContextDrawImage(context, imageExtent, source.CGImage);
              CGContextSetBlendMode(context, kCGBlendModeHue);
              [[UIColor colorWithHue:hue saturation:1.0 brightness:1 alpha:alpha] set];
              UIBezierPath *imagePath = [UIBezierPath bezierPathWithRect:imageExtent];
              [imagePath fill];
          
              CGContextRestoreGState(context); // remove clip region
          
              // Retrieve the new image.
              UIImage *result = UIGraphicsGetImageFromCurrentImageContext();
              UIGraphicsEndImageContext();
          
              return result;
          }
          

          感谢:

          How to change hue of UIIMAGE having transparent area?

          CGContextClipToMask UIImage Mask Invert Up and Down

          【讨论】:

          • 谢谢,这正是我想要的,但是我能提出一个小建议吗?我会将UIGraphicsBeginImageContext(imageSize) 更改为UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0.0),以便跨设备保持图像比例。当然,如果需要,不透明的布尔值可以不同。
          【解决方案6】:

          对于从@JonLoard 更新的 Swift 5.0

           func changeHue(_ image: UIImage, hueValue:CGFloat)->UIImage?{
              if let sourceCGImage = image.cgImage{
                  let sourceCore = CIImage(cgImage: sourceCGImage)
                  // Apply a CIHueAdjust filter
                  let hueAdjust = CIFilter(name: "CIHueAdjust")
                  hueAdjust?.setDefaults()
                  hueAdjust?.setValue(sourceCore, forKey: "inputImage")
                  hueAdjust?.setValue(CGFloat(hueValue), forKey: "inputAngle")
                  if let resultCore  = hueAdjust?.value(forKey: "outputImage") as? CIImage{
                      let context = CIContext(options: nil)
                      if let resultRef = context.createCGImage(resultCore, from: resultCore.extent){
                          let result = UIImage(cgImage: resultRef,scale: 1,orientation: image.imageOrientation)
                          return result
                      }
                  }
                  
              }
              return image
          }
          

          【讨论】:

            猜你喜欢
            • 2012-08-10
            • 1970-01-01
            • 2019-07-16
            • 1970-01-01
            • 1970-01-01
            • 2018-01-31
            • 1970-01-01
            • 1970-01-01
            • 2015-04-02
            相关资源
            最近更新 更多