用另一种颜色替换图像中的特定颜色

Posted

技术标签:

【中文标题】用另一种颜色替换图像中的特定颜色【英文标题】:Replace a particular color inside an image with another color 【发布时间】:2011-08-24 07:06:45 【问题描述】:

我有一个“房间”图像。

现在,用户将单击图像中的任何特定颜色,假设为蓝色。

用户也会选择替换颜色,如“黑色”颜色。

因此,图像内的所有“蓝色”颜色都将替换为“黑色”颜色。

有人知道如何在 iPhone 中实现这一点吗?

感谢您的帮助。

【问题讨论】:

是的,完美的颜色替换是可能的,但它实际上不适用于现实世界的视频数据。有关更多信息和真正的解决方案,请参阅此问题:***.com/questions/18452808/… 【参考方案1】:
    您必须遍历图像中的每个像素并获取其 rgb 价值观 检查其 rgb 值是否与您的 fromColor rgb 值匹配,如果是的话 将像素值更改为您的 toColor rgb 值。如果没有,请离开 该像素并转到下一个..

凭记忆写了一个函数..可能有错误..自己改正

-(UIImage*)changeColor:(UIImage*)myImage fromColor:(UIColor*)fromColor toColor:(UIColor*)toColor
    CGImageRef originalImage    = [myImage CGImage];
    CGColorSpaceRef colorSpace  = CGColorSpaceCreateDeviceRGB();
    CGContextRef bitmapContext  = 
CGBitmapContextCreate(NULL,CGImageGetWidth(originalImage),CGImageGetHeight(originalImage),
 8,CGImageGetWidth(originalImage)*4,colorSpace,kCGImageAlphaPremultipliedLast);
    CGColorSpaceRelease(colorSpace);
    CGContextDrawImage(bitmapContext, CGRectMake(0, 0, 
CGBitmapContextGetWidth(bitmapContext),CGBitmapContextGetHeight(bitmapContext)), 
originalImage);
    UInt8 *data          = CGBitmapContextGetData(bitmapContext);
    int numComponents    = 4;
    int bytesInContext   = CGBitmapContextGetHeight(bitmapContext) *      
    CGBitmapContextGetBytesPerRow(bitmapContext);
    double redIn, greenIn, blueIn,alphaIn;
    CGFloat fromRed,fromGreen,fromBlue,fromAlpha;
    CGFloat toRed,toGreen,toBlue,toAlpha; 

    //Get RGB values of fromColor
    int fromCountComponents = CGColorGetNumberOfComponents([fromColor CGColor]);
    if (fromCountComponents == 4) 
     const CGFloat *_components = CGColorGetComponents([fromColor CGColor]);
     fromRed = _components[0];
     fromGreen = _components[1];
     fromBlue = _components[2];
     fromAlpha = _components[3];
    


    //Get RGB values for toColor
    int toCountComponents = CGColorGetNumberOfComponents([toColor CGColor]);
    if (toCountComponents == 4) 
      const CGFloat *_components = CGColorGetComponents([toColor CGColor]);
      toRed   = _components[0];
      toGreen = _components[1];
      toBlue  = _components[2];
      toAlpha = _components[3];
    


    //Now iterate through each pixel in the image..
    for (int i = 0; i < bytesInContext; i += numComponents) 
        //rgba value of current pixel..
        redIn    =   (double)data[i]/255.0;
        greenIn  =   (double)data[i+1]/255.0;
        blueIn   =   (double)data[i+2]/255.0;
        alphaIn  =   (double)data[i+3]/255.0;

        //now you got current pixel rgb values...check it curresponds with your fromColor
        if( redIn == fromRed && greenIn == fromGreen && blueIn == fromBlue )
            //image color matches fromColor, then change current pixel color to toColor
            data[i]    =   toRed;
            data[i+1]  =   toGreen;
            data[i+2]  =   toBlue;
            data[i+3]  = toAlpha;       
        
    
    CGImageRef outImage =   CGBitmapContextCreateImage(bitmapContext);
    myImage             =   [UIImage imageWithCGImage:outImage];
    CGImageRelease(outImage);
    return myImage;

