2013-06-27 40 views
0

我想获得UIImage的中心16像素的平均UIColor,但是结果颜色永远不会接近正确。我在这里做错了什么?点参数是正确的,我已经验证了这一点。我还有另一种方法,它使用这个效果很好的相同点返回中心像素的UIColor。UIImage和查找中心像素的平均UIColor

+ (UIColor*)getAverageColorForImage:(UIImage *)image atLocation:(CGPoint)point 
{ 
    int radialSize = 2; 

    int xStartPoint = point.x - radialSize; 
    int yStartPoint = point.y - radialSize; 
    int xEndPoint = point.x + radialSize; 
    int yEndPoint = point.y + radialSize; 

    CGImageRef rawImageRef = [image CGImage]; 

    CFDataRef data = CGDataProviderCopyData(CGImageGetDataProvider(rawImageRef)); 
    const UInt8 *rawPixelData = CFDataGetBytePtr(data); 

    NSUInteger bytesPerRow = CGImageGetBytesPerRow(rawImageRef); 
    NSUInteger stride = CGImageGetBitsPerPixel(rawImageRef)/8; 

    unsigned int red = 0; 
    unsigned int green = 0; 
    unsigned int blue = 0; 

    for(int row = yStartPoint; row < yEndPoint; row++) 
    { 
     const UInt8 *rowPtr = rawPixelData + bytesPerRow * row; 

     for(int column = xStartPoint; column < xEndPoint; column++) 
     { 
      red += rowPtr[0]; 
      green += rowPtr[1]; 
      blue += rowPtr[2]; 

      rowPtr += stride; 
     } 
    } 

    CFRelease(data); 

    CGFloat f = 1.0f/(255.0f * (yEndPoint - yStartPoint) * (xEndPoint - xStartPoint)); 
    return [UIColor colorWithRed:f * red green:f * green blue:f * blue alpha:1.0f]; 
} 

回答

1

你只迭代的像素从startPoint到一个更低的endPoint。也许使用

for(int row = yStartPoint; row <= yEndPoint; row++) 
// ... 
for(int column = xStartPoint; column <= xEndPoint; column++) 

会修复它吗?你

也将有调整rowPtrxStartPoint开始:

const UInt8 *rowPtr = rawPixelData + bytesPerRow * row + stride * xStartPoint; 

否则你会x = 0的每一行开始。

而且你的平均分应计算如下所示:

int numberOfPixels = (yEndPoint - yStartPoint) * (xEndPoint - xStartPoint); 

red /= numberOfPixels; 
green /= numberOfPixels; 
blue /= numberOfPixels; 

return [UIColor colorWithRed:red/255.0 green:green/255.0 blue:blue/255.0 alpha:1.0f]; 
+0

感谢您指出了这一点。我已经更新了代码,但是颜色仍然会出现 - 尽管当我指向图像的不同部分时颜色现在正在改变。我得到了很多紫色,粉红色,紫罗兰。我想,还有些事情还没有结束。我试着将radialSize变量降到1来尝试平均更少的像素,但仍然不正确。 – mservidio

+0

你可以上传一个示例图片,并写出明确的调用你的方法? – Danilo

+0

实际上尝试别的,我会更新我的答案。 – Danilo

1

这篇文章是从相当长一段时间以前,但任何人碰到这个希望做类似的东西运行,我相信我已经找到了解决办法。实质上,这是一个Photoshop颜色采样器在选择3x3,5x5,11x11等选项时的功能。你的里程可能会有所不同,但我发现这对我有用。

这不是真的清理,可能看起来有点janky,但它的作品。

+ (UIColor*)getAverageColorForImage:(UIImage *)image atLocation:(CGPoint)point withRadius:(int)radialSize 
{ 
    int sampleSize = (radialSize * 2) + 1; 
    int pixelsToCount = sampleSize * sampleSize; 

    int xStartPoint = point.x - radialSize; 
    int yStartPoint = point.y - radialSize; 

    // Make sure we are not running off the edge of the image 
    if(xStartPoint < 0){ 
     xStartPoint = 0; 
    } 
    else if (xStartPoint + sampleSize > image.size.width){ 
     xStartPoint = image.size.width - sampleSize - 1; 
    } 

    if(yStartPoint < 0){ 
     yStartPoint = 0; 
    } 
    else if (yStartPoint + sampleSize > image.size.height){ 
     yStartPoint = image.size.height - sampleSize - 1; 
    } 

    // This is the representation of the pixels we would like to average 
    CGImageRef imageRef = CGImageCreateWithImageInRect(image.CGImage, CGRectMake(xStartPoint, yStartPoint, sampleSize, sampleSize)); 

    // Get the image dimensions 
    NSUInteger width = CGImageGetWidth(imageRef); 
    NSUInteger height = CGImageGetHeight(imageRef); 

    // Set the color space to RGB 
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 

    // Understand the bit length of the data 
    unsigned char *rawData = (unsigned char*) calloc(height * width * 4, sizeof(unsigned char)); 
    NSUInteger bytesPerPixel = 4; 
    NSUInteger bytesPerRow = bytesPerPixel * width; 
    NSUInteger bitsPerComponent = (NSUInteger)8; 

    // Set up a Common Graphics Context 
    CGContextRef context = CGBitmapContextCreate(rawData, width, height, bitsPerComponent, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big); 
    CGColorSpaceRelease(colorSpace); 

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

    // Now your rawData contains the image data in the RGBA8888 pixel format. 
    int byteIndex = (int)((bytesPerRow * 0) + 0 * bytesPerPixel); 

    CGFloat cumulativeRed = 0.0; 
    CGFloat cumulativeGreen = 0.0; 
    CGFloat cumulativeBlue = 0.0; 

    for (int ii = 0 ; ii < pixelsToCount ; ++ii){ 
     CGFloat red = (rawData[byteIndex]  * 1.0)/255.0; 
     CGFloat green = (rawData[byteIndex + 1] * 1.0)/255.0; 
     CGFloat blue = (rawData[byteIndex + 2] * 1.0)/255.0; 
     __unused CGFloat alpha = (rawData[byteIndex + 3] * 1.0)/255.0; 

     cumulativeRed += red; 
     cumulativeGreen += green; 
     cumulativeBlue += blue; 

     byteIndex += 4; 
    } 

    CGFloat avgRed = (cumulativeRed/pixelsToCount); 
    CGFloat avgGreen = (cumulativeGreen/pixelsToCount); 
    CGFloat avgBlue = (cumulativeBlue/pixelsToCount); 

    free(rawData); 

    return [UIColor colorWithRed:avgRed green:avgGreen blue:avgBlue alpha:1.0]; 
}