CGImageCreate с CGColorSpaceCreateDeviceGray на iOS12

Я использовал CGImageCreate с CGColorSpaceCreateDeviceGray для преобразования буфера (CVPixelBufferRef) в изображение в градациях серого. Это было очень быстро и хорошо работало до iOS 12... теперь возвращаемое изображение пустое.

Код выглядит так:

bitmapInfo = kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst;

CGDataProviderRef provider = CGDataProviderCreateWithData((void *)i_PixelBuffer,
                                                              sourceBaseAddr,
                                                              sourceRowBytes * height,
                                                              ReleaseCVPixelBuffer);
    retImage = CGImageCreate(width,
                             height,
                             8,
                             32,
                             sourceRowBytes,
                             CGColorSpaceCreateDeviceGray(),
                             bitmapInfo,
                             provider,
                             NULL,
                             true,
                             kCGRenderingIntentDefault);
    CGDataProviderRelease(provider);

Это известная ошибка в iOS 12? Если эта функция больше не поддерживает серый цвет устройства, можете ли вы предложить мне другой способ сделать это?

Обратите внимание, что преобразование должно занять менее 0,1 секунды для изображения 4K.

Заранее спасибо!


person David Gagnon    schedule 23.10.2018    source источник
comment
Я полагаю, вы могли бы рассматривать буфер как CIImage и обесцвечивать его или что-то подобное.   -  person matt    schedule 23.10.2018
comment
Кстати, мне интересно, связано ли это каким-то образом с новой функцией iOS 12, когда графический контекст самостоятельно настраивает свою глубину в зависимости от того, что вы в нем рисуете. Эта новая функция тоже доставила мне немало хлопот.   -  person matt    schedule 23.10.2018


Ответы (2)


Согласно списку Поддерживаемые форматы пикселей в Руководстве по программированию Quartz 2D, iOS не поддерживает 32 бита на пиксель с серыми цветовыми пространствами. И даже в macOS серый цвет 32 бит на пиксель требует использования kCGBitmapFloatComponents (и данных с плавающей запятой).

Ваши данные действительно 32 бит на пиксель? Если да, то он плавающий? Что вы используете для bitmapInfo?

Я бы не ожидал, что CGImageCreate() "преобразует" буфер, в том числе в оттенки серого. Предоставляемые вами параметры указывают, как интерпретировать данные. Если вы не используете компоненты с плавающей запятой, я подозреваю, что вы просто берете один из цветовых каналов и интерпретируете его как уровень серого и игнорируете другие компоненты. Таким образом, это не было правильным преобразованием оттенков серого.

Apple советует создать изображение, которое правильно представляет изображение; создайте контекст растрового изображения с цветовым пространством, расположением пикселей и растровой информацией, которую вы хотите; втянуть первое во второе; и создайте финальное изображение из контекста.

person Ken Thomases    schedule 23.10.2018
comment
Вы знаете об этом гораздо больше, чем я, но я не могу отделаться от ощущения, что мы не понимаем, почему это якобы работает в iOS 11. - person matt; 23.10.2018
comment
@matt Мое предположение находится в моем третьем абзаце, но мы не можем быть уверены без а) дополнительной информации и б) некоторого тестирования исходных и полученных изображений и т. д. Это интересная загадка, но… *пожимает плечами* - person Ken Thomases; 23.10.2018
comment
Спасибо за ответ на мой вопрос! Мои данные, вероятно, в порядке, потому что они работают в течение длительного времени, в настоящее время данные kCVPixelFormatType_32BGRA. И да, возможно, что один из цветовых каналов использовался для черно-белого преобразования. - person David Gagnon; 27.10.2018

Наконец-то я нашел обходной путь для своей цели. Обратите внимание, что CVPixelBuffer поступает с видеокамеры.

  • Формат выходных пикселей камеры изменен на
    kCVPixelFormatType_420YpCbCr8BiPlanarFullRange (AVCaptureVideoDataOutput).
  • Извлеките плоскость Y из YpCbCr
  • Создайте CGImage с плоскостью Y

Код:

// some code

colorSpace = CGColorSpaceCreateDeviceGray();
sourceRowBytes = CVPixelBufferGetBytesPerRowOfPlane(i_PixelBuffer, 0);
sourceBaseAddr = (unsigned char*)CVPixelBufferGetBaseAddressOfPlane(i_PixelBuffer,0);
bitmapInfo = kCGImageByteOrderDefault;

// some code

CGContextRef context = CGBitmapContextCreate(sourceBaseAddr,
                                             width,
                                             height,
                                             8,
                                             sourceRowBytes,
                                             colorSpace,
                                             bitmapInfo);
retImage = CGBitmapContextCreateImage(context);

// some code

Вы также можете посмотреть этот связанный пост: 6315159#6315159">420YpCbCr8BiPlanarVideoRange To YUV420?/Как скопировать плоскости Y и Cbcr в одну плоскость?

person David Gagnon    schedule 07.01.2019