我希望你不要每次都调用这个函数......它有点重处理器......如果我是你的处理器,我不会对你满意......:)

【讨论】:

对我有用。颜色没有任何变化 @Shailesh,这段代码是几年前编写的,当时还没有适用于 ios 的原生图像过滤库。 iOS 现在有核心图像框架,这可能是你应该研究的。 是的..我正在这样做。顺便说一句..这是我发布的问题。 ***.com/questions/27482508/…如果您能提供帮助,我将不胜感激 @Shailesh 我很乐意提供帮助。但在过去的 3 年里我没有接触过 iOS 开发。我得先重新学习 好的。我想我会找到解决办法的。如果可能的话,我会在这里发布解决方案。由于网络上没有太多关于此问题的材料【参考方案2】:

我在寻找用另一种颜色替换颜色时偶然发现了这个答案。 好吧,既然我需要 Swift 代码,我已经尝试了几次,我找到了一个不错的解决方案。感谢@Rob 的answer。

extension UIImageView 

    @discardableResult func replace(color: UIColor, withColor replacingColor: UIColor) -> Bool 
        guard let inputCGImage = self.image?.cgImage else 
            return false
        
        let colorSpace       = CGColorSpaceCreateDeviceRGB()
        let width            = inputCGImage.width
        let height           = inputCGImage.height
        let bytesPerPixel    = 4
        let bitsPerComponent = 8
        let bytesPerRow      = bytesPerPixel * width
        let bitmapInfo       = RGBA32.bitmapInfo

        guard let context = CGContext(data: nil, width: width, height: height, bitsPerComponent: bitsPerComponent, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: bitmapInfo) else 
            print("unable to create context")
            return false
        
        context.draw(inputCGImage, in: CGRect(x: 0, y: 0, width: width, height: height))

        guard let buffer = context.data else 
            return false
        

        let pixelBuffer = buffer.bindMemory(to: RGBA32.self, capacity: width * height)

        let inColor = RGBA32(color: color)
        let outColor = RGBA32(color: replacingColor)
        for row in 0 ..< Int(height) 
            for column in 0 ..< Int(width) 
                let offset = row * width + column
                if pixelBuffer[offset] == inColor 
                    pixelBuffer[offset] = outColor
                
            
        

        guard let outputCGImage = context.makeImage() else 
            return false
        
        self.image = UIImage(cgImage: outputCGImage, scale: self.image!.scale, orientation: self.image!.imageOrientation)
        return true
    


其中 RGBA32 结构很简单:

struct RGBA32: Equatable 
    private var color: UInt32

    var redComponent: UInt8 
        return UInt8((self.color >> 24) & 255)
    

    var greenComponent: UInt8 
        return UInt8((self.color >> 16) & 255)
    

    var blueComponent: UInt8 
        return UInt8((self.color >> 8) & 255)
    

    var alphaComponent: UInt8 
        return UInt8((self.color >> 0) & 255)
    

    init(red: UInt8, green: UInt8, blue: UInt8, alpha: UInt8) 
        self.color = (UInt32(red) << 24) | (UInt32(green) << 16) | (UInt32(blue) << 8) | (UInt32(alpha) << 0)
    

    init(color: UIColor) 
        let components = color.cgColor.components ?? [0.0, 0.0, 0.0, 1.0]
        let colors = components.map  UInt8($0 * 255) 
        self.init(red: colors[0], green: colors[1], blue: colors[2], alpha: colors[3])
    

    static let bitmapInfo = CGImageAlphaInfo.premultipliedLast.rawValue | CGBitmapInfo.byteOrder32Little.rawValue

    static func ==(lhs: RGBA32, rhs: RGBA32) -> Bool 
        return lhs.color == rhs.color
    


这样,在你的代码中的任何地方:

let imageView = UIImageView()
let image = UIImage(color: .red) // (*)
imageView.image = image
imageView.replace(color: .red, withColor: .green)

(*) 用颜色创建图像解释here。

【讨论】:

