2015-02-16 15 views
9

Attualmente sto usando questo metodo per scorrere ogni pixel e inserire un valore in un array 3D basato su valori RGB. Ho bisogno di questo array per altre parti del mio programma, tuttavia è straordinariamente lento. Quando viene eseguito su un'immagine 50 x 50, è quasi istantaneo, ma non appena inizi a entrare in centinaia di centinaia ci vuole molto tempo al punto in cui l'app è inutile. Qualcuno ha qualche idea su come accelerare il mio metodo?UIImage Loop Through Pixel altamente inefficiente?

@IBAction func convertImage(sender: AnyObject) { 
    if let image = myImageView.image { 

     var pixelData = CGDataProviderCopyData(CGImageGetDataProvider(image.CGImage)) 
     var data: UnsafePointer<UInt8> = CFDataGetBytePtr(pixelData) 

     let height = Int(image.size.height) 
     let width = Int(image.size.width) 
     var zArry = [Int](count:3, repeatedValue: 0) 
     var yArry = [[Int]](count:width, repeatedValue: zArry) 
     var xArry = [[[Int]]](count:height, repeatedValue: yArry) 

     for (var h = 0; h < height; h++) { 
      for (var w = 0; w < width; w++) { 
       var pixelInfo: Int = ((Int(image.size.width) * Int(h)) + Int(w)) * 4 
       var rgb = 0 
       xArry[h][w][rgb] = Int(data[pixelInfo]) 
       rgb++ 
       xArry[h][w][rgb] = Int(data[pixelInfo+1]) 
       rgb++ 
       xArry[h][w][rgb] = Int(data[pixelInfo+2]) 
       } 
     } 
     println(xArry[20][20][1]) 
    } 
} 

forse c'è un modo per convertire l'UIImage ad un diverso tipo di immagine e creare una matrice di pixel. Sono aperto a tutti i suggerimenti. Grazie!

OBIETTIVO: l'obiettivo è utilizzare la matrice per modificare i valori RGB di tutti i pixel e creare una nuova immagine con i pixel modificati. Ho provato semplicemente a scorrere tutti i pixel senza archiviarli e modificarli in un nuovo array per creare un'immagine, ma ho avuto gli stessi problemi di prestazioni.

+0

Solo un suggerimento, ma si potrebbe iniziare rilasciando il ciclo rgb . –

+0

Va bene che il ciclo è ora svolto. Ancora molto lento. Grazie per il suggerimento comunque perché probabilmente ha contribuito ad accelerare un po '. – Kendel

+0

Un mio amico probabilmente suggerirebbe di utilizzare le istruzioni NEON (istruzione singola/dati multipli) per parallelizzare la lettura dei dati, ma non conosco i dettagli e forse non è possibile fare da swift (al contrario di C/Objective- C). Se almeno ti serve come puntatore ... –

risposta

6

Aggiornamento:

Dopo innumerevoli tentativi mi sono reso conto che stavo facendo le mie prove su di debug configurazione.

Passato a versione, e ora è molto più veloce.

Swift sembra essere molte volte più lento nella configurazione di debug.

La differenza ora tra il tuo codice e la mia versione ottimizzata è molte volte più veloce.

Sembra che si abbia un grande rallentamento dall'uso di image.size.width invece della variabile locale width.

originale

ho cercato di ottimizzare un po 'e venire con questo:

@IBAction func convertImage() { 

    if let image = UIImage(named: "test") { 

     let pixelData = CGDataProviderCopyData(CGImageGetDataProvider(image.CGImage)) 
     let data: UnsafePointer<UInt8> = CFDataGetBytePtr(pixelData) 

     let height = Int(image.size.height) 
     let width = Int(image.size.width) 
     let zArry = [Int](count:3, repeatedValue: 0) 
     let yArry = [[Int]](count:width, repeatedValue: zArry) 
     let xArry = [[[Int]]](count:height, repeatedValue: yArry) 

     for (index, value) in xArry.enumerate() { 
      for (index1, value1) in value.enumerate() { 
       for (index2, var value2) in value1.enumerate() { 

        let pixelInfo: Int = ((width * index) + index1) * 4 + index2 

        value2 = Int(data[pixelInfo]) 
       } 
      } 
     } 
    } 
} 

Tuttavia nel mio test questo è appena il 15% più veloce. Ciò di cui hai bisogno sono gli ordini di grandezza più veloci.

Un'altra ideea è utilizzare l'oggetto dati direttamente in caso di necessità senza creare l'array come questo:

let image = UIImage(named: "test")! 

let pixelData = CGDataProviderCopyData(CGImageGetDataProvider(image.CGImage)) 
let data: UnsafePointer<UInt8> = CFDataGetBytePtr(pixelData) 

let width = Int(image.size.width) 

// value for [x][y][z] 
let value = Int(data[((width * x) + y) * 4 + z]) 

Lei non ha detto come si utilizza questa matrice nella vostra applicazione, ma sento che anche se trovi un modo per ottenere questo array creato molto più velocemente, si otterrebbe un altro problema quando si tenta di usarlo, come ci vorrebbe molto tempo ..

+0

Se si sostituiscono le moltiplicazioni per addizione, si otterrà un enorme aumento delle prestazioni. L'inizializzazione di 'repeatValue:' è anche una perdita per le prestazioni. – Sulthan

+0

Il tempo trascorso con le moltiplicazioni è di circa l'1% http://i61.tinypic.com/35n7o7l.png Il tempo di inizializzazione sembra essere trascurabile. – pteofil

+0

Inserirò anche questo nel post originale, ma l'obiettivo è utilizzare la matrice per modificare i valori RGB di tutti i pixel e creare una nuova immagine con i pixel modificati. Ho provato semplicemente a scorrere tutti i pixel senza archiviarli e modificarli in un nuovo array per creare un'immagine, ma ho avuto gli stessi problemi di prestazioni. – Kendel