Cambiar blanca píxeles en una UIImage

votos
1

Tengo un UIImage los cuales es un esbozo, y uno que está lleno, ambos fueron creados a partir de OpenCV, uno de corte de agarre y el otro del elemento estructurante.

mis dos imágenes son como esto:

introducir

introducir

Estoy tratando de cambiar todos los píxeles blancos en la imagen esbozado porque quiero fusionar las dos imágenes juntas, así que termino con un contorno rojo y una zona llena de blanco en el centro. Estoy utilizando esta fusionar los dos juntos, y soy consciente en lugar de rojo que será una especie de color rosa de color y un color gris en lugar de blanco, ya que estoy simplemente mezclándolos con canal alfa.

// Start an image context
UIGraphicsBeginImageContext(grabcutResult.size)

// Create rect for this draw session
let rect = CGRect(x: 0.0, y: 0.0, width: grabcutResult.size.width, height: grabcutResult.size.height)
grabcutResult.draw(in: rect)
redGrabcutOutline.draw(in: rect, blendMode: .normal, alpha: 0.5)

let finalImage = UIGraphicsGetImageFromCurrentImageContext()

y la idea es que debe ser algo como esto.

introducir

Quiero ser capaz de completar esta operación rápidamente, pero las únicas soluciones que he encontrado son ya sea para ImageView (que sólo afecta a cómo las cosas no se representa la UIImage subyacente) o que implican un bucle sobre toda la imagen píxel a píxel.

Estoy tratando de encontrar una solución que se acaba de enmascarar todos los píxeles blancos en el contorno de color rojo sin tener que bucle sobre toda la imagen píxel a píxel, ya que es demasiado lento.

Lo ideal sería bueno si pudiera conseguir OPENCV a regresar simplemente un contorno rojo en lugar de blanco, pero no creo que su posible cambiar esto (tal vez im mal).

Usando rápida por cierto ... pero cualquier ayuda se agradece, gracias de antemano.

Publicado el 09/10/2019 a las 18:54
fuente por usuario
En otros idiomas...                            


3 respuestas

votos
0

Esto puede funcionar para usted - usando código sólo Swift ...

extension UIImage {

    func maskWithColor(color: UIColor) -> UIImage? {

        let maskingColors: [CGFloat] = [1, 255, 1, 255, 1, 255]
        let bounds = CGRect(origin: .zero, size: size)

        let maskImage = cgImage!
        var returnImage: UIImage?

        // make sure image has no alpha channel
        let rFormat = UIGraphicsImageRendererFormat()
        rFormat.opaque = true
        let renderer = UIGraphicsImageRenderer(size: size, format: rFormat)
        let noAlphaImage = renderer.image {
            (context) in
            self.draw(at: .zero)
        }

        let noAlphaCGRef = noAlphaImage.cgImage

        if let imgRefCopy = noAlphaCGRef?.copy(maskingColorComponents: maskingColors) {

            let rFormat = UIGraphicsImageRendererFormat()
            rFormat.opaque = false
            let renderer = UIGraphicsImageRenderer(size: size, format: rFormat)
            returnImage = renderer.image {
                (context) in
                context.cgContext.clip(to: bounds, mask: maskImage)
                context.cgContext.setFillColor(color.cgColor)
                context.cgContext.fill(bounds)
                context.cgContext.draw(imgRefCopy, in: bounds)
            }

        }
        return returnImage
    }

}

Esta extensión devuelve una UIImagecon el blanco reemplazado por el pasado UIColor, y el "fondo" negro cambiado a transparente.

Usarlo de esta manera:

// change filled white star to gray with transparent background
let modFilledImage = filledImage.maskWithColor(color: UIColor(red: 200, green: 200, blue: 200))

// change outlined white star to red with transparent background
let modOutlineImage = outlineImage.maskWithColor(color: UIColor.red)

// combine the images on a black background

Aquí está un ejemplo completo, con sus dos imágenes originales (la mayor parte del código es la creación de vistas de imágenes para mostrar los resultados):

extension UIImage {

