Замена определенного цвета внутри изображения другим цветом

У меня одно "комнатное" изображение.

Теперь пользователь будет щелкать любой конкретный цвет, предположим, синий цвет на изображении.

А также пользователь выберет заменяемый цвет как «черный» цвет.

Таким образом, весь «синий» цвет внутри изображения будет заменен на «черный» цвет.

Кто-нибудь знает, как этого добиться в iPhone?

Помощь приветствуется.


person Nishant B    schedule 24.08.2011    source источник
comment
Да, идеальная замена цвета возможна, но на самом деле она не работает в реальных видеоданных. См. Этот вопрос для получения дополнительной информации и реального решения: stackoverflow.com/questions/18452808/   -  person MoDJ    schedule 04.09.2017


Ответы (4)


  1. Вам нужно перебрать каждый пиксель изображения и взять его значения rgb.
  2. Убедитесь, что его значения 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;
}

Надеюсь, вы не вызываете эту функцию каждый раз ... Это немного тяжеловато для процессора ... И если бы я был вашим процессором, я бы не был доволен вами .. :)

person Krishnabhadra    schedule 24.08.2011
comment
У меня нет работы. не получил никаких изменений в цвете - person Shailesh; 16.12.2014
comment
@Shailesh, этот код был написан много лет назад, когда для iOS не было собственной библиотеки фильтрации изображений. У iOS теперь есть основная структура изображений, и, вероятно, это то, на что вам стоит обратить внимание. - person Krishnabhadra; 16.12.2014
comment
Ага .. Я делаю это. Кстати ... вот вопрос, который я разместил. stackoverflow.com/questions/27482508/ Я был бы признателен, если бы вы могли помочь - person Shailesh; 16.12.2014
comment
@Shailesh Я бы хотел помочь. Но последние 3 года я не касался iOS-разработки. Мне придется сначала переучиться - person Krishnabhadra; 16.12.2014
comment
Хорошо. Думаю, я найду способ обойти проблему .. Если возможно, выложу решение здесь. Поскольку в Интернете не так много материалов об этой проблеме - person Shailesh; 16.12.2014

Я наткнулся на этот ответ, пытаясь заменить один цвет другим. Ну, так как мне нужен код Swift, я попробовал несколько раз и нашел хорошее решение. Спасибо @Rob за его ответ.

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)

(*) создание изображения с цветом объясняется здесь .

person Luca Davanzo    schedule 07.11.2017

Каким-то образом вам понадобится доступ к необработанным данным пикселей (см. этот ответ или код пользователя Кришнабхадры). Выполните поиск по всем пикселям и, например, для замены синий-> черный, замените все синие пиксели черными. Посмотрите, как преобразовать цвет в HSV, что упростит расчет замены цвета.

person damian    schedule 24.08.2011

Я немного изменил код Кришнабхадры, так как я использую RGB как для ввода цвета, так и для вывода, например:

[UIColor colorWithRed: 191.0f / 255.0f зеленый: 30.0f / 255.0f синий: 45.0f / 255.0f альфа: 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;}
person Tyler Chong    schedule 18.08.2015