Reputation: 22707
I'm trying to get the average color of a CIImage
, using code that is similar to that of this question, but I get error messages in the console that say
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.
I guess the CIImage
originally comes from OpenGL, but where did I ask for a metal context? How can I avoid this error?
My code:
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];
I tried some other things like creating a NSBitmapImageRep
from the CIImage
and using -[NSBitmapImageRep colorAtX: y:]
but get similar errors.
Things are a bit more complicated than I initially thought. I'm doing this in the Objective-C part of a Core Image filter, and it turns out that my averaging code works every other time the filter gets called. When it succeeds, there is a partial backtrace
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
whereas when it fails and shows a console log error message, the partial backtrace is:
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
An answer suggests using a CIContext
created from a GL context (not EAGL, this is macOS). Using this approach, I get a console error message "Cannot render image (with an input Metal texture) using a opengl context." when the backtrace mentions CA::OGL::emit_filter
, but in either case I don't get a nonzero average color.
In my particular case, I do have a workaround. I wanted the average color to pass as a parameter to my filter's kernel. But instead I can pass the average color image to the kernel as a sampler, and let the kernel sample it to get the color. So it's probably not worth fighting with it.
Upvotes: 1
Views: 236
Reputation: 10383
When you initialize a CIContext
with init
or initWithOptions:
, it will be using Metal by default on all platforms now. You need to use contextWithEAGLContext:options:
initializer and pass the same EGAGLContext
that you used to create the texture of inputImage
, then Core Image can work with that image.
Note, however, that OpenGL is deprecated on all platforms. So this might stop working in the near future.
Upvotes: 1