代码之家  ›  专栏  ›  技术社区  ›  Duck

使用加速平均像素颜色

  •  0
  • Duck  · 技术社区  · 6 年前

    是的,我知道使用 CIAreaAverate CIFilter 获取像素的平均颜色。

    我正在尝试用 Accelerate Framework 看看我能不能快点来。

    我正在渲染 CIImage 根据上下文。为此我有这个 CIImage extension

    let device: MTLDevice = MTLCreateSystemDefaultDevice()!
    let context = CIContext.init(mtlDevice: device, options: [.workingColorSpace: kCFNull])
    
    let w = self.extent.width
    let h = self.extent.height
    let size = w * h * 4
    
    var bitmap = [UInt8](repeating: 0, count:Int(size))
    
    
    context.render(self,
                          toBitmap: &bitmap,
                          rowBytes: 4 * Int(w),
                          bounds: self.extent,
                          format: .BGRA8,
                          colorSpace: nil)
    

    在这一点上我有 bitmap 包含交错的bgra字节。

    为了得到r,g和b的平均值,我所要做的就是这样:

    var averageBlue : Int = 0
    
    for x in stride(from:0, through: bitmap.count-4, by: 4) {
      let value = bitmap[Int(x)]
      averageBlue += Int(value)
    }
    
    averageBlue /= numberOfPixels
    

    但是这个 for 正如预期的那样,循环非常慢。

    我在考虑用一些 Accelerate 功能类似

    vDSP_meanvD(bitmap, 2, &r, vDSP_Length(numberOfPixels))
    

    但是这个功能需要 位图 成为 UnsafePointer<Double>

    我可以改变 位图 但那需要 对于 循环,很慢…

    有没有办法提取这些r,g和b像素,然后用一些加速的方法求出它们各自的平均值?

    1 回复  |  直到 6 年前
        1
  •  1
  •   Rob Md Fahim Faez Abir    6 年前

    就像雅雅曼尼斯说的,你可以用 vDSP_vfltu8 建立缓冲区 Float 很有效率。

    但你也可以使用 cblas_sgemv (或) cblas_sgemm )要在一次通话中计算所有四个平均值:

    let pixelCount: Int = width * height
    let channelsPerPixel: Int = 4
    
    let m: Int32 = Int32(channelsPerPixel)
    let n: Int32 = Int32(pixelCount)
    let lda = m
    
    var a = [Float](repeating: 0, count: pixelCount * channelsPerPixel)
    
    vDSP_vfltu8(pixelBuffer, vDSP_Stride(1), &a, vDSP_Stride(1), vDSP_Length(pixelCount * channelsPerPixel))
    
    var x = [Float](repeating: 1 / Float(pixelCount), count: pixelCount)
    
    var y = [Float](repeating: 0, count: channelsPerPixel)
    
    cblas_sgemv(CblasColMajor, CblasNoTrans, m, n, 1, &a, lda, &x, 1, 1, &y, 1)
    
    print(y)
    
        2
  •  1
  •   ielyamani    6 年前

    你可以转换 bitmap 使用 vDSP_vfltu8(_:_:_:_:_:) :

    let bitmap: [UInt8] = [1, 10,  50,  0,
                           2, 20, 150,  5,
                           3, 30, 250, 10]
    
    //Blue
    var blueFloats = [Float](repeating: 0, count: bitmap.count/4)
    
    vDSP_vfltu8(bitmap,
                vDSP_Stride(4),
                &blueFloats,
                vDSP_Stride(1),
                vDSP_Length(blueFloats.count))
    

    然后使用 vDSP_meanv(_:_:_:_:) :

    var blue: Float = 0
    
    vDSP_meanv(blueFloats,
               vDSP_Stride(1),
               &blue,
               vDSP_Length(blueFloats.count))
    
    print("blue =", blue)     //2.0
    

    至于红军:

    //Red
    var redFloats = [Float](repeating: 0, count: bitmap.count/4)
    
    vDSP_vfltu8(UnsafePointer.init(bitmap).advanced(by: 2),
                vDSP_Stride(4),
                &redFloats,
                vDSP_Stride(1),
                vDSP_Length(redFloats.count))
    
    var red: Float = 0
    
    vDSP_meanv(redFloats,
               vDSP_Stride(1),
               &red,
               vDSP_Length(redFloats.count))
    
    print("red =", red) //150.0