【参考方案3】:

您需要以某种方式访问​​原始像素数据(请参阅this answer 或用户 Krishnabhadra 的代码)。搜索所有像素,例如蓝色->黑色替换,用黑色替换所有蓝色像素。看看将颜色转换为 HSV,这将使颜色替换计算更容易。

【讨论】:

【参考方案4】:

我修改了一些 Krishnabhadra 的代码,因为我使用 RGB 进行颜色输入和输出,例如:

[UIColor colorWithRed:191.0f/255.0f green:30.0f/255.0f blue:45.0f/255.0f alpha:1.0f]

为我工作。

-(UIImage*)changeColor:(UIImage*)myImage fromColor:(UIColor*)fromColor toColor:(UIColor*)toColor
CGImageRef originalImage    = [myImage CGImage];
CGColorSpaceRef colorSpace  = CGColorSpaceCreateDeviceRGB();
CGContextRef bitmapContext  =
CGBitmapContextCreate(NULL,CGImageGetWidth(originalImage),CGImageGetHeight(originalImage),
                      8,CGImageGetWidth(originalImage)*4,colorSpace,kCGImageAlphaPremultipliedLast);
CGColorSpaceRelease(colorSpace);
CGContextDrawImage(bitmapContext, CGRectMake(0, 0,
                                             CGBitmapContextGetWidth(bitmapContext),CGBitmapContextGetHeight(bitmapContext)),
                   originalImage);
UInt8 *data          = CGBitmapContextGetData(bitmapContext);
int numComponents    = 4;
int bytesInContext   = CGBitmapContextGetHeight(bitmapContext) *
CGBitmapContextGetBytesPerRow(bitmapContext);
double redIn, greenIn, blueIn,alphaIn;
CGFloat fromRed,fromGreen,fromBlue,fromAlpha;
CGFloat toRed,toGreen,toBlue,toAlpha;

//Get RGB values of fromColor
int fromCountComponents = CGColorGetNumberOfComponents([fromColor CGColor]);
if (fromCountComponents == 4) 
    const CGFloat *_components = CGColorGetComponents([fromColor CGColor]);
    fromRed = _components[0];
    fromGreen = _components[1];
    fromBlue = _components[2];
    fromAlpha = _components[3];



//Get RGB values for toColor
int toCountComponents = CGColorGetNumberOfComponents([toColor CGColor]);
if (toCountComponents == 4) 
    const CGFloat *_components = CGColorGetComponents([toColor CGColor]);
    toRed   = _components[0]*255;
    toGreen = _components[1]*255;
    toBlue  = _components[2]*255;
    toAlpha = _components[3]*255;



//Now iterate through each pixel in the image..
for (int i = 0; i < bytesInContext; i += numComponents) 
    //rgba value of current pixel..
    redIn    =   (double)data[i];
    greenIn  =   (double)data[i+1];
    blueIn   =   (double)data[i+2];
    alphaIn  =   (double)data[i+3];
    //now you got current pixel rgb values...check it curresponds with your fromColor
    if( redIn == fromRed && greenIn == fromGreen && blueIn == fromBlue && alphaIn != 0 )
        //image color matches fromColor, then change current pixel color to toColor
        data[i]    =   toRed;
        data[i+1]  =   toGreen;
        data[i+2]  =   toBlue;
        data[i+3]  = toAlpha;
    

CGImageRef outImage =   CGBitmapContextCreateImage(bitmapContext);
myImage             =   [UIImage imageWithCGImage:outImage];
CGImageRelease(outImage);
return myImage;

【讨论】:

以上是关于用另一种颜色替换图像中的特定颜色的主要内容,如果未能解决你的问题,请参考以下文章

ps怎么换颜色

如何在不透明的 UIImage 上用另一种颜色替换给定颜色 [重复]

用另一种颜色显示 System.out.println 输出

用一种颜色作为描边绘制一个多边形,用另一种颜色作为填充?

ps怎么把一种颜色变成另一种颜色

ps中 怎么把一张图片的一种颜色全部替换成另外一种颜色?