Простой проход через ядро ​​искажает значения цвета

Я написал ядро ​​rgbToHSV для преобразования пикселей в изображениях; однако он работает некорректно. Я сузил его до того факта, что значения RGB искажаются по пути.

Чтобы упростить свой код, я изменил его на простой сквозной фильтр.

Я передал изображения 1280 x 720 изображений одного цвета, а затем произвел выборку цветов пикселей в позиции (100, 100) v до и после прохождения через cikernel.

Вот результаты:

Красный перед: pixelColor :: rgba: 1.0: 0.0: 0.0: 1.0 после: pixelColor :: rgba: 1.0: 0.07450980392156863: 0.0: 1.0

Зеленый до: pixelColor :: rgba: 0.0: 1.0: 0.0: 1.0 после: pixelColor :: rgba: 0.0: 0.984313725490196: 0.0: 1.0

Синий перед: pixelColor :: rgba: 0.0: 0.0: 1.0: 1.0 после: pixelColor :: rgba: 0.0: 0.1803921568627451: 1.0: 1.0

Как видите, красный и зеленый слегка искажены, а синий - сильно искажен.

Я сохранил выходные файлы и проверил цвета, и фильтр определенно меняет цвета.

Мы очень ценим любое понимание того, почему простой переход изменяет цвета.

Упрощенный сквозной фильтр:

kernel vec4 rgbToHsv( __sample rgb) {
  return rgb;
}

Вот CIFilter, который использует cikernel:

class RgbToHsvFilter: CIFilter {
  @objc dynamic var inputImage: CIImage?

  
  private lazy var kernel: CIColorKernel? = {
    guard let path = Bundle.main.path(forResource: "RgbToHsv", ofType: "cikernel"),
      let code = try? String(contentsOfFile: path) else { fatalError("Failed to load RgbToHsv.cikernel from bundle") }
    let kernel = CIColorKernel(source: code)
    return kernel
  }()

  override public var outputImage: CIImage! {
    get {
      if let inputImage = self.inputImage {
        
        let args = [inputImage as AnyObject]
        return self.kernel?.apply(extent: inputImage.extent, arguments: args)
      } else {
        return nil
      }
    }
  }
}

Вызов фильтра

    let rgbToHsvFilter = RgbToHsvFilter()
    let currentCI = CIImage(cgImage: colorImage!.cgImage!)
    rgbToHsvFilter.setValue(currentCI, forKey: kCIInputImageKey)
    
    if let hsvImage = rgbToHsvFilter.outputImage {
      if let image = cgImage(from: hsvImage) {
        let newImage = UIImage(cgImage: image as! CGImage)
        
        
        let _ = newImage.getPixelColor(pos: pixelPoint)
     
        //UIImageWriteToSavedPhotosAlbum(newImage, self, #selector(image(_:didFinishSavingWithError:contextInfo:)), nil)
      }
    }
  }

метод getPixelColor, где для CGPoint установлено значение (100, 100). Я думал, что проблема может возникать здесь как возможное искажение в заявлении печати выходящего цвета, но я проверил фактические выходные изображения, и фильтр изменяет цвета изображения:

  func getPixelColor(pos: CGPoint) -> UIColor {
    
    let pixelData = self.cgImage!.dataProvider!.data
    let data: UnsafePointer<UInt8> = CFDataGetBytePtr(pixelData)
    
    let pixelInfo: Int = ((Int(self.size.width) * Int(pos.y)) + Int(pos.x)) * 4
    
    let r = CGFloat(data[pixelInfo]) / CGFloat(255.0)
    let g = CGFloat(data[pixelInfo+1]) / CGFloat(255.0)
    let b = CGFloat(data[pixelInfo+2]) / CGFloat(255.0)
    let a = CGFloat(data[pixelInfo+3]) / CGFloat(255.0)
    
    print("pixelColor :: rgba : \(r) : \(g) : \(b) : \(a)")
    
    return UIColor(red: r, green: g, blue: b, alpha: a)
  }

и cgImage (отредактировано):


  func cgImage(from ciImage: CIImage) -> CGImage? {
      let context = CIContext(options: nil)
      return context.createCGImage(ciImage, from: ciImage.extent)
  }

person Will Chen    schedule 11.09.2020    source источник
comment
Я думаю, это связано с проблемой разговора linear_to_srgb или srgb_to_linear   -  person SPatel    schedule 12.09.2020
comment
Как сказал SPatel, это может быть связано с гамма-коррекцией. Не могли бы вы показать реализацию метода cgImage(from: hsvImage)?   -  person Frank Schlegel    schedule 12.09.2020
comment
@FrankSchlegel отредактировал.   -  person Will Chen    schedule 14.09.2020
comment
Не могли бы вы попробовать создать CGImage с createCGImage(ciImage, from: ciImage.extent, colorSpace: CGColorspace(name: CGColorSpace.sRGB)!) и посмотреть, изменится ли это?   -  person Frank Schlegel    schedule 14.09.2020
comment
Я попробовал это с форматом: и синим изображением со следующими результатами: формат .RGBA8, которые дали мне те же результаты. @FrankSchlegel   -  person Will Chen    schedule 16.09.2020
comment
.RGBA8, который дал мне те же результаты. pixelColor :: rgba: 0.0: 0.1803921568627451: 1.0: 1.0   -  person Will Chen    schedule 16.09.2020
comment
.RGBA16 pixelColor :: rgba: 0,0: 0,0: 0,9372549019607843: 0,17647058823529413   -  person Will Chen    schedule 16.09.2020
comment
.RGBAf pixelColor :: rgba: 0,027450980392156862: 0,07450980392156863: 0,9058823529411765: 0,7372549019607844   -  person Will Chen    schedule 16.09.2020
comment
.RGBAh pixelColor :: rgba: 0,2235294117647059: 0,6549019607843137: 0,7450980392156863: 0,19215686274509805   -  person Will Chen    schedule 16.09.2020
comment
Я обнаружил, что что-то при переходе от CIImage к UIImage вызывает искажение цвета. CiKernel не имеет отношения к проблеме. Я собираюсь открыть еще один вопрос, посвященный этому.   -  person Will Chen    schedule 17.09.2020


Ответы (1)


Таким образом, CIContext не инициализирован должным образом в методе cgImage.

Вот исправленный метод:

  func cgImage(from ciImage: CIImage) -> CGImage? {
    let context = CIContext(options: [CIContextOption.workingColorSpace: kCFNull!])
    return context.createCGImage(ciImage, from: ciImage.extent, format: .RGBA8, colorSpace: CGColorSpace.init(name: CGColorSpace.sRGB)!)
  }
person Will Chen    schedule 19.09.2020