    func maskWithColor(color: UIColor) -> UIImage? {

        let maskingColors: [CGFloat] = [1, 255, 1, 255, 1, 255]
        let bounds = CGRect(origin: .zero, size: size)

        let maskImage = cgImage!
        var returnImage: UIImage?

        // make sure image has no alpha channel
        let rFormat = UIGraphicsImageRendererFormat()
        rFormat.opaque = true
        let renderer = UIGraphicsImageRenderer(size: size, format: rFormat)
        let noAlphaImage = renderer.image {
            (context) in
            self.draw(at: .zero)
        }

        let noAlphaCGRef = noAlphaImage.cgImage

        if let imgRefCopy = noAlphaCGRef?.copy(maskingColorComponents: maskingColors) {

            let rFormat = UIGraphicsImageRendererFormat()
            rFormat.opaque = false
            let renderer = UIGraphicsImageRenderer(size: size, format: rFormat)
            returnImage = renderer.image {
                (context) in
                context.cgContext.clip(to: bounds, mask: maskImage)
                context.cgContext.setFillColor(color.cgColor)
                context.cgContext.fill(bounds)
                context.cgContext.draw(imgRefCopy, in: bounds)
            }

        }
        return returnImage
    }

}

class MaskWorkViewController: UIViewController {

    let origFilledImgView: UIImageView = {
        let v = UIImageView()
        v.translatesAutoresizingMaskIntoConstraints = false
        v.contentMode = .center
        return v
    }()

    let origOutlineImgView: UIImageView = {
        let v = UIImageView()
        v.translatesAutoresizingMaskIntoConstraints = false
        v.contentMode = .center
        return v
    }()

    let modifiedFilledImgView: UIImageView = {
        let v = UIImageView()
        v.translatesAutoresizingMaskIntoConstraints = false
        v.contentMode = .center
        return v
    }()

    let modifiedOutlineImgView: UIImageView = {
        let v = UIImageView()
        v.translatesAutoresizingMaskIntoConstraints = false
        v.contentMode = .center
        return v
    }()

    let combinedImgView: UIImageView = {
        let v = UIImageView()
        v.translatesAutoresizingMaskIntoConstraints = false
        v.contentMode = .center
        return v
    }()

    let origStack: UIStackView = {
        let v = UIStackView()
        v.translatesAutoresizingMaskIntoConstraints = false
        v.axis = .horizontal
        v.spacing = 20
        return v
    }()

    let modifiedStack: UIStackView = {
        let v = UIStackView()
        v.translatesAutoresizingMaskIntoConstraints = false
        v.axis = .horizontal
        v.spacing = 20
        return v
    }()

    let mainStack: UIStackView = {
        let v = UIStackView()
        v.translatesAutoresizingMaskIntoConstraints = false
        v.axis = .vertical
        v.alignment = .center
        v.spacing = 10
        return v
    }()

    override func viewDidLoad() {
        super.viewDidLoad()

        guard let filledImage = UIImage(named: "StarFill"),
            let outlineImage = UIImage(named: "StarEdge") else {
                return
        }

        var modifiedFilledImage: UIImage = UIImage()
        var modifiedOutlineImage: UIImage = UIImage()
        var combinedImage: UIImage = UIImage()

        // for both original images, replace white with color
        // and make black transparent
        if let modFilledImage = filledImage.maskWithColor(color: UIColor(red: 200, green: 200, blue: 200)),
            let modOutlineImage = outlineImage.maskWithColor(color: UIColor.red) {

            modifiedFilledImage = modFilledImage
            modifiedOutlineImage = modOutlineImage

            let rFormat = UIGraphicsImageRendererFormat()
            rFormat.opaque = true

            let renderer = UIGraphicsImageRenderer(size: modifiedFilledImage.size, format: rFormat)

            // combine modified images on black background
            combinedImage = renderer.image {
                (context) in
                context.cgContext.setFillColor(UIColor.black.cgColor)
                context.cgContext.fill(CGRect(origin: .zero, size: modifiedFilledImage.size))
                modifiedFilledImage.draw(at: .zero)
                modifiedOutlineImage.draw(at: .zero)
            }

        }

        // setup image views and set .image properties
        setupUI(filledImage.size)

        origFilledImgView.image = filledImage
        origOutlineImgView.image = outlineImage

        modifiedFilledImgView.image = modifiedFilledImage
        modifiedOutlineImgView.image = modifiedOutlineImage

        combinedImgView.image = combinedImage

    }

