Как я могу получить средний цвет CIImage без ошибок

Я пытаюсь получить средний цвет CIImage, используя код, аналогичный коду этот вопрос, но я получаю сообщения об ошибках в консоли, которые говорят

Cannot render image (with an input GL texture) using a metal-DG context.
Failed to render 1 pixels because a CIKernel's ROI function did not allow tiling.

Я предполагаю, что CIImage изначально исходит из OpenGL, но где я просил металлический контекст? Как я могу избежать этой ошибки?

Мой код:

CIFilter*   aveFilter = [CIFilter filterWithName: @"CIAreaAverage"];
[aveFilter setValue: inputImage forKey: @"inputImage"];

CGRect  srcExtent = [inputImage extent];
CIVector* extentVec = [CIVector
    vectorWithX: srcExtent.origin.x
    Y: srcExtent.origin.y
    Z: srcExtent.size.width
    W: srcExtent.size.height ];
[aveFilter setValue: extentVec forKey: @"inputExtent"];
CIImage*    aveColorPixel = [aveFilter valueForKey: @"outputImage"];

CIContext* bitContext = [[[CIContext alloc]
    initWithOptions: @{
        kCIContextWorkingColorSpace: [NSNull null],
        kCIContextWorkingFormat: @(kCIFormatRGBA8)
    }] autorelease];

unsigned char bitmap[4];
[bitContext render: aveColorPixel
            toBitmap: bitmap
            rowBytes: 4
            bounds: CGRectMake( 0.0, 0.0, 1.0, 1.0 )
            format: kCIFormatRGBA8
            colorSpace: nil];

Я пробовал некоторые другие вещи, такие как создание NSBitmapImageRep из CIImage и использование -[NSBitmapImageRep colorAtX: y:], но получаю аналогичные ошибки.


Все немного сложнее, чем я думал изначально. Я делаю это в части Objective-C фильтра Core Image, и оказывается, что мой код усреднения работает каждый раз, когда вызывается фильтр. Когда это удается, есть частичная обратная трассировка

frame #3: 0x00007fff41a35351 QuartzCore`CA::OGL::apply_cifilter(CA::Render::Filter const*, void const*) + 123
frame #4: 0x00007fff419cbc34 QuartzCore`CA::OGL::emit_filter(CA::OGL::Renderer&, CA::OGL::Filter const&, CA::OGL::Layer const&, float, CA::OGL::Surface*, float, CA::Vec2<float>, CA::Shape const*, float*) + 1678
frame #5: 0x00007fff41949ddd QuartzCore`CA::OGL::FilterNode::apply(float, CA::OGL::Surface**, float*) + 673
frame #6: 0x00007fff41936889 QuartzCore`CA::OGL::ImagingNode::render(CA::OGL::ImagingNode::RenderClosure*, unsigned int) + 473
frame #7: 0x00007fff4193edad QuartzCore`CA::OGL::ImagingNode::retain_surface(float&, unsigned int) + 171
frame #8: 0x00007fff41936743 QuartzCore`CA::OGL::ImagingNode::render(CA::OGL::ImagingNode::RenderClosure*, unsigned int) + 147

тогда как, когда он терпит неудачу и показывает сообщение об ошибке журнала консоли, частичная обратная трассировка:

frame #3: 0x00007fff41a35351 QuartzCore`CA::OGL::apply_cifilter(CA::Render::Filter const*, void const*) + 123
frame #4: 0x00007fff41942cd3 QuartzCore`CA::OGL::measure_filter(CA::OGL::Renderer&, CA::OGL::Filter const&, CA::OGL::Layer const&, CA::OGL::Gstate const&, CA::Bounds const&, CA::Bounds&) + 267
frame #5: 0x00007fff41942b2c QuartzCore`CA::OGL::FilterNode::propagate_roi(CA::Bounds const&) + 58
frame #6: 0x00007fff41935c2b QuartzCore`CA::OGL::ImagingNode::set_roi(CA::Shape const*) + 405
frame #7: 0x00007fff419356d8 QuartzCore`CA::OGL::prepare_layers_roi(CA::OGL::Renderer&, CA::OGL::Layer*, CA::OGL::Gstate const&) + 974
frame #8: 0x00007fff41a42a3d QuartzCore`CA::OGL::LayerNode::prepare_sublayers_roi_if_needed() + 43
frame #9: 0x00007fff41937f08 QuartzCore`CA::OGL::LayerNode::apply(float, CA::OGL::Surface**, float*) + 150
frame #10: 0x00007fff41936889 QuartzCore`CA::OGL::ImagingNode::render(CA::OGL::ImagingNode::RenderClosure*, unsigned int) + 473

В ответе предлагается использовать CIContext, созданный из контекста GL (не EAGL, это macOS). Используя этот подход, я получаю сообщение об ошибке консоли. Невозможно отобразить изображение (с входной металлической текстурой) с использованием контекста opengl. когда в трассировке упоминается CA::OGL::emit_filter, но в любом случае я не получаю ненулевой средний цвет.

В моем конкретном случае у меня есть обходной путь. Я хотел, чтобы средний цвет передавался в качестве параметра ядру моего фильтра. Но вместо этого я могу передать усредненное цветное изображение ядру в качестве сэмплера и позволить ядру сэмплировать его, чтобы получить цвет. Так что бороться с этим, наверное, не стоит.


person JWWalker    schedule 23.07.2020    source источник


Ответы (1)


Когда вы инициализируете CIContext с помощью init или initWithOptions:, теперь он будет использовать Metal по умолчанию на всех платформах. Вам нужно использовать инициализатор contextWithEAGLContext:options: и передать тот же EGAGLContext, который вы использовали для создания текстуры inputImage, после чего Core Image сможет работать с этим изображением.

Обратите внимание, однако, что OpenGL устарел на всех платформах. Так что это может перестать работать в ближайшем будущем.

person Frank Schlegel    schedule 25.07.2020