2017-07-17 36 views
3

我想將圖像轉換爲二進制黑白,在我通過像素(存儲在UnsafeMutableBufferPointer)循環使用正常的嵌套循環的時刻,比較每個RGB進行平均並將其設置爲黑色或白色,但是。變換圖像爲二進制中迅速

這似乎很慢,我相信有一個內置在使用GPU或良好優化的方式。如果您可以提供代碼示例或鏈接,那就太棒了。

for var y in 0..<height { 
    for var x in 0..<width{ 
     //Pixel is small class i made for 8 bit access and comparison 
     if (Buffer[x+y*width] < AVRRGB) { 
      Buffer[x+y*width] = Pixel(RGB: 0x000000FF) 
     } else{ 
      Buffer[x+y*width] = Pixel(RGB: 0xFFFFFFFF) 
     } 
    } 
} 
+0

我同意你最後的陳述,應該有一些現有的lib來做這個操作,最好是使用GPU,但是「思考」 - 註釋:你目前以非順序方式訪問像素。在處理性能關鍵應用程序(如圖像處理)時,務必確保按照存儲順序依次訪問存儲器。由於你的緩衝區(看起來)只是一個很長的數組,你應該依次讀寫它的元素。 – dfri

+0

查看[這些搜索結果](https://stackoverflow.com/search?tab=newest&q=%5bios%5d%20uiimage%20convert%20black%20white)。 – rmaddy

+1

不要不必要地使用標籤。這個問題與Xcode完全無關。使用前請閱讀標籤說明。 – rmaddy

回答

4

一對夫婦的意見:

  1. 確保您有一個發佈版本的設備上做了測試(或優化關閉)。僅此而已,這使得它更快。在iPhone 7+上,它將1920 x 1080像素彩色圖像的灰度從1.7秒降低到了不到0.1秒。

  2. 您可能需要使用DispatchQueue.concurrentPerform同時處理象素。在我的iPhone 7+上,這使它快了一倍。

根據我的經驗,核心圖像過濾器速度並不快,但如果你需要更快的速度,你可以考慮使用vImage或Metal。但除非你處理的是非常大的圖像,否則帶有優化(可能併發)簡單Swift代碼的響應時間可能就足夠了。

一個無關的觀察:

  • 另外,我不知道如何轉換爲黑白作品,但往往你要計算的顏色relative luminance像素(例如,0.2126 *紅色+ 0.7152 *綠色+ 0.0722 *藍色)。當然,轉換時的彩色圖像灰度你會做這樣的事情來獲得更緊密地代表着什麼人眼可以看到的圖像,以及我個人做這樣的事情,如果轉換成黑色和白色,太。

  • 僅供參考,我的雨燕3/4顏色到灰度例行的樣子:

    func blackAndWhite(image: UIImage, completion: @escaping (UIImage?) -> Void) { 
        DispatchQueue.global(qos: .userInitiated).async { 
         // get information about image 
    
         let imageref = image.cgImage! 
         let width = imageref.width 
         let height = imageref.height 
    
         // create new bitmap context 
    
         let bitsPerComponent = 8 
         let bytesPerPixel = 4 
         let bytesPerRow = width * bytesPerPixel 
         let colorSpace = CGColorSpaceCreateDeviceRGB() 
         let bitmapInfo = Pixel.bitmapInfo 
         let context = CGContext(data: nil, width: width, height: height, bitsPerComponent: bitsPerComponent, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: bitmapInfo)! 
    
         // draw image to context 
    
         let rect = CGRect(x: 0, y: 0, width: CGFloat(width), height: CGFloat(height)) 
         context.draw(imageref, in: rect) 
    
         // manipulate binary data 
    
         guard let buffer = context.data else { 
          print("unable to get context data") 
          completion(nil) 
          return 
         } 
    
         let pixels = buffer.bindMemory(to: Pixel.self, capacity: width * height) 
    
         DispatchQueue.concurrentPerform(iterations: height) { row in 
          for col in 0 ..< width { 
           let offset = Int(row * width + col) 
    
           let red = Float(pixels[offset].red) 
           let green = Float(pixels[offset].green) 
           let blue = Float(pixels[offset].blue) 
           let alpha = pixels[offset].alpha 
           let luminance = UInt8(0.2126 * red + 0.7152 * green + 0.0722 * blue) 
           pixels[offset] = Pixel(red: luminance, green: luminance, blue: luminance, alpha: alpha) 
          } 
         } 
    
         // return the image 
    
         let outputImage = context.makeImage()! 
         completion(UIImage(cgImage: outputImage, scale: image.scale, orientation: image.imageOrientation)) 
        } 
    } 
    
    struct Pixel: Equatable { 
        private var rgba: UInt32 
    
        var red: UInt8 { 
         return UInt8((rgba >> 24) & 255) 
        } 
    
        var green: UInt8 { 
         return UInt8((rgba >> 16) & 255) 
        } 
    
        var blue: UInt8 { 
         return UInt8((rgba >> 8) & 255) 
        } 
    
        var alpha: UInt8 { 
         return UInt8((rgba >> 0) & 255) 
        } 
    
        init(red: UInt8, green: UInt8, blue: UInt8, alpha: UInt8) { 
         rgba = (UInt32(red) << 24) | (UInt32(green) << 16) | (UInt32(blue) << 8) | (UInt32(alpha) << 0) 
        } 
    
        static let bitmapInfo = CGImageAlphaInfo.premultipliedLast.rawValue | CGBitmapInfo.byteOrder32Little.rawValue 
    
        static func ==(lhs: Pixel, rhs: Pixel) -> Bool { 
         return lhs.rgba == rhs.rgba 
        } 
    } 
    

    顯然,如果你想將它轉換爲絕對黑色和白色,然後調整算法相應地,但是這說明了併發圖像緩衝器操作例程。

    +0

    yup發佈構建伎倆,即使是我的整個例程,現在花費的時間可以忽略不計,謝謝小號 – temo

    0

    的VIMAGE轉換爲1位爲vImageConvert_Planar8ToPlanar1。我建議使用抖動選項之一。您需要先將RGB圖像轉換爲灰度圖像。原則上,這是vImageMatrixMultiply_ARGB8888ToPlanar8(),但實際上它可能要涉及一些更復雜的色彩空間轉換,而不是一個簡單的矩陣。

    如果這聽起來太複雜了,只需使用vImageConvert_AnyToAny,它應該做正確的事情。

    相關問題