我正在制作一个OS X应用程序,该应用程序从图像的主要颜色创建配色方案。

第一步,我使用NSCountedSetcolorAtX从图像中获取所有颜色并计算它们的出现:

func sampleImage(#width: Int, height: Int, imageRep: NSBitmapImageRep) -> (NSCountedSet, NSCountedSet) {
    // Store all colors from image
    var colors = NSCountedSet(capacity: width * height)
    // Store the colors from left edge of the image
    var leftEdgeColors = NSCountedSet(capacity: height)
    // Loop over the image pixels
    var x = 0
    var y = 0
    while x < width {
        while y < height {
            // Instruments shows that `colorAtX` is very slow
            // and using `NSCountedSet` is also very slow
            if let color = imageRep.colorAtX(x, y: y) {
                if x == 0 {
                    leftEdgeColors.addObject(color)
                }
                colors.addObject(color)
            }
            y++
        }
        // Reset y every x loop
        y = 0
        // We sample a vertical line every x pixels
        x += 1
    }
    return (colors, leftEdgeColors)
}


我的问题是,这非常慢。在Instruments中,我看到了两个大瓶颈:NSCountedSetcolorAtX

所以首先我想也许可以用一个纯Swift替代物替换NSCountedSet,但是新的实现并不比NSCountedSet慢得多。

对于colorAtX,有一个this有趣的SO答案,但我无法将其转换为Swift(并且对于该项目,我无法在Objective-C中使用桥接头)。

我在尝试翻译时的问题是我不理解答案中的unsigned charchar部分。

我应该尝试比colorAtX更快地扫描颜色吗?


继续努力修改Objective-C答案,因为这是一个很好的答案?尽管暂时停滞不前,也许我以后可以实现。
使用我不知道的另一种Foundation / Cocoa方法?
还有什么我可以尝试改进我的代码的吗?


TL; DR

colorAtX很慢,由于unsigned char我不知道如何将this Objective-C answer适应Swift。

最佳答案

替代colorAtX()最快的方法是使用let bitmapBytes = imageRep.bitmapData遍历图像的原始字节,然后根据该信息自行组成颜色,如果只是RGBA数据,这应该非常简单。代替您的for x / y循环,执行以下操作...

let bitmapBytes = imageRep.bitmapData
var colors = Dictionary<UInt32, Int>()

var index = 0
for _ in 0..<(width * height) {
    let r = UInt32(bitmapBytes[index++])
    let g = UInt32(bitmapBytes[index++])
    let b = UInt32(bitmapBytes[index++])
    let a = UInt32(bitmapBytes[index++])
    let finalColor = (r << 24) + (g << 16) + (b << 8) + a

    if colors[finalColor] == nil {
        colors[finalColor] = 1
    } else {
        colors[finalColor]!++
    }
}


我猜想,您将不得不检查RGBA值的顺序!

保持计数最快的方法可能只是将像素值转换为[Int,Int]字典,进行类似colors[color]++的操作。稍后,如果需要,您可以使用NSColor(calibratedRed red: CGFloat, green green: CGFloat, blue blue: CGFloat, alpha alpha: CGFloat)将其转换为NSColor。

关于objective-c - 计算图像中的颜色:NSCountedSet和colorAtX非常慢,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/31026763/

10-11 12:10