Преобразование цветов каждого пикселя в предварительном просмотре видео — Swift

У меня есть следующий код, который отображает предварительный просмотр камеры, извлекает цвет одного пикселя из UIImage и преобразует это значение в «отфильтрованный» цвет.

func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
    connection.videoOrientation = orientation
    let videoOutput = AVCaptureVideoDataOutput()
    videoOutput.setSampleBufferDelegate(self, queue: DispatchQueue.main)

    let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)
    let cameraImage = CIImage(cvImageBuffer: pixelBuffer!)

    let typeOfColourBlindness = ColourBlindType(rawValue: "deuteranomaly")

    /* Gets colour from a single pixel - currently 0,0 and converts it into the 'colour blind' version */

    let captureImage = convert(cmage: cameraImage)

    let colour = captureImage.getPixelColour(pos: CGPoint(x: 0, y: 0))

    var redval: CGFloat = 0
    var greenval: CGFloat = 0
    var blueval: CGFloat = 0
    var alphaval: CGFloat = 0

    _ = colour.getRed(&redval, green: &greenval, blue: &blueval, alpha: &alphaval)
    print("Colours are r: \(redval) g: \(greenval) b: \(blueval) a: \(alphaval)")

    let filteredColour = CBColourBlindTypes.getModifiedColour(.deuteranomaly, red: Float(redval), green: Float(greenval), blue: Float(blueval))
    print(filteredColour)

    /* #################################################################################### */

    DispatchQueue.main.async {
        // placeholder for now
        self.filteredImage.image = self.applyFilter(cameraImage: cameraImage, colourBlindness: typeOfColourBlindness!)
    }
}

Вот где преобразуется значение x: 0, y: 0 пикселя:

import Foundation

enum ColourBlindType: String {
    case deuteranomaly = "deuteranomaly"
    case protanopia = "protanopia"
    case deuteranopia = "deuteranopia"
    case protanomaly = "protanomaly"
}

class CBColourBlindTypes: NSObject {
   class func getModifiedColour(_ type: ColourBlindType, red: Float, green: Float, blue: Float) -> Array<Float> {
        switch type {
        case .deuteranomaly:
            return [(red*0.80)+(green*0.20)+(blue*0),
                    (red*0.25833)+(green*0.74167)+(blue*0),
                    (red*0)+(green*0.14167)+(blue*0.85833)]
        case .protanopia:
            return [(red*0.56667)+(green*0.43333)+(blue*0),
                    (red*0.55833)+(green*0.44167)+(blue*0),
                    (red*0)+(green*0.24167)+(blue*0.75833)]
        case .deuteranopia:
            return [(red*0.625)+(green*0.375)+(blue*0),
                    (red*0.7)+(green*0.3)+(blue*0),
                    (red*0)+(green*0.3)+(blue*0.7)]
        case .protanomaly:
            return [(red*0.81667)+(green*0.18333)+(blue*0.0),
                    (red*0.33333)+(green*0.66667)+(blue*0.0),
                    (red*0.0)+(green*0.125)+(blue*0.875)]
        }

    }

}

Комментарий placeholder for now относится к следующей функции:

func applyFilter(cameraImage: CIImage, colourBlindness: ColourBlindType) -> UIImage {

    //do stuff with pixels to render new image


    /*      Placeholder code for shifting the hue      */

    // Create a place to render the filtered image
    let context = CIContext(options: nil)

    // Create filter angle
    let filterAngle = 207 * Double.pi / 180

    // Create a random color to pass to a filter
    let randomColor = [kCIInputAngleKey: filterAngle]

    // Apply a filter to the image
    let filteredImage = cameraImage.applyingFilter("CIHueAdjust", parameters: randomColor)

    // Render the filtered image
    let renderedImage = context.createCGImage(filteredImage, from: filteredImage.extent)

    // Return a UIImage
    return UIImage(cgImage: renderedImage!)
}

А вот мое расширение для получения цвета пикселя:

extension UIImage {
    func getPixelColour(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)

        return UIColor(red: r, green: g, blue: b, alpha: a)
    }

}

Например, как создать фильтр для следующего цветового диапазона? введите здесь описание изображения

Я хочу получить вход с камеры, заменить цвета на диапазон Deuteranopia и отобразить это на экране в режиме реального времени с помощью Swift.

Я использую UIImageView для отображения изображения.


person nopassport1    schedule 22.11.2017    source источник


Ответы (2)


Чтобы узнать, как выполнить фильтрацию захвата видео и отображение отфильтрованного изображения в реальном времени, вы можете изучить AVCamPhotoFilter пример кода от Apple и других источников, таких как это руководство по objc.io

Короче говоря, использование UIImage для рендеринга в реальном времени — не очень хорошая идея — это слишком медленно. Используйте OpenGL (например, GLKView) или Metal (например, MTKView). Код AVCamPhotoFilter использует MTKView и выполняет рендеринг в промежуточные буферы, но вы также можете рендерить CIImage напрямую, используя соответствующие методы CIContext, например. для металла https://developer.apple.com/documentation/coreimage/cicontext/1437835-render

Кроме того, что касается вашего цветового фильтра, вы можете взглянуть на основной фильтр изображения CIColorCube, как показано здесь< /а>.

person Sébastien A    schedule 03.12.2017

let filterName = "CIColorCrossPolynomial"
//deuteronomaly
let param = ["inputRedCoefficients" : CIVector(values: [0.8, 0.2, 0, 0, 0, 0, 0, 0, 0, 0], count: 10),
             "inputGreenCoefficients" : CIVector(values: [0.25833, 0.74167, 0, 0, 0, 0, 0, 0, 0, 0], count: 10),
             "inputBlueCoefficients" : CIVector(values: [0, 0.14167, 0.85833, 0, 0, 0, 0, 0, 0, 0], count: 10)]

let filter = CIFilter(name: filterName, parameters: param)

let startImage = CIImage(image: image!)
filter?.setValue(startImage, forKey: kCIInputImageKey)

let newImage = UIImage(ciImage: ((filter?.outputImage)!))

результат фильтрации: результат фильтрации

результат фильтрации 2: результат фильтрации 2

person Nik    schedule 09.02.2019
comment
Написание кода — это хорошо, но небольшое объяснение того, почему этот код будет работать, было бы неплохо. Из обзора - person Vaibhav Vishal; 09.02.2019