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

£可爱£侵袭症+ 提交于 2020-01-11 15:40:58

问题


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

回答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!




回答2:


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...




回答3:


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



回答4:


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




回答5:


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



回答6:


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!



来源:https://stackoverflow.com/questions/16236934/how-to-change-the-skin-color-of-face-from-the-source-image-in-ios

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!