如何计算UIImage的平均颜色? [英] How to calculate the average color of a UIImage?

查看:436
本文介绍了如何计算UIImage的平均颜色?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想建立一个应用程式,让使用者选取图片并输出「平均颜色」。



例如,此图片:





平均颜色是绿色/淡黄色。 / p>

此时,我收到了以下代码:

  //一个UIColor扩展
public static func fromImage(image:UIImage) - > UIColor {
var totalR:CGFloat = 0
var totalG:CGFloat = 0
var totalB:CGFloat = 0

var count:CGFloat = 0

for x in 0 ..< Int(image.size.width){
for y in 0 ..< Int(image.size.height){
count + = 1
var rF:CGFloat = 0,
gF:CGFloat = 0,
bF:CGFloat = 0,
aF:CGFloat = 0
image.getPixelColor x:x,y:y))。getRed(& rF,green:& gF,blue:& bF,alpha:& aF)
totalR + = rF
totalG + = gF
totalB + = bF
}
}

let averageR = totalR / count
let averageG = totalG / count
let averageB = totalB / count

return UIColor(red:averageR,green:averageG,blue:averageB,alpha:1.0)
}

其中 getPixelColor 定义为:

  extension UIImage {
func getPixelColor(pos:CGPoint) - > UIColor {

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

让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 [pixelInfo + 2])/ CGFloat(255.0)
let a = CGFloat(data [pixelInfo + 3])/ CGFloat(255.0)

return UIColor(red:r,green:g ,blue:b,alpha:a)
}
}

可以看到,我在这里做的是天真的:我循环通过图像中的所有像素,添加他们的RGBs,并除以计数。



当我运行应用程序并选择图像时,应用程序会冻结。我知道这是因为图像太大,并且两个嵌套的for循环执行了太多次。



我想找到一种有效地获得平均颜色的方法的图像。

解决方案

您将需要使用Accelerate库,Apple有一个手册包含一些示例代码,它将在Swift或ObjC中工作



这里是一个让你去的示例,我用它来计算一个人的心率和心率变异性,使用颜色的变化



此处的完整代码:
https://github.com/timestocome/SwiftHeartRate/blob/master/Swift%20Pulse%20Reader/ViewController.swift



这是在旧版本的Swift,但我想你会得到的想法。



这里的相关代码:

  //计算reg,green,blue和total的亮度
//从像素中取出颜色值--- image是BGRA
var greenVector: Float] = Array(count:numberOfPixels,repeatedValue:0.0)
var blueVector:[Float] = Array(count:numberOfPixels,repeatedValue:0.0)
var redVector:[Float] = Array(count:numberOfPixels ,repeatedValue:0.0)

vDSP_vfltu8(dataBuffer,4,& blueVector,1,vDSP_Length(numberOfPixels))
vDSP_vfltu8(dataBuffer + 1,4,& greenVector,1,vDSP_Length numberOfPixels))
vDSP_vfltu8(dataBuffer + 2,4,& redVector,1,vDSP_Length(numberOfPixels))



//计算每种颜色的平均值
var redAverage:Float = 0.0
var blueAverage:Float = 0.0
var greenAverage:Float = 0.0

vDSP_meamgv(& redVector,1,& redAverage,vDSP_Length numberOfPixels))
vDSP_meamgv(& greenVector,1,& greenAverage,vDSP_Length(numberOfPixels))
vDSP_meamgv(& blueVector,1,& blueAverage,vDSP_Length(numberOfPixels))



//转换为HSV(色相,饱和度,值)
//这样可以得到更快,更准确的答案
var hue:CGFloat = 0.0
var saturation:CGFloat = 0.0
var brightness:CGFloat = 0.0
var alpha:CGFloat = 1.0

var color:UIColor = UIColor(red:CGFloat(redAverage / 255.0),绿色:CGFloat(greenAverage / 255.0),蓝色:CGFloat(blueAverage / 255.0),alpha:alpha)
color.getHue(& hue,saturation:& saturation,brightness:& brightness,alpha: alpha)




// 5计数滚动平均值
let currentHueAverage = hue / movingAverageCount
movingAverageArray.removeAtIndex(0)
moveAverageArray.append(currentHueAverage)

让moveAverage = movingAverageArray [0] + movingAverageArray [1] + movingAverageArray [2] + movingAverageArray [3] + movingAverageArray [4]


