Acelerar la iteración de píxeles

El problema que estoy teniendo es no ser capaz de iterar sobre todos los píxeles en un UIImage lo suficientemente rápido, revisando cada color contra uno particular (verde). La iteración debe procesarse tan pronto como el usuario la inicie. Por el momento hay una demora de ~ 0.5s.

Estoy usando esto para crear una captura de pantalla de la vista:

func screenshot() -> UIImage { UIGraphicsBeginImageContextWithOptions(view.bounds.size, false, UIScreen.main.scale) view.layer.render(in: UIGraphicsGetCurrentContext()!) let screenShot = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return screenShot! } 

Esto para get el color de un solo píxel:

 extension UIImage { 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) return UIColor(networking: r, green: g, blue: b, alpha: a) } } 

Y este ciclo para verificar cada píxel de la image:

 testImage = screenshot() greenPresent = false for yCo in 0 ..< Int(testImage.size.height) { for xCo in 0 ..< Int(testImage.size.width) { if testImage.getPixelColor(pos: CGPoint(x: xCo, y: yCo)) == UIColor(networking: 0, green: 1, blue: 0, alpha: 1) { greenPresent = true greenCount += 1 } } } 

Cualquier sugerencia sera apreciada.

EDITAR

El performance tiene un impacto en un factor de escala de 0.0; Estoy buscando acomodar esto.

Aquí hay una versión mucho más eficiente del código que publicaste:

 testImage = imageFromView() var greenCount = 0 if let cfdata = testImage.cgImage?.dataProvider?.data { let data = cfdata as Data for i in stride(from: 0, to: data.count, by: 4) { let r = data[i] let g = data[i+1] let b = data[i+2] if g == 255 && r == 0 && b == 0 { greenCount += 1 } } } 

Este código elimina muchas ineficiencias en el código original. Los datos solo se obtienen una vez. No se usan puntos. Los bytes de datos son accedidos directamente. No se necesita creación de UIColor . No se necesita conversión a CGFloat .

Recomendaría almacenar en caching el puntero de data :

 let data: UnsafePointer<UInt8> = ... 

en lugar de computar desde cero cada vez que llama al método getPixelColor .

Además: considere crear un struct Color class UIColor simple en lugar de utilizar la class UIColor estándar class UIColor . ¡La creación (y desasignación) de que muchas instancias de class pueden resultar caras rápidamente!


Por cierto, también debe agregar un break simple después de encontrar el píxel deseado. Por supuesto, suponiendo que su algorithm final se mantenga igual 😉

Para empezar, salga de su ciclo tan pronto como encuentre un píxel verde:

 yLoop: for yCo in 0 ..< Int(testImage.size.height) { for xCo in 0 ..< Int(testImage.size.width) { if testImage.getPixelColor(pos: CGPoint(x: xCo, y: yCo)) == UIColor(networking: 0, green: 1, blue: 0, alpha: 1) { greenPresent = true break yLoop } } } 

Como todo lo que quiere saber es si hay un solo píxel verde, no tiene sentido continuar después de encontrar uno. Esto acelerará su control en un 50% en promedio (aunque un solo píxel verde en la parte inferior derecha tomará el mayor time posible).