web-dev-qa-db-ja.com

UIImageをグレースケールに変換して画質を維持

同じUIImageをグレースケールで取得するために、この拡張機能(obj-cにあり、Swift3に変換)があります。

public func getGrayScale() -> UIImage
{
    let imgRect = CGRect(x: 0, y: 0, width: width, height: height)

    let colorSpace = CGColorSpaceCreateDeviceGray()

    let context = CGContext(data: nil, width: Int(width), height: Int(height), bitsPerComponent: 8, bytesPerRow: 0, space: colorSpace, bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.none.rawValue).rawValue)
    context?.draw(self.cgImage!, in: imgRect)

    let imageRef = context!.makeImage()
    let newImg = UIImage(cgImage: imageRef!)

    return newImg
}

グレーの画像は表示できますが、品質はかなり悪いです...品質に関連するのは、コンテキストコンストラクターのbitsPerComponent: 8だけです。しかし、アップルのドキュメントを見ると、ここに私が得るものがあります:

enter image description here

IOSは8bpcのみをサポートしていることを示しています...それで、なぜ品質を改善できないのですか?

16
Dliix

以下のコードを試してください:

注:コードの更新とエラーの修正...

  • Swift 3。
  • originalImageは、変換しようとしているイメージです。

回答1:

     var context = CIContext(options: nil)

更新:CIContextrenderingを処理するコアイメージコンポーネントであり、コアイメージの処理はすべてCIContextで行われます。これはCore GraphicsまたはOpenGL contextと多少似ています。詳細については、 Apple Doc。

     func Noir() {

        let currentFilter = CIFilter(name: "CIPhotoEffectNoir") 
        currentFilter!.setValue(CIImage(image: originalImage.image!), forKey: kCIInputImageKey)
        let output = currentFilter!.outputImage 
        let cgimg = context.createCGImage(output!,from: output!.extent)
        let processedImage = UIImage(cgImage: cgimg!)
        originalImage.image = processedImage
      }

また、同様の効果を生み出すことができる次のフィルターを考慮する必要があります

  • CIPhotoEffectMono
  • CIPhotoEffectTonal

回答1からの出力:

enter image description here

回答2からの出力:

enter image description here

改善された答え:

Answer 2:coreImageフィルターを適用する前に入力画像を自動調整する

var context = CIContext(options: nil)

func Noir() {


    //Auto Adjustment to Input Image
    var inputImage = CIImage(image: originalImage.image!)
    let options:[String : AnyObject] = [CIDetectorImageOrientation:1 as AnyObject]
    let filters = inputImage!.autoAdjustmentFilters(options: options)

    for filter: CIFilter in filters {
       filter.setValue(inputImage, forKey: kCIInputImageKey)
   inputImage =  filter.outputImage
      }
    let cgImage = context.createCGImage(inputImage!, from: inputImage!.extent)
    self.originalImage.image =  UIImage(cgImage: cgImage!)

    //Apply noir Filter
    let currentFilter = CIFilter(name: "CIPhotoEffectTonal") 
    currentFilter!.setValue(CIImage(image: UIImage(cgImage: cgImage!)), forKey: kCIInputImageKey)

    let output = currentFilter!.outputImage 
    let cgimg = context.createCGImage(output!, from: output!.extent)
    let processedImage = UIImage(cgImage: cgimg!)
    originalImage.image = processedImage

}

注:より良い結果を確認したい場合は、simulator...ではなくreal deviceでコードをテストする必要があります。

31
Joe

Swift 4.拡張機能。オプションのUIImageを返し、将来のクラッシュの可能性を回避します。

import UIKit

extension UIImage {
    var noir: UIImage? {
        let context = CIContext(options: nil)
        guard let currentFilter = CIFilter(name: "CIPhotoEffectNoir") else { return nil }
        currentFilter.setValue(CIImage(image: self), forKey: kCIInputImageKey)
        if let output = currentFilter.outputImage,
            let cgImage = context.createCGImage(output, from: output.extent) {
            return UIImage(cgImage: cgImage, scale: scale, orientation: imageOrientation)
        }
        return nil
    }
}

これを使用するには:

let image = UIImage(...)
let noirImage = image.noir // noirImage is an optional UIImage (UIImage?)
15
CodeBender

異なるスケールで正しく機能するSwift 4UIImage拡張としてのJoeの答え:

