使用CIAreaMaximum检测主色始终返回RGB(255,255,255)求助
CIAreaMaximum检测图片主色始终返回白色?你误解了它的功能
你确实误解了CIAreaMaximum的作用——它**不是用来检测图片主色(最常出现的颜色)**的,而是分别计算图片中红色、绿色、蓝色三个通道的最大值,然后将这三个最大值组合成一个颜色返回。也就是说,只要你的图片里存在任何一个白色像素(RGB各通道都是255),或者某通道有像素达到255,最终结果就会偏向对应通道最大值的颜色,这就是你总是得到白色的原因。
正确实现图片主色检测的方法
如果你的需求是找到图片中最频繁出现的主色,可以用以下两种方案:
方案1:使用CIKMeans聚类滤镜(推荐)
CoreImage的CIKMeans滤镜可以通过聚类分析找出图片中的代表性颜色,适合快速获取主色:
extension UIImage { var dominantColor: UIColor? { guard let inputImage = CIImage(image: self) else { return nil } // 设置CIKMeans参数:聚类数量设为1,只取最主要的颜色 let parameters = [ kCIInputImageKey: inputImage, kCIInputCountKey: 1, kCIInputExtentKey: CIVector(x: inputImage.extent.origin.x, y: inputImage.extent.origin.y, z: inputImage.extent.size.width, w: inputImage.extent.size.height) ] guard let filter = CIFilter(name: "CIKMeans", parameters: parameters), let outputImage = filter.outputImage else { return nil } var bitmap = [UInt8](repeating: 0, count: 4) let context = CIContext(options: [.workingColorSpace: kCFNull as Any]) context.render(outputImage, toBitmap: &bitmap, rowBytes: 4, bounds: CGRect(x: 0, y: 0, width: 1, height: 1), format: .RGBA8, colorSpace: nil) return UIColor(red: CGFloat(bitmap[0])/255, green: CGFloat(bitmap[1])/255, blue: CGFloat(bitmap[2])/255, alpha: CGFloat(bitmap[3])/255) } }
然后在ContentView中替换maxColor为dominantColor即可。
方案2:统计像素颜色频率
如果需要更精确的结果,可以遍历图片像素,统计每个颜色出现的次数,取频率最高的颜色:
extension UIImage { var dominantColorByCount: UIColor? { guard let cgImage = self.cgImage else { return nil } let width = cgImage.width let height = cgImage.height let bytesPerPixel = 4 let bytesPerRow = bytesPerPixel * width let pixelCount = width * height var pixelData = [UInt8](repeating: 0, count: bytesPerRow * height) let context = CGContext(data: &pixelData, width: width, height: height, bitsPerComponent: 8, bytesPerRow: bytesPerRow, space: CGColorSpaceCreateDeviceRGB(), bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue) context?.draw(cgImage, in: CGRect(x: 0, y: 0, width: width, height: height)) // 统计颜色频率 var colorCounts = [UInt32: Int]() for i in stride(from: 0, to: pixelCount * bytesPerPixel, by: bytesPerPixel) { let r = pixelData[i] let g = pixelData[i+1] let b = pixelData[i+2] let a = pixelData[i+3] // 忽略透明像素 guard a > 0 else { continue } // 将RGB打包成一个UInt32作为键 let colorKey = (UInt32(r) << 24) | (UInt32(g) << 16) | (UInt32(b) << 8) | UInt32(a) colorCounts[colorKey, default: 0] += 1 } // 找到出现次数最多的颜色 guard let mostFrequentKey = colorCounts.max(by: { $0.value < $1.value })?.key else { return nil } let r = CGFloat((mostFrequentKey >> 24) & 0xFF) / 255 let g = CGFloat((mostFrequentKey >> 16) & 0xFF) / 255 let b = CGFloat((mostFrequentKey >> 8) & 0xFF) / 255 let a = CGFloat(mostFrequentKey & 0xFF) / 255 return UIColor(red: r, green: g, blue: b, alpha: a) } }
总结
CIAreaMaximum的作用是取各通道最大值,不是主色检测- 主色检测优先用
CIKMeans,简单高效;需要精确结果可以用像素统计法
内容的提问来源于stack exchange,提问作者test1229
相关产品推荐
相关产品推荐

