【问题标题】:How to change the skin color of face from the source image in ios?如何从ios中的源图像更改面部的肤色?
【发布时间】:2013-04-20 15:46:11
【问题描述】:

我的代码: 如何管理不同肤色的RGB值,以及如何应用? 这段代码会随着头发改变脸的颜色,但我想要 1.除了头发,只涂脸。

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

【问题讨论】:

标签: iphone ios xcode4.2


【解决方案1】:

快速的答案是更改您的 OR:

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

到与:

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

然后调整 RGB 范围以接近图像中的肤色范围(尝试在 UI 中使用一些滑块)。

顺便说一句,我想你知道这个:

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

将红色通道分配给绿色通道,将绿色通道分配给蓝色通道,value 分配给 ALPHA 通道。我不希望那是你想要的。

此外,您的needToModified 图像可能与firstImageV.image 的图像相同,这不会像现在这样反映在您的代码中。

只有当您识别的颜色范围完全且仅存在于图像的肉块区域时,此方法才有效。

long 答案可以着眼于更复杂的颜色范围选择、选择图像区域的替代方法、CIFilter 或 openCV 框架的使用...

【讨论】:

  • 应用 AND 运算符后,它将从图像中留下一些像素并为所有图像着色。我只想更改肤色。
  • “这种方法仅在您识别的颜色范围完全且仅存在于图像的肉体区域时才有效。”...这是选择您感兴趣的区域的一种非常粗略的方法。你真的需要像 Photoshop 的魔棒工具来选择图像的相邻相似区域和一些交互式用户输入/UI。我建议你调查一下openCV...
【解决方案2】:

尝试遮罩图像...这将有助于更改遮罩中定义的特定颜色范围

代码:

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

【讨论】:

    【解决方案3】:

    尝试使用 Brad Larson 的 GPUImage 框架:

    https://github.com/BradLarson/GPUImage

    这是一个非常强大的图像处理框架。

    阅读这个问题:

    GPUImage create a custom Filter that change selected colors

    希望对你有帮助!

    【讨论】:

      【解决方案4】:

      CFDataGetBytePtr 根据文档,它返回一个指向 CFData 对象字节的只读指针。你确定你不是在寻找 CFDataGetBytes,它将 CFData 对象的字节内容复制到外部缓冲区。在这种情况下,您必须分配缓冲区以包含宽度 * 高度 * bpp。获得此副本后,您可以随意操作它来创建新图片。

      像素选择根据您的问题,我似乎了解您想将肤色从白色更改为黑色。您当前的代码遍历每个像素以更改其颜色。您应该评估像素颜色与您要查找的内容之间的“距离”,如果它低于某个阈值,请对其进行处理。在 HSV 中执行操作可能比处理 RGB 颜色更容易

      【讨论】:

        【解决方案5】:

        1) 获取要应用算法的人脸的 CGPath。 2) 获取CGimage的宽度。

        int width = CGImageGetWidth(image);
        

        3) 获取当前处理像素的像素CGPoint。在应用您的算法之前检查条件。然后应用你的条件。而已。这是代码的示例部分。

        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】:

          将脸部和头发作为对象。对象具有颜色并具有更改其颜色的全局方法。然后在你的主体中,制作两个对象(头发,脸)并指定你想要准确着色的内容。这是正确的做法。希望有帮助!

          【讨论】:

            猜你喜欢
            • 2012-05-18
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-04-11
            • 2016-11-18
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多