How to change the skin color of face from the source image in ios?
Asked Answered
C

6

14

MY code: How to manage RGB value for differet shades of face,and how to apply? this code will change the color of face along with hair,but i want 1.only face to be colored excluding hair.

    -(void)changeSkinColorValue:(float)value WithImage:(UIImage*)needToModified
    {

        CGContextRef ctx;

        CGImageRef imageRef = needToModified.CGImage;
        NSUInteger width = CGImageGetWidth(imageRef);
        NSUInteger height = CGImageGetHeight(imageRef);
        CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
        //unsigned char *rawData = malloc(firstImageV.image.size.height * firstImageV.image.size.width * 10);

        CFMutableDataRef m_DataRef = CFDataCreateMutableCopy(0, 0,CGDataProviderCopyData(CGImageGetDataProvider(firstImageV.image.CGImage)));
        UInt8 *rawData = (UInt8 *) CFDataGetMutableBytePtr(m_DataRef);
        int length = CFDataGetLength(m_DataRef);
        NSUInteger bytesPerPixel = 4;
        NSUInteger bytesPerRow = bytesPerPixel * firstImageV.image.size.width;
        NSUInteger bitsPerComponent = 8;

                CGContextRef context1 = CGBitmapContextCreate(rawData, firstImageV.image.size.width, firstImageV.image.size.height, bitsPerComponent, bytesPerRow, colorSpace,                     kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
        CGColorSpaceRelease(colorSpace);

        CGContextDrawImage(context1, CGRectMake(0, 0, firstImageV.image.size.width, firstImageV.image.size.height), imageRef);

        NSLog(@"%d::%d",width,height);


       // for(int ii = 0 ; ii < 250   ; ii+=4)
        //{

            for(int ii = 0 ; ii < length ; ii+=4)
            {
            //NSLog(@"Raw data %s",rawData);

            int  R = rawData[ii];
            int G = rawData[ii+1];
            int B = rawData[ii+2];

            //        NSLog(@"%d   %d   %d", R, G, B);
            //if( ( (R>60)&&(R<237) ) || ((G>10)&&(G<120))||((B>4) && (B<120)))
                 //       if( ( (R>100)&&(R<186) ) || ((G>56)&&(G<130))||((B>30) && (B<120)))
                //        if( ( (R>188)&&(R<228) ) || ((G>123)&&(G<163))||((B>85) && (B<125)))
                       // if( ( (R>95)&&(R<260) ) || ((G>40)&&(G<210))||((B>20) && (B<170)))

                        //new code......

                if( ( (R>0)&&(R<260) ) || ((G>0)&&(G<210))||((B>0) && (B<170)))

                    {
                        rawData[ii+1]=R;//13;
                        rawData[ii+2]=G;//43;
                        rawData[ii+3]=value;//63
                    }
                }


        ctx = CGBitmapContextCreate(rawData,
                            CGImageGetWidth( imageRef ),
                            CGImageGetHeight( imageRef ),
                            8,
                            CGImageGetBytesPerRow( imageRef ),
                            CGImageGetColorSpace( imageRef ),
                            kCGImageAlphaPremultipliedLast );

        imageRef = CGBitmapContextCreateImage(ctx);
        UIImage* rawImage = [UIImage imageWithCGImage:imageRef];
        //UIImageView *ty=[[UIImageView alloc]initWithFrame:CGRectMake(100, 200, 400, 400)];
        //ty.image=rawImage;
        //[self.view addSubview:ty];
        [secondImageV setImage:rawImage];
        CGContextRelease(context1);
        CGContextRelease(ctx);  
        free(rawData);
    }
Casa answered 26/4, 2013 at 12:51 Comment(2)
This code changes not only face and hair but all the image, doesn't it ?Antiseptic
@SAMIR RATHOD can u help me in the same question of image face color change ? #37114240Ruano
H
1

Try to use GPUImage Framework by Brad Larson:

https://github.com/BradLarson/GPUImage

This is very powerful framework for working with images.

Read this question:

GPUImage create a custom Filter that change selected colors

Hope it helps!

Hy answered 17/5, 2013 at 21:9 Comment(0)
E
0

The quick answer is to change your ORs:

            if( ( (R>0)&&(R<260) ) || ((G>0)&&(G<210)) || ((B>0) && (B<170)))

to ANDs:

            if( ( (R>0)&&(R<260) ) && ((G>0)&&(G<210)) && ((B>0) && (B<170)))

Then adjust your RGB ranges to approximate the range of skin tones in the image (try with some sliders in your UI).

By the way, I presume you know that this:

        rawData[ii+1]=R;//13;
        rawData[ii+2]=G;//43;
        rawData[ii+3]=value;//63

is assigning the red channel to the green channel, the green channel to the blue channel, and value to the ALPHA channel. I don't expect that is what you want.

Also your needToModified image is probably intended to be the same image as firstImageV.image, which is not reflected in your code as it is now.

This approach will only work if your identified colour ranges are wholly and only present in flesh regions of the image.

A long answer could look at more sophisticated selection of colour ranges, alternative ways of selecting image regions, the use of CIFilter or the openCV framework...

Electrophoresis answered 26/4, 2013 at 17:43 Comment(2)
After applying the AND operator it will left some pixels from image and color all the image.I want to change only skin color.Casa
"This approach will only work if your identified colour ranges are wholly and only present in flesh regions of the image."...this is a very crude approach to selecting your region of interest. You really need something like Photoshop's magic wand tool to select adjacent similar areas of an image and some interactive user input / UI. I suggest you investigate openCV...Electrophoresis
T
0

Try Masking the image ... it will help to change the specific range of colors defined in mask

Code:

- (UIImage *)doctorTheImage:(UIImage *)originalImage
{

   const float brownsMask[6] = {85, 255, 85, 255, 85, 255};


    UIImageView *imageView = [[UIImageView alloc] initWithImage:originalImage];

    UIGraphicsBeginImageContext(originalImage.size);
    CGContextRef context = UIGraphicsGetCurrentContext();

    CGContextSetRGBFillColor (context, 1.0,1.0, 1.0, 1);


    CGContextFillRect(context, CGRectMake(0, 0, imageView.image.size.width, imageView.image.size.height));

    CGImageRef brownRef = CGImageCreateWithMaskingColors(imageView.image.CGImage, brownsMask);

    CGRect imageRect = CGRectMake(0, 0, imageView.image.size.width, imageView.image.size.height);

    CGContextTranslateCTM(context, 0, imageView.image.size.height);
    CGContextScaleCTM(context, 1.0, -1.0);
    //CGImageRef whiteRef = CGImageCreateWithMaskingColors(brownRef, whiteMask);
    CGContextDrawImage (context, imageRect, brownRef);

    //[originalImage drawInRect:CGRectMake(0, 0, imageView.image.size.width, imageView.image.size.height)];

    CGImageRelease(brownRef);
   // CGImageRelease(whiteRef);

    UIImage *doctoredImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return doctoredImage;
}
Throughcomposed answered 2/5, 2013 at 11:28 Comment(0)
A
0

CFDataGetBytePtr According to the docs, it Returns a read-only pointer to the bytes of a CFData object., are you sure you're not looking for CFDataGetBytes which Copies the byte contents of a CFData object to an external buffer. In which case you'll have to allocate your buffer to contain width * height * bpp. Once you have this copy, you can manipulate it anyway you want to create the new picture.

Pixel Selection According to your question, I seem to understand that you want to change skin color from White to Black. Your current code iterates over every pixel to change its color. You should evaluate the "distance" between the pixel color and what you're looking for, and if it's below a certain threshold process it. It might be easier to perform the operation in HSV than by dealing with RGB colors

Aeromancy answered 30/7, 2013 at 19:4 Comment(0)
D
0

1) Get a CGPath of face where you want to apply your algorithm. 2) Get width of CGimage.

int width = CGImageGetWidth(image);

3) Get pixel CGPoint of currently processing pixel. Check for the condition before applying your algorithm. And then apply your condition. That's it. Here is the sample portion of code.

CGFloat pointY = (int)(i/4)/(int)width;
CGFloat pointX = (int)(i/4)%(int)width;
CGPoint point = CGPointMake(pointX, pointY);

if (CGPathContainsPoint(yourFacePath, NULL, point, NO))
{
    if( ( (R>0)&&(R<260) ) || ((G>0)&&(G<210))||((B>0) && (B<170)))
    {
        rawData[ii+1]=R;//13;
        rawData[ii+2]=G;//43;
        rawData[ii+3]=value;//63
    }
}
Drawl answered 13/9, 2013 at 7:16 Comment(0)
O
0

make the face and the hair as objects. object have color and have a global method to change their colors. then in your main,make both objects (hair, face) and specify what you want to color exactly. This is the right approach. hope it helps!

Offish answered 25/2, 2015 at 16:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.