0

UIImage の中央の 16 ピクセルの平均 UIColor を取得しようとしていますが、結果の色は決して正しいものではありません。ここで何が間違っていますか?ポイント パラメータが正しいことを確認しました。また、この同じポイントを使用して中心ピクセルの 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];
}
4

2 に答える 2

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];
}
于 2014-05-01T02:13:01.467 に答える
1

startPointからのピクセルを の 1 つ少ない値まで反復しているだけです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];
于 2013-06-27T23:25:49.223 に答える