I want to build an app that lets the user select an image and it outputs the "average color".

For example, this image:

The average color would be a greenish/yellowish color.

At the moment, I got this code:

// In a UIColor extension
public static func fromImage(image: UIImage) -> UIColor {
    var totalR: CGFloat = 0
    var totalG: CGFloat = 0
    var totalB: CGFloat = 0

    var count: CGFloat = 0

    for x in 0..<Int(image.size.width) {
        for y in 0..<Int(image.size.height) {
            count += 1
            var rF: CGFloat = 0,
            gF: CGFloat = 0,
            bF: CGFloat = 0,
            aF: CGFloat = 0
            image.getPixelColor(CGPoint(x: x, y: y)).getRed(&rF, green: &gF, blue: &bF, alpha: &aF)
            totalR += rF
            totalG += gF
            totalB += bF
        }
    }

    let averageR = totalR / count
    let averageG = totalG / count
    let averageB = totalB / count

    return UIColor(red: averageR, green: averageG, blue: averageB, alpha: 1.0)
}

Where getPixelColor is defined as:

extension UIImage {
    func getPixelColor(pos: CGPoint) -> UIColor {

        let pixelData = CGDataProviderCopyData(CGImageGetDataProvider(self.CGImage))
        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)
    }
}

As you can see, what I did here is pretty naive: I loop through all the pixels in the image, add their RGBs up, and divide by the count.

When I run the app and selects the image, the app freezes. I know that this is because the image is too large and the two nested for loops are executed too many times.

I want to find a way to efficiently get the average color of an image. How do I do that?

解决方案

You'll need to use the Accelerate Library, Apple has a manual with some sample code, it'll work in Swift or ObjC

Here is a sample to get you going, I use this to calculate a person's heart rate and heart rate variability using the change in colors of a finger over the camera lens.

Full code here: https://github.com/timestocome/SwiftHeartRate/blob/master/Swift%20Pulse%20Reader/ViewController.swift

It's in an older version of Swift but I think you'll get the idea. I was doing this at 240 fps, but with a cropped smaller section of the image.

Relevant code here:

// compute the brightness for reg, green, blue and total
    // pull out color values from pixels ---  image is BGRA
    var greenVector:[Float] = Array(count: numberOfPixels, repeatedValue: 0.0)
    var blueVector:[Float] = Array(count: numberOfPixels, repeatedValue: 0.0)
    var redVector:[Float] = Array(count: numberOfPixels, repeatedValue: 0.0)

    vDSP_vfltu8(dataBuffer, 4, &blueVector, 1, vDSP_Length(numberOfPixels))
    vDSP_vfltu8(dataBuffer+1, 4, &greenVector, 1, vDSP_Length(numberOfPixels))
    vDSP_vfltu8(dataBuffer+2, 4, &redVector, 1, vDSP_Length(numberOfPixels))



    // compute average per color
    var redAverage:Float = 0.0
    var blueAverage:Float = 0.0
    var greenAverage:Float = 0.0

    vDSP_meamgv(&redVector, 1, &redAverage, vDSP_Length(numberOfPixels))
    vDSP_meamgv(&greenVector, 1, &greenAverage, vDSP_Length(numberOfPixels))
    vDSP_meamgv(&blueVector, 1, &blueAverage, vDSP_Length(numberOfPixels))



    // convert to HSV ( hue, saturation, value )
    // this gives faster, more accurate answer
    var hue: CGFloat = 0.0
    var saturation: CGFloat = 0.0
    var brightness: CGFloat = 0.0
    var alpha: CGFloat = 1.0

    var color: UIColor = UIColor(red: CGFloat(redAverage/255.0), green: CGFloat(greenAverage/255.0), blue: CGFloat(blueAverage/255.0), alpha: alpha)
    color.getHue(&hue, saturation: &saturation, brightness: &brightness, alpha: &alpha)




    // 5 count rolling average
    let currentHueAverage = hue/movingAverageCount
    movingAverageArray.removeAtIndex(0)
    movingAverageArray.append(currentHueAverage)

    let movingAverage = movingAverageArray[0] + movingAverageArray[1] + movingAverageArray[2] + movingAverageArray[3] + movingAverageArray[4]

这篇关于如何计算UIImage的平均颜色?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