extension UIImage {
    var noir: UIImage {
        let context = CIContext(options: nil)
        let currentFilter = CIFilter(name: "CIPhotoEffectNoir")!
        currentFilter.setValue(CIImage(image: self), forKey: kCIInputImageKey)
        let output = currentFilter.outputImage!
        let cgImage = context.createCGImage(output, from: output.extent)!
        let processedImage = UIImage(cgImage: cgImage, scale: scale, orientation: imageOrientation)

        return processedImage
    }
}
9
Peter Prokop

Objective Cのカテゴリを次に示します。重要なことに、このバージョンではスケールが考慮されることに注意してください。

- (UIImage *)grayscaleImage{
    return [self imageWithCIFilter:@"CIPhotoEffectMono"];
}

- (UIImage *)imageWithCIFilter:(NSString*)filterName{
    CIImage *unfiltered = [CIImage imageWithCGImage:self.CGImage];
    CIFilter *filter = [CIFilter filterWithName:filterName];
    [filter setValue:unfiltered forKey:kCIInputImageKey];
    CIImage *filtered = [filter outputImage];
    CIContext *context = [CIContext contextWithOptions:nil];
    CGImageRef cgimage = [context createCGImage:filtered fromRect:CGRectMake(0, 0, self.size.width*self.scale, self.size.height*self.scale)];
    // Do not use initWithCIImage because that renders the filter each time the image is displayed.  This causes slow scrolling in tableviews.
    UIImage *image = [[UIImage alloc] initWithCGImage:cgimage scale:self.scale orientation:self.imageOrientation];
    CGImageRelease(cgimage);
    return image;
}
6
arsenius

CoreImageを使用しますが、これにより品質が維持される場合があります。

func convertImageToBW(image:UIImage) -> UIImage {

    let filter = CIFilter(name: "CIPhotoEffectMono")

    // convert UIImage to CIImage and set as input

    let ciInput = CIImage(image: image)
    filter?.setValue(ciInput, forKey: "inputImage")

    // get output CIImage, render as CGImage first to retain proper UIImage scale

    let ciOutput = filter?.outputImage
    let ciContext = CIContext()
    let cgImage = ciContext.createCGImage(ciOutput!, from: (ciOutput?.extent)!)

    return UIImage(cgImage: cgImage!)
}

このコードの使用方法によっては、パフォーマンス上の理由から、コードの外側にCIContextを作成することもできます。

4
dfd

Joe answerに従って、OriginalをB&Wに簡単に変換しました。しかし、元に戻る imageはこれらのコードを参照します:

var context = CIContext(options: nil)
var startingImage : UIImage = UIImage()

func Noir() {     
    startingImage = imgView.image!
    var inputImage = CIImage(image: imgView.image!)!
    let options:[String : AnyObject] = [CIDetectorImageOrientation:1 as AnyObject]
    let filters = inputImage.autoAdjustmentFilters(options: options)

    for filter: CIFilter in filters {
        filter.setValue(inputImage, forKey: kCIInputImageKey)
        inputImage =  filter.outputImage!
    }
    let cgImage = context.createCGImage(inputImage, from: inputImage.extent)
    self.imgView.image =  UIImage(cgImage: cgImage!)

    //Filter Logic
    let currentFilter = CIFilter(name: "CIPhotoEffectNoir")
    currentFilter!.setValue(CIImage(image: UIImage(cgImage: cgImage!)), forKey: kCIInputImageKey)

    let output = currentFilter!.outputImage
    let cgimg = context.createCGImage(output!, from: output!.extent)
    let processedImage = UIImage(cgImage: cgimg!)
    imgView.image = processedImage
}

func Original(){ 
    imgView.image = startingImage
}
1
SPooja

現在の向きとスケールを保存する:

extension UIImage {

func noir() -> UIImage {
    let context = CIContext(options: nil)

    let currentFilter = CIFilter(name: "CIPhotoEffectNoir")
    currentFilter!.setValue(CIImage(image: self), forKey: kCIInputImageKey)
    let output = currentFilter!.outputImage
    let cgimg = context.createCGImage(output!, from: output!.extent)
    let processedImage = UIImage(cgImage: cgimg!, scale: scale, orientation: imageOrientation)
    return processedImage
}}
1
RomanV