Ios 获取Swift中UIImage的平均颜色
我最近试图将代码从转换为Swift。然而,无论图像如何,我总是得到白色。这是我的密码:Ios 获取Swift中UIImage的平均颜色,ios,swift,uiimage,Ios,Swift,Uiimage,我最近试图将代码从转换为Swift。然而,无论图像如何,我总是得到白色。这是我的密码: // Playground - noun: a place where people can play import UIKit extension UIImage { func averageColor() -> UIColor { var colorSpace = CGColorSpaceCreateDeviceRGB() var rgba: [CGFlo
// Playground - noun: a place where people can play
import UIKit
extension UIImage {
func averageColor() -> UIColor {
var colorSpace = CGColorSpaceCreateDeviceRGB()
var rgba: [CGFloat] = [0,0,0,0]
var context = CGBitmapContextCreate(&rgba, 1, 1, 8, 4, colorSpace, CGBitmapInfo.fromRaw(CGImageAlphaInfo.PremultipliedLast.toRaw())!)
rgba
CGContextDrawImage(context, CGRectMake(0, 0, 1, 1), self.CGImage)
if rgba[3] > 0 {
var alpha = rgba[3] / 255
var multiplier = alpha / 255
return UIColor(red: rgba[0] * multiplier, green: rgba[1] * multiplier, blue: rgba[2] * multiplier, alpha: alpha)
} else {
return UIColor(red: rgba[0] / 255, green: rgba[1] / 255, blue: rgba[2] / 255, alpha: rgba[3] / 255)
}
}
}
var img = UIImage(data: NSData(contentsOfURL: NSURL(string: "http://upload.wikimedia.org/wikipedia/commons/c/c3/Aurora_as_seen_by_IMAGE.PNG")))
img.averageColor()
提前感谢。您是否正确设置了上下文?如果我查看CGBitmapContext参考的文档: 看起来您只为CGFloat数组中包含的映像分配了足够的内存。看起来你也在告诉编译器你的图像只会是一个像素对一个像素 当您在CGContextDrawImage中设置CGRect时,看起来该大小也被确认为一个像素一个像素 如果游乐场只创建一个像素一个像素的图像,这就解释了为什么你只看到一个白色屏幕。这里有一个解决方案:
func averageColor() -> UIColor {
let rgba = UnsafeMutablePointer<CUnsignedChar>.alloc(4)
let colorSpace: CGColorSpaceRef = CGColorSpaceCreateDeviceRGB()
let info = CGBitmapInfo(CGImageAlphaInfo.PremultipliedLast.rawValue)
let context: CGContextRef = CGBitmapContextCreate(rgba, 1, 1, 8, 4, colorSpace, info)
CGContextDrawImage(context, CGRectMake(0, 0, 1, 1), self.CGImage)
if rgba[3] > 0 {
let alpha: CGFloat = CGFloat(rgba[3]) / 255.0
let multiplier: CGFloat = alpha / 255.0
return UIColor(red: CGFloat(rgba[0]) * multiplier, green: CGFloat(rgba[1]) * multiplier, blue: CGFloat(rgba[2]) * multiplier, alpha: alpha)
} else {
return UIColor(red: CGFloat(rgba[0]) / 255.0, green: CGFloat(rgba[1]) / 255.0, blue: CGFloat(rgba[2]) / 255.0, alpha: CGFloat(rgba[3]) / 255.0)
}
}
func averageColor()->UIColor{
设rgba=unsafemeutablepointer.alloc(4)
let colorSpace:CGColorSpaceRef=CGColorSpaceCreateDeviceRGB()
let info=CGBitmapInfo(CGImageAlphaInfo.PremultipliedLast.rawValue)
let context:CGContextRef=CGBitmapContextCreate(rgba,1,1,8,4,颜色空间,信息)
CGContextDrawImage(上下文,CGRectMake(0,0,1,1),self.CGImage)
如果rgba[3]>0{
设alpha:CGFloat=CGFloat(rgba[3])/255.0
let乘数:CGFloat=alpha/255.0
返回UIColor(红色:CGFloat(rgba[0])*乘法器,绿色:CGFloat(rgba[1])*乘法器,蓝色:CGFloat(rgba[2])*乘法器,alpha:alpha)
}否则{
返回UIColor(红色:CGFloat(rgba[0])/255.0,绿色:CGFloat(rgba[1])/255.0,蓝色:CGFloat(rgba[2])/255.0,alpha:CGFloat(rgba[3])/255.0)
}
}
iOS 9中的CoreImage:使用CIAreaAverage过滤器并传递要平均的整个图像的范围
另外,它的速度要快得多,因为它要么在GPU上运行,要么作为高度优化的CPU内核运行
import UIKit
extension UIImage {
func areaAverage() -> UIColor {
var bitmap = [UInt8](count: 4, repeatedValue: 0)
if #available(iOS 9.0, *) {
// Get average color.
let context = CIContext()
let inputImage = CIImage ?? CoreImage.CIImage(CGImage: CGImage!)
let extent = inputImage.extent
let inputExtent = CIVector(x: extent.origin.x, y: extent.origin.y, z: extent.size.width, w: extent.size.height)
let filter = CIFilter(name: "CIAreaAverage", withInputParameters: [kCIInputImageKey: inputImage, kCIInputExtentKey: inputExtent])!
let outputImage = filter.outputImage!
let outputExtent = outputImage.extent
assert(outputExtent.size.width == 1 && outputExtent.size.height == 1)
// Render to bitmap.
context.render(outputImage, toBitmap: &bitmap, rowBytes: 4, bounds: CGRect(x: 0, y: 0, width: 1, height: 1), format: kCIFormatRGBA8, colorSpace: CGColorSpaceCreateDeviceRGB())
} else {
// Create 1x1 context that interpolates pixels when drawing to it.
let context = CGBitmapContextCreate(&bitmap, 1, 1, 8, 4, CGColorSpaceCreateDeviceRGB(), CGBitmapInfo.ByteOrderDefault.rawValue | CGImageAlphaInfo.PremultipliedLast.rawValue)!
let inputImage = CGImage ?? CIContext().createCGImage(CIImage!, fromRect: CIImage!.extent)
// Render to bitmap.
CGContextDrawImage(context, CGRect(x: 0, y: 0, width: 1, height: 1), inputImage)
}
// Compute result.
let result = UIColor(red: CGFloat(bitmap[0]) / 255.0, green: CGFloat(bitmap[1]) / 255.0, blue: CGFloat(bitmap[2]) / 255.0, alpha: CGFloat(bitmap[3]) / 255.0)
return result
}
}
斯威夫特3
func areaAverage() -> UIColor {
var bitmap = [UInt8](repeating: 0, count: 4)
if #available(iOS 9.0, *) {
// Get average color.
let context = CIContext()
let inputImage: CIImage = ciImage ?? CoreImage.CIImage(cgImage: cgImage!)
let extent = inputImage.extent
let inputExtent = CIVector(x: extent.origin.x, y: extent.origin.y, z: extent.size.width, w: extent.size.height)
let filter = CIFilter(name: "CIAreaAverage", withInputParameters: [kCIInputImageKey: inputImage, kCIInputExtentKey: inputExtent])!
let outputImage = filter.outputImage!
let outputExtent = outputImage.extent
assert(outputExtent.size.width == 1 && outputExtent.size.height == 1)
// Render to bitmap.
context.render(outputImage, toBitmap: &bitmap, rowBytes: 4, bounds: CGRect(x: 0, y: 0, width: 1, height: 1), format: kCIFormatRGBA8, colorSpace: CGColorSpaceCreateDeviceRGB())
} else {
// Create 1x1 context that interpolates pixels when drawing to it.
let context = CGContext(data: &bitmap, width: 1, height: 1, bitsPerComponent: 8, bytesPerRow: 4, space: CGColorSpaceCreateDeviceRGB(), bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue)!
let inputImage = cgImage ?? CIContext().createCGImage(ciImage!, from: ciImage!.extent)
// Render to bitmap.
context.draw(inputImage!, in: CGRect(x: 0, y: 0, width: 1, height: 1))
}
// Compute result.
let result = UIColor(red: CGFloat(bitmap[0]) / 255.0, green: CGFloat(bitmap[1]) / 255.0, blue: CGFloat(bitmap[2]) / 255.0, alpha: CGFloat(bitmap[3]) / 255.0)
return result
}
Swift 3:
func areaAverage() -> UIColor {
var bitmap = [UInt8](repeating: 0, count: 4)
let context = CIContext(options: nil)
let cgImg = context.createCGImage(CoreImage.CIImage(cgImage: self.cgImage!), from: CoreImage.CIImage(cgImage: self.cgImage!).extent)
let inputImage = CIImage(cgImage: cgImg!)
let extent = inputImage.extent
let inputExtent = CIVector(x: extent.origin.x, y: extent.origin.y, z: extent.size.width, w: extent.size.height)
let filter = CIFilter(name: "CIAreaAverage", withInputParameters: [kCIInputImageKey: inputImage, kCIInputExtentKey: inputExtent])!
let outputImage = filter.outputImage!
let outputExtent = outputImage.extent
assert(outputExtent.size.width == 1 && outputExtent.size.height == 1)
// Render to bitmap.
context.render(outputImage, toBitmap: &bitmap, rowBytes: 4, bounds: CGRect(x: 0, y: 0, width: 1, height: 1), format: kCIFormatRGBA8, colorSpace: CGColorSpaceCreateDeviceRGB())
// Compute result.
let result = UIColor(red: CGFloat(bitmap[0]) / 255.0, green: CGFloat(bitmap[1]) / 255.0, blue: CGFloat(bitmap[2]) / 255.0, alpha: CGFloat(bitmap[3]) / 255.0)
return result
}
我基本上是从我包含的链接()复制代码,并将其转换为Swift。它试图做的是让Quartz将整个图像绘制成一个像素,从而平滑图像并给出一个像素的平均颜色。在我看来,如果它在斯威夫特成功的话,它是聪明的。我认为我的问题要么与数组的启动/引用方式有关,要么与分配的内存量有关。你介意给我一个更准确的答案吗?谢谢如果你看操场上的控制台,你会发现代表颜色的浮标数组从不从零开始改变。我相信你看不到任何颜色的原因是因为阵列从未改变。您永远不会调用语句的第一部分,因为alpha永远不会大于零。此外,一切都将乘以零,并且没有任何变化。我注意到,在设置了上下文之后,代码中有一行代码,其中只有“rgba”本身。我想知道它为什么在那里。你打算做些什么来改变这些值吗?我最初感到困惑,因为在过去,当我使用石英时,你有白色,白色代表一个或更大的值。我本以为所有的零都是黑色的,而不是白色的。啊。对不起,我弄错了。alpha等于0,因此它显示为白色。我的错。当我把“rgba”放在自己的位置上,这样我就可以在操场上看到它的值。你解决过这个问题吗?你需要使用var rgba:[UInt8]=[0,0,0]永远不要手动计算:)使用GPU。这很简单:你真的把它描述成“饼干之神”了吗?我想你会惊讶地发现,在这种情况下,CoreImage速度较慢,尽管CireaAverage过滤器提供了更好的结果。你确定你只设置了一次CIContext,而没有为每次运行的图像删除一个,然后再打开另一个吗?我同意这一点,如果只设置一次CIContext,CoreImage的性能将令人印象深刻。当您想要有效地提取图像的颜色时,问题就出现了。我还没有找到一种有效的方法来做到这一点。它们允许您在非常大的图像上操作,占用的内存非常小。做所有的瓷砖、切片、切割和抛光:)。非常简单的API。您是否有一些代码,例如@GodofBiscuits?出于某种原因,iOS 9版本的此代码为不同的图像返回了恒定的灰色?iOS 9 swift 3代码仍然是我应用程序中占用CPU最多的代码。太贵了,还有其他方法吗?上下文应该创建一次,而不是每次调用函数。@DannyBravo我想看看您的解决方案。您应该在核心映像中完成所有操作。如果要处理多个图像,请创建一个CIContexr,然后使用适当的CIFilter在图像上循环以获取它。这是一个扩展,因此对我来说,拥有全局上下文没有任何意义。永远不要手动计算:)使用GPU。这很简单: