2013-06-27 4 views
0

Я пытаюсь получить средний UIColor центра 16 пикселей UIImage, однако полученный цвет никогда не близок к правильности. Что я здесь делаю неправильно? Точный параметр правильный, я это проверил. У меня также есть другой метод, который просто возвращает 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++) 

исправит это?

Кроме того, вам придется настроить rowPtr, чтобы начать в вашем xStartPoint:

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 и т. Д. Ваш пробег может отличаться, но я нашел, что это работает для меня.

Это не совсем очищено и может показаться немного странным, но оно работает.

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