Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/109.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 获取Swift中UIImage的平均颜色_Ios_Swift_Uiimage - Fatal编程技术网

Ios 获取Swift中UIImage的平均颜色

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

我最近试图将代码从转换为Swift。然而,无论图像如何,我总是得到白色。这是我的密码:

// 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。这很简单: