2

I have one image which is in grayscale and I am applying it's original color in some part of that image and I have achieved it. Now I want to change color of that part in which I have applied original color in image

I have this: Original Image

I want to convert in this: Result Image

CGImageRef imageRef = [image CGImage];
NSUInteger width = CGImageGetWidth(imageRef);
NSUInteger height = CGImageGetHeight(imageRef);

NSUInteger bytesPerPixel = 4;
NSUInteger bytesPerRow = bytesPerPixel * width;
NSUInteger bitsPerComponent = 8;

NSUInteger bytesCount = height * width * bytesPerPixel;

CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
unsigned char *rawData = (unsigned char *)calloc(bytesCount, sizeof(unsigned char));
CGContextRef context = CGBitmapContextCreate(rawData, width, height,
                                             bitsPerComponent, bytesPerRow, colorSpace,
                                             kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);

CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
CGContextRelease(context);

unsigned char *outputData = (unsigned char *)calloc(bytesCount, sizeof(unsigned char));

NSUInteger byteIndex = 0;
for (NSUInteger i=0; i<bytesCount / bytesPerPixel; ++i) {
    CGFloat red = (CGFloat)rawData[byteIndex];
    CGFloat green = (CGFloat)rawData[byteIndex+1];
    CGFloat blue = (CGFloat)rawData[byteIndex+2];
    CGFloat alpha = (CGFloat)rawData[byteIndex+3];

    BOOL grayscale = red == green == blue;

    if (!grayscale) {
        // test for near values
        CGFloat diff = MAX(ABS(red-green), MAX(ABS(red-blue), ABS(green-blue)));

        static CGFloat allowedDifference = 100; // in range of 0-255

        if (diff > allowedDifference) {

//                CGFloat redTemp = 236;
//                red = green;
//                green = redTemp;
            red = 236.0;
            green = 17.0;
            blue = 17.0;

        }
    }

    outputData[byteIndex] = red;
    outputData[byteIndex+1] = green;
    outputData[byteIndex+2] = blue;
    outputData[byteIndex+3] = alpha;

    byteIndex += bytesPerPixel;
}

free(rawData);


CGDataProviderRef outputDataProvider = CGDataProviderCreateWithData(NULL,
                                                                    outputData,
                                                                    bytesCount,
                                                                    NULL);
free(outputData);

CGImageRef outputImageRef = CGImageCreate(width,
                                          height,
                                          bitsPerComponent,
                                          bytesPerPixel * 8,
                                          bytesPerRow,
                                          colorSpace,
                                          kCGBitmapByteOrderDefault,
                                          outputDataProvider,
                                          NULL,NO,
                                          kCGRenderingIntentDefault);


CGColorSpaceRelease(colorSpace);
CGDataProviderRelease(outputDataProvider);

UIImage *outputImage = [UIImage imageWithCGImage:outputImageRef];
CGImageRelease(outputImageRef);

I tried bitmapcontext and everything, but not getting desired result.

Does anyone have idea ?

1 Answers1

1

You can try grabbing pixel data from an image by using CGBitmapContextCreate to create a color space, then draw an image to it via CGContextDrawImage.

Secondly, you will receive an array of bytes of one dimension. Like this: [r1, g1, b1, a1, r2, g2, b2, a2, ...] where r,g,b,a - color components, 1,2 - nu. of pixel.

After this, you can iterate over the array and compare each pixel's color components. Since you should skip grayscale pixels, you need to compare rgb params and they theoretically must be equal, but you can also support some little errors in few digits +-.

And if concrete pixel is not grayscale, just swap red and green bytes.

Should be the way to go.

Updated with example:

UIImage *image = [UIImage imageNamed:@"qfjsc.png"];

CGImageRef imageRef = [image CGImage];
NSUInteger width = CGImageGetWidth(imageRef);
NSUInteger height = CGImageGetHeight(imageRef);

NSUInteger bytesPerPixel = 4;
NSUInteger bytesPerRow = bytesPerPixel * width;
NSUInteger bitsPerComponent = 8;

NSUInteger bytesCount = height * width * bytesPerPixel;

CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
unsigned char *rawData = (unsigned char *)calloc(bytesCount, sizeof(unsigned char));
CGContextRef context = CGBitmapContextCreate(rawData, width, height,
                                             bitsPerComponent, bytesPerRow, colorSpace,
                                             kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);

CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
CGContextRelease(context);

unsigned char *outputData = (unsigned char *)calloc(bytesCount, sizeof(unsigned char));

