加快像素迭代

时间:2017-04-24 01:00:05

标签: ios swift uiimage pixel uicolor

我遇到的问题是无法足够快地迭代UIImage中的所有像素,检查每种颜色与特定的颜色(绿色)。一旦用户启动迭代,就必须立即处理迭代。目前有0.5秒的延迟。

我使用它来创建视图的屏幕截图:

func screenshot() -> UIImage { 

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

这是为了获得单个像素的颜色:

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(red: r, green: g, blue: b, alpha: a)
    }
}

这个循环检查图像的每个像素:

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(red: 0, green: 1, blue: 0, alpha: 1) {
            greenPresent = true
            greenCount += 1
        }
    }
}

任何建议都将不胜感激。

修改

性能受到0.0的比例因子的影响;我希望能适应这一点。

3 个答案:

答案 0 :(得分:4)

这是您发布的代码的更高效版本:

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
        }
    }
}

此代码消除了原始代码中的许多低效率。数据只获得一次。没有使用积分。直接访问数据字节。无需创建UIColor。无法转换为CGFloat

答案 1 :(得分:1)

我建议缓存 data指针:

let data: UnsafePointer<UInt8> = ...

而不是从头开始计算每次一次调用getPixelColor方法。

另外:考虑创建一个简单的struct Color,而不是使用标准class UIColor。创建(和解除分配)许多class实例可能会很快变得昂贵!

顺便说一句,您还应该在找到所需像素后添加一个简单的break。当然,假设你的最终算法保持不变; - )

答案 2 :(得分:0)

对于初学者,一找到绿色像素就会突破循环:

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(red: 0, green: 1, blue: 0, alpha: 1) {
            greenPresent = true
            break yLoop
        }
    }
}

由于您只想知道是否有一个绿色像素,所以在找到之后继续没有意义。这将使您的检查平均加速50%(尽管右下方的单个绿色像素将花费的时间一样长。)