    func setupUI(_ imageSize: CGSize) -> Void {

        origStack.addArrangedSubview(origFilledImgView)
        origStack.addArrangedSubview(origOutlineImgView)

        modifiedStack.addArrangedSubview(modifiedFilledImgView)
        modifiedStack.addArrangedSubview(modifiedOutlineImgView)

        var lbl = UILabel()
        lbl.textAlignment = .center
        lbl.text = "Original Images"

        mainStack.addArrangedSubview(lbl)

        mainStack.addArrangedSubview(origStack)

        lbl = UILabel()
        lbl.textAlignment = .center
        lbl.numberOfLines = 0
        lbl.text = "Modified Images\n(UIImageViews have Green Background)"

        mainStack.addArrangedSubview(lbl)

        mainStack.addArrangedSubview(modifiedStack)

        lbl = UILabel()
        lbl.textAlignment = .center
        lbl.text = "Combined on Black Background"

        mainStack.addArrangedSubview(lbl)

        mainStack.addArrangedSubview(combinedImgView)

        view.addSubview(mainStack)

        NSLayoutConstraint.activate([

            mainStack.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 20.0),
            mainStack.centerXAnchor.constraint(equalTo: view.centerXAnchor, constant: 0.0),

        ])

        [origFilledImgView, origOutlineImgView, modifiedFilledImgView, modifiedOutlineImgView, combinedImgView].forEach {

            $0.backgroundColor = .green

            NSLayoutConstraint.activate([

                $0.widthAnchor.constraint(equalToConstant: imageSize.width),
                $0.heightAnchor.constraint(equalToConstant: imageSize.height),

            ])

        }

    }

}

Y el resultado, que muestra la imagen combinada original, modificado y última ... vistas de imagen no tienen fondos verdes para mostrar las áreas transparentes:

introducir descripción de la imagen aquí

Respondida el 14/10/2019 a las 19:12
fuente por usuario

votos
0

La idea es que bitwise-orlas dos máscaras juntos, que "fusiona" las dos máscaras. Desde esta imagen en escala de grises combinado nuevo sigue siendo una única imagen (1-canal), necesitamos convertirlo a un 3-canal, de manera que podemos aplicar color a la imagen. Por último, colorear la máscara esquema con rojo para obtener nuestro resultado

introducir descripción de la imagen aquí

He implementado en Python OpenCV pero se puede adaptar la misma idea con Swift

import cv2

# Read in images as grayscale
full = cv2.imread('1.png', 0)
outline = cv2.imread('2.png', 0)

# Bitwise-or masks
combine = cv2.bitwise_or(full, outline)

# Combine to 3 color channel and color outline red
combine = cv2.merge([combine, combine, combine])
combine[outline > 120] = (57,0,204)

cv2.imshow('combine', combine)
cv2.waitKey()

Los puntos de referencia utilizando IPython

In [3]: %timeit combine()
782 µs ± 10.4 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

Uso de la función vectorizada de Numpy, parece ser bastante rápido

Respondida el 10/10/2019 a las 00:31
fuente por usuario

votos
0

prueba esto:

public func maskWithColor2( color:UIColor) -> UIImage {

    UIGraphicsBeginImageContextWithOptions(self.size, false, UIScreen.main.scale)
    let context = UIGraphicsGetCurrentContext()!

    color.setFill()

    context.translateBy(x: 0, y: self.size.height)
    context.scaleBy(x: 1.0, y: -1.0)

    let rect = CGRect(x: 0.0, y: 0.0, width: self.size.width, height: self.size.height)
    context.draw(self.cgImage!, in: rect)

    context.setBlendMode(CGBlendMode.sourceIn)
    context.addRect(rect)
    context.drawPath(using: CGPathDrawingMode.fill)

    let coloredImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    return coloredImage!
}
Respondida el 09/10/2019 a las 19:44
fuente por usuario

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more