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

时间:2011-08-24 07:06:45

标签: ios cocoa-touch uiimageview uiimage uicolor

我有一个“房间”形象。

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

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

因此,图像中的所有“蓝色”颜色将被“黑色”替换。

任何人都知道如何在iPhone中实现这一目标?

帮助表示赞赏。

4 个答案:

答案 0 :(得分:6)

  1. 您必须遍历图像中的每个像素并获取其rgb 值
  2. 检查其rgb值是否与fromColor rgb值匹配,如果是的话 将像素值更改为toColor rgb值。如果不是,请离开 该像素并转到下一个..
  3. 从记忆中写出一个函数......可能的错误......纠正自己

    -(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;
    }
    

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

答案 1 :(得分:1)

我偶然发现这个答案正在寻找用另一种颜色替换颜色。 好吧,既然我需要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解释用颜色创建图像。

答案 2 :(得分:0)

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

答案 3 :(得分:0)

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

[UIColor colorWithRed:191.0f / 255.0f绿色:30.0f / 255.0f蓝色: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;}