"нераспознанный селектор" при попытке доступа к outputImage CIFilter

Я впервые экспериментирую с Core Image (на OS X, 10.7.3) и сталкиваюсь с кирпичной стеной. Я уверен, что это что-то глупое, что я делаю, и просто нужен кто-то, более знакомый со структурой, чтобы указать мне.

Рассмотрим следующий код (давайте оговорим, что imageURL является допустимым URL-адресом файла, указывающим на JPG на диске):

CIImage *inputImage = [CIImage imageWithContentsOfURL:imageURL];
CIFilter *filter = [CIFilter filterWithName:@"CIAreaAverage" keysAndValues:
                                                  kCIInputImageKey, inputImage,
                                                  kCIInputExtentKey, [inputImage valueForKey:@"extent"],
                                                  nil];
CIImage *outputImage = (CIImage *)[filter valueForKey:@"outputImage"];

При запуске этого кода запускается последняя строка:

0   CoreFoundation                      0x00007fff96c2efc6 __exceptionPreprocess + 198
1   libobjc.A.dylib                     0x00007fff9153cd5e objc_exception_throw + 43
2   CoreFoundation                      0x00007fff96cbb2ae -[NSObject doesNotRecognizeSelector:] + 190
3   CoreFoundation                      0x00007fff96c1be73 ___forwarding___ + 371
4   CoreFoundation                      0x00007fff96c1bc88 _CF_forwarding_prep_0 + 232
5   CoreImage                           0x00007fff8f03c38d -[CIAreaAverage outputImage] + 52
6   Foundation                          0x00007fff991d8384 _NSGetUsingKeyValueGetter + 62
7   Foundation                          0x00007fff991d8339 -[NSObject(NSKeyValueCoding) valueForKey:] + 392

Теперь в справочнике Core Image Filter Reference четко указано, что CIAreaAverage "возвращает однопиксельное изображение, которое содержит средний цвет для интересующей области". На самом деле, еще больше сбивает с толку, когда я проверяю атрибуты фильтра в отладчике (перед тем как valueForKey: вызов):

(lldb) po [filter attributes]
(id) $3 = 0x00007fb3e3ef0e00 {
    CIAttributeDescription = "Calculates the average color for the specified area in an image, returning the result in a pixel.";
    CIAttributeFilterCategories =     (
        CICategoryReduction,
        CICategoryVideo,
        CICategoryStillImage,
        CICategoryBuiltIn
    );
    CIAttributeFilterDisplayName = "Area Average";
    CIAttributeFilterName = CIAreaAverage;
    CIAttributeReferenceDocumentation = "http://developer.apple.com/cgi-bin/apple_ref.cgi?apple_ref=//apple_ref/doc/filter/ci/CIAreaAverage";
    inputExtent =     {
        CIAttributeClass = CIVector;
        CIAttributeDefault = "[0 0 640 80]";
        CIAttributeDescription = "A rectangle that specifies the subregion of the image that you want to process.";
        CIAttributeDisplayName = Extent;
        CIAttributeType = CIAttributeTypeRectangle;
        CIUIParameterSet = CIUISetBasic;
    };
    inputImage =     {
        CIAttributeClass = CIImage;
        CIAttributeDescription = "The image to process.";
        CIAttributeDisplayName = Image;
        CIUIParameterSet = CIUISetBasic;
    };
    outputImage =     {
        CIAttributeClass = CIImage;
    };
}

Там в outputImage прямо здесь - задано как тип CIImage!

Итак, что я делаю не так? Все документы и учебники, которые я видел, показывают, что -valueForKey: правильный способ доступа к атрибутам, в том числе outputImage,

2 ответа

Решение

Я полагаю, что ваша степень виновник (как бы странно это ни было). Когда я изменяю экстенты на CIVector*, это работает.

NSURL *imageURL = [NSURL fileURLWithPath:@"/Users/david/Desktop/video.png"];
CIImage *inputImage = [CIImage imageWithContentsOfURL:imageURL];
CIFilter *filter = [CIFilter filterWithName:@"CIAreaAverage"];
[filter setValue:inputImage forKey:kCIInputImageKey];
CGRect inputExtent = [inputImage extent];
CIVector *extent = [CIVector vectorWithX:inputExtent.origin.x
                                       Y:inputExtent.origin.y
                                       Z:inputExtent.size.width
                                       W:inputExtent.size.height];
[filter setValue:extent forKey:kCIInputExtentKey];
CIImage *outputImage = [filter valueForKey:@"outputImage"];

[inputImage экстент] возвращает CGRect, но, очевидно, CIVector* работает лучше.

Вот как я заставил CIAreaAverage работать в приложении для iOS:

CGRect inputExtent = [self.inputImage extent];
CIVector *extent = [CIVector vectorWithX:inputExtent.origin.x
                                       Y:inputExtent.origin.y
                                       Z:inputExtent.size.width
                                       W:inputExtent.size.height];
CIImage* inputAverage = [CIFilter filterWithName:@"CIAreaAverage" keysAndValues:@"inputImage", self.inputImage, @"inputExtent", extent, nil].outputImage;

//CIImage* inputAverage = [self.inputImage imageByApplyingFilter:@"CIAreaMinimum" withInputParameters:@{@"inputImage" : inputImage, @"inputExtent" : extent}];
EAGLContext *myEAGLContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
NSDictionary *options = @{ kCIContextWorkingColorSpace : [NSNull null] };
CIContext *myContext = [CIContext contextWithEAGLContext:myEAGLContext options:options];

size_t rowBytes = 32 ; // ARGB has 4 components
uint8_t byteBuffer[rowBytes]; // Buffer to render into

[myContext render:inputAverage toBitmap:byteBuffer rowBytes:rowBytes bounds:[inputAverage extent] format:kCIFormatRGBA8 colorSpace:nil];

const uint8_t* pixel = &byteBuffer[0];
float red   = pixel[0] / 255.0;
float green = pixel[1] / 255.0;
float blue  = pixel[2] / 255.0;
NSLog(@"%f, %f, %f\n", red, green, blue);


return outputImage;
}
@end

Вывод будет выглядеть примерно так:

2015-05-23 15:58:20.935 CIFunHouse[2400:489913] 0.752941, 0.858824, 0.890196
2015-05-23 15:58:20.981 CIFunHouse[2400:489913] 0.752941, 0.858824, 0.890196
Другие вопросы по тегам