Boucle à travers les pixels dans les images

J’ai écrit la fonction suivante:

class func convertImageToBlackAndWhite(#data:UnsafeMutablePointer, inputWidth:UInt32, inputHeight:UInt32) -> UnsafeMutablePointer { var currentPixel = UnsafeMutablePointer() currentPixel = data for (var i = 0; i < Int(inputHeight); i++) { for (var j = 0; j < Int(inputWidth); j++) { var color:UInt32 = currentPixel.memory // Average of RGB = greyscale var averageColor:UInt32 = (R(color) + G(color) + B(color)) / 3 var updatedColor:UInt32 = RGBAMake(averageColor, g: averageColor, b: averageColor, a: A(color)) currentPixel.memory = updatedColor currentPixel++ } } var outputData = UnsafeMutablePointer((calloc(UInt(inputHeight*inputWidth), UInt(sizeof(UInt32))))) outputData = currentPixel return outputData } 

Je veux renvoyer le outputData pour l’afficher à l’écran. C’est pourquoi j’ai créé dans une autre fonction ce code:

  class func processUsingPixels(#inputImage:UIImage) -> UIImage { var inputCGImage:CGImageRef = inputImage.CGImage var colorSpace:CGColorSpaceRef = CGColorSpaceCreateDeviceRGB() var inputWidth:UInt = CGImageGetWidth(inputCGImage) var inputHeight:UInt = CGImageGetHeight(inputCGImage) var bytesPerPixel:UInt = 4 var bitsPerComponent:UInt = 8 var inputBytesPerRow = bytesPerPixel * inputWidth let bitmapInfo = CGBitmapInfo(CGBitmapInfo.ByteOrder32Big.rawValue | CGImageAlphaInfo.PremultipliedLast.rawValue) let inputPixels = UnsafeMutablePointer(calloc(UInt(inputHeight*inputWidth), UInt(sizeof(UInt32)))) var outputData = UnsafeMutablePointer() outputData = self.convertImageToBlackAndWhite(data: inputPixels, inputWidth: UInt32(inputWidth), inputHeight: UInt32(inputHeight)) let context:CGContextRef = CGBitmapContextCreate(outputData, inputWidth, inputHeight, bitsPerComponent, inputBytesPerRow, colorSpace, bitmapInfo) CGContextDrawImage(context, CGRectMake(0, 0, CGFloat(inputWidth), CGFloat(inputHeight)), inputCGImage) return inputImage } 

Le outputData était les données que je voulais maintenant afficher. Je m’attendais à ce que les modifications effectuées par la boucle for dans “ConvertImageToBlackAndWhite” soient sockets en compte, mais aucune modification ne se produit du tout.

Grâce à Rob, j’ai eu de précieuses idées avant. mais toujours cette image ne change pas du tout.

mes questions seraient:

1) est-il correct de créer cette donnée de sortie var comme valeur de retour? Est-ce que cela a du sens?

2) J’utilise cette variable outputData qui a été renvoyée pour créer un contexte et dessiner le contexte. Mais cela n’a aucun effet. Dois-je d’abord créer une nouvelle image? La valeur de retour de processusingPixels est un UIImage. Mais je pensais que CGContextDrawImage serait suffisant. Est-ce faux?

Vous initialisez currentPixel dans les boucles for . Faites-le avant de commencer les boucles, par exemple:

 var currentPixel = inputPixels for row in 0 ..< inputHeight { for column in 0 ..< inputWidth { var color: UInt32 = currentPixel.memory print(String(format:"%X", color)) currentPixel++ } } 

Lorsque vous avez terminé, vous pouvez créer une nouvelle image à l'aide de CGBitmapContextCreateImage :

 func processUsingPixels(inputImage inputImage: UIImage) -> UIImage { let inputCGImage = inputImage.CGImage let colorSpace = CGColorSpaceCreateDeviceRGB() let width = CGImageGetWidth(inputCGImage) let height = CGImageGetHeight(inputCGImage) let bytesPerPixel: UInt = 4 let bitsPerComponent: UInt = 8 let bytesPerRow = bytesPerPixel * width let bitmapInfo = CGBitmapInfo.ByteOrder32Big.rawValue | CGImageAlphaInfo.PremultipliedLast.rawValue let context:CGContextRef = CGBitmapContextCreate(nil, width, height, bitsPerComponent, bytesPerRow, colorSpace, bitmapInfo) CGContextDrawImage(context, CGRectMake(0, 0, CGFloat(width), CGFloat(height)), inputCGImage) let pixelBuffer = UnsafeMutablePointer(CGBitmapContextGetData(context)) var currentPixel = pixelBuffer for row in 0 ..< inputHeight { for column in 0 ..< inputWidth { currentPixel.memory = grayScaleFromColor(currentPixel.memory) currentPixel++ } } let outputCGImage = CGBitmapContextCreateImage(context) return UIImage(CGImage: outputCGImage)! } func grayScaleFromColor(color: UInt32) -> UInt32 { let r = Double(red(color)) let g = Double(green(color)) let b = Double(blue(color)) let a = alpha(color) let gray = UInt8(0.2126 * r + 0.7152 * g + 0.0722 * b) return rgba(red: gray, green: gray, blue: gray, alpha: a) } 

Remarque, j'ai supprimé le calloc de ce qui précède. Si vous gardez cela dans votre routine, assurez-vous de la free .


Dans la question initiale, les fonctions implicites UInt32 à extraire les valeurs RGBA de la couleur UInt32 et à créer une couleur à partir des valeurs RGBA. Par souci d’exhaustivité, je vais inclure quelques exemples de rendus:

 func red(color: UInt32) -> UInt8 { return UInt8(color & 255) } func green(color: UInt32) -> UInt8 { return UInt8((color >> 8) & 255) } func blue(color: UInt32) -> UInt8 { return UInt8((color >> 16) & 255) } func alpha(color: UInt32) -> UInt8 { return UInt8((color >> 24) & 255) } func rgba(#red: UInt8, green: UInt8, blue: UInt8, alpha: UInt8) -> UInt32 { return UInt32(red) | (UInt32(green) << 8) | (UInt32(blue) << 16) | (UInt32(alpha) << 24) } 

Personnellement, je n'aime pas trop jouer avec ce décalage de bits, donc je serais naturellement enclin à utiliser une struct (comme je l'ai fait dans cette réponse ; qui utilisait PremultipliedFirst plutôt que PremultipliedLast utilisé dans la question ici, mais le le concept serait le même). Mais accédez / manipulez le tampon comme vous le souhaitez.