NSUInteger byteIndex = 0;
for (NSUInteger i=0; i<bytesCount / bytesPerPixel; ++i) {
    CGFloat red = (CGFloat)rawData[byteIndex];
    CGFloat green = (CGFloat)rawData[byteIndex+1];
    CGFloat blue = (CGFloat)rawData[byteIndex+2];
    CGFloat alpha = (CGFloat)rawData[byteIndex+3];

    BOOL grayscale = red == green == blue;

    if (!grayscale) {
        // test for near values
        CGFloat diff = MAX(ABS(red-green), MAX(ABS(red-blue), ABS(green-blue)));

        static CGFloat allowedDifference = 50.0; // in range of 0-255

        if (diff > allowedDifference) {

            CGFloat redTemp = red;
            red = green;
            green = redTemp;

        }
    }

    outputData[byteIndex] = red;
    outputData[byteIndex+1] = green;
    outputData[byteIndex+2] = blue;
    outputData[byteIndex+3] = alpha;

    byteIndex += bytesPerPixel;
}

free(rawData);


CGDataProviderRef outputDataProvider = CGDataProviderCreateWithData(NULL,
                                                                    outputData,
                                                                    bytesCount,
                                                                    NULL);
free(outputData);

CGImageRef outputImageRef = CGImageCreate(width,
                                          height,
                                          bitsPerComponent,
                                          bytesPerPixel * 8,
                                          bytesPerRow,
                                          colorSpace,
                                          kCGBitmapByteOrderDefault,
                                          outputDataProvider,
                                          NULL,NO,
                                          kCGRenderingIntentDefault);


CGColorSpaceRelease(colorSpace);
CGDataProviderRelease(outputDataProvider);

UIImage *outputImage = [UIImage imageWithCGImage:outputImageRef];
CGImageRelease(outputImageRef);

Note the static allowed difference variable. It allows you to skip almost non grayscale pixels, but which are in RGB color space and almost grayscale by its nature.

Here are examples:

  1. Allowed difference = 0 Allowed difference = 0
  2. Allowed difference = 50 Allowed difference = 50
Alex Posplaw
  • 116
  • 8
  • Can you post any code ? because It is too complex to write down this all. – krishna patel Nov 04 '15 at 12:18
  • @krishnapatel I've updated an answer with tested example – Alex Posplaw Nov 04 '15 at 12:48
  • @krishnapatel your resulting image looks more bright and orange, so if you got the idea, you can easily play with resulting color when you swap it by changing color components to reach needed result – Alex Posplaw Nov 04 '15 at 13:06
  • I tried your code, but when I change red and green color in if (diff > allowedDifference) condition, then result is too bad – krishna patel Nov 04 '15 at 13:19
  • @krishnapatel couldn't you please update your question with what you've changed, since my example works fine – Alex Posplaw Nov 04 '15 at 13:21
  • @krishnapatel unforunately, you've updated my answer, but I've seen your resulting image. The problem might be that you've prepared your image wrong since you get these results. I've made the code that correctly fits the needs of your initial question. And as I mentioned, try changing allowed difference since your source image seems to be incorrect. – Alex Posplaw Nov 04 '15 at 13:25
  • I have updated my question. You can check. And what is the "difference" role ? – krishna patel Nov 04 '15 at 13:27
  • @krishnapatel and [from what i've seen](http://i.stack.imgur.com/jtF1o.png) if you get such red colors with 255 of 255 component, it seems you either have source image with green of 255/255 in those pixels or you've changed mechanism of swapping colors somehow that it produces such weird result – Alex Posplaw Nov 04 '15 at 13:28
  • @krishnapatel allowed difference lets you skip pixels with slight expectoration from grayscale color, like if you made some pixel with value of 55,55,63, allowed difference of 8 will skip this pixel as grayscale, but with value of 7, it will be swapped – Alex Posplaw Nov 04 '15 at 13:31
  • I have posted code in my question, and I am using same code here – krishna patel Nov 04 '15 at 13:32
  • @krishnapatel you've changed my answer's code to set pixel's color to 236,17,17 so why are you surprised that you painted part of an image with a solid color? :) definitely your mistake – Alex Posplaw Nov 04 '15 at 13:34
  • @krishnapatel I don't know what are you trying to do, but this is not your initial question anymore. Now, you've got a solution to swap the image's pixels from green to red, and if it solved your question mark it as approved, then create a new question with existing code and point your new aim you're trying to achieve. – Alex Posplaw Nov 04 '15 at 13:39
  • I want to swap image pixel color from any color to any color. It is not limited to only green to red. By the way I don't have 15 reputation, once I will get 15 reputation, I will upvote your answer. – krishna patel Nov 04 '15 at 13:50
  • @krishnapatel as question's author you can set an answer as accepted, while upvote is optional. Your next aim is more complex task than you originally asked, so you should make new question and expect links to some techniques not related to iOS since it's language-independent question. – Alex Posplaw Nov 04 '15